diff options
author | ian <ian@FreeBSD.org> | 2014-05-14 14:17:51 +0000 |
---|---|---|
committer | ian <ian@FreeBSD.org> | 2014-05-14 14:17:51 +0000 |
commit | 1baea4807a7a800ea024080ecb08d8018d423b35 (patch) | |
tree | 8bba76de8ef5301e1c8c1469cba379463335efa1 /sys/powerpc/pseries | |
parent | 796f2c87ad85df08fa64cd699bc66b9054363166 (diff) | |
download | FreeBSD-src-1baea4807a7a800ea024080ecb08d8018d423b35.zip FreeBSD-src-1baea4807a7a800ea024080ecb08d8018d423b35.tar.gz |
MFC r258800, r258802, r258805, r258806, r258807, r258851, r258857,
r259199, r259484, r259513, r259514, r259516
The kernel stack guard pages are only below the stack pointer, not above.
Remove unnecessary double-setting of the thread's onfault state in
copyinstr().
Open Firmware mandates that certain cross-references, in particular those
in /chosen, be ihandles. The ePAPR spec makes those cross-reference phandles,
since FDT has no concept of ihandles. Have the OF FDT CI module interpret
queries about ihandles as cross-reference phandles.
Real OF systems have an ihandle under /chosen/stdout, not a phandle. Use
the right type.
Rearchitect platform memory map parsing to make it less
Open Firmware-centric.
Remove fdtbus_bs_tag definition, which is now obsolete. The remainder of
this file is also slated for future demolition.
Return the correct IEEE 1275 code for "nextprop".
Use the common Open Firmware PCI interrupt routing code instead of the
duplicate version in dev/fdt.
Configure interrupt sense based on device tree information.
Simplify the ofw_bus_lookup_imap() API slightly: make it allocate maskbuf
internally instead of requiring the caller to allocate it.
Diffstat (limited to 'sys/powerpc/pseries')
-rw-r--r-- | sys/powerpc/pseries/platform_chrp.c | 106 |
1 files changed, 101 insertions, 5 deletions
diff --git a/sys/powerpc/pseries/platform_chrp.c b/sys/powerpc/pseries/platform_chrp.c index 3112ddc..f668b9a 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); } +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 |