Date: Mon, 22 Jul 2013 21:24:28 GMT From: John Baldwin <jhb@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 231353 for review Message-ID: <201307222124.r6MLOSON080132@skunkworks.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@231353?ac=10 Change 231353 by jhb@jhb_jhbbsd on 2013/07/22 21:24:19 WIP changes to move the secbus resource up into the PCI bus layer a bit. Affected files ... .. //depot/projects/pci/sys/dev/pccbb/pccbb_pci.c#9 edit .. //depot/projects/pci/sys/dev/pci/pci.c#45 edit .. //depot/projects/pci/sys/dev/pci/pci_pci.c#43 edit .. //depot/projects/pci/sys/dev/pci/pcib_private.h#27 edit Differences ... ==== //depot/projects/pci/sys/dev/pccbb/pccbb_pci.c#9 (text+ko) ==== @@ -326,8 +326,6 @@ sc->pribus = pcib_get_bus(parent); #if defined(NEW_PCIB) && defined(PCI_RES_BUS) pci_write_config(brdev, PCIR_PRIBUS_2, sc->pribus, 1); - sc->bus.sec_reg = PCIR_SECBUS_2; - sc->bus.sub_reg = PCIR_SUBBUS_2; pcib_setup_secbus(brdev, &sc->bus); #endif SLIST_INIT(&sc->rl); ==== //depot/projects/pci/sys/dev/pci/pci.c#45 (text+ko) ==== @@ -349,6 +349,13 @@ SYSCTL_INT(_hw_pci, OID_AUTO, clear_bars, CTLFLAG_RDTUN, &pci_clear_bars, 0, "Ignore firmware-assigned resources for BARs."); +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) +static int pci_clear_buses; +TUNABLE_INT("hw.pci.clear_buses", &pci_clear_buses); +SYSCTL_INT(_hw_pci, OID_AUTO, clear_buses, CTLFLAG_RDTUN, &pci_clear_buses, 0, + "Ignore firmware-assigned bus numbers."); +#endif + static int pci_has_quirk(uint32_t devid, int quirk) { @@ -3195,6 +3202,134 @@ bus_release_resource(self, SYS_RES_MEMORY, rid, res); } +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) +static void +pci_reserve_secbus(device_t bus, device_t dev, pcicfgregs *cfg, + struct resource_list *rl) +{ + struct resource *res; + u_long start, end, count; + int rid, sec_bus, sec_reg, sub_bus, sub_reg; + + switch (cfg->hdrtype & PCIM_HDRTYPE) { + case PCIM_HDRTYPE_BRIDGE: + sec_reg = PCIR_SECBUS_1; + sub_reg = PCIR_SUBBUS_1; + break; + case PCIM_HDRTYPE_CARDBUS: + sec_reg = PCIR_SECBUS_2; + sub_reg = PCIR_SUBBUS_2; + break; + default: + return; + } + + /* + * If requested, clear secondary bus registers in bridge devices + * to force a complete renumbering rather than reserving the + * existing range. + */ + if (pci_clear_buses) { + PCI_WRITE_CONFIG(bus, dev, sec_reg, 0, 1); + PCI_WRITE_CONFIG(bus, dev, sub_reg, 0, 1); + return; + } + + /* + * If the existing bus range is valid, attempt to reserve it + * from our parent. If this fails for any reason, clear the + * secbus and subbus registers. + * + * XXX: Should we reset sub_bus to sec_bus if it is < sec_bus? + * This would at least preserve the existing sec_bus if it is + * valid. + */ + sec_bus = PCI_READ_CONFIG(bus, dev, sec_reg, 1); + sub_bus = PCI_READ_CONFIG(bus, dev, sub_reg, 1); + if (bootverbose) + printf("\tsecbus=%d, subbus=%d\n", sec_bus, sub_bus); + if (sec_bus > 0 && sub_bus >= sec_bus) { + start = sec_bus; + end = sub_bus; + count = end - start + 1; + + resource_list_add(rl, PCI_RES_BUS, 0, start, end, count); + rid = 0; + res = resource_list_reserve(rl, bus, dev, PCI_RES_BUS, &rid, + start, end, count, 0); + if (res == NULL) { + if (bootverbose) + device_printf(bus, + "pci%d:%d:%d:%d secbus failed to allocate\n", + pci_get_domain(dev), pci_get_bus(dev), + pci_get_slot(dev), pci_get_function(dev)); + resource_list_delete(rl, PCI_RES_BUS, 0); + } + } else + res = NULL; + if (res == NULL) { + PCI_WRITE_CONFIG(bus, dev, sec_reg, 0, 1); + PCI_WRITE_CONFIG(bus, dev, sub_reg, 0, 1); + } +} + +static struct resource * +pci_alloc_secbus(device_t dev, device_t child, int *rid, u_long start, + u_long end, u_long count, u_int flags) +{ + struct pci_devinfo *dinfo; + pcicfgregs *cfg; + struct resource_list *rl; + struct resource *res; + int sec_reg, sub_reg; + + dinfo = device_get_ivars(dev); + cfg = &dinfo->cfg; + rl = &dinfo->resources; + switch (cfg->hdrtype & PCIM_HDRTYPE) { + case PCIM_HDRTYPE_BRIDGE: + sec_reg = PCIR_SECBUS_1; + sub_reg = PCIR_SUBBUS_1; + break; + case PCIM_HDRTYPE_CARDBUS: + sec_reg = PCIR_SECBUS_2; + sub_reg = PCIR_SUBBUS_2; + break; + default: + return (NULL); + } + + /* + * rid 0 is used to request an already reserved range while + * rid 1 is used to request an arbitrary range with a specific + * count. + */ + if (*rid > 1) + return (NULL); + + if (*rid == 1) { + *rid = 0; + resource_list_add(rl, PCI_RES_BUS, *rid, start, end, count); + res = resource_list_reserve(rl, dev, child, PCI_RES_BUS, rid, + start, end, count, flags & ~RF_ACTIVE); + if (res == NULL) { + resource_list_delete(rl, PCI_RES_BUS, *rid); + device_printf(child, "allocating %lu bus%s failed\n", + count, count == 1 ? "" : "es"); + return (NULL); + } + if (bootverbose) + device_printf(child, + "Lazy allocation of %lu bus%s at %lu\n", count, + count == 1 ? "" : "es", rman_get_start(res)); + PCI_WRITE_CONFIG(dev, child, sec_reg, rman_get_start(res), 1); + PCI_WRITE_CONFIG(dev, child, sub_reg, rman_get_end(res), 1); + } + return (resource_list_alloc(rl, dev, child, PCI_RES_BUS, rid, start, + end, count, flags)); +} +#endif + void pci_add_resources(device_t bus, device_t dev, int force, uint32_t prefetchmask) { @@ -3267,6 +3402,14 @@ else if (pci_get_progif(dev) == PCIP_SERIALBUS_USB_UHCI) uhci_early_takeover(dev); } + +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) + /* + * Reserve resources for secondary bus ranges behind bridge + * devices. + */ + pci_reserve_secbus(bus, dev, cfg, rl); +#endif } void @@ -3736,6 +3879,10 @@ retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx"); retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx"); retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); +#ifdef PCI_RES_BUS + /* XXX: Maybe? */ + retval += resource_list_print_type(rl, "bus", PCI_RES_BUS, "%ld"); +#endif if (device_get_flags(dev)) retval += printf(" flags %#x", device_get_flags(dev)); @@ -4211,7 +4358,6 @@ { struct pci_devinfo *dinfo = device_get_ivars(child); struct resource_list *rl = &dinfo->resources; - struct resource_list_entry *rle; struct resource *res; struct pci_map *pm; pci_addr_t map, testval; @@ -4284,23 +4430,16 @@ * Allocate enough resource, and then write back the * appropriate BAR for that resource. */ - res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, type, rid, - start, end, count, flags & ~RF_ACTIVE); + resource_list_add(rl, type, *rid, start, end, count); + res = resource_list_reserve(rl, dev, child, type, rid, start, end, + count, flags & ~RF_ACTIVE); if (res == NULL) { + resource_list_delete(rl, type, *rid); device_printf(child, "%#lx bytes of rid %#x res %d failed (%#lx, %#lx).\n", count, *rid, type, start, end); goto out; } - resource_list_add(rl, type, *rid, start, end, count); - rle = resource_list_find(rl, type, *rid); - if (rle == NULL) - panic("pci_reserve_map: unexpectedly can't find resource."); - rle->res = res; - rle->start = rman_get_start(res); - rle->end = rman_get_end(res); - rle->count = count; - rle->flags = RLE_RESERVED; if (bootverbose) device_printf(child, "Lazy allocation of %#lx bytes rid %#x type %d at %#lx\n", @@ -4334,17 +4473,8 @@ switch (type) { #if defined(NEW_PCIB) && defined(PCI_RES_BUS) case PCI_RES_BUS: - /* - * If rid 0 is not already allocated, create a new - * resource list entry. - */ - if (*rid != 0) - return (NULL); - rle = resource_list_find(rl, type, *rid); - if (rle != NULL && rle->res != NULL) - return (NULL); - resource_list_add(rl, type, *rid, start, end, count); - break; + return (pci_alloc_secbus(dev, child, rid, start, end, count, + flags)); #endif case SYS_RES_IRQ: /* ==== //depot/projects/pci/sys/dev/pci/pci_pci.c#43 (text+ko) ==== @@ -539,6 +539,16 @@ char buf[64]; int error, rid; + switch (pci_read_config(dev, PCIR_HDRTYPE, 1) & PCIM_HDRTYPE) { + case PCIM_HDRTYPE_BRIDGE: + bus->sub_reg = PCIR_SUBBUS_1; + break; + case PCIM_HDRTYPE_CARDBUS: + bus->sub_reg = PCIR_SUBBUS_2; + break; + default: + panic("not a PCI bridge"); + } bus->dev = dev; bus->rman.rm_start = 0; bus->rman.rm_end = PCI_BUSMAX; @@ -550,41 +560,15 @@ panic("Failed to initialize %s bus number rman", device_get_nameunit(dev)); -#if 0 - /* - * XXX: Should we reset subbus to secbus if it is < secbus? - * This would at least preserve the existing secbus if it is - * valid. - */ - if (bus->sub < bus->sec) - bus->sub = bus->sec; -#endif + /* Allocate any existing bus range. */ + rid = 0; + bus->res = bus_alloc_resource_any(dev, PCI_RES_BUS, &rid, 0); - /* - * Allocate a resource for the existing secondary bus number - * range if it is valid. - */ - if (bus->sec != 0 && bus->sub >= bus->sec) { - rid = 0; - bus->res = bus_alloc_resource(dev, PCI_RES_BUS, &rid, bus->sec, - bus->sub, bus->sub - bus->sec + 1, 0); - if (bus->res == NULL) { - if (bootverbose || 1) - device_printf(dev, - "failed to allocate initial secbus range: %u-%u\n", - bus->sec, bus->sub); -#if 0 - /* XXX: Should we clear these on failure? */ - bus->sec = 0; - bus->sub = 0; -#endif - } - /* XXX */ - if (bus->res != NULL) - device_printf(dev, - "allocated initial secbus range %lu-%lu\n", - rman_get_start(bus->res), rman_get_end(bus->res)); - } + /* XXX */ + if (bus->res != NULL) + device_printf(dev, + "allocated initial secbus range %lu-%lu\n", + rman_get_start(bus->res), rman_get_end(bus->res)); /* * If we don't have a valid resource, allocate a fresh resource @@ -600,7 +584,7 @@ * This doesn't use bus_alloc_resource_any() as the * count of 1 is explicit. */ - rid = 0; + rid = 1; bus->res = bus_alloc_resource(dev, PCI_RES_BUS, &rid, 0ul, ~0ul, 1, 0); if (bus->res != NULL) { @@ -610,25 +594,22 @@ device_printf(bus->dev, "allocated initial secbus %lu\n", rman_get_start(bus->res)); - bus->sec = rman_get_start(bus->res); - bus->sub = rman_get_end(bus->res); } else device_printf(bus->dev, "failed to allocate secondary bus number\n"); } /* - * Add the initial resource to the rman and write updated - * secbus and subbus registers. + * Add the initial resource to the rman. */ if (bus->res != NULL) { error = rman_manage_region(&bus->rman, rman_get_start(bus->res), rman_get_end(bus->res)); if (error) panic("Failed to add resource to rman"); + bus->sec = rman_get_start(bus->res); + bus->sub = rman_get_end(bus->res); } - pci_write_config(dev, bus->sec_reg, bus->sec, 1); - pci_write_config(dev, bus->sub_reg, bus->sub, 1); } static struct resource * @@ -637,7 +618,8 @@ { struct resource *res; - res = rman_reserve_resource(&bus->rman, start, end, count, flags, child); + res = rman_reserve_resource(&bus->rman, start, end, count, flags, + child); if (res == NULL) return (NULL); @@ -968,6 +950,8 @@ * Quirk handling. */ switch (pci_get_devid(dev)) { +#if 0 + /* XXX: This is now broken */ case 0x12258086: /* Intel 82454KX/GX (Orion) */ { uint8_t supbus; @@ -979,6 +963,7 @@ } break; } +#endif /* * The i82380FB mobile docking controller is a PCI-PCI bridge, @@ -992,6 +977,7 @@ sc->flags |= PCIB_SUBTRACTIVE; break; +#if !defined(NEW_PCIB) && !defined(PCI_RES_BUS) /* Compaq R3000 BIOS sets wrong subordinate bus number. */ case 0x00dd10de: { @@ -1017,6 +1003,7 @@ } break; } +#endif } if (pci_msi_device_blacklisted(dev)) @@ -1039,8 +1026,6 @@ #ifdef NEW_PCIB #ifdef PCI_RES_BUS - sc->bus.sec_reg = PCIR_SECBUS_1; - sc->bus.sub_reg = PCIR_SUBBUS_1; pcib_setup_secbus(dev, &sc->bus); #endif pcib_probe_windows(sc); ==== //depot/projects/pci/sys/dev/pci/pcib_private.h#27 (text+ko) ==== @@ -91,7 +91,6 @@ struct rman rman; struct resource *res; const char *name; - int sec_reg; int sub_reg; #endif };
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201307222124.r6MLOSON080132>