diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-06-30 00:21:34 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-06-30 00:21:34 +0000 |
commit | 3917ac5846dd0f9ad1238166f90caab9912052e6 (patch) | |
tree | 1c298935def4f29edb39192365a65d73de999155 /arch/mips/mm/init.c | |
parent | af2f803c8b2d469fe38e4a7ce952658dfcb6681a (diff) |
o Merge with Linux 2.1.100.
o Cleanup the machine dependencies of floppy and rtc. The driver for
the Dallas thingy in the Indy is still missing.
o Handle allocation of zero'd pages correct for R4000SC / R4400SC.
o Page colouring shit to match the virtual and physical colour of all
mapped pages. This tends to produce extreme fragmentation problems,
so it's deactivated for now. Users of R4000SC / R4400SC may re-enable
the code in arch/mips/mm/init.c by removing the definition of
CONF_GIVE_A_SHIT_ABOUT_COLOURS. Should get them somewhat further -
but don't shake to hard ...
o Fixed ptrace(2)-ing of syscalls, strace is now working again.
o Fix the interrupt forwarding from the keyboard driver to the psaux
driver, PS/2 mice are now working on the Indy. The fix is somewhat
broken as it prevents generic kernels for Indy and machines which handle
things different.
o Things I can't remember.
Diffstat (limited to 'arch/mips/mm/init.c')
-rw-r--r-- | arch/mips/mm/init.c | 142 |
1 files changed, 133 insertions, 9 deletions
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index dd2fcbad2..f9ee7c554 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -1,11 +1,10 @@ -/* +/* $Id: init.c,v 1.5 1998/04/05 11:23:54 ralf Exp $ + * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1994, 1995, 1996 by Ralf Baechle - * - * $Id: init.c,v 1.4 1998/03/22 23:27:15 ralf Exp $ + * Copyright (C) 1994, 1995, 1996, 1997, 1998 by Ralf Baechle */ #include <linux/config.h> #include <linux/init.h> @@ -16,10 +15,12 @@ #include <linux/errno.h> #include <linux/string.h> #include <linux/types.h> +#include <linux/pagemap.h> #include <linux/ptrace.h> #include <linux/mman.h> #include <linux/mm.h> #include <linux/swap.h> +#include <linux/swapctl.h> #ifdef CONFIG_BLK_DEV_INITRD #include <linux/blk.h> #endif @@ -28,13 +29,17 @@ #include <asm/cachectl.h> #include <asm/dma.h> #include <asm/jazzdma.h> -#include <asm/vector.h> #include <asm/system.h> #include <asm/pgtable.h> #ifdef CONFIG_SGI #include <asm/sgialib.h> #endif +/* + * Define this to effectivly disable the userpage colouring shit. + */ +#define CONF_GIVE_A_SHIT_ABOUT_COLOURS + extern void deskstation_tyne_dma_init(void); extern void show_net_buffers(void); @@ -48,6 +53,46 @@ asmlinkage int sys_cacheflush(void *addr, int bytes, int cache) } /* + * We have upto 8 empty zeroed pages so we can map one of the right colour + * when needed. This is necessary only on R4000 / R4400 SC and MC versions + * where we have to avoid VCED / VECI exceptions for good performance at + * any price. Since page is never written to after the initialization we + * don't have to care about aliases on other CPUs. + */ +unsigned long empty_zero_page, zero_page_mask; + +static inline unsigned long setup_zero_pages(void) +{ + unsigned long order, size, pg; + + switch (mips_cputype) { + case CPU_R4000SC: + case CPU_R4000MC: + case CPU_R4400SC: + case CPU_R4400MC: + order = 3; + default: + order = 0; + } + + empty_zero_page = __get_free_pages(GFP_KERNEL, order); + if (!empty_zero_page) + panic("Oh boy, that early out of memory?"); + + pg = MAP_NR(empty_zero_page); + while(pg < MAP_NR(empty_zero_page) + (1 << order)) { + set_bit(PG_reserved, &mem_map[pg].flags); + pg++; + } + + size = PAGE_SIZE << order; + zero_page_mask = (size - 1) & PAGE_MASK; + memset((void *)empty_zero_page, 0, size); + + return size; +} + +/* * BAD_PAGE is the page that is used for page faults when linux * is out-of-memory. Older versions of linux just did a * do_exit(), but using this instead means there is less risk @@ -126,6 +171,83 @@ pte_t __bad_page(void) return pte_mkdirty(mk_pte(page, PAGE_SHARED)); } +#ifdef __SMP__ +spinlock_t user_page_lock = SPIN_LOCK_UNLOCKED; +#endif +struct upcache user_page_cache[8] __attribute__((aligned(32))); +static unsigned long user_page_order; +unsigned long user_page_colours; + +unsigned long get_user_page_slow(int which) +{ + unsigned long chunk; + struct upcache *up = &user_page_cache[0]; + struct page *p, *res; + int i; + + do { + chunk = __get_free_pages(GFP_KERNEL, user_page_order); + } while(chunk==0); + + p = mem_map + MAP_NR(chunk); + res = p + which; + spin_lock(&user_page_lock); + for (i=user_page_colours; i>=0; i--,p++,up++,chunk+=PAGE_SIZE) { + atomic_set(&p->count, 1); + p->age = PAGE_INITIAL_AGE; + + if (p != res) { + if(up->count < USER_PAGE_WATER) { + p->next = up->list; + up->list = p; + up->count++; + } else + free_pages(chunk, 0); + } + } + spin_unlock(&user_page_lock); + + return page_address(res); +} + +static inline void user_page_setup(void) +{ + unsigned long assoc = 0; + unsigned long dcache_log, icache_log, cache_log; + unsigned long config = read_32bit_cp0_register(CP0_CONFIG); + + switch(mips_cputype) { + case CPU_R4000SC: + case CPU_R4000MC: + case CPU_R4400SC: + case CPU_R4400MC: + cache_log = 3; /* => 32k, sucks */ + break; + + case CPU_R4600: /* two way set associative caches? */ + case CPU_R4700: + case CPU_R5000: + case CPU_NEVADA: + assoc = 1; + /* fall through */ + default: + /* use bigger cache */ + icache_log = (config >> 9) & 7; + dcache_log = (config >> 6) & 7; + if (dcache_log > icache_log) + cache_log = dcache_log; + else + cache_log = icache_log; + } + +#ifdef CONF_GIVE_A_SHIT_ABOUT_COLOURS + cache_log = assoc = 0; +#endif + + user_page_order = cache_log - assoc; + user_page_colours = (1 << (cache_log - assoc)) - 1; +} + void show_mem(void) { int i, free = 0, total = 0, reserved = 0; @@ -178,9 +300,6 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) max_mapnr = num_physpages = MAP_NR(end_mem); high_memory = (void *)end_mem; - /* clear the zero-page */ - clear_page((unsigned long)empty_zero_page); - /* mark usable pages in the mem_map[] */ start_mem = PAGE_ALIGN(start_mem); @@ -217,13 +336,18 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) free_page(tmp); } tmp = nr_free_pages << PAGE_SHIFT; + + /* Setup zeroed pages. */ + tmp -= setup_zero_pages(); + printk("Memory: %luk/%luk available (%dk kernel code, %dk data)\n", tmp >> 10, max_mapnr << (PAGE_SHIFT-10), codepages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10)); - return; + /* Initialize allocator for colour matched mapped pages. */ + user_page_setup(); } extern char __init_begin, __init_end; |