svn commit: r258807 - in head/sys/powerpc: booke include mpc85xx ofw powermac powerpc ps3 pseries wii

Nathan Whitehorn nwhitehorn at FreeBSD.org
Sun Dec 1 19:43:18 UTC 2013


Author: nwhitehorn
Date: Sun Dec  1 19:43:15 2013
New Revision: 258807
URL: http://svnweb.freebsd.org/changeset/base/258807

Log:
  Rearchitect platform memory map parsing to make it less
  Open Firmware-centric:
  - Keep the static list of regions in platform.c instead of ofw_machdep.c
  - Move various merging and sorting operations to platform.c as well
  - Move apple_hacks code out of ofw_machdep.c and into platform_powermac.c,
    where it belongs
  - Move CHRP-specific dynamic-reconfiguration memory parsing into
    platform_chrp.c instead of pretending it is shared code

Modified:
  head/sys/powerpc/booke/platform_bare.c
  head/sys/powerpc/include/ofw_machdep.h
  head/sys/powerpc/mpc85xx/platform_mpc85xx.c
  head/sys/powerpc/ofw/ofw_machdep.c
  head/sys/powerpc/powermac/platform_powermac.c
  head/sys/powerpc/powerpc/platform.c
  head/sys/powerpc/powerpc/platform_if.m
  head/sys/powerpc/ps3/platform_ps3.c
  head/sys/powerpc/pseries/platform_chrp.c
  head/sys/powerpc/wii/platform_wii.c

Modified: head/sys/powerpc/booke/platform_bare.c
==============================================================================
--- head/sys/powerpc/booke/platform_bare.c	Sun Dec  1 19:05:32 2013	(r258806)
+++ head/sys/powerpc/booke/platform_bare.c	Sun Dec  1 19:43:15 2013	(r258807)
@@ -45,8 +45,8 @@ __FBSDID("$FreeBSD$");
 extern uint32_t *bootinfo;
 
 static int bare_probe(platform_t);
-static void bare_mem_regions(platform_t, struct mem_region **phys, int *physsz,
-    struct mem_region **avail, int *availsz);
+static void bare_mem_regions(platform_t, struct mem_region *phys, int *physsz,
+    struct mem_region *avail, int *availsz);
 static u_long bare_timebase_freq(platform_t, struct cpuref *cpuref);
 
 static void bare_reset(platform_t);
@@ -80,8 +80,8 @@ bare_probe(platform_t plat)
 }
 
 void
-bare_mem_regions(platform_t plat, struct mem_region **phys, int *physsz,
-    struct mem_region **avail, int *availsz)
+bare_mem_regions(platform_t plat, struct mem_region *phys, int *physsz,
+    struct mem_region *avail, int *availsz)
 {
 
 	ofw_mem_regions(phys, physsz, avail, availsz);

Modified: head/sys/powerpc/include/ofw_machdep.h
==============================================================================
--- head/sys/powerpc/include/ofw_machdep.h	Sun Dec  1 19:05:32 2013	(r258806)
+++ head/sys/powerpc/include/ofw_machdep.h	Sun Dec  1 19:43:15 2013	(r258807)
@@ -45,7 +45,7 @@ boolean_t OF_bootstrap(void);
 
 void OF_reboot(void);
 
-void ofw_mem_regions(struct mem_region **, int *, struct mem_region **, int *);
+void ofw_mem_regions(struct mem_region *, int *, struct mem_region *, int *);
 void ofw_quiesce(void); /* Must be called before VM is up! */
 void ofw_save_trap_vec(char *);
 

Modified: head/sys/powerpc/mpc85xx/platform_mpc85xx.c
==============================================================================
--- head/sys/powerpc/mpc85xx/platform_mpc85xx.c	Sun Dec  1 19:05:32 2013	(r258806)
+++ head/sys/powerpc/mpc85xx/platform_mpc85xx.c	Sun Dec  1 19:43:15 2013	(r258807)
@@ -72,8 +72,8 @@ static int cpu, maxcpu;
 
 static int mpc85xx_probe(platform_t);
 static int mpc85xx_attach(platform_t);
-static void mpc85xx_mem_regions(platform_t, struct mem_region **phys,
-    int *physsz, struct mem_region **avail, int *availsz);
+static void mpc85xx_mem_regions(platform_t, struct mem_region *phys,
+    int *physsz, struct mem_region *avail, int *availsz);
 static u_long mpc85xx_timebase_freq(platform_t, struct cpuref *cpuref);
 static int mpc85xx_smp_first_cpu(platform_t, struct cpuref *cpuref);
 static int mpc85xx_smp_next_cpu(platform_t, struct cpuref *cpuref);
@@ -201,8 +201,8 @@ mpc85xx_attach(platform_t plat)
 }
 
 void
-mpc85xx_mem_regions(platform_t plat, struct mem_region **phys, int *physsz,
-    struct mem_region **avail, int *availsz)
+mpc85xx_mem_regions(platform_t plat, struct mem_region *phys, int *physsz,
+    struct mem_region *avail, int *availsz)
 {
 
 	ofw_mem_regions(phys, physsz, avail, availsz);

Modified: head/sys/powerpc/ofw/ofw_machdep.c
==============================================================================
--- head/sys/powerpc/ofw/ofw_machdep.c	Sun Dec  1 19:05:32 2013	(r258806)
+++ head/sys/powerpc/ofw/ofw_machdep.c	Sun Dec  1 19:43:15 2013	(r258807)
@@ -61,11 +61,6 @@ __FBSDID("$FreeBSD$");
 #include <machine/ofw_machdep.h>
 #include <machine/trap.h>
 
-static struct mem_region OFmem[PHYS_AVAIL_SZ], OFavail[PHYS_AVAIL_SZ];
-static struct mem_region OFfree[PHYS_AVAIL_SZ];
-
-static int	apple_hacks;
-
 #ifdef AIM
 extern register_t ofmsr[5];
 extern void	*openfirmware_entry;
@@ -80,7 +75,7 @@ static int	openfirmware(void *args);
 __inline void
 ofw_save_trap_vec(char *save_trap_vec)
 {
-	if (apple_hacks)
+	if (!ofw_real_mode)
                 return;
 
 	bcopy((void *)EXC_RST, save_trap_vec, EXC_LAST - EXC_RST);
@@ -89,7 +84,7 @@ ofw_save_trap_vec(char *save_trap_vec)
 static __inline void
 ofw_restore_trap_vec(char *restore_trap_vec)
 {
-	if (apple_hacks)
+	if (!ofw_real_mode)
                 return;
 
 	bcopy(restore_trap_vec, (void *)EXC_RST, EXC_LAST - EXC_RST);
@@ -104,7 +99,7 @@ register_t	ofw_sprg0_save;
 static __inline void
 ofw_sprg_prepare(void)
 {
-	if (!apple_hacks)
+	if (ofw_real_mode)
 		return;
 	
 	/*
@@ -126,8 +121,10 @@ ofw_sprg_prepare(void)
 static __inline void
 ofw_sprg_restore(void)
 {
-	if (!apple_hacks)
+#if 0
+	if (ofw_real_mode)
 		return;
+#endif
 	
 	/*
 	 * Note that SPRG1-3 contents are irrelevant. They are scratch
@@ -140,50 +137,6 @@ ofw_sprg_restore(void)
 }
 #endif
 
-/*
- * Memory region utilities: determine if two regions overlap,
- * and merge two overlapping regions into one
- */
-static int
-memr_overlap(struct mem_region *r1, struct mem_region *r2)
-{
-	if ((r1->mr_start + r1->mr_size) < r2->mr_start ||
-	    (r2->mr_start + r2->mr_size) < r1->mr_start)
-		return (FALSE);
-	
-	return (TRUE);	
-}
-
-static void
-memr_merge(struct mem_region *from, struct mem_region *to)
-{
-	vm_offset_t end;
-	end = ulmax(to->mr_start + to->mr_size, from->mr_start + from->mr_size);
-	to->mr_start = ulmin(from->mr_start, to->mr_start);
-	to->mr_size = end - to->mr_start;
-}
-
-/*
- * Quick sort callout for comparing memory regions.
- */
-static int	mr_cmp(const void *a, const void *b);
-
-static int
-mr_cmp(const void *a, const void *b)
-{
-	const struct	mem_region *regiona;
-	const struct	mem_region *regionb;
-
-	regiona = a;
-	regionb = b;
-	if (regiona->mr_start < regionb->mr_start)
-		return (-1);
-	else if (regiona->mr_start > regionb->mr_start)
-		return (1);
-	else
-		return (0);
-}
-
 static int
 parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
 {
@@ -209,14 +162,6 @@ parse_ofw_memory(phandle_t node, const c
 		size_cells = 1;
 
 	/*
-	 * On Apple hardware, address_cells is always 1 for "available",
-	 * even when it is explicitly set to 2. All memory above 4 GB
-	 * also needs to be added by hand to the available list.
-	 */
-	if (strcmp(prop, "available") == 0 && apple_hacks)
-		address_cells = 1;
-
-	/*
 	 * Get memory.
 	 */
 	if (node == -1 || (sz = OF_getprop(node, prop,
@@ -267,103 +212,9 @@ parse_ofw_memory(phandle_t node, const c
 	}
 	sz = j*sizeof(output[0]);
 
-	#ifdef __powerpc64__
-	if (strcmp(prop, "available") == 0 && apple_hacks) {
-		/* Add in regions above 4 GB to the available list */
-		struct mem_region himem[16];
-		int hisz;
-
-		hisz = parse_ofw_memory(node, "reg", himem);
-		for (i = 0; i < hisz/sizeof(himem[0]); i++) {
-			if (himem[i].mr_start > BUS_SPACE_MAXADDR_32BIT) {
-				output[j].mr_start = himem[i].mr_start;
-				output[j].mr_size = himem[i].mr_size;
-				j++;
-			}
-		}
-		sz = j*sizeof(output[0]);
-	}
-	#endif
-
 	return (sz);
 }
 
-static int
-parse_drconf_memory(int *msz, int *asz, struct mem_region *ofmem,
-		    struct mem_region *ofavail)
-{
-	phandle_t phandle;
-	vm_offset_t base;
-	int i, idx, len, lasz, lmsz, res;
-	uint32_t lmb_size[2];
-	unsigned long *dmem, flags;
-
-	lmsz = *msz;
-	lasz = *asz;
-
-	phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory");
-	if (phandle == -1)
-		/* No drconf node, return. */
-		return (0);
-
-	res = OF_getprop(phandle, "ibm,lmb-size", lmb_size, sizeof(lmb_size));
-	if (res == -1)
-		return (0);
-	printf("Logical Memory Block size: %d MB\n", lmb_size[1] >> 20);
-
-	/* Parse the /ibm,dynamic-memory.
-	   The first position gives the # of entries. The next two words
- 	   reflect the address of the memory block. The next four words are
-	   the DRC index, reserved, list index and flags.
-	   (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory)
-	   
-	    #el  Addr   DRC-idx  res   list-idx  flags
-	   -------------------------------------------------
-	   | 4 |   8   |   4   |   4   |   4   |   4   |....
-	   -------------------------------------------------
-	*/
-
-	len = OF_getproplen(phandle, "ibm,dynamic-memory");
-	if (len > 0) {
-
-		/* We have to use a variable length array on the stack
-		   since we have very limited stack space.
-		*/
-		cell_t arr[len/sizeof(cell_t)];
-
-		res = OF_getprop(phandle, "ibm,dynamic-memory", &arr,
-				 sizeof(arr));
-		if (res == -1)
-			return (0);
-
-		/* Number of elements */
-		idx = arr[0];
-
-		/* First address. */
-		dmem = (void*)&arr[1];
-	
-		for (i = 0; i < idx; i++) {
-			base = *dmem;
-			dmem += 2;
-			flags = *dmem;
-			/* Use region only if available and not reserved. */
-			if ((flags & 0x8) && !(flags & 0x80)) {
-				ofmem[lmsz].mr_start = base;
-				ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1];
-				ofavail[lasz].mr_start = base;
-				ofavail[lasz].mr_size = (vm_size_t)lmb_size[1];
-				lmsz++;
-				lasz++;
-			}
-			dmem++;
-		}
-	}
-
-	*msz = lmsz;
-	*asz = lasz;
-
-	return (1);
-}
 /*
  * This is called during powerpc_init, before the system is really initialized.
  * It shall provide the total and the available regions of RAM.
@@ -372,14 +223,12 @@ parse_drconf_memory(int *msz, int *asz, 
  * to provide space for two additional entry beyond the terminating one.
  */
 void
-ofw_mem_regions(struct mem_region **memp, int *memsz,
-		struct mem_region **availp, int *availsz)
+ofw_mem_regions(struct mem_region *memp, int *memsz,
+		struct mem_region *availp, int *availsz)
 {
 	phandle_t phandle;
-	vm_offset_t maxphysaddr;
-	int asz, msz, fsz;
-	int i, j, res;
-	int still_merging;
+	int asz, msz;
+	int res;
 	char name[31];
 
 	asz = msz = 0;
@@ -394,72 +243,18 @@ ofw_mem_regions(struct mem_region **memp
 		if (strncmp(name, "memory", sizeof(name)) != 0)
 			continue;
 
-		res = parse_ofw_memory(phandle, "reg", &OFmem[msz]);
+		res = parse_ofw_memory(phandle, "reg", &memp[msz]);
 		msz += res/sizeof(struct mem_region);
 		if (OF_getproplen(phandle, "available") >= 0)
 			res = parse_ofw_memory(phandle, "available",
-			    &OFavail[asz]);
+			    &availp[asz]);
 		else
-			res = parse_ofw_memory(phandle, "reg", &OFavail[asz]);
+			res = parse_ofw_memory(phandle, "reg", &availp[asz]);
 		asz += res/sizeof(struct mem_region);
 	}
 
-	/* Check for memory in ibm,dynamic-reconfiguration-memory */
-	parse_drconf_memory(&msz, &asz, OFmem, OFavail);
-
-	qsort(OFmem, msz, sizeof(*OFmem), mr_cmp);
-	qsort(OFavail, asz, sizeof(*OFavail), mr_cmp);
-
-	*memp = OFmem;
 	*memsz = msz;
-
-	/*
-	 * On some firmwares (SLOF), some memory may be marked available that
-	 * doesn't actually exist. This manifests as an extension of the last
-	 * available segment past the end of physical memory, so truncate that
-	 * one.
-	 */
-	maxphysaddr = 0;
-	for (i = 0; i < msz; i++)
-		if (OFmem[i].mr_start + OFmem[i].mr_size > maxphysaddr)
-			maxphysaddr = OFmem[i].mr_start + OFmem[i].mr_size;
-
-	if (OFavail[asz - 1].mr_start + OFavail[asz - 1].mr_size > maxphysaddr)
-		OFavail[asz - 1].mr_size = maxphysaddr -
-		    OFavail[asz - 1].mr_start;
-
-	/*
-	 * OFavail may have overlapping regions - collapse these
-	 * and copy out remaining regions to OFfree
-	 */
-	do {
-		still_merging = FALSE;
-		for (i = 0; i < asz; i++) {
-			if (OFavail[i].mr_size == 0)
-				continue;
-			for (j = i+1; j < asz; j++) {
-				if (OFavail[j].mr_size == 0)
-					continue;
-				if (memr_overlap(&OFavail[j], &OFavail[i])) {
-					memr_merge(&OFavail[j], &OFavail[i]);
-					/* mark inactive */
-					OFavail[j].mr_size = 0;
-					still_merging = TRUE;
-				}
-			}
-		}
-	} while (still_merging == TRUE);
-
-	/* evict inactive ranges */
-	for (i = 0, fsz = 0; i < asz; i++) {
-		if (OFavail[i].mr_size != 0) {
-			OFfree[fsz] = OFavail[i];
-			fsz++;
-		}
-	}
-
-	*availp = OFfree;
-	*availsz = fsz;
+	*availsz = asz;
 }
 
 #ifdef AIM
@@ -509,9 +304,6 @@ OF_bootstrap()
 		OF_init(fdt);
 	} 
 
-	/* Apple firmware has some bugs. Check for a "mac-io" alias. */
-	apple_hacks = (OF_finddevice("mac-io") != -1) ? 1 : 0;
-
 	return (status);
 }
 

Modified: head/sys/powerpc/powermac/platform_powermac.c
==============================================================================
--- head/sys/powerpc/powermac/platform_powermac.c	Sun Dec  1 19:05:32 2013	(r258806)
+++ head/sys/powerpc/powermac/platform_powermac.c	Sun Dec  1 19:43:15 2013	(r258807)
@@ -57,8 +57,8 @@ extern void *ap_pcpu;
 
 static int powermac_probe(platform_t);
 static int powermac_attach(platform_t);
-void powermac_mem_regions(platform_t, struct mem_region **phys, int *physsz,
-    struct mem_region **avail, int *availsz);
+void powermac_mem_regions(platform_t, struct mem_region *phys, int *physsz,
+    struct mem_region *avail, int *availsz);
 static u_long powermac_timebase_freq(platform_t, struct cpuref *cpuref);
 static int powermac_smp_first_cpu(platform_t, struct cpuref *cpuref);
 static int powermac_smp_next_cpu(platform_t, struct cpuref *cpuref);
@@ -114,10 +114,60 @@ powermac_probe(platform_t plat)
 }
 
 void
-powermac_mem_regions(platform_t plat, struct mem_region **phys, int *physsz,
-    struct mem_region **avail, int *availsz)
+powermac_mem_regions(platform_t plat, struct mem_region *phys, int *physsz,
+    struct mem_region *avail, int *availsz)
 {
-	ofw_mem_regions(phys,physsz,avail,availsz);
+	phandle_t memory;
+	cell_t memoryprop[PHYS_AVAIL_SZ * 2];
+	ssize_t propsize, i, j;
+	int physacells = 1;
+
+	memory = OF_finddevice("/memory");
+
+	/* "reg" has variable #address-cells, but #size-cells is always 1 */
+	OF_getprop(OF_parent(memory), "#address-cells", &physacells,
+	    sizeof(physacells));
+
+	propsize = OF_getprop(memory, "reg", memoryprop, sizeof(memoryprop));
+	propsize /= sizeof(cell_t);
+	for (i = 0, j = 0; i < propsize; i += physacells+1, j++) {
+		phys[j].mr_start = memoryprop[i];
+		if (physacells == 2) {
+#ifndef __powerpc64__
+			/* On 32-bit PPC, ignore regions starting above 4 GB */
+			if (memoryprop[i] != 0) {
+				j--;
+				continue;
+			}
+#else
+			phys[j].mr_start <<= 32;
+#endif
+			phys[j].mr_start |= memoryprop[i+1];
+		}
+		phys[j].mr_size = memoryprop[i + physacells];
+	}
+	*physsz = j;
+
+	/* "available" always has #address-cells = 1 */
+	propsize = OF_getprop(memory, "available", memoryprop,
+	    sizeof(memoryprop));
+	propsize /= sizeof(cell_t);
+	for (i = 0, j = 0; i < propsize; i += 2, j++) {
+		avail[j].mr_start = memoryprop[i];
+		avail[j].mr_size = memoryprop[i + 1];
+	}
+
+#ifdef __powerpc64__
+	/* Add in regions above 4 GB to the available list */
+	for (i = 0; i < *physsz; i++) {
+		if (phys[i].mr_start > BUS_SPACE_MAXADDR_32BIT) {
+			avail[j].mr_start = phys[i].mr_start;
+			avail[j].mr_size = phys[i].mr_size;
+			j++;
+		}
+	}
+#endif
+	*availsz = j;
 }
 
 static int

Modified: head/sys/powerpc/powerpc/platform.c
==============================================================================
--- head/sys/powerpc/powerpc/platform.c	Sun Dec  1 19:05:32 2013	(r258806)
+++ head/sys/powerpc/powerpc/platform.c	Sun Dec  1 19:43:15 2013	(r258807)
@@ -64,17 +64,93 @@ static char plat_name[64] = "";
 SYSCTL_STRING(_hw, OID_AUTO, platform, CTLFLAG_RD | CTLFLAG_TUN,
     plat_name, 0, "Platform currently in use");
 
-static struct mem_region *pregions = NULL;
-static struct mem_region *aregions = NULL;
+static struct mem_region pregions[PHYS_AVAIL_SZ];
+static struct mem_region aregions[PHYS_AVAIL_SZ];
 static int npregions, naregions;
 
+/*
+ * Memory region utilities: determine if two regions overlap,
+ * and merge two overlapping regions into one
+ */
+static int
+memr_overlap(struct mem_region *r1, struct mem_region *r2)
+{
+	if ((r1->mr_start + r1->mr_size) < r2->mr_start ||
+	    (r2->mr_start + r2->mr_size) < r1->mr_start)
+		return (FALSE);
+
+	return (TRUE);
+}
+
+static void
+memr_merge(struct mem_region *from, struct mem_region *to)
+{
+	vm_offset_t end;
+	end = ulmax(to->mr_start + to->mr_size, from->mr_start + from->mr_size);
+	to->mr_start = ulmin(from->mr_start, to->mr_start);
+	to->mr_size = end - to->mr_start;
+}
+
+/*
+ * Quick sort callout for comparing memory regions.
+ */
+static int
+mr_cmp(const void *a, const void *b)
+{
+	const struct mem_region *regiona, *regionb;
+
+	regiona = a;
+	regionb = b;
+	if (regiona->mr_start < regionb->mr_start)
+		return (-1);
+	else if (regiona->mr_start > regionb->mr_start)
+		return (1);
+	else
+		return (0);
+}
+
 void
 mem_regions(struct mem_region **phys, int *physsz, struct mem_region **avail,
     int *availsz)
 {
-	if (pregions == NULL)
-		PLATFORM_MEM_REGIONS(plat_obj, &pregions, &npregions,
-		    &aregions, &naregions);
+	int i, j, still_merging;
+
+	if (npregions == 0) {
+		PLATFORM_MEM_REGIONS(plat_obj, &pregions[0], &npregions,
+		    aregions, &naregions);
+		qsort(pregions, npregions, sizeof(*pregions), mr_cmp);
+		qsort(aregions, naregions, sizeof(*aregions), mr_cmp);
+
+		/* Remove overlapping available regions */
+		do {
+			still_merging = FALSE;
+			for (i = 0; i < naregions; i++) {
+				if (aregions[i].mr_size == 0)
+					continue;
+				for (j = i+1; j < naregions; j++) {
+					if (aregions[j].mr_size == 0)
+						continue;
+					if (!memr_overlap(&aregions[j],
+					    &aregions[i]))
+						continue;
+
+					memr_merge(&aregions[j], &aregions[i]);
+					/* mark inactive */
+					aregions[j].mr_size = 0;
+					still_merging = TRUE;
+				}
+			}
+		} while (still_merging == TRUE);
+
+		/* Collapse zero-length available regions */
+		for (i = 0; i < naregions; i++) {
+			if (aregions[i].mr_size == 0) {
+				memcpy(&aregions[i], &aregions[i+1],
+				    (naregions - i - 1)*sizeof(*aregions));
+				naregions--;
+			}
+		}
+	}
 
 	*phys = pregions;
 	*avail = aregions;
@@ -87,9 +163,11 @@ mem_valid(vm_offset_t addr, int len)
 {
 	int i;
 
-	if (pregions == NULL)
-		PLATFORM_MEM_REGIONS(plat_obj, &pregions, &npregions,
-		    &aregions, &naregions);
+	if (npregions == 0) {
+		struct mem_region *p, *a;
+		int na, np;
+		mem_regions(&p, &np, &a, &na);
+	}
 
 	for (i = 0; i < npregions; i++)
 		if ((addr >= pregions[i].mr_start)

Modified: head/sys/powerpc/powerpc/platform_if.m
==============================================================================
--- head/sys/powerpc/powerpc/platform_if.m	Sun Dec  1 19:05:32 2013	(r258806)
+++ head/sys/powerpc/powerpc/platform_if.m	Sun Dec  1 19:43:15 2013	(r258807)
@@ -120,9 +120,9 @@ METHOD int attach {
 
 METHOD void mem_regions {
 	platform_t	    _plat;
-	struct mem_region **_memp;
+	struct mem_region  *_memp;
 	int		   *_memsz;
-	struct mem_region **_availp;
+	struct mem_region  *_availp;
 	int		   *_availsz;
 };
 

Modified: head/sys/powerpc/ps3/platform_ps3.c
==============================================================================
--- head/sys/powerpc/ps3/platform_ps3.c	Sun Dec  1 19:05:32 2013	(r258806)
+++ head/sys/powerpc/ps3/platform_ps3.c	Sun Dec  1 19:43:15 2013	(r258807)
@@ -58,8 +58,8 @@ extern void *ap_pcpu;
 
 static int ps3_probe(platform_t);
 static int ps3_attach(platform_t);
-static void ps3_mem_regions(platform_t, struct mem_region **phys, int *physsz,
-    struct mem_region **avail, int *availsz);
+static void ps3_mem_regions(platform_t, struct mem_region *phys, int *physsz,
+    struct mem_region *avail, int *availsz);
 static vm_offset_t ps3_real_maxaddr(platform_t);
 static u_long ps3_timebase_freq(platform_t, struct cpuref *cpuref);
 #ifdef SMP
@@ -107,12 +107,31 @@ ps3_probe(platform_t plat)
 	return (BUS_PROBE_NOWILDCARD);
 }
 
-#define MEM_REGIONS	2
-static struct mem_region avail_regions[MEM_REGIONS];
-
 static int
 ps3_attach(platform_t plat)
 {
+	uint64_t junk;
+	int count;
+	struct mem_region avail_regions[2];
+
+	ps3_mem_regions(plat, NULL, NULL, avail_regions, &count);
+
+	lv1_allocate_memory(avail_regions[1].mr_size, 24 /* 16 MB pages */,
+	    0, 0x04 /* any address */, &avail_regions[1].mr_start, &junk);
+
+	pmap_mmu_install("mmu_ps3", BUS_PROBE_SPECIFIC);
+	cpu_idle_hook = ps3_cpu_idle;
+
+	/* Set a breakpoint to make NULL an invalid address */
+	lv1_set_dabr(0x7 /* read and write, MMU on */, 2 /* kernel accesses */);
+
+	return (0);
+}
+
+void
+ps3_mem_regions(platform_t plat, struct mem_region *phys, int *physsz,
+    struct mem_region *avail_regions, int *availsz)
+{
 	uint64_t lpar_id, junk, ppe_id;
 
 	/* Get real mode memory region */
@@ -133,26 +152,12 @@ ps3_attach(platform_t plat)
 	/* Convert to maximum amount we can allocate in 16 MB pages */
 	avail_regions[1].mr_size -= avail_regions[0].mr_size;
 	avail_regions[1].mr_size -= avail_regions[1].mr_size % (16*1024*1024);
+	*availsz = 2;
 
-	lv1_allocate_memory(avail_regions[1].mr_size, 24 /* 16 MB pages */,
-	    0, 0x04 /* any address */, &avail_regions[1].mr_start, &junk);
-
-	pmap_mmu_install("mmu_ps3", BUS_PROBE_SPECIFIC);
-	cpu_idle_hook = ps3_cpu_idle;
-
-	/* Set a breakpoint to make NULL an invalid address */
-	lv1_set_dabr(0x7 /* read and write, MMU on */, 2 /* kernel accesses */);
-
-	return (0);
-}
-
-void
-ps3_mem_regions(platform_t plat, struct mem_region **phys, int *physsz,
-    struct mem_region **avail, int *availsz)
-{
-
-	*phys = *avail = avail_regions;
-	*physsz = *availsz = MEM_REGIONS;
+	if (phys != NULL) {
+		memcpy(phys, avail_regions, sizeof(*phys)*2);
+		*physsz = 2;
+	}
 }
 
 static u_long
@@ -241,7 +246,12 @@ ps3_reset(platform_t plat)
 static vm_offset_t
 ps3_real_maxaddr(platform_t plat)
 {
-	return (avail_regions[0].mr_start + avail_regions[0].mr_size);
+	struct mem_region *phys, *avail;
+	int nphys, navail;
+
+	mem_regions(&phys, &nphys, &avail, &navail);
+
+	return (phys[0].mr_start + phys[0].mr_size);
 }
 
 static void

Modified: head/sys/powerpc/pseries/platform_chrp.c
==============================================================================
--- head/sys/powerpc/pseries/platform_chrp.c	Sun Dec  1 19:05:32 2013	(r258806)
+++ head/sys/powerpc/pseries/platform_chrp.c	Sun Dec  1 19:43:15 2013	(r258807)
@@ -65,8 +65,8 @@ static vm_offset_t realmaxaddr = VM_MAX_
 
 static int chrp_probe(platform_t);
 static int chrp_attach(platform_t);
-void chrp_mem_regions(platform_t, struct mem_region **phys, int *physsz,
-    struct mem_region **avail, int *availsz);
+void chrp_mem_regions(platform_t, struct mem_region *phys, int *physsz,
+    struct mem_region *avail, int *availsz);
 static vm_offset_t chrp_real_maxaddr(platform_t);
 static u_long chrp_timebase_freq(platform_t, struct cpuref *cpuref);
 static int chrp_smp_first_cpu(platform_t, struct cpuref *cpuref);
@@ -157,11 +157,107 @@ chrp_attach(platform_t plat)
 	return (0);
 }
 
+static int
+parse_drconf_memory(int *msz, int *asz, struct mem_region *ofmem,
+		    struct mem_region *ofavail)
+{
+	phandle_t phandle;
+	vm_offset_t base;
+	int i, idx, len, lasz, lmsz, res;
+	uint32_t lmb_size[2];
+	unsigned long *dmem, flags;
+
+	lmsz = *msz;
+	lasz = *asz;
+
+	phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory");
+	if (phandle == -1)
+		/* No drconf node, return. */
+		return (0);
+
+	res = OF_getprop(phandle, "ibm,lmb-size", lmb_size, sizeof(lmb_size));
+	if (res == -1)
+		return (0);
+	printf("Logical Memory Block size: %d MB\n", lmb_size[1] >> 20);
+
+	/* Parse the /ibm,dynamic-memory.
+	   The first position gives the # of entries. The next two words
+ 	   reflect the address of the memory block. The next four words are
+	   the DRC index, reserved, list index and flags.
+	   (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory)
+	   
+	    #el  Addr   DRC-idx  res   list-idx  flags
+	   -------------------------------------------------
+	   | 4 |   8   |   4   |   4   |   4   |   4   |....
+	   -------------------------------------------------
+	*/
+
+	len = OF_getproplen(phandle, "ibm,dynamic-memory");
+	if (len > 0) {
+
+		/* We have to use a variable length array on the stack
+		   since we have very limited stack space.
+		*/
+		cell_t arr[len/sizeof(cell_t)];
+
+		res = OF_getprop(phandle, "ibm,dynamic-memory", &arr,
+				 sizeof(arr));
+		if (res == -1)
+			return (0);
+
+		/* Number of elements */
+		idx = arr[0];
+
+		/* First address. */
+		dmem = (void*)&arr[1];
+	
+		for (i = 0; i < idx; i++) {
+			base = *dmem;
+			dmem += 2;
+			flags = *dmem;
+			/* Use region only if available and not reserved. */
+			if ((flags & 0x8) && !(flags & 0x80)) {
+				ofmem[lmsz].mr_start = base;
+				ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1];
+				ofavail[lasz].mr_start = base;
+				ofavail[lasz].mr_size = (vm_size_t)lmb_size[1];
+				lmsz++;
+				lasz++;
+			}
+			dmem++;
+		}
+	}
+
+	*msz = lmsz;
+	*asz = lasz;
+
+	return (1);
+}
+
 void
-chrp_mem_regions(platform_t plat, struct mem_region **phys, int *physsz,
-    struct mem_region **avail, int *availsz)
+chrp_mem_regions(platform_t plat, struct mem_region *phys, int *physsz,
+    struct mem_region *avail, int *availsz)
 {
-	ofw_mem_regions(phys,physsz,avail,availsz);
+	vm_offset_t maxphysaddr;
+	int i;
+
+	ofw_mem_regions(phys, physsz, avail, availsz);
+	parse_drconf_memory(physsz, availsz, phys, avail);
+
+	/*
+	 * On some firmwares (SLOF), some memory may be marked available that
+	 * doesn't actually exist. This manifests as an extension of the last
+	 * available segment past the end of physical memory, so truncate that
+	 * one.
+	 */
+	maxphysaddr = 0;
+	for (i = 0; i < *physsz; i++)
+		if (phys[i].mr_start + phys[i].mr_size > maxphysaddr)
+			maxphysaddr = phys[i].mr_start + phys[i].mr_size;
+
+	for (i = 0; i < *availsz; i++)
+		if (avail[i].mr_start + avail[i].mr_size > maxphysaddr)
+			avail[i].mr_size = maxphysaddr - avail[i].mr_start;
 }
 
 static vm_offset_t

Modified: head/sys/powerpc/wii/platform_wii.c
==============================================================================
--- head/sys/powerpc/wii/platform_wii.c	Sun Dec  1 19:05:32 2013	(r258806)
+++ head/sys/powerpc/wii/platform_wii.c	Sun Dec  1 19:43:15 2013	(r258807)
@@ -56,8 +56,8 @@ __FBSDID("$FreeBSD$");
 
 static int		wii_probe(platform_t);
 static int		wii_attach(platform_t);
-static void		wii_mem_regions(platform_t, struct mem_region **,
-			    int *, struct mem_region **, int *);
+static void		wii_mem_regions(platform_t, struct mem_region *,
+			    int *, struct mem_region *, int *);
 static unsigned long	wii_timebase_freq(platform_t, struct cpuref *);
 static void		wii_reset(platform_t);
 static void		wii_cpu_idle(sbintime_t);
@@ -107,12 +107,9 @@ wii_attach(platform_t plat)
 	return (0);
 }
 
-#define MEM_REGIONS     2
-static struct mem_region avail_regions[MEM_REGIONS];
-
 static void
-wii_mem_regions(platform_t plat, struct mem_region **phys, int *physsz,
-    struct mem_region **avail, int *availsz)
+wii_mem_regions(platform_t plat, struct mem_region *phys, int *physsz,
+    struct mem_region *avail_regions, int *availsz)
 {
 	/* 24MB 1T-SRAM */
 	avail_regions[0].mr_start = 0x00000000;
@@ -139,8 +136,8 @@ wii_mem_regions(platform_t plat, struct 
 	 */
 	avail_regions[1].mr_size -= WIIIPC_IOH_LEN + 1;
 
-	*phys = *avail = avail_regions;
-	*physsz = *availsz = MEM_REGIONS;
+	memcpy(phys, avail, 2*sizeof(*avail);
+	*physsz = *availsz = 2;
 }
 
 static u_long


More information about the svn-src-all mailing list