summaryrefslogtreecommitdiffstats
path: root/sys/powerpc
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2014-05-14 14:17:51 +0000
committerian <ian@FreeBSD.org>2014-05-14 14:17:51 +0000
commit1baea4807a7a800ea024080ecb08d8018d423b35 (patch)
tree8bba76de8ef5301e1c8c1469cba379463335efa1 /sys/powerpc
parent796f2c87ad85df08fa64cd699bc66b9054363166 (diff)
downloadFreeBSD-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')
-rw-r--r--sys/powerpc/aim/trap_subr32.S3
-rw-r--r--sys/powerpc/aim/trap_subr64.S3
-rw-r--r--sys/powerpc/booke/platform_bare.c8
-rw-r--r--sys/powerpc/include/fdt.h8
-rw-r--r--sys/powerpc/include/ofw_machdep.h2
-rw-r--r--sys/powerpc/mpc85xx/platform_mpc85xx.c8
-rw-r--r--sys/powerpc/ofw/ofw_machdep.c236
-rw-r--r--sys/powerpc/ofw/ofw_pci.c17
-rw-r--r--sys/powerpc/ofw/ofw_pcib_pci.c17
-rw-r--r--sys/powerpc/powermac/platform_powermac.c60
-rw-r--r--sys/powerpc/powerpc/copyinout.c12
-rw-r--r--sys/powerpc/powerpc/platform.c94
-rw-r--r--sys/powerpc/powerpc/platform_if.m4
-rw-r--r--sys/powerpc/ps3/platform_ps3.c60
-rw-r--r--sys/powerpc/pseries/platform_chrp.c106
-rw-r--r--sys/powerpc/wii/platform_wii.c15
16 files changed, 334 insertions, 319 deletions
diff --git a/sys/powerpc/aim/trap_subr32.S b/sys/powerpc/aim/trap_subr32.S
index 1eb35ec..fccca03 100644
--- a/sys/powerpc/aim/trap_subr32.S
+++ b/sys/powerpc/aim/trap_subr32.S
@@ -672,11 +672,12 @@ disitrap:
stw %r31,(PC_TEMPSAVE+CPUSAVE_AIM_DSISR)(%r1)
#ifdef KDB
- /* Try and detect a kernel stack overflow */
+ /* Try to detect a kernel stack overflow */
mfsrr1 %r31
mtcr %r31
bt 17,realtrap /* branch is user mode */
mfsprg1 %r31 /* get old SP */
+ clrrwi %r31,%r31,11 /* Round SP down to nearest page */
sub. %r30,%r31,%r30 /* SP - DAR */
bge 1f
neg %r30,%r30 /* modulo value */
diff --git a/sys/powerpc/aim/trap_subr64.S b/sys/powerpc/aim/trap_subr64.S
index f05e30d..611a0ec 100644
--- a/sys/powerpc/aim/trap_subr64.S
+++ b/sys/powerpc/aim/trap_subr64.S
@@ -580,11 +580,12 @@ disitrap:
std %r31,(PC_TEMPSAVE+CPUSAVE_AIM_DSISR)(%r1)
#ifdef KDB
- /* Try and detect a kernel stack overflow */
+ /* Try to detect a kernel stack overflow */
mfsrr1 %r31
mtcr %r31
bt 17,realtrap /* branch is user mode */
mfsprg1 %r31 /* get old SP */
+ clrrdi %r31,%r31,11 /* Round SP down to nearest page */
sub. %r30,%r31,%r30 /* SP - DAR */
bge 1f
neg %r30,%r30 /* modulo value */
diff --git a/sys/powerpc/booke/platform_bare.c b/sys/powerpc/booke/platform_bare.c
index 7449732..c11620a 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/fdt.h b/sys/powerpc/include/fdt.h
index 116f562..955e3c7 100644
--- a/sys/powerpc/include/fdt.h
+++ b/sys/powerpc/include/fdt.h
@@ -35,15 +35,7 @@
#include <machine/bus.h>
#include <machine/intr_machdep.h>
-/* Max interrupt number */
-#define FDT_INTR_MAX INTR_VECTORS
-
/* Map phandle/intpin pair to global IRQ number */
#define FDT_MAP_IRQ(node, pin) powerpc_get_irq(node, pin)
-/*
- * Bus space tag. XXX endianess info needs to be derived from the blob.
- */
-#define fdtbus_bs_tag (&bs_be_tag)
-
#endif /* _MACHINE_FDT_H_ */
diff --git a/sys/powerpc/include/ofw_machdep.h b/sys/powerpc/include/ofw_machdep.h
index 023fa4c..0ee75f4 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 b190392..a7724cf 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 4969ec0..02a3d4a 100644
--- a/sys/powerpc/ofw/ofw_machdep.c
+++ b/sys/powerpc/ofw/ofw_machdep.c
@@ -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 char *prop, struct mem_region *output)
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 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/ofw/ofw_pci.c b/sys/powerpc/ofw/ofw_pci.c
index 957a8ca..692b1ab 100644
--- a/sys/powerpc/ofw/ofw_pci.c
+++ b/sys/powerpc/ofw/ofw_pci.c
@@ -256,9 +256,9 @@ ofw_pci_route_interrupt(device_t bus, device_t dev, int pin)
{
struct ofw_pci_softc *sc;
struct ofw_pci_register reg;
- uint32_t pintr, mintr;
+ uint32_t pintr, mintr[2];
+ int intrcells;
phandle_t iparent;
- uint8_t maskbuf[sizeof(reg) + sizeof(pintr)];
sc = device_get_softc(bus);
pintr = pin;
@@ -269,10 +269,15 @@ ofw_pci_route_interrupt(device_t bus, device_t dev, int pin)
(pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) |
(pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT);
- if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, &reg,
- sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr),
- &iparent, maskbuf))
- return (ofw_bus_map_intr(dev, iparent, mintr));
+ intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev),
+ &sc->sc_pci_iinfo, &reg, sizeof(reg), &pintr, sizeof(pintr),
+ mintr, sizeof(mintr), &iparent);
+ if (intrcells) {
+ pintr = ofw_bus_map_intr(dev, iparent, mintr[0]);
+ if (intrcells == 2)
+ ofw_bus_config_intr(dev, pintr, mintr[1]);
+ return (pintr);
+ }
/* Maybe it's a real interrupt, not an intpin */
if (pin > 4)
diff --git a/sys/powerpc/ofw/ofw_pcib_pci.c b/sys/powerpc/ofw/ofw_pcib_pci.c
index 6e3faea..df274c4 100644
--- a/sys/powerpc/ofw/ofw_pcib_pci.c
+++ b/sys/powerpc/ofw/ofw_pcib_pci.c
@@ -134,9 +134,9 @@ ofw_pcib_pci_route_interrupt(device_t bridge, device_t dev, int intpin)
struct ofw_pcib_softc *sc;
struct ofw_bus_iinfo *ii;
struct ofw_pci_register reg;
- cell_t pintr, mintr;
+ cell_t pintr, mintr[2];
+ int intrcells;
phandle_t iparent;
- uint8_t maskbuf[sizeof(reg) + sizeof(pintr)];
sc = device_get_softc(bridge);
ii = &sc->ops_iinfo;
@@ -149,15 +149,20 @@ ofw_pcib_pci_route_interrupt(device_t bridge, device_t dev, int intpin)
(pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) |
(pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT);
- if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), ii, &reg,
- sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr),
- &iparent, maskbuf)) {
+ intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev), ii, &reg,
+ sizeof(reg), &pintr, sizeof(pintr), mintr, sizeof(mintr),
+ &iparent);
+ if (intrcells) {
/*
* If we've found a mapping, return it and don't map
* it again on higher levels - that causes problems
* in some cases, and never seems to be required.
*/
- return (ofw_bus_map_intr(dev, iparent, mintr));
+ mintr[0] = ofw_bus_map_intr(dev, iparent, mintr[0]);
+ if (intrcells == 2)
+ ofw_bus_config_intr(dev, mintr[0], mintr[1]);
+
+ return (mintr[0]);
}
} else if (intpin >= 1 && intpin <= 4) {
/*
diff --git a/sys/powerpc/powermac/platform_powermac.c b/sys/powerpc/powermac/platform_powermac.c
index ce73622..3e1bf7a 100644
--- a/sys/powerpc/powermac/platform_powermac.c
+++ b/sys/powerpc/powermac/platform_powermac.c
@@ -58,8 +58,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);
@@ -117,10 +117,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/copyinout.c b/sys/powerpc/powerpc/copyinout.c
index a1c0456..a8108d6 100644
--- a/sys/powerpc/powerpc/copyinout.c
+++ b/sys/powerpc/powerpc/copyinout.c
@@ -250,22 +250,11 @@ copyin(const void *udaddr, void *kaddr, size_t len)
int
copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
{
- struct thread *td;
- pmap_t pm;
- faultbuf env;
const char *up;
char *kp;
size_t l;
int rv, c;
- td = curthread;
- pm = &td->td_proc->p_vmspace->vm_pmap;
-
- if (setfault(env)) {
- td->td_pcb->pcb_onfault = NULL;
- return (EFAULT);
- }
-
kp = kaddr;
up = udaddr;
@@ -288,7 +277,6 @@ copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
*done = l;
}
- td->td_pcb->pcb_onfault = NULL;
return (rv);
}
diff --git a/sys/powerpc/powerpc/platform.c b/sys/powerpc/powerpc/platform.c
index 6fae2e8..c7ab51f 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 55f9ae6..dfa2be1 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 207382d..c772a8d 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,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
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
diff --git a/sys/powerpc/wii/platform_wii.c b/sys/powerpc/wii/platform_wii.c
index f43ee91..c5709f4 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_regions, 2*sizeof(*avail_regions));
+ *physsz = *availsz = 2;
}
static u_long
OpenPOWER on IntegriCloud