patch-2.3.30 linux/arch/ppc/mm/init.c

Next file: linux/arch/ppc/mm/mem_pieces.c
Previous file: linux/arch/ppc/mm/fault.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.29/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
@@ -40,6 +40,7 @@
 #include <linux/blk.h>		/* for initrd_* */
 #endif
 
+#include <asm/pgalloc.h>
 #include <asm/prom.h>
 #include <asm/io.h>
 #include <asm/mmu_context.h>
@@ -56,6 +57,10 @@
 #include <asm/amigahw.h>
 #include <asm/gemini.h>
 
+#include "mem_pieces.h"
+
+#define	PGTOKB(pages)	(((pages) * PAGE_SIZE) >> 10)
+
 int prom_trashed;
 atomic_t next_mmu_context;
 unsigned long *end_of_DRAM;
@@ -71,7 +76,6 @@
 extern char __pmac_begin, __pmac_end;
 extern char __apus_begin, __apus_end;
 extern char __openfirmware_begin, __openfirmware_end;
-char *klimit = _end;
 struct device_node *memory_node;
 unsigned long ioremap_base;
 unsigned long ioremap_bot;
@@ -98,34 +102,13 @@
 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;
-
-static void remove_mem_piece(struct mem_pieces *, unsigned, unsigned, int);
-static void set_phys_avail(void);
-void *find_mem_piece(unsigned, unsigned);
-static void print_mem_pieces(struct mem_pieces *);
-#if defined(CONFIG_PREP) || defined(CONFIG_APUS) || defined(CONFIG_ALL_PPC)
-static void append_mem_piece(struct mem_pieces *, unsigned, unsigned);
-#endif
 
 extern struct task_struct *current_set[NR_CPUS];
 
 PTE *Hash, *Hash_end;
 unsigned long Hash_size, Hash_mask;
-#ifndef CONFIG_8xx
+#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
 #ifdef CONFIG_PPC64
 unsigned long long _SDR1;
 #else
@@ -174,12 +157,10 @@
 	return 0;
 }
 
-#else /* CONFIG_8xx */
-
-/* 8xx doesn't have BATs */
+#else /* CONFIG_4xx || CONFIG_8xx */
 #define v_mapped_by_bats(x)	(0UL)
 #define p_mapped_by_bats(x)	(0UL)
-#endif /* CONFIG_8xx */
+#endif /* !CONFIG_4xx && !CONFIG_8xx */
 
 /*
  * this tells the system to map all of ram with the segregs
@@ -343,24 +324,23 @@
 
 void si_meminfo(struct sysinfo *val)
 {
-	int i;
+	int i, c;
 
 	i = max_mapnr;
-	val->totalram = 0;
-	val->sharedram = 0;
+	val->totalram = totalram_pages;
 	val->freeram = nr_free_pages();
 	val->bufferram = atomic_read(&buffermem_pages);
+	val->sharedram = 0;
 	while (i-- > 0)  {
 		if (PageReserved(mem_map+i))
 			continue;
-		val->totalram++;
-		if (!atomic_read(&mem_map[i].count))
-			continue;
-		val->sharedram += atomic_read(&mem_map[i].count) - 1;
-	}
-	val->totalram <<= PAGE_SHIFT;
-	val->sharedram <<= PAGE_SHIFT;
-	return;
+		c = atomic_read(&mem_map[i].count);
+		if (c > 1)
+			val->sharedram += c - 1;
+	}
+	val->totalhigh = 0;
+	val->freehigh = 0;
+	val->mem_unit = PAGE_SIZE;
 }
 
 void *
@@ -422,7 +402,7 @@
 	
 	if (mem_init_done) {
 		struct vm_struct *area;
-		area = get_vm_area(size, VM_ALLOC);
+		area = get_vm_area(size, VM_IOREMAP);
 		if (area == 0)
 			return NULL;
 		v = VMALLOC_VMADDR(area->addr);
@@ -593,195 +573,14 @@
 }
 #endif /* CONFIG_8xx */
 
-/*
- * Set phys_avail to phys_mem less the kernel text/data/bss.
- */
-static void __init set_phys_avail(void)
-{
-	unsigned long kstart, ksize;
-
-	/* we can't call the prom any more at this stage, so
-	   all of memory is available (after klimit) */
-	phys_avail = phys_mem;
-
-	/*
-	 * phys_avail records memory we can use.
-	 * Make sure the kernel text/data/bss is not in it.
-	 */
-	kstart = __pa(_stext);	/* should be 0 */
-	ksize = PAGE_ALIGN(klimit - _stext);
-	remove_mem_piece(&phys_avail, kstart, ksize, 0);
-	remove_mem_piece(&phys_avail, 0, 0x4000, 0);
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	if (initrd_start) {
-		/*
-		 * Remove the initialized ramdisk from the available memory.
-		 */
-		remove_mem_piece(&phys_avail, __pa(initrd_start),
-				 initrd_end - initrd_start, 1);
-	}
-#endif /* CONFIG_BLK_DEV_INITRD */
-}
-
-/*
- * Scan a region for a piece of a given size with the required alignment.
- */
-void __init *find_mem_piece(unsigned size, unsigned align)
-{
-	int i;
-	unsigned a, e;
-	struct mem_pieces *mp = &phys_avail;
-
-	for (i = 0; i < mp->n_regions; ++i) {
-		a = mp->regions[i].address;
-		e = a + mp->regions[i].size;
-		a = (a + align - 1) & -align;
-		if (a + size <= e) {
-			remove_mem_piece(mp, a, size, 1);
-			return __va(a);
-		}
-	}
-	printk("Couldn't find %u bytes at %u alignment\n", size, align);
-	abort();
-	return NULL;
-}
-
-/*
- * Remove some memory from an array of pieces
- */
-static void __init 
-remove_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size,
-		 int must_exist)
-{
-	int i, j;
-	unsigned end, rs, re;
-	struct reg_property *rp;
-
-	end = start + size;
-	for (i = 0, rp = mp->regions; i < mp->n_regions; ++i, ++rp) {
-		if (end > rp->address && start < rp->address + rp->size)
-			break;
-	}
-	if (i >= mp->n_regions) {
-		if (must_exist)
-			printk("remove_mem_piece: [%x,%x) not in any region\n",
-			       start, end);
-		return;
-	}
-	for (; i < mp->n_regions && end > rp->address; ++i, ++rp) {
-		rs = rp->address;
-		re = rs + rp->size;
-		if (must_exist && (start < rs || end > re)) {
-			printk("remove_mem_piece: bad overlap [%x,%x) with",
-			       start, end);
-			print_mem_pieces(mp);
-			must_exist = 0;
-		}
-		if (start > rs) {
-			rp->size = start - rs;
-			if (end < re) {
-				/* need to split this entry */
-				if (mp->n_regions >= MAX_MEM_REGIONS)
-					panic("eek... mem_pieces overflow");
-				for (j = mp->n_regions; j > i + 1; --j)
-					mp->regions[j] = mp->regions[j-1];
-				++mp->n_regions;
-				rp[1].address = end;
-				rp[1].size = re - end;
-			}
-		} else {
-			if (end < re) {
-				rp->address = end;
-				rp->size = re - end;
-			} else {
-				/* need to delete this entry */
-				for (j = i; j < mp->n_regions - 1; ++j)
-					mp->regions[j] = mp->regions[j+1];
-				--mp->n_regions;
-				--i;
-				--rp;
-			}
-		}
-	}
-}
-
-static void __init print_mem_pieces(struct mem_pieces *mp)
-{
-	int i;
-
-	for (i = 0; i < mp->n_regions; ++i)
-		printk(" [%x, %x)", mp->regions[i].address,
-		       mp->regions[i].address + mp->regions[i].size);
-	printk("\n");
-}
-
-#if defined(CONFIG_PREP) || defined(CONFIG_APUS) || defined(CONFIG_ALL_PPC)
-/*
- * Add some memory to an array of pieces
- */
-static void __init
-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;
-}
-#endif
-
-#ifndef CONFIG_8xx
-static void hash_init(void);
+#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
 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 __init sort_mem_pieces(struct mem_pieces *mp)
-{
-	unsigned long a, s;
-	int i, j;
-
-	for (i = 1; i < mp->n_regions; ++i) {
-		a = mp->regions[i].address;
-		s = mp->regions[i].size;
-		for (j = i - 1; j >= 0; --j) {
-			if (a >= mp->regions[j].address)
-				break;
-			mp->regions[j+1] = mp->regions[j];
-		}
-		mp->regions[j+1].address = a;
-		mp->regions[j+1].size = s;
-	}
-}
-
-static void __init coalesce_mem_pieces(struct mem_pieces *mp)
-{
-	unsigned long a, s, ns;
-	int i, j, d;
-
-	d = 0;
-	for (i = 0; i < mp->n_regions; i = j) {
-		a = mp->regions[i].address;
-		s = mp->regions[i].size;
-		for (j = i + 1; j < mp->n_regions
-			     && mp->regions[j].address - a <= s; ++j) {
-			ns = mp->regions[j].address + mp->regions[j].size - a;
-			if (ns > s)
-				s = ns;
-		}
-		mp->regions[d].address = a;
-		mp->regions[d].size = s;
-		++d;
-	}
-	mp->n_regions = d;
-}
 
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC)
 /*
  * Read in a property describing some pieces of memory.
  */
+
 static void __init get_mem_prop(char *name, struct mem_pieces *mp)
 {
 	struct reg_property *rp;
@@ -797,9 +596,10 @@
 	memcpy(mp->regions, rp, s);
 
 	/* Make sure the pieces are sorted. */
-	sort_mem_pieces(mp);
-	coalesce_mem_pieces(mp);
+	mem_pieces_sort(mp);
+	mem_pieces_coalesce(mp);
 }
+#endif /* CONFIG_PMAC || CONFIG_CHRP || CONFIG_ALL_PPC */
 
 /*
  * Set up one of the I/D BAT (block address translation) register pairs.
@@ -915,7 +715,7 @@
 				f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
 #ifndef CONFIG_8xx
 			else
-				/* On the powerpc (not 8xx), no user access
+				/* On the powerpc, denying user access
 				   forces R/W kernel access */
 				f |= _PAGE_USER;
 #endif /* CONFIG_8xx */
@@ -936,7 +736,7 @@
 	} else if (init_bootmem_done) {
 		p = alloc_bootmem_pages(PAGE_SIZE);
 	} else {
-		p = find_mem_piece(PAGE_SIZE, PAGE_SIZE);
+		p = mem_pieces_find(PAGE_SIZE, PAGE_SIZE);
 	}
 	if (p == 0)
 		panic("couldn't get a page in MMU_get_page");
@@ -997,18 +797,32 @@
 			 num_openfirmware_pages );
 	
 	printk ("Freeing unused kernel memory: %ldk init",
-		(num_freed_pages * PAGE_SIZE) >> 10);
+		PGTOKB(num_freed_pages));
+
 	if ( num_prep_pages )
-		printk(" %ldk prep",(num_prep_pages*PAGE_SIZE)>>10);
+		printk(" %ldk prep", PGTOKB(num_prep_pages));
 	if ( num_pmac_pages )
-		printk(" %ldk pmac",(num_pmac_pages*PAGE_SIZE)>>10);
+		printk(" %ldk pmac", PGTOKB(num_pmac_pages));
 	if ( num_openfirmware_pages )
-		printk(" %ldk open firmware",(num_openfirmware_pages*PAGE_SIZE)>>10);
+		printk(" %ldk open firmware", PGTOKB(num_openfirmware_pages));
 	if ( num_apus_pages )
-		printk(" %ldk apus",(num_apus_pages*PAGE_SIZE)>>10);
+		printk(" %ldk apus", PGTOKB(num_apus_pages));
 	printk("\n");
 }
 
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+	for (; start < end; start += PAGE_SIZE) {
+		ClearPageReserved(mem_map + MAP_NR(start));
+		set_page_count(mem_map+MAP_NR(start), 1);
+		free_page(start);
+		totalram_pages++;
+	}
+	printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+}
+#endif
+
 /*
  * Do very early mm setup such as finding the size of memory
  * and setting up the hash table.
@@ -1060,7 +874,7 @@
 		setbat(3, 0x90000000, 0x90000000, 0x10000000, IO_PAGE);
 		break;
 	case _MACH_Pmac:
-#if 0
+#if 1
 		{
 			unsigned long base = 0xf3000000;
 			struct device_node *macio = find_devices("mac-io");
@@ -1152,7 +966,8 @@
 				    __pa(end_of_DRAM) >> PAGE_SHIFT);
 
 	/* remove the bootmem bitmap from the available memory */
-	remove_mem_piece(&phys_avail, start, boot_mapsize, 1);
+	mem_pieces_remove(&phys_avail, start, boot_mapsize, 1);
+
 	/* add everything in phys_avail into the bootmem map */
 	for (i = 0; i < phys_avail.n_regions; ++i)
 		free_bootmem(phys_avail.regions[i].address,
@@ -1213,15 +1028,21 @@
 	empty_bad_page = alloc_bootmem_pages(PAGE_SIZE);
 	empty_bad_page_table = alloc_bootmem_pages(PAGE_SIZE);
 	{
-		unsigned int zones_size[2];
+		unsigned int zones_size[MAX_NR_ZONES], i;
 		/*
-		 * All pages are DMA-able so this is wrong - the zone code is assuming
-		 * both regions have a value so this is necessary for now.
+		 * All pages are DMA-able so this is wrong - the zone code is
+		 * assuming both regions have a value so this is necessary for
+		 * now.
 		 * -- Cort
 		 */
-		zones_size[0] = virt_to_phys(end_of_DRAM-(1<<20)) >> PAGE_SHIFT;
-		zones_size[1] = (1<<20) >> PAGE_SHIFT;
-
+#if 1
+		for ( i = 1; i < MAX_NR_ZONES; i++ )
+			zones_size[i] = 1<<MAX_ORDER;
+		zones_size[0] = (virt_to_phys(end_of_DRAM) >> PAGE_SHIFT) -
+			((MAX_NR_ZONES-1)*(1<<MAX_ORDER));
+#else
+		zones_size[0] = virt_to_phys(end_of_DRAM) >> PAGE_SHIFT;
+#endif
 		free_area_init(zones_size);
 	}
 }
@@ -1232,8 +1053,9 @@
 	int codepages = 0;
 	int datapages = 0;
 	int initpages = 0;
+#if defined(CONFIG_CHRP) || defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC)
 	extern unsigned int rtas_data, rtas_size;
-
+#endif /* CONFIG_CHRP || CONFIG_PMAC || CONFIG_ALL_PPC */
 	max_mapnr = max_low_pfn;
 	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
 	num_physpages = max_mapnr;	/* RAM is assumed contiguous */
@@ -1249,11 +1071,13 @@
 	}
 #endif /* CONFIG_BLK_DEV_INITRD */
 
+#if defined(CONFIG_CHRP) || defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC)
 	/* mark the RTAS pages as reserved */
 	if ( rtas_data )
-		for (addr = (rtas_data+PAGE_OFFSET); addr < PAGE_ALIGN(PAGE_OFFSET+rtas_data+rtas_size) ;
-		     rtas_data += PAGE_SIZE)
+		for (addr = rtas_data; addr < PAGE_ALIGN(rtas_data+rtas_size) ;
+		     addr += PAGE_SIZE)
 			SetPageReserved(mem_map + MAP_NR(addr));
+#endif /* CONFIG_CHRP || CONFIG_PMAC || CONFIG_ALL_PPC */
 	
 	for (addr = PAGE_OFFSET; addr < (unsigned long)end_of_DRAM;
 	     addr += PAGE_SIZE) {
@@ -1264,12 +1088,12 @@
 		else if (addr >= (unsigned long)&__init_begin
 			 && addr < (unsigned long)&__init_end)
 			initpages++;
-		else if (addr < (ulong) klimit)
+		else
 			datapages++;
 	}
 
         printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08x,%08lx]\n",
-	       (unsigned long) nr_free_pages << (PAGE_SHIFT-10),
+	       (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
 	       codepages << (PAGE_SHIFT-10),
 	       datapages << (PAGE_SHIFT-10), 
 	       initpages << (PAGE_SHIFT-10),
@@ -1277,7 +1101,7 @@
 	mem_init_done = 1;
 }
 
-#ifndef CONFIG_8xx
+#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
 #if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC)
 /*
  * On systems with Open Firmware, collect information about
@@ -1339,7 +1163,7 @@
 		phys_mem.n_regions = 1;
 	}
 
-	set_phys_avail();
+	set_phys_avail(&phys_mem);
 
 #undef RAM_LIMIT
 	return __va(total);
@@ -1368,8 +1192,8 @@
 		total = 0x02000000;
 		printk("Ramsize default to be %ldM\n", total>>20);
 	}
-	append_mem_piece(&phys_mem, 0, total);
-	set_phys_avail();
+	mem_pieces_append(&phys_mem, 0, total);
+	set_phys_avail(&phys_mem);
 
 	return (__va(total));
 }
@@ -1391,7 +1215,7 @@
 	phys_mem.n_regions = 1;
 	
 	ret = __va(phys_mem.regions[0].size);
-	set_phys_avail();
+	set_phys_avail(&phys_mem);
 	return ret;
 }
 #endif /* defined(CONFIG_GEMINI) */
@@ -1427,8 +1251,8 @@
 	}
 
 	/* Now register the memory block. */
-	append_mem_piece(&phys_mem, memory[0].addr, memory[0].size);
-	set_phys_avail();
+	mem_pieces_append(&phys_mem, memory[0].addr, memory[0].size);
+	set_phys_avail(&phys_mem);
 
 	/* Remove the memory chunks that are controlled by special
            Phase5 hardware. */
@@ -1442,8 +1266,8 @@
 		if (shadow)
 		{
 			top -= HARDWARE_MAPPED_SIZE;
-			remove_mem_piece(&phys_avail, top,
-					 HARDWARE_MAPPED_SIZE, 0);
+			mem_pieces_remove(&phys_avail, top,
+					  HARDWARE_MAPPED_SIZE, 0);
 		}
 
 		/* Remove the upper 512KB where the PPC exception
@@ -1451,9 +1275,9 @@
 		top -= HARDWARE_MAPPED_SIZE;
 #if 0
 		/* This would be neat, but it breaks on A3000 machines!? */
-		remove_mem_piece(&phys_avail, top, 16384, 0);
+		mem_pieces_remove(&phys_avail, top, 16384, 0);
 #else
-		remove_mem_piece(&phys_avail, top, HARDWARE_MAPPED_SIZE, 0);
+		mem_pieces_remove(&phys_avail, top, HARDWARE_MAPPED_SIZE, 0);
 #endif
 
 	}
@@ -1512,7 +1336,7 @@
 	if ( ppc_md.progress ) ppc_md.progress("hash:find piece", 0x322);
 	/* Find some memory for the hash table. */
 	if ( Hash_size )
-		Hash = find_mem_piece(Hash_size, Hash_size);
+		Hash = mem_pieces_find(Hash_size, Hash_size);
 	else
 		Hash = 0;
 
@@ -1590,7 +1414,7 @@
 	ret = __va(phys_mem.regions[0].address+
 		   phys_mem.regions[0].size);
 
-	set_phys_avail();
+	set_phys_avail(&phys_mem);
 	return ret;
 }
 #endif /* ndef CONFIG_8xx */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)