From c1cb22d75552d172b2daaa4b12b6297886fda4d3 Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Sun, 1 Dec 2013 19:43:15 +0000 Subject: [PATCH] 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 --- sys/powerpc/booke/platform_bare.c | 8 +- sys/powerpc/include/ofw_machdep.h | 2 +- sys/powerpc/mpc85xx/platform_mpc85xx.c | 8 +- sys/powerpc/ofw/ofw_machdep.c | 236 ++--------------------- sys/powerpc/powermac/platform_powermac.c | 60 +++++- sys/powerpc/powerpc/platform.c | 94 ++++++++- sys/powerpc/powerpc/platform_if.m | 4 +- sys/powerpc/ps3/platform_ps3.c | 60 +++--- sys/powerpc/pseries/platform_chrp.c | 108 ++++++++++- sys/powerpc/wii/platform_wii.c | 15 +- 10 files changed, 309 insertions(+), 286 deletions(-) diff --git a/sys/powerpc/booke/platform_bare.c b/sys/powerpc/booke/platform_bare.c index 7449732797ed..c11620a3ae71 100644 --- a/sys/powerpc/booke/platform_bare.c +++ b/sys/powerpc/booke/platform_bare.c @@ -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); diff --git a/sys/powerpc/include/ofw_machdep.h b/sys/powerpc/include/ofw_machdep.h index 023fa4c56252..0ee75f435193 100644 --- a/sys/powerpc/include/ofw_machdep.h +++ b/sys/powerpc/include/ofw_machdep.h @@ -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 *); diff --git a/sys/powerpc/mpc85xx/platform_mpc85xx.c b/sys/powerpc/mpc85xx/platform_mpc85xx.c index b1903929970f..a7724cf05b75 100644 --- a/sys/powerpc/mpc85xx/platform_mpc85xx.c +++ b/sys/powerpc/mpc85xx/platform_mpc85xx.c @@ -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); diff --git a/sys/powerpc/ofw/ofw_machdep.c b/sys/powerpc/ofw/ofw_machdep.c index 4969ec0b66e9..02a3d4a588c6 100644 --- a/sys/powerpc/ofw/ofw_machdep.c +++ b/sys/powerpc/ofw/ofw_machdep.c @@ -61,11 +61,6 @@ __FBSDID("$FreeBSD$"); #include #include -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) { @@ -208,14 +161,6 @@ parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) sizeof(size_cells)) < (ssize_t)sizeof(size_cells)) 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. */ @@ -267,103 +212,9 @@ parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) } 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, struct mem_region *ofmem, * 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, int *memsz, 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); } diff --git a/sys/powerpc/powermac/platform_powermac.c b/sys/powerpc/powermac/platform_powermac.c index 1954ae9f4e5a..8855d459a9b7 100644 --- a/sys/powerpc/powermac/platform_powermac.c +++ b/sys/powerpc/powermac/platform_powermac.c @@ -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 diff --git a/sys/powerpc/powerpc/platform.c b/sys/powerpc/powerpc/platform.c index 6f7e7b561159..474f55e5c2c3 100644 --- a/sys/powerpc/powerpc/platform.c +++ b/sys/powerpc/powerpc/platform.c @@ -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) diff --git a/sys/powerpc/powerpc/platform_if.m b/sys/powerpc/powerpc/platform_if.m index cd878e02b6c4..587811b1c521 100644 --- a/sys/powerpc/powerpc/platform_if.m +++ b/sys/powerpc/powerpc/platform_if.m @@ -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; }; diff --git a/sys/powerpc/ps3/platform_ps3.c b/sys/powerpc/ps3/platform_ps3.c index 207382d86fd1..c772a8db3709 100644 --- a/sys/powerpc/ps3/platform_ps3.c +++ b/sys/powerpc/ps3/platform_ps3.c @@ -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,11 +107,30 @@ 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; @@ -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 diff --git a/sys/powerpc/pseries/platform_chrp.c b/sys/powerpc/pseries/platform_chrp.c index 3112ddcc114b..f668b9a098e8 100644 --- a/sys/powerpc/pseries/platform_chrp.c +++ b/sys/powerpc/pseries/platform_chrp.c @@ -65,8 +65,8 @@ static vm_offset_t realmaxaddr = VM_MAX_ADDRESS; 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); } -void -chrp_mem_regions(platform_t plat, struct mem_region **phys, int *physsz, - struct mem_region **avail, int *availsz) +static int +parse_drconf_memory(int *msz, int *asz, struct mem_region *ofmem, + struct mem_region *ofavail) { - ofw_mem_regions(phys,physsz,avail,availsz); + 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) +{ + 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 diff --git a/sys/powerpc/wii/platform_wii.c b/sys/powerpc/wii/platform_wii.c index f43ee9198066..9625578c8e11 100644 --- a/sys/powerpc/wii/platform_wii.c +++ b/sys/powerpc/wii/platform_wii.c @@ -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 mem_region **phys, int *physsz, */ 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