summaryrefslogtreecommitdiffstats
path: root/arch/sparc/mm
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-08-25 09:12:35 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-08-25 09:12:35 +0000
commitc7fc24dc4420057f103afe8fc64524ebc25c5d37 (patch)
tree3682407a599b8f9f03fc096298134cafba1c9b2f /arch/sparc/mm
parent1d793fade8b063fde3cf275bf1a5c2d381292cd9 (diff)
o Merge with Linux 2.1.116.
o New Newport console code. o New G364 console code.
Diffstat (limited to 'arch/sparc/mm')
-rw-r--r--arch/sparc/mm/Makefile20
-rw-r--r--arch/sparc/mm/fault.c4
-rw-r--r--arch/sparc/mm/io-unit.c15
-rw-r--r--arch/sparc/mm/iommu.c85
-rw-r--r--arch/sparc/mm/srmmu.c40
-rw-r--r--arch/sparc/mm/sun4c.c31
6 files changed, 120 insertions, 75 deletions
diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile
index 18eeb1f52..929b2a6f0 100644
--- a/arch/sparc/mm/Makefile
+++ b/arch/sparc/mm/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.30 1998/03/09 14:03:53 jj Exp $
+# $Id: Makefile,v 1.31 1998/07/26 03:02:45 davem Exp $
# Makefile for the linux Sparc-specific parts of the memory manager.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -22,8 +22,6 @@ endif
include $(TOPDIR)/Rules.make
-ifdef SMP
-
hypersparc.o: hypersparc.S
$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o hypersparc.o hypersparc.S
@@ -35,19 +33,3 @@ viking.o: viking.S
tsunami.o: tsunami.S
$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o tsunami.o tsunami.S
-
-else
-
-hypersparc.o: hypersparc.S
- $(CC) -D__ASSEMBLY__ -ansi -c -o hypersparc.o hypersparc.S
-
-turbosparc.o: turbosparc.S
- $(CC) -D__ASSEMBLY__ -ansi -c -o turbosparc.o turbosparc.S
-
-viking.o: viking.S
- $(CC) -D__ASSEMBLY__ -ansi -c -o viking.o viking.S
-
-tsunami.o: tsunami.S
- $(CC) -D__ASSEMBLY__ -ansi -c -o tsunami.o tsunami.S
-
-endif
diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c
index 274b9eebf..88d85004c 100644
--- a/arch/sparc/mm/fault.c
+++ b/arch/sparc/mm/fault.c
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.93 1998/03/25 10:43:16 jj Exp $
+/* $Id: fault.c,v 1.94 1998/05/01 16:00:27 jj Exp $
* fault.c: Page fault handlers for the Sparc.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -248,9 +248,11 @@ bad_area:
extern const unsigned __csum_partial_copy_start[];
extern const unsigned __csum_partial_copy_end[];
+#ifdef DEBUG_EXCEPTIONS
printk("Exception: PC<%08lx> faddr<%08lx>\n", regs->pc, address);
printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n",
regs->pc, fixup, g2);
+#endif
if ((regs->pc >= (unsigned long)__memset_start &&
regs->pc < (unsigned long)__memset_end) ||
(regs->pc >= (unsigned long)__csum_partial_copy_start &&
diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c
index d293fc71c..41bd72671 100644
--- a/arch/sparc/mm/io-unit.c
+++ b/arch/sparc/mm/io-unit.c
@@ -1,4 +1,4 @@
-/* $Id: io-unit.c,v 1.10 1998/03/03 12:31:14 jj Exp $
+/* $Id: io-unit.c,v 1.11 1998/04/13 07:26:37 davem Exp $
* io-unit.c: IO-UNIT specific routines for memory management.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -23,22 +23,17 @@
#define IOD(x) do { } while (0)
#endif
-#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
-
#define IOPERM (IOUPTE_CACHE | IOUPTE_WRITE | IOUPTE_VALID)
#define MKIOPTE(phys) __iopte((((phys)>>4) & IOUPTE_PAGE) | IOPERM)
-__initfunc(unsigned long
-iounit_init(int sbi_node, int io_node, unsigned long memory_start,
- unsigned long memory_end, struct linux_sbus *sbus))
+__initfunc(void
+iounit_init(int sbi_node, int io_node, struct linux_sbus *sbus))
{
iopte_t *xpt, *xptend;
struct iounit_struct *iounit;
struct linux_prom_registers iommu_promregs[PROMREG_MAX];
- memory_start = LONG_ALIGN(memory_start);
- iounit = (struct iounit_struct *)memory_start;
- memory_start = LONG_ALIGN(memory_start + sizeof(struct iounit_struct));
+ iounit = kmalloc(sizeof(struct iounit_struct), GFP_ATOMIC);
memset(iounit, 0, sizeof(*iounit));
iounit->limit[0] = IOUNIT_BMAP1_START;
@@ -62,8 +57,6 @@ iounit_init(int sbi_node, int io_node, unsigned long memory_start,
for (xptend = iounit->page_table + (16 * PAGE_SIZE) / sizeof(iopte_t);
xpt < xptend;)
*xpt++ = 0;
-
- return memory_start;
}
/* One has to hold iounit->lock to call this */
diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c
index e46216233..c7c6bdd5f 100644
--- a/arch/sparc/mm/iommu.c
+++ b/arch/sparc/mm/iommu.c
@@ -1,4 +1,4 @@
-/* $Id: iommu.c,v 1.7 1998/02/22 10:32:26 ecd Exp $
+/* $Id: iommu.c,v 1.9 1998/04/15 14:58:37 jj Exp $
* iommu.c: IOMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -10,6 +10,7 @@
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/mm.h>
#include <linux/malloc.h>
#include <asm/pgtable.h>
#include <asm/sbus.h>
@@ -26,14 +27,12 @@ static int viking_flush = 0;
extern void viking_flush_page(unsigned long page);
extern void viking_mxcc_flush_page(unsigned long page);
-#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
-
#define IOPERM (IOPTE_CACHE | IOPTE_WRITE | IOPTE_VALID)
#define MKIOPTE(phys) (((((phys)>>4) & IOPTE_PAGE) | IOPERM) & ~IOPTE_WAZ)
-static inline void iommu_map_dvma_pages_for_iommu(struct iommu_struct *iommu,
- unsigned long kern_end)
+static inline void iommu_map_dvma_pages_for_iommu(struct iommu_struct *iommu)
{
+ unsigned long kern_end = (unsigned long) high_memory;
unsigned long first = page_offset;
unsigned long last = kern_end;
iopte_t *iopte = iommu->page_table;
@@ -45,18 +44,17 @@ static inline void iommu_map_dvma_pages_for_iommu(struct iommu_struct *iommu,
}
}
-__initfunc(unsigned long
-iommu_init(int iommund, unsigned long memory_start,
- unsigned long memory_end, struct linux_sbus *sbus))
+__initfunc(void
+iommu_init(int iommund, struct linux_sbus *sbus))
{
unsigned int impl, vers, ptsize;
unsigned long tmp;
struct iommu_struct *iommu;
struct linux_prom_registers iommu_promregs[PROMREG_MAX];
+ int i, j, k, l, m;
+ struct iommu_alloc { unsigned long addr; int next; } *ia;
- memory_start = LONG_ALIGN(memory_start);
- iommu = (struct iommu_struct *) memory_start;
- memory_start += sizeof(struct iommu_struct);
+ iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC);
prom_getproperty(iommund, "reg", (void *) iommu_promregs,
sizeof(iommu_promregs));
iommu->regs = (struct iommu_regs *)
@@ -98,16 +96,68 @@ iommu_init(int iommund, unsigned long memory_start,
ptsize = iommu->end - iommu->start + 1;
ptsize = (ptsize >> PAGE_SHIFT) * sizeof(iopte_t);
- /* Stupid alignment constraints give me a headache. */
- memory_start = PAGE_ALIGN(memory_start);
- memory_start = (((memory_start) + (ptsize - 1)) & ~(ptsize - 1));
- iommu->lowest = iommu->page_table = (iopte_t *) memory_start;
- memory_start += ptsize;
+ /* Stupid alignment constraints give me a headache.
+ We want to get very large aligned memory area, larger than
+ maximum what get_free_pages gives us (128K): we need
+ 256K or 512K or 1M or 2M aligned to its size. */
+ ia = (struct iommu_alloc *) kmalloc (sizeof(struct iommu_alloc) * 128, GFP_ATOMIC);
+ for (i = 0; i < 128; i++) {
+ ia[i].addr = 0;
+ ia[i].next = -1;
+ }
+ k = 0;
+ for (i = 0; i < 128; i++) {
+ ia[i].addr = __get_free_pages(GFP_DMA, 5);
+ if (ia[i].addr <= ia[k].addr) {
+ if (i) {
+ ia[i].next = k;
+ k = i;
+ }
+ } else {
+ for (m = k, l = ia[k].next; l != -1; m = l, l = ia[l].next)
+ if (ia[i].addr <= ia[l].addr) {
+ ia[i].next = l;
+ ia[m].next = i;
+ }
+ if (l == -1)
+ ia[m].next = i;
+ }
+ for (m = -1, j = 0, l = k; l != -1; l = ia[l].next) {
+ if (!(ia[l].addr & (ptsize - 1))) {
+ tmp = ia[l].addr;
+ m = l;
+ j = 128 * 1024;
+ } else if (m != -1) {
+ if (ia[l].addr != tmp + j)
+ m = -1;
+ else {
+ j += 128 * 1024;
+ if (j == ptsize) {
+ break;
+ }
+ }
+ }
+ }
+ if (l != -1)
+ break;
+ }
+ if (i == 128) {
+ prom_printf("Could not allocate iopte of size 0x%08x\n", ptsize);
+ prom_halt();
+ }
+ for (l = m, j = 0; j < ptsize; j += 128 * 1024, l = ia[l].next)
+ ia[l].addr = 0;
+ for (l = k; l != -1; l = ia[l].next)
+ if (ia[l].addr)
+ free_pages(ia[l].addr, 5);
+ kfree (ia);
+ iommu->lowest = iommu->page_table = (iopte_t *)tmp;
+
/* Initialize new table. */
flush_cache_all();
memset(iommu->page_table, 0, ptsize);
- iommu_map_dvma_pages_for_iommu(iommu, memory_end);
+ iommu_map_dvma_pages_for_iommu(iommu);
if(viking_mxcc_present) {
unsigned long start = (unsigned long) iommu->page_table;
unsigned long end = (start + ptsize);
@@ -130,7 +180,6 @@ iommu_init(int iommund, unsigned long memory_start,
sbus->iommu = iommu;
printk("IOMMU: impl %d vers %d page table at %p of size %d bytes\n",
impl, vers, iommu->page_table, ptsize);
- return memory_start;
}
static __u32 iommu_get_scsi_one_noflush(char *vaddr, unsigned long len, struct linux_sbus *sbus)
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index f9794125d..97bd5be37 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.170 1998/03/09 14:04:01 jj Exp $
+/* $Id: srmmu.c,v 1.173 1998/08/04 20:48:57 davem Exp $
* srmmu.c: SRMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -512,7 +512,7 @@ static inline pgd_t *srmmu_get_pgd_fast(void)
pgd_cache_size--;
}
spin_unlock(&pgd_spinlock);
- return (pte_t *)ret;
+ return (pgd_t *)ret;
}
static inline pgd_t *srmmu_get_pgd_slow(void)
@@ -1034,7 +1034,7 @@ static void cypress_flush_cache_mm(struct mm_struct *mm)
FLUSH_BEGIN(mm)
flush_user_windows();
- save_and_cli(flags);
+ __save_and_cli(flags);
octx = srmmu_get_context();
srmmu_set_context(mm->context);
a = 0x20; b = 0x40; c = 0x60;
@@ -1058,7 +1058,7 @@ static void cypress_flush_cache_mm(struct mm_struct *mm)
"r" (e), "r" (f), "r" (g));
} while(faddr);
srmmu_set_context(octx);
- restore_flags(flags);
+ __restore_flags(flags);
FLUSH_END
}
@@ -1070,7 +1070,7 @@ static void cypress_flush_cache_range(struct mm_struct *mm, unsigned long start,
FLUSH_BEGIN(mm)
flush_user_windows();
- save_and_cli(flags);
+ __save_and_cli(flags);
octx = srmmu_get_context();
srmmu_set_context(mm->context);
a = 0x20; b = 0x40; c = 0x60;
@@ -1099,7 +1099,7 @@ static void cypress_flush_cache_range(struct mm_struct *mm, unsigned long start,
start += SRMMU_PMD_SIZE;
}
srmmu_set_context(octx);
- restore_flags(flags);
+ __restore_flags(flags);
FLUSH_END
}
@@ -1112,7 +1112,7 @@ static void cypress_flush_cache_page(struct vm_area_struct *vma, unsigned long p
FLUSH_BEGIN(mm)
flush_user_windows();
- save_and_cli(flags);
+ __save_and_cli(flags);
octx = srmmu_get_context();
srmmu_set_context(mm->context);
a = 0x20; b = 0x40; c = 0x60;
@@ -1138,7 +1138,7 @@ static void cypress_flush_cache_page(struct vm_area_struct *vma, unsigned long p
"r" (e), "r" (f), "r" (g));
} while(line != page);
srmmu_set_context(octx);
- restore_flags(flags);
+ __restore_flags(flags);
FLUSH_END
}
@@ -2019,7 +2019,7 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
pmd_t *pmdp;
pte_t *ptep;
- save_and_cli(flags);
+ __save_and_cli(flags);
file = vma->vm_file;
if (!file)
@@ -2065,7 +2065,7 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
flush_tlb_page(vma, address);
}
done:
- restore_flags(flags);
+ __restore_flags(flags);
}
}
@@ -2722,16 +2722,12 @@ __initfunc(static void get_srmmu_type(void))
srmmu_is_bad();
}
-/* Low and high watermarks for page table cache.
- The system should try to have pgt_water[0] <= cache elements <= pgt_water[1]
- */
-extern int pgt_cache_water[2];
-
-void srmmu_check_pgt_cache(void)
+static int srmmu_check_pgt_cache(int low, int high)
{
struct page *page, *page2;
+ int freed = 0;
- if (pgtable_cache_size > pgt_cache_water[0]) {
+ if (pgtable_cache_size > high) {
spin_lock(&pte_spinlock);
for (page2 = NULL, page = (struct page *)pte_quicklist; page;) {
if ((unsigned int)page->pprev_hash == 0xffff) {
@@ -2743,11 +2739,12 @@ void srmmu_check_pgt_cache(void)
page->pprev_hash = NULL;
pgtable_cache_size -= 16;
free_page(PAGE_OFFSET + (page->map_nr << PAGE_SHIFT));
+ freed++;
if (page2)
page = page2->next_hash;
else
page = (struct page *)pte_quicklist;
- if (pgtable_cache_size <= pgt_cache_water[1])
+ if (pgtable_cache_size <= low)
break;
continue;
}
@@ -2756,7 +2753,7 @@ void srmmu_check_pgt_cache(void)
}
spin_unlock(&pte_spinlock);
}
- if (pgd_cache_size > pgt_cache_water[0] / 4) {
+ if (pgd_cache_size > high / 4) {
spin_lock(&pgd_spinlock);
for (page2 = NULL, page = (struct page *)pgd_quicklist; page;) {
if ((unsigned int)page->pprev_hash == 0xf) {
@@ -2768,11 +2765,12 @@ void srmmu_check_pgt_cache(void)
page->pprev_hash = NULL;
pgd_cache_size -= 4;
free_page(PAGE_OFFSET + (page->map_nr << PAGE_SHIFT));
+ freed++;
if (page2)
page = page2->next_hash;
else
page = (struct page *)pgd_quicklist;
- if (pgd_cache_size <= pgt_cache_water[1] / 4)
+ if (pgd_cache_size <= low / 4)
break;
continue;
}
@@ -2781,6 +2779,7 @@ void srmmu_check_pgt_cache(void)
}
spin_unlock(&pgd_spinlock);
}
+ return freed;
}
extern unsigned long spwin_mmu_patchme, fwin_mmu_patchme,
@@ -2853,6 +2852,7 @@ __initfunc(void ld_mmu_srmmu(void))
BTFIXUPSET_CALL(get_pgd_fast, srmmu_get_pgd_fast, BTFIXUPCALL_RETINT(0));
BTFIXUPSET_CALL(free_pte_slow, srmmu_free_pte_slow, BTFIXUPCALL_NOP);
BTFIXUPSET_CALL(free_pgd_slow, srmmu_free_pgd_slow, BTFIXUPCALL_NOP);
+ BTFIXUPSET_CALL(do_check_pgt_cache, srmmu_check_pgt_cache, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(set_pgdir, srmmu_set_pgdir, BTFIXUPCALL_NORM);
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
index d247e1f2d..448881608 100644
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.163 1998/03/11 04:08:21 tdyas Exp $
+/* $Id: sun4c.c,v 1.166 1998/08/04 20:49:05 davem Exp $
* sun4c.c: Doing in software what should be done in hardware.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -611,9 +611,8 @@ __initfunc(static void sun4c_probe_mmu(void))
break;
case (SM_SUN4|SM_4_260):
- prom_printf("No support for 4200 yet\n");
- prom_halt();
- num_segmaps = 512;
+ /* should be 512 segmaps. when it get fixed */
+ num_segmaps = 256;
num_contexts = 16;
break;
@@ -658,7 +657,7 @@ __initfunc(void sun4c_probe_memerr_reg(void))
struct linux_prom_registers regs[1];
if (ARCH_SUN4) {
- sun4c_memerr_reg = sparc_alloc_io(SUN4_MEMREG_PHYSADDR, 0,
+ sun4c_memerr_reg = sparc_alloc_io(sun4_memreg_physaddr, 0,
PAGE_SIZE,
"memory parity error",
0x0, 0);
@@ -756,11 +755,13 @@ static inline void fix_permissions(unsigned long vaddr, unsigned long bits_on,
~bits_off);
}
+/* the 4/260 dies real hard on the prom_putsegment line.
+ not sure why, but it seems to work without it cgd */
static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
{
unsigned long vaddr;
unsigned char pseg, ctx;
-
+#ifndef CONFIG_SUN4
for(vaddr = KADB_DEBUGGER_BEGVM;
vaddr < LINUX_OPPROM_ENDVM;
vaddr += SUN4C_REAL_PGDIR_SIZE) {
@@ -772,6 +773,7 @@ static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0);
}
}
+#endif
for(vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
pseg = sun4c_get_segmap(vaddr);
mmu_entry_pool[pseg].locked = 1;
@@ -2536,6 +2538,22 @@ extern __inline__ pgd_t *sun4c_get_pgd_fast(void)
return (pgd_t *)ret;
}
+static int sun4c_check_pgt_cache(int low, int high)
+{
+ int freed = 0;
+ if(pgtable_cache_size > high) {
+ do {
+ if(pgd_quicklist)
+ free_pgd_slow(get_pgd_fast()), freed++;
+ if(pmd_quicklist)
+ free_pmd_slow(get_pmd_fast()), freed++;
+ if(pte_quicklist)
+ free_pte_slow(get_pte_fast()), freed++;
+ } while(pgtable_cache_size > low);
+ }
+ return freed;
+}
+
static void sun4c_set_pgdir(unsigned long address, pgd_t entry)
{
/* Nothing to do */
@@ -2803,6 +2821,7 @@ __initfunc(void ld_mmu_sun4c(void))
BTFIXUPSET_CALL(get_pgd_fast, sun4c_pgd_alloc, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(free_pte_slow, sun4c_free_pte_slow, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(free_pgd_slow, sun4c_free_pgd_slow, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(do_check_pgt_cache, sun4c_check_pgt_cache, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(set_pgdir, sun4c_set_pgdir, BTFIXUPCALL_NOP);