diff options
29 files changed, 388 insertions, 754 deletions
diff --git a/sys/arm/mv/mv_pci.c b/sys/arm/mv/mv_pci.c index f708b90..ff12974 100644 --- a/sys/arm/mv/mv_pci.c +++ b/sys/arm/mv/mv_pci.c @@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$"); #include <dev/fdt/fdt_common.h> #include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_pci.h> #include <dev/ofw/ofw_bus_subr.h> #include <dev/pci/pcivar.h> #include <dev/pci/pcireg.h> @@ -142,7 +143,7 @@ struct mv_pcib_softc { int sc_type; int sc_mode; /* Endpoint / Root Complex */ - struct fdt_pci_intr sc_intr_info; + struct ofw_bus_iinfo sc_pci_iinfo; }; /* Local forward prototypes */ @@ -155,7 +156,6 @@ static void mv_pcib_hw_cfgwrite(struct mv_pcib_softc *, u_int, u_int, static int mv_pcib_init(struct mv_pcib_softc *, int, int); static int mv_pcib_init_all_bars(struct mv_pcib_softc *, int, int, int, int); static void mv_pcib_init_bridge(struct mv_pcib_softc *, int, int, int); -static int mv_pcib_intr_info(phandle_t, struct mv_pcib_softc *); static inline void pcib_write_irq_mask(struct mv_pcib_softc *, uint32_t); static void mv_pcib_enable(struct mv_pcib_softc *, uint32_t); static int mv_pcib_mem_init(struct mv_pcib_softc *); @@ -243,8 +243,8 @@ mv_pcib_probe(device_t self) if (!fdt_is_type(node, "pci")) return (ENXIO); - if (!(fdt_is_compatible(node, "mrvl,pcie") || - fdt_is_compatible(node, "mrvl,pci"))) + if (!(ofw_bus_is_compatible(self, "mrvl,pcie") || + ofw_bus_is_compatible(self, "mrvl,pci"))) return (ENXIO); device_set_desc(self, "Marvell Integrated PCI/PCI-E Controller"); @@ -299,11 +299,8 @@ mv_pcib_attach(device_t self) /* * Get PCI interrupt info. */ - if ((sc->sc_mode == MV_MODE_ROOT) && - (mv_pcib_intr_info(node, sc) != 0)) { - device_printf(self, "could not retrieve interrupt info\n"); - return (ENXIO); - } + if (sc->sc_mode == MV_MODE_ROOT) + ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(pcell_t)); /* * Configure decode windows for PCI(E) access. @@ -881,19 +878,32 @@ mv_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func, } static int -mv_pcib_route_interrupt(device_t pcib, device_t dev, int pin) +mv_pcib_route_interrupt(device_t bus, device_t dev, int pin) { struct mv_pcib_softc *sc; - int err, interrupt; + struct ofw_pci_register reg; + uint32_t pintr, mintr; + phandle_t iparent; + + sc = device_get_softc(bus); + pintr = pin; + + /* Fabricate imap information in case this isn't an OFW device */ + bzero(®, sizeof(reg)); + reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) | + (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) | + (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT); - sc = device_get_softc(pcib); + if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, ®, + sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), + &iparent)) + return (ofw_bus_map_intr(dev, iparent, mintr)); - err = fdt_pci_route_intr(pci_get_bus(dev), pci_get_slot(dev), - pci_get_function(dev), pin, &sc->sc_intr_info, &interrupt); - if (err == 0) - return (interrupt); + /* Maybe it's a real interrupt, not an intpin */ + if (pin > 4) + return (pin); - device_printf(pcib, "could not route pin %d for device %d.%d\n", + device_printf(bus, "could not route pin %d for device %d.%d\n", pin, pci_get_slot(dev), pci_get_function(dev)); return (PCI_INVALID_IRQ); } @@ -938,17 +948,6 @@ mv_pcib_decode_win(phandle_t node, struct mv_pcib_softc *sc) return (0); } -static int -mv_pcib_intr_info(phandle_t node, struct mv_pcib_softc *sc) -{ - int error; - - if ((error = fdt_pci_intr_info(node, &sc->sc_intr_info)) != 0) - return (error); - - return (0); -} - #if defined(SOC_MV_ARMADAXP) static int mv_pcib_map_msi(device_t dev, device_t child, int irq, uint64_t *addr, diff --git a/sys/dev/fdt/fdt_common.h b/sys/dev/fdt/fdt_common.h index 8c16257..499d1f8 100644 --- a/sys/dev/fdt/fdt_common.h +++ b/sys/dev/fdt/fdt_common.h @@ -47,14 +47,6 @@ struct fdt_pci_range { u_long len; }; -struct fdt_pci_intr { - int addr_cells; - int intr_cells; - int map_len; - pcell_t *map; - pcell_t *mask; -}; - struct fdt_sense_level { enum intr_trigger trig; enum intr_polarity pol; @@ -110,11 +102,9 @@ int fdt_is_enabled(phandle_t); int fdt_pm_is_enabled(phandle_t); int fdt_is_type(phandle_t, const char *); int fdt_parent_addr_cells(phandle_t); -int fdt_pci_intr_info(phandle_t, struct fdt_pci_intr *); int fdt_pci_ranges(phandle_t, struct fdt_pci_range *, struct fdt_pci_range *); int fdt_pci_ranges_decode(phandle_t, struct fdt_pci_range *, struct fdt_pci_range *); -int fdt_pci_route_intr(int, int, int, int, struct fdt_pci_intr *, int *); int fdt_ranges_verify(pcell_t *, int, int, int, int); int fdt_reg_to_rl(phandle_t, struct resource_list *); int fdt_pm(phandle_t); diff --git a/sys/dev/fdt/fdt_pci.c b/sys/dev/fdt/fdt_pci.c index fae5f07..d4f4b6c 100644 --- a/sys/dev/fdt/fdt_pci.c +++ b/sys/dev/fdt/fdt_pci.c @@ -180,159 +180,6 @@ fdt_pci_ranges(phandle_t node, struct fdt_pci_range *io_space, return (0); } -static int -fdt_addr_cells(phandle_t node, int *addr_cells) -{ - pcell_t cell; - int cell_size; - - cell_size = sizeof(cell); - if (OF_getprop(node, "#address-cells", &cell, cell_size) < cell_size) - return (EINVAL); - *addr_cells = fdt32_to_cpu((int)cell); - - if (*addr_cells > 3) - return (ERANGE); - return (0); -} - -static int -fdt_interrupt_cells(phandle_t node) -{ - pcell_t intr_cells; - - if (OF_getprop(node, "#interrupt-cells", &intr_cells, - sizeof(intr_cells)) <= 0) { - debugf("no intr-cells defined, defaulting to 1\n"); - intr_cells = 1; - } - intr_cells = fdt32_to_cpu(intr_cells); - - return ((int)intr_cells); -} - -int -fdt_pci_intr_info(phandle_t node, struct fdt_pci_intr *intr_info) -{ - void *map, *mask; - int acells, icells; - int error, len; - - error = fdt_addr_cells(node, &acells); - if (error) - return (error); - - icells = fdt_interrupt_cells(node); - - /* - * Retrieve the interrupt map and mask properties. - */ - len = OF_getprop_alloc(node, "interrupt-map-mask", 1, &mask); - if (len / sizeof(pcell_t) != (acells + icells)) { - debugf("bad mask len = %d\n", len); - goto err; - } - - len = OF_getprop_alloc(node, "interrupt-map", 1, &map); - if (len <= 0) { - debugf("bad map len = %d\n", len); - goto err; - } - - intr_info->map_len = len; - intr_info->map = map; - intr_info->mask = mask; - intr_info->addr_cells = acells; - intr_info->intr_cells = icells; - - debugf("acells=%u, icells=%u, map_len=%u\n", acells, icells, len); - return (0); - -err: - free(mask, M_OFWPROP); - return (ENXIO); -} - -int -fdt_pci_route_intr(int bus, int slot, int func, int pin, - struct fdt_pci_intr *intr_info, int *interrupt) -{ - pcell_t child_spec[4], masked[4]; - phandle_t iph; - pcell_t intr_par; - pcell_t *map_ptr; - uint32_t addr; - int i, j, map_len; - int par_intr_cells, par_addr_cells, child_spec_cells, row_cells; - int par_idx, spec_idx, err, trig, pol; - - child_spec_cells = intr_info->addr_cells + intr_info->intr_cells; - if (child_spec_cells > sizeof(child_spec) / sizeof(pcell_t)) - return (ENOMEM); - - addr = (bus << 16) | (slot << 11) | (func << 8); - child_spec[0] = addr; - child_spec[1] = 0; - child_spec[2] = 0; - child_spec[3] = pin; - - map_len = intr_info->map_len; - map_ptr = intr_info->map; - - par_idx = child_spec_cells; - i = 0; - while (i < map_len) { - iph = fdt32_to_cpu(map_ptr[par_idx]); - intr_par = OF_xref_phandle(iph); - - err = fdt_addr_cells(intr_par, &par_addr_cells); - if (err != 0) { - debugf("could not retrieve intr parent #addr-cells\n"); - return (err); - } - par_intr_cells = fdt_interrupt_cells(intr_par); - - row_cells = child_spec_cells + 1 + par_addr_cells + - par_intr_cells; - - /* - * Apply mask and look up the entry in interrupt map. - */ - for (j = 0; j < child_spec_cells; j++) { - masked[j] = child_spec[j] & - fdt32_to_cpu(intr_info->mask[j]); - - if (masked[j] != fdt32_to_cpu(map_ptr[j])) - goto next; - } - - /* - * Decode interrupt of the parent intr controller. - */ - spec_idx = child_spec_cells + 1 + par_addr_cells; - err = fdt_intr_decode(intr_par, &map_ptr[spec_idx], - interrupt, &trig, &pol); - if (err != 0) { - debugf("could not decode interrupt\n"); - return (err); - } - debugf("decoded intr = %d, trig = %d, pol = %d\n", *interrupt, - trig, pol); - -#if defined(__powerpc__) - powerpc_config_intr(FDT_MAP_IRQ(iph, *interrupt), trig, - pol); -#endif - return (0); - -next: - map_ptr += row_cells; - i += (row_cells * sizeof(pcell_t)); - } - - return (ENXIO); -} - #if defined(__arm__) int fdt_pci_devmap(phandle_t node, struct arm_devmap_entry *devmap, vm_offset_t io_va, @@ -360,217 +207,3 @@ fdt_pci_devmap(phandle_t node, struct arm_devmap_entry *devmap, vm_offset_t io_v } #endif -#if 0 -static int -fdt_pci_config_bar(device_t dev, int bus, int slot, int func, int bar) -{ -} - -static int -fdt_pci_config_normal(device_t dev, int bus, int slot, int func) -{ - int bar; - uint8_t command, intline, intpin; - - command = PCIB_READ_CONFIG(dev, bus, slot, func, PCIR_COMMAND, 1); - command &= ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN); - PCIB_WRITE_CONFIG(dev, bus, slot, func, PCIR_COMMAND, command, 1); - - /* Program the base address registers. */ - bar = 0; - while (bar <= PCIR_MAX_BAR_0) - bar += fdt_pci_config_bar(dev, bus, slot, func, bar); - - /* Perform interrupt routing. */ - intpin = PCIB_READ_CONFIG(dev, bus, slot, func, PCIR_INTPIN, 1); - intline = fsl_pcib_route_int(dev, bus, slot, func, intpin); - PCIB_WRITE_CONFIG(dev, bus, slot, func, PCIR_INTLINE, intline, 1); - - command |= PCIM_CMD_MEMEN | PCIM_CMD_PORTEN; - PCIB_WRITE_CONFIG(dev, bus, slot, func, PCIR_COMMAND, command, 1); -} - -static int -fdt_pci_config_bridge(device_t dev, int bus, int secbus, int slot, int func) -{ - int maxbar; - uint8_t command; - - command = PCIB_READ_CONFIG(dev, bus, slot, func, PCIR_COMMAND, 1); - command &= ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN); - PCIB_WRITE_CONFIG(dev, bus, slot, func, PCIR_COMMAND, command, 1); - - /* Program the base address registers. */ - maxbar = (hdrtype & PCIM_HDRTYPE) ? 1 : 6; - bar = 0; - while (bar < maxbar) - bar += fsl_pcib_init_bar(sc, bus, slot, func, - bar); - - /* Perform interrupt routing. */ - intpin = fsl_pcib_read_config(sc->sc_dev, bus, slot, - func, PCIR_INTPIN, 1); - intline = fsl_pcib_route_int(sc, bus, slot, func, - intpin); - fsl_pcib_write_config(sc->sc_dev, bus, slot, func, - PCIR_INTLINE, intline, 1); - - command |= PCIM_CMD_MEMEN | PCIM_CMD_PORTEN; - fsl_pcib_write_config(sc->sc_dev, bus, slot, func, - PCIR_COMMAND, command, 1); - - /* - * Handle PCI-PCI bridges - */ - class = fsl_pcib_read_config(sc->sc_dev, bus, slot, - func, PCIR_CLASS, 1); - subclass = fsl_pcib_read_config(sc->sc_dev, bus, slot, - func, PCIR_SUBCLASS, 1); - - /* Allow only proper PCI-PCI briges */ - if (class != PCIC_BRIDGE) - continue; - if (subclass != PCIS_BRIDGE_PCI) - continue; - - secbus++; - - /* Program I/O decoder. */ - fsl_pcib_write_config(sc->sc_dev, bus, slot, func, - PCIR_IOBASEL_1, sc->sc_ioport.rm_start >> 8, 1); - fsl_pcib_write_config(sc->sc_dev, bus, slot, func, - PCIR_IOLIMITL_1, sc->sc_ioport.rm_end >> 8, 1); - fsl_pcib_write_config(sc->sc_dev, bus, slot, func, - PCIR_IOBASEH_1, sc->sc_ioport.rm_start >> 16, 2); - fsl_pcib_write_config(sc->sc_dev, bus, slot, func, - PCIR_IOLIMITH_1, sc->sc_ioport.rm_end >> 16, 2); - - /* Program (non-prefetchable) memory decoder. */ - fsl_pcib_write_config(sc->sc_dev, bus, slot, func, - PCIR_MEMBASE_1, sc->sc_iomem.rm_start >> 16, 2); - fsl_pcib_write_config(sc->sc_dev, bus, slot, func, - PCIR_MEMLIMIT_1, sc->sc_iomem.rm_end >> 16, 2); - - /* Program prefetchable memory decoder. */ - fsl_pcib_write_config(sc->sc_dev, bus, slot, func, - PCIR_PMBASEL_1, 0x0010, 2); - fsl_pcib_write_config(sc->sc_dev, bus, slot, func, - PCIR_PMLIMITL_1, 0x000f, 2); - fsl_pcib_write_config(sc->sc_dev, bus, slot, func, - PCIR_PMBASEH_1, 0x00000000, 4); - fsl_pcib_write_config(sc->sc_dev, bus, slot, func, - PCIR_PMLIMITH_1, 0x00000000, 4); - - /* Read currect bus register configuration */ - old_pribus = fsl_pcib_read_config(sc->sc_dev, bus, - slot, func, PCIR_PRIBUS_1, 1); - old_secbus = fsl_pcib_read_config(sc->sc_dev, bus, - slot, func, PCIR_SECBUS_1, 1); - old_subbus = fsl_pcib_read_config(sc->sc_dev, bus, - slot, func, PCIR_SUBBUS_1, 1); - - if (bootverbose) - printf("PCI: reading firmware bus numbers for " - "secbus = %d (bus/sec/sub) = (%d/%d/%d)\n", - secbus, old_pribus, old_secbus, old_subbus); - - new_pribus = bus; - new_secbus = secbus; - - secbus = fsl_pcib_init(sc, secbus, - (subclass == PCIS_BRIDGE_PCI) ? PCI_SLOTMAX : 0); - - new_subbus = secbus; - - if (bootverbose) - printf("PCI: translate firmware bus numbers " - "for secbus %d (%d/%d/%d) -> (%d/%d/%d)\n", - secbus, old_pribus, old_secbus, old_subbus, - new_pribus, new_secbus, new_subbus); - - fsl_pcib_write_config(sc->sc_dev, bus, slot, func, - PCIR_PRIBUS_1, new_pribus, 1); - fsl_pcib_write_config(sc->sc_dev, bus, slot, func, - PCIR_SECBUS_1, new_secbus, 1); - fsl_pcib_write_config(sc->sc_dev, bus, slot, func, - PCIR_SUBBUS_1, new_subbus, 1); - -} - -static int -fdt_pci_config_slot(device_t dev, int bus, int secbus, int slot) -{ - int func, maxfunc; - uint16_t vendor; - uint8_t hdrtype; - - maxfunc = 0; - for (func = 0; func <= maxfunc; func++) { - hdrtype = PCIB_READ_CONFIG(dev, bus, slot, func, - PCIR_HDRTYPE, 1); - if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) - continue; - if (func == 0 && (hdrtype & PCIM_MFDEV)) - maxfunc = PCI_FUNCMAX; - - vendor = PCIB_READ_CONFIG(dev, bus, slot, func, - PCIR_VENDOR, 2); - if (vendor == 0xffff) - continue; - - if ((hdrtype & PCIM_HDRTYPE) == PCIM_HDRTYPE_NORMAL) - fdt_pci_config_normal(dev, bus, slot, func); - else - secbus = fdt_pci_config_bridge(dev, bus, secbus, - slot, func); - } - - return (secbus); -} - -static int -fdt_pci_config_bus(device_t dev, int bus, int maxslot) -{ - int func, maxfunc, secbus, slot; - - secbus = bus; - for (slot = 0; slot <= maxslot; slot++) - secbus = fdt_pci_config_slot(dev, bus, secbus, slot); - - return (secbus); -} - -int -fdt_pci_config_domain(device_t dev) -{ - pcell_t bus_range[2]; - phandle_t root; - int bus, error, maxslot; - - root = ofw_bus_get_node(dev); - if (root == 0) - return (EINVAL); - if (!fdt_is_type(root, "pci")) - return (EINVAL); - - /* - * Determine the bus number of the root in this domain. - * Lacking any information, this will be bus 0. - * Write the bus number to the bus device, using the IVAR. - */ - if ((OF_getprop(root, "bus-range", bus_range, sizeof(bus_range)) <= 0) - bus = 0; - else - bus = fdt32_to_cpu(bus_range[0]); - - error = BUS_WRITE_IVAR(dev, NULL, PCIB_IVAR_BUS, bus); - if (error) - return (error); - - /* Get the maximum slot number for bus-enumeration. */ - maxslot = PCIB_MAXSLOTS(dev); - - bus = fdt_pci_config_bus(dev, bus, maxslot); - return (0); -} -#endif diff --git a/sys/dev/ofw/ofw_bus_subr.c b/sys/dev/ofw/ofw_bus_subr.c index 26a6759..bf552a8 100644 --- a/sys/dev/ofw/ofw_bus_subr.c +++ b/sys/dev/ofw/ofw_bus_subr.c @@ -251,8 +251,9 @@ ofw_bus_setup_iinfo(phandle_t node, struct ofw_bus_iinfo *ii, int intrsz) int ofw_bus_lookup_imap(phandle_t node, struct ofw_bus_iinfo *ii, void *reg, int regsz, void *pintr, int pintrsz, void *mintr, int mintrsz, - phandle_t *iparent, void *maskbuf) + phandle_t *iparent) { + uint8_t maskbuf[regsz + pintrsz]; int rv; if (ii->opi_imapsz <= 0) @@ -285,7 +286,7 @@ ofw_bus_lookup_imap(phandle_t node, struct ofw_bus_iinfo *ii, void *reg, * maskbuf must point to a buffer of length physsz + intrsz. * The interrupt is returned in result, which must point to a buffer of length * rintrsz (which gives the expected size of the mapped interrupt). - * Returns 1 if a mapping was found, 0 otherwise. + * Returns number of cells in the interrupt if a mapping was found, 0 otherwise. */ int ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz, @@ -325,19 +326,13 @@ ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz, tsz = physsz + intrsz + sizeof(phandle_t) + pintrsz; KASSERT(i >= tsz, ("ofw_bus_search_intrmap: truncated map")); - /* - * XXX: Apple hardware uses a second cell to set information - * on the interrupt trigger type. This information should - * be used somewhere to program the PIC. - */ - if (bcmp(ref, mptr, physsz + intrsz) == 0) { bcopy(mptr + physsz + intrsz + sizeof(parent), - result, rintrsz); + result, MIN(rintrsz, pintrsz)); if (iparent != NULL) *iparent = parent; - return (1); + return (pintrsz/sizeof(pcell_t)); } mptr += tsz; i -= tsz; diff --git a/sys/dev/ofw/ofw_bus_subr.h b/sys/dev/ofw/ofw_bus_subr.h index 184ab07..e9ef5e4 100644 --- a/sys/dev/ofw/ofw_bus_subr.h +++ b/sys/dev/ofw/ofw_bus_subr.h @@ -68,7 +68,7 @@ bus_child_pnpinfo_str_t ofw_bus_gen_child_pnpinfo_str; /* Routines for processing firmware interrupt maps */ void ofw_bus_setup_iinfo(phandle_t, struct ofw_bus_iinfo *, int); int ofw_bus_lookup_imap(phandle_t, struct ofw_bus_iinfo *, void *, int, - void *, int, void *, int, phandle_t *, void *); + void *, int, void *, int, phandle_t *); int ofw_bus_search_intrmap(void *, int, void *, int, void *, int, void *, void *, void *, int, phandle_t *); diff --git a/sys/dev/ofw/ofw_fdt.c b/sys/dev/ofw/ofw_fdt.c index b53bdab..617d2a3 100644 --- a/sys/dev/ofw/ofw_fdt.c +++ b/sys/dev/ofw/ofw_fdt.c @@ -207,7 +207,8 @@ static phandle_t ofw_fdt_instance_to_package(ofw_t ofw, ihandle_t instance) { - return (-1); + /* Where real OF uses ihandles in the tree, FDT uses xref phandles */ + return (OF_xref_phandle(instance)); } /* Get the length of a property of a package. */ @@ -266,8 +267,10 @@ ofw_fdt_getprop(ofw_t ofw, phandle_t package, const char *propname, void *buf, } /* - * Get the next property of a package. Return the actual len of retrieved - * prop name. + * Get the next property of a package. Return values: + * -1: package or previous property does not exist + * 0: no more properties + * 1: success */ static int ofw_fdt_nextprop(ofw_t ofw, phandle_t package, const char *previous, char *buf, @@ -309,7 +312,7 @@ ofw_fdt_nextprop(ofw_t ofw, phandle_t package, const char *previous, char *buf, strncpy(buf, fdt_string(fdtp, fdt32_to_cpu(prop->nameoff)), size); - return (strlen(buf)); + return (1); } /* Set the value of a property of a package. */ @@ -350,8 +353,13 @@ ofw_fdt_finddevice(ofw_t ofw, const char *device) static ssize_t ofw_fdt_instance_to_path(ofw_t ofw, ihandle_t instance, char *buf, size_t len) { + phandle_t phandle; - return (-1); + phandle = OF_instance_to_package(instance); + if (phandle == -1) + return (-1); + + return (OF_package_to_path(phandle, buf, len)); } /* Return the fully qualified pathname corresponding to a package. */ diff --git a/sys/dev/uart/uart_cpu_powerpc.c b/sys/dev/uart/uart_cpu_powerpc.c index 44f6338..0791c77 100644 --- a/sys/dev/uart/uart_cpu_powerpc.c +++ b/sys/dev/uart/uart_cpu_powerpc.c @@ -89,13 +89,13 @@ ofw_get_console_phandle_path(phandle_t node, phandle_t *result, return (ENXIO); OF_getprop(node, prop, &field, sizeof(field)); - /* This property might be a phandle or might be a path. Hooray. */ + /* This property might be either a ihandle or path. Hooray. */ output = -1; if (field.buf[size - 1] == 0) output = OF_finddevice(field.buf); if (output == -1 && size == 4) - output = OF_xref_phandle(field.ref); + output = OF_instance_to_package(field.ref); if (output != -1) { *result = output; 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, ®, - 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, ®, 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, ®, - sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), - &iparent, maskbuf)) { + intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev), ii, ®, + 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 diff --git a/sys/sparc64/ebus/ebus.c b/sys/sparc64/ebus/ebus.c index 677e31d..93ad342 100644 --- a/sys/sparc64/ebus/ebus.c +++ b/sys/sparc64/ebus/ebus.c @@ -638,7 +638,6 @@ ebus_setup_dinfo(device_t dev, struct ebus_softc *sc, phandle_t node) uint64_t start; uint32_t rintr; int i, nintr, nreg, rv; - uint8_t maskbuf[sizeof(reg) + sizeof(intr)]; edi = malloc(sizeof(*edi), M_DEVBUF, M_ZERO | M_WAITOK); if (ofw_bus_gen_setup_devinfo(&edi->edi_obdinfo, node) != 0) { @@ -673,7 +672,7 @@ ebus_setup_dinfo(device_t dev, struct ebus_softc *sc, phandle_t node) intr = intrs[i]; rv = ofw_bus_lookup_imap(node, &sc->sc_iinfo, ®, sizeof(reg), &intr, sizeof(intr), &rintr, - sizeof(rintr), NULL, maskbuf); + sizeof(rintr), NULL); #ifndef SUN4V if (rv != 0) rintr = INTMAP_VEC(sc->sc_ign, rintr); diff --git a/sys/sparc64/isa/ofw_isa.c b/sys/sparc64/isa/ofw_isa.c index 0d0f5b6..dbe5d8a 100644 --- a/sys/sparc64/isa/ofw_isa.c +++ b/sys/sparc64/isa/ofw_isa.c @@ -129,7 +129,6 @@ ofw_isa_route_intr(device_t bridge, phandle_t node, struct ofw_bus_iinfo *ii, ofw_isa_intr_t intr) { struct isa_regs reg; - uint8_t maskbuf[sizeof(reg) + sizeof(intr)]; device_t pbridge; ofw_isa_intr_t mintr; @@ -139,7 +138,7 @@ ofw_isa_route_intr(device_t bridge, phandle_t node, struct ofw_bus_iinfo *ii, * fully specified, so we may not continue to map. */ if (!ofw_bus_lookup_imap(node, ii, ®, sizeof(reg), - &intr, sizeof(intr), &mintr, sizeof(mintr), NULL, maskbuf)) { + &intr, sizeof(intr), &mintr, sizeof(mintr), NULL)) { /* Try routing at the parent bridge. */ mintr = PCIB_ROUTE_INTERRUPT(pbridge, bridge, intr); } diff --git a/sys/sparc64/pci/fire.c b/sys/sparc64/pci/fire.c index 4209f84..84526f0 100644 --- a/sys/sparc64/pci/fire.c +++ b/sys/sparc64/pci/fire.c @@ -1472,13 +1472,12 @@ fire_route_interrupt(device_t bridge, device_t dev, int pin) struct fire_softc *sc; struct ofw_pci_register reg; ofw_pci_intr_t pintr, mintr; - uint8_t maskbuf[sizeof(reg) + sizeof(pintr)]; sc = device_get_softc(bridge); pintr = pin; if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, ®, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), - NULL, maskbuf) != 0) + NULL) != 0) return (mintr); device_printf(bridge, "could not route pin %d for device %d.%d\n", diff --git a/sys/sparc64/pci/ofw_pcib_subr.c b/sys/sparc64/pci/ofw_pcib_subr.c index 2ffb32d..14fa72b 100644 --- a/sys/sparc64/pci/ofw_pcib_subr.c +++ b/sys/sparc64/pci/ofw_pcib_subr.c @@ -70,7 +70,6 @@ ofw_pcib_gen_route_interrupt(device_t bridge, device_t dev, int intpin) struct ofw_bus_iinfo *ii; struct ofw_pci_register reg; ofw_pci_intr_t pintr, mintr; - uint8_t maskbuf[sizeof(reg) + sizeof(pintr)]; sc = device_get_softc(bridge); ii = &sc->ops_iinfo; @@ -78,7 +77,7 @@ ofw_pcib_gen_route_interrupt(device_t bridge, device_t dev, int intpin) pintr = intpin; if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), ii, ®, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), - NULL, maskbuf)) { + NULL)) { /* * If we've found a mapping, return it and don't map * it again on higher levels - that causes problems diff --git a/sys/sparc64/pci/psycho.c b/sys/sparc64/pci/psycho.c index 8717426..4881d1f 100644 --- a/sys/sparc64/pci/psycho.c +++ b/sys/sparc64/pci/psycho.c @@ -1048,13 +1048,12 @@ psycho_route_interrupt(device_t bridge, device_t dev, int pin) struct ofw_pci_register reg; bus_addr_t intrmap; ofw_pci_intr_t pintr, mintr; - uint8_t maskbuf[sizeof(reg) + sizeof(pintr)]; sc = device_get_softc(bridge); pintr = pin; if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, ®, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), - NULL, maskbuf)) + NULL)) return (mintr); /* * If this is outside of the range for an intpin, it's likely a full diff --git a/sys/sparc64/pci/schizo.c b/sys/sparc64/pci/schizo.c index f92aa78..b89c7c0 100644 --- a/sys/sparc64/pci/schizo.c +++ b/sys/sparc64/pci/schizo.c @@ -1121,13 +1121,12 @@ schizo_route_interrupt(device_t bridge, device_t dev, int pin) struct schizo_softc *sc; struct ofw_pci_register reg; ofw_pci_intr_t pintr, mintr; - uint8_t maskbuf[sizeof(reg) + sizeof(pintr)]; sc = device_get_softc(bridge); pintr = pin; if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, ®, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), - NULL, maskbuf)) + NULL)) return (mintr); device_printf(bridge, "could not route pin %d for device %d.%d\n", |