diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-08-25 09:12:35 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-08-25 09:12:35 +0000 |
commit | c7fc24dc4420057f103afe8fc64524ebc25c5d37 (patch) | |
tree | 3682407a599b8f9f03fc096298134cafba1c9b2f /arch/sparc/mm | |
parent | 1d793fade8b063fde3cf275bf1a5c2d381292cd9 (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/Makefile | 20 | ||||
-rw-r--r-- | arch/sparc/mm/fault.c | 4 | ||||
-rw-r--r-- | arch/sparc/mm/io-unit.c | 15 | ||||
-rw-r--r-- | arch/sparc/mm/iommu.c | 85 | ||||
-rw-r--r-- | arch/sparc/mm/srmmu.c | 40 | ||||
-rw-r--r-- | arch/sparc/mm/sun4c.c | 31 |
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); |