diff options
Diffstat (limited to 'arch/ppc/mm/init.c')
-rw-r--r-- | arch/ppc/mm/init.c | 132 |
1 files changed, 78 insertions, 54 deletions
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 44104fd4e..b80d4c21c 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -1,5 +1,5 @@ /* - * $Id: init.c,v 1.130 1998/11/10 10:09:20 paulus Exp $ + * $Id: init.c,v 1.139 1998/12/29 19:53:49 cort Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -55,7 +55,7 @@ /* END APUS includes */ int prom_trashed; -int next_mmu_context; +atomic_t next_mmu_context; unsigned long *end_of_DRAM; int mem_init_done; extern pgd_t swapper_pg_dir[]; @@ -71,7 +71,8 @@ unsigned long ioremap_base; unsigned long ioremap_bot; unsigned long avail_start; struct pgtable_cache_struct quicklists; -struct mem_info memory[NUM_MEMINFO]; +extern int num_memory; +extern struct mem_info memory[NUM_MEMINFO]; extern boot_infos_t *boot_infos; void MMU_init(void); @@ -89,6 +90,27 @@ void map_page(struct task_struct *, unsigned long va, extern void die_if_kernel(char *,struct pt_regs *,long); extern void show_net_buffers(void); + +/* + * The following stuff defines a data structure for representing + * areas of memory as an array of (address, length) pairs, and + * procedures for manipulating them. + */ +#define MAX_MEM_REGIONS 32 + +struct mem_pieces { + int n_regions; + struct reg_property regions[MAX_MEM_REGIONS]; +}; +struct mem_pieces phys_mem; +struct mem_pieces phys_avail; +struct mem_pieces prom_mem; + +static void remove_mem_piece(struct mem_pieces *, unsigned, unsigned, int); +void *find_mem_piece(unsigned, unsigned); +static void print_mem_pieces(struct mem_pieces *); +static void append_mem_piece(struct mem_pieces *, unsigned, unsigned); + extern struct task_struct *current_set[NR_CPUS]; PTE *Hash, *Hash_end; @@ -529,38 +551,19 @@ mmu_context_overflow(void) } read_unlock(&tasklist_lock); flush_hash_segments(0x10, 0xffffff); - next_mmu_context = 0; + atomic_set(&next_mmu_context, 0); /* make sure current always has a context */ - current->mm->context = MUNGE_CONTEXT(++next_mmu_context); + current->mm->context = MUNGE_CONTEXT(atomic_inc_return(&next_mmu_context)); set_context(current->mm->context); #else /* We set the value to -1 because it is pre-incremented before * before use. */ - next_mmu_context = -1; + atomic_set(&next_mmu_context, -1); #endif } /* - * The following stuff defines a data structure for representing - * areas of memory as an array of (address, length) pairs, and - * procedures for manipulating them. - */ -#define MAX_MEM_REGIONS 32 - -struct mem_pieces { - int n_regions; - struct reg_property regions[MAX_MEM_REGIONS]; -}; -struct mem_pieces phys_mem; -struct mem_pieces phys_avail; -struct mem_pieces prom_mem; - -static void remove_mem_piece(struct mem_pieces *, unsigned, unsigned, int); -void *find_mem_piece(unsigned, unsigned); -static void print_mem_pieces(struct mem_pieces *); - -/* * Scan a region for a piece of a given size with the required alignment. */ __initfunc(void * @@ -653,14 +656,26 @@ __initfunc(static void print_mem_pieces(struct mem_pieces *mp)) printk("\n"); } +/* + * Add some memory to an array of pieces + */ +__initfunc(static void + append_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size)) +{ + struct reg_property *rp; + if (mp->n_regions >= MAX_MEM_REGIONS) + return; + rp = &mp->regions[mp->n_regions++]; + rp->address = start; + rp->size = size; +} #ifndef CONFIG_8xx static void hash_init(void); static void get_mem_prop(char *, struct mem_pieces *); static void sort_mem_pieces(struct mem_pieces *); static void coalesce_mem_pieces(struct mem_pieces *); -static void append_mem_piece(struct mem_pieces *, unsigned, unsigned); __initfunc(static void sort_mem_pieces(struct mem_pieces *mp)) { @@ -703,21 +718,6 @@ __initfunc(static void coalesce_mem_pieces(struct mem_pieces *mp)) } /* - * Add some memory to an array of pieces - */ -__initfunc(static void - append_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size)) -{ - struct reg_property *rp; - - if (mp->n_regions >= MAX_MEM_REGIONS) - return; - rp = &mp->regions[mp->n_regions++]; - rp->address = start; - rp->size = size; -} - -/* * Read in a property describing some pieces of memory. */ @@ -963,8 +963,10 @@ __initfunc(void MMU_init(void)) #ifndef CONFIG_8xx if (have_of) end_of_DRAM = pmac_find_end_of_memory(); +#ifdef CONFIG_APUS else if (_machine == _MACH_apus ) end_of_DRAM = apus_find_end_of_memory(); +#endif else /* prep */ end_of_DRAM = prep_find_end_of_memory(); @@ -1023,8 +1025,10 @@ __initfunc(void MMU_init(void)) */ ioremap(NVRAM_ADDR, NVRAM_SIZE); ioremap(MBX_CSR_ADDR, MBX_CSR_SIZE); - ioremap(MBX_IMAP_ADDR, MBX_IMAP_SIZE); + ioremap(IMAP_ADDR, IMAP_SIZE); ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE); + /* ide needs to be able to get at PCI space -- Cort */ + ioremap(0x80000000, 0x4000); #endif /* CONFIG_8xx */ } @@ -1189,7 +1193,7 @@ __initfunc(unsigned long *mbx_find_end_of_memory(void)) volatile memctl8xx_t *mcp; unsigned long *ret; - binfo = (bd_t *)&res; + binfo = (bd_t *)res; /* * The MBX does weird things with the mmaps for ram. @@ -1200,11 +1204,13 @@ __initfunc(unsigned long *mbx_find_end_of_memory(void)) * In fact, it might be the best idea to just read the DRAM * config registers and set the mem areas accordingly. */ - mcp = (memctl8xx_t *)(&(((immap_t *)MBX_IMAP_ADDR)->im_memctl)); + mcp = (memctl8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_memctl)); + append_mem_piece(&phys_mem, 0, binfo->bi_memsize); +#if 0 phys_mem.regions[0].address = 0; - phys_mem.regions[0].size = binfo->bi_memsize; - + phys_mem.regions[0].size = binfo->bi_memsize; phys_mem.n_regions = 1; +#endif ret = __va(phys_mem.regions[0].address+ phys_mem.regions[0].size); @@ -1293,7 +1299,7 @@ __initfunc(unsigned long *pmac_find_end_of_memory(void)) /* * This finds the amount of physical ram and does necessary * setup for prep. This is pretty architecture specific so - * this will likely stay seperate from the pmac. + * this will likely stay separate from the pmac. * -- Cort */ __initfunc(unsigned long *prep_find_end_of_memory(void)) @@ -1322,6 +1328,7 @@ __initfunc(unsigned long *prep_find_end_of_memory(void)) return (__va(total)); } +#ifdef CONFIG_APUS #define HARDWARE_MAPPED_SIZE (512*1024) __initfunc(unsigned long *apus_find_end_of_memory(void)) { @@ -1381,15 +1388,22 @@ __initfunc(unsigned long *apus_find_end_of_memory(void)) /* Remove the upper 512KB where the PPC exception vectors are mapped. */ top -= HARDWARE_MAPPED_SIZE; - remove_mem_piece(&phys_avail, top, - HARDWARE_MAPPED_SIZE, 0); +#if 0 + /* This would be neat, but it breaks on A3000 machines!? */ + remove_mem_piece(&phys_avail, top, 16384, 0); +#else + remove_mem_piece(&phys_avail, top, HARDWARE_MAPPED_SIZE, 0); +#endif + } - /* FIXME:APUS: Only handles one block of memory! Problem is - that the VTOP/PTOV code in head.S would be a mess if it had - to handle more than one block. */ + /* Linux/APUS only handles one block of memory -- the one on + the PowerUP board. Other system memory is horrible slow in + comparison. The user can use other memory for swapping + using the z2ram device. */ return __va(memory[0].addr + memory[0].size); } +#endif /* CONFIG_APUS */ /* * Initialize the hash table and patch the instructions in head.S. @@ -1400,7 +1414,7 @@ __initfunc(static void hash_init(void)) unsigned long h, ramsize; extern unsigned int hash_page_patch_A[], hash_page_patch_B[], - hash_page_patch_C[]; + hash_page_patch_C[], hash_page[]; /* * Allow 64k of hash table for every 16MB of memory, @@ -1475,7 +1489,17 @@ __initfunc(static void hash_init(void)) flush_icache_range((unsigned long) b(hash_page_patch_A), (unsigned long) b(hash_page_patch_C + 1)); } - else + else { Hash_end = 0; + /* + * Put a blr (procedure return) instruction at the + * start of hash_page, since we can still get DSI + * exceptions on a 603. + */ + *b(hash_page) = 0x4e800020; + flush_icache_range((unsigned long) b(hash_page), + (unsigned long) b(hash_page + 1)); + } } #endif /* ndef CONFIG_8xx */ + |