summaryrefslogtreecommitdiffstats
path: root/sys/powerpc/ofw
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/ofw
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/ofw')
-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
3 files changed, 36 insertions, 234 deletions
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) {
/*
OpenPOWER on IntegriCloud