diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2015-02-02 14:27:13 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2015-02-13 10:34:19 +0100 |
commit | 7eeb079d84bc4abe9897be0047fc28a754e46ecd (patch) | |
tree | 9b47ac7055ce0cb1e2d86c684a2a7a1cd20c0c4d /freebsd/sys/dev/pci | |
parent | freebsd-to-rtems.py: Fix revert includes (diff) | |
download | rtems-libbsd-7eeb079d84bc4abe9897be0047fc28a754e46ecd.tar.bz2 |
Update to FreeBSD 9.3
Diffstat (limited to 'freebsd/sys/dev/pci')
-rw-r--r-- | freebsd/sys/dev/pci/pci.c | 283 | ||||
-rw-r--r-- | freebsd/sys/dev/pci/pci_pci.c | 508 | ||||
-rw-r--r-- | freebsd/sys/dev/pci/pci_private.h | 2 | ||||
-rw-r--r-- | freebsd/sys/dev/pci/pci_user.c | 128 | ||||
-rw-r--r-- | freebsd/sys/dev/pci/pcib_private.h | 3 | ||||
-rw-r--r-- | freebsd/sys/dev/pci/pcireg.h | 9 | ||||
-rw-r--r-- | freebsd/sys/dev/pci/pcivar.h | 9 |
7 files changed, 733 insertions, 209 deletions
diff --git a/freebsd/sys/dev/pci/pci.c b/freebsd/sys/dev/pci/pci.c index 94eeb844..7dcaa0d5 100644 --- a/freebsd/sys/dev/pci/pci.c +++ b/freebsd/sys/dev/pci/pci.c @@ -164,7 +164,7 @@ static device_method_t pci_methods[] = { DEVMETHOD(bus_delete_resource, pci_delete_resource), DEVMETHOD(bus_alloc_resource, pci_alloc_resource), DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), - DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), + DEVMETHOD(bus_release_resource, pci_release_resource), DEVMETHOD(bus_activate_resource, pci_activate_resource), DEVMETHOD(bus_deactivate_resource, pci_deactivate_resource), DEVMETHOD(bus_child_pnpinfo_str, pci_child_pnpinfo_str_method), @@ -347,6 +347,11 @@ SYSCTL_INT(_hw_pci, OID_AUTO, usb_early_takeover, CTLFLAG_RDTUN, Disable this if you depend on BIOS emulation of USB devices, that is\n\ you use USB devices (like keyboard or mouse) but do not load USB drivers"); +static int pci_clear_bars; +TUNABLE_INT("hw.pci.clear_bars", &pci_clear_bars); +SYSCTL_INT(_hw_pci, OID_AUTO, clear_bars, CTLFLAG_RDTUN, &pci_clear_bars, 0, + "Ignore firmware-assigned resources for BARs."); + static int pci_has_quirk(uint32_t devid, int quirk) { @@ -999,7 +1004,7 @@ pci_read_vpd(device_t pcib, pcicfgregs *cfg) state = -2; break; } - dflen = byte2; + cfg->vpd.vpd_ros[off].len = dflen = byte2; if (dflen == 0 && strncmp(cfg->vpd.vpd_ros[off].keyword, "RV", 2) == 0) { @@ -1200,6 +1205,17 @@ pci_get_vpd_readonly_method(device_t dev, device_t child, const char *kw, return (ENXIO); } +struct pcicfg_vpd * +pci_fetch_vpd_list(device_t dev) +{ + struct pci_devinfo *dinfo = device_get_ivars(dev); + pcicfgregs *cfg = &dinfo->cfg; + + if (!cfg->vpd.vpd_cached && cfg->vpd.vpd_reg != 0) + pci_read_vpd(device_get_parent(device_get_parent(dev)), cfg); + return (&cfg->vpd); +} + /* * Find the requested extended capability and return the offset in * configuration space via the pointer provided. The function returns @@ -2668,7 +2684,7 @@ pci_add_map(device_t bus, device_t dev, int reg, struct resource_list *rl, struct pci_map *pm; pci_addr_t base, map, testval; pci_addr_t start, end, count; - int barlen, basezero, maprange, mapsize, type; + int barlen, basezero, flags, maprange, mapsize, type; uint16_t cmd; struct resource *res; @@ -2774,7 +2790,10 @@ pci_add_map(device_t bus, device_t dev, int reg, struct resource_list *rl, } count = (pci_addr_t)1 << mapsize; - if (basezero || base == pci_mapbase(testval)) { + flags = RF_ALIGNMENT_LOG2(mapsize); + if (prefetch) + flags |= RF_PREFETCHABLE; + if (basezero || base == pci_mapbase(testval) || pci_clear_bars) { start = 0; /* Let the parent decide. */ end = ~0ul; } else { @@ -2790,7 +2809,7 @@ pci_add_map(device_t bus, device_t dev, int reg, struct resource_list *rl, * pci_alloc_resource(). */ res = resource_list_reserve(rl, bus, dev, type, ®, start, end, count, - prefetch ? RF_PREFETCHABLE : 0); + flags); if (pci_do_realloc_bars && res == NULL && (start != 0 || end != ~0ul)) { /* * If the allocation fails, try to allocate a resource for @@ -2801,7 +2820,7 @@ pci_add_map(device_t bus, device_t dev, int reg, struct resource_list *rl, resource_list_delete(rl, type, reg); resource_list_add(rl, type, reg, 0, ~0ul, count); res = resource_list_reserve(rl, bus, dev, type, ®, 0, ~0ul, - count, prefetch ? RF_PREFETCHABLE : 0); + count, flags); } if (res == NULL) { /* @@ -3650,105 +3669,107 @@ static const struct { int class; int subclass; + int report; /* 0 = bootverbose, 1 = always */ const char *desc; } pci_nomatch_tab[] = { - {PCIC_OLD, -1, "old"}, - {PCIC_OLD, PCIS_OLD_NONVGA, "non-VGA display device"}, - {PCIC_OLD, PCIS_OLD_VGA, "VGA-compatible display device"}, - {PCIC_STORAGE, -1, "mass storage"}, - {PCIC_STORAGE, PCIS_STORAGE_SCSI, "SCSI"}, - {PCIC_STORAGE, PCIS_STORAGE_IDE, "ATA"}, - {PCIC_STORAGE, PCIS_STORAGE_FLOPPY, "floppy disk"}, - {PCIC_STORAGE, PCIS_STORAGE_IPI, "IPI"}, - {PCIC_STORAGE, PCIS_STORAGE_RAID, "RAID"}, - {PCIC_STORAGE, PCIS_STORAGE_ATA_ADMA, "ATA (ADMA)"}, - {PCIC_STORAGE, PCIS_STORAGE_SATA, "SATA"}, - {PCIC_STORAGE, PCIS_STORAGE_SAS, "SAS"}, - {PCIC_STORAGE, PCIS_STORAGE_NVM, "NVM"}, - {PCIC_NETWORK, -1, "network"}, - {PCIC_NETWORK, PCIS_NETWORK_ETHERNET, "ethernet"}, - {PCIC_NETWORK, PCIS_NETWORK_TOKENRING, "token ring"}, - {PCIC_NETWORK, PCIS_NETWORK_FDDI, "fddi"}, - {PCIC_NETWORK, PCIS_NETWORK_ATM, "ATM"}, - {PCIC_NETWORK, PCIS_NETWORK_ISDN, "ISDN"}, - {PCIC_DISPLAY, -1, "display"}, - {PCIC_DISPLAY, PCIS_DISPLAY_VGA, "VGA"}, - {PCIC_DISPLAY, PCIS_DISPLAY_XGA, "XGA"}, - {PCIC_DISPLAY, PCIS_DISPLAY_3D, "3D"}, - {PCIC_MULTIMEDIA, -1, "multimedia"}, - {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_VIDEO, "video"}, - {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_AUDIO, "audio"}, - {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_TELE, "telephony"}, - {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_HDA, "HDA"}, - {PCIC_MEMORY, -1, "memory"}, - {PCIC_MEMORY, PCIS_MEMORY_RAM, "RAM"}, - {PCIC_MEMORY, PCIS_MEMORY_FLASH, "flash"}, - {PCIC_BRIDGE, -1, "bridge"}, - {PCIC_BRIDGE, PCIS_BRIDGE_HOST, "HOST-PCI"}, - {PCIC_BRIDGE, PCIS_BRIDGE_ISA, "PCI-ISA"}, - {PCIC_BRIDGE, PCIS_BRIDGE_EISA, "PCI-EISA"}, - {PCIC_BRIDGE, PCIS_BRIDGE_MCA, "PCI-MCA"}, - {PCIC_BRIDGE, PCIS_BRIDGE_PCI, "PCI-PCI"}, - {PCIC_BRIDGE, PCIS_BRIDGE_PCMCIA, "PCI-PCMCIA"}, - {PCIC_BRIDGE, PCIS_BRIDGE_NUBUS, "PCI-NuBus"}, - {PCIC_BRIDGE, PCIS_BRIDGE_CARDBUS, "PCI-CardBus"}, - {PCIC_BRIDGE, PCIS_BRIDGE_RACEWAY, "PCI-RACEway"}, - {PCIC_SIMPLECOMM, -1, "simple comms"}, - {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_UART, "UART"}, /* could detect 16550 */ - {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_PAR, "parallel port"}, - {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MULSER, "multiport serial"}, - {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MODEM, "generic modem"}, - {PCIC_BASEPERIPH, -1, "base peripheral"}, - {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PIC, "interrupt controller"}, - {PCIC_BASEPERIPH, PCIS_BASEPERIPH_DMA, "DMA controller"}, - {PCIC_BASEPERIPH, PCIS_BASEPERIPH_TIMER, "timer"}, - {PCIC_BASEPERIPH, PCIS_BASEPERIPH_RTC, "realtime clock"}, - {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PCIHOT, "PCI hot-plug controller"}, - {PCIC_BASEPERIPH, PCIS_BASEPERIPH_SDHC, "SD host controller"}, - {PCIC_INPUTDEV, -1, "input device"}, - {PCIC_INPUTDEV, PCIS_INPUTDEV_KEYBOARD, "keyboard"}, - {PCIC_INPUTDEV, PCIS_INPUTDEV_DIGITIZER,"digitizer"}, - {PCIC_INPUTDEV, PCIS_INPUTDEV_MOUSE, "mouse"}, - {PCIC_INPUTDEV, PCIS_INPUTDEV_SCANNER, "scanner"}, - {PCIC_INPUTDEV, PCIS_INPUTDEV_GAMEPORT, "gameport"}, - {PCIC_DOCKING, -1, "docking station"}, - {PCIC_PROCESSOR, -1, "processor"}, - {PCIC_SERIALBUS, -1, "serial bus"}, - {PCIC_SERIALBUS, PCIS_SERIALBUS_FW, "FireWire"}, - {PCIC_SERIALBUS, PCIS_SERIALBUS_ACCESS, "AccessBus"}, - {PCIC_SERIALBUS, PCIS_SERIALBUS_SSA, "SSA"}, - {PCIC_SERIALBUS, PCIS_SERIALBUS_USB, "USB"}, - {PCIC_SERIALBUS, PCIS_SERIALBUS_FC, "Fibre Channel"}, - {PCIC_SERIALBUS, PCIS_SERIALBUS_SMBUS, "SMBus"}, - {PCIC_WIRELESS, -1, "wireless controller"}, - {PCIC_WIRELESS, PCIS_WIRELESS_IRDA, "iRDA"}, - {PCIC_WIRELESS, PCIS_WIRELESS_IR, "IR"}, - {PCIC_WIRELESS, PCIS_WIRELESS_RF, "RF"}, - {PCIC_INTELLIIO, -1, "intelligent I/O controller"}, - {PCIC_INTELLIIO, PCIS_INTELLIIO_I2O, "I2O"}, - {PCIC_SATCOM, -1, "satellite communication"}, - {PCIC_SATCOM, PCIS_SATCOM_TV, "sat TV"}, - {PCIC_SATCOM, PCIS_SATCOM_AUDIO, "sat audio"}, - {PCIC_SATCOM, PCIS_SATCOM_VOICE, "sat voice"}, - {PCIC_SATCOM, PCIS_SATCOM_DATA, "sat data"}, - {PCIC_CRYPTO, -1, "encrypt/decrypt"}, - {PCIC_CRYPTO, PCIS_CRYPTO_NETCOMP, "network/computer crypto"}, - {PCIC_CRYPTO, PCIS_CRYPTO_ENTERTAIN, "entertainment crypto"}, - {PCIC_DASP, -1, "dasp"}, - {PCIC_DASP, PCIS_DASP_DPIO, "DPIO module"}, - {0, 0, NULL} + {PCIC_OLD, -1, 1, "old"}, + {PCIC_OLD, PCIS_OLD_NONVGA, 1, "non-VGA display device"}, + {PCIC_OLD, PCIS_OLD_VGA, 1, "VGA-compatible display device"}, + {PCIC_STORAGE, -1, 1, "mass storage"}, + {PCIC_STORAGE, PCIS_STORAGE_SCSI, 1, "SCSI"}, + {PCIC_STORAGE, PCIS_STORAGE_IDE, 1, "ATA"}, + {PCIC_STORAGE, PCIS_STORAGE_FLOPPY, 1, "floppy disk"}, + {PCIC_STORAGE, PCIS_STORAGE_IPI, 1, "IPI"}, + {PCIC_STORAGE, PCIS_STORAGE_RAID, 1, "RAID"}, + {PCIC_STORAGE, PCIS_STORAGE_ATA_ADMA, 1, "ATA (ADMA)"}, + {PCIC_STORAGE, PCIS_STORAGE_SATA, 1, "SATA"}, + {PCIC_STORAGE, PCIS_STORAGE_SAS, 1, "SAS"}, + {PCIC_STORAGE, PCIS_STORAGE_NVM, 1, "NVM"}, + {PCIC_NETWORK, -1, 1, "network"}, + {PCIC_NETWORK, PCIS_NETWORK_ETHERNET, 1, "ethernet"}, + {PCIC_NETWORK, PCIS_NETWORK_TOKENRING, 1, "token ring"}, + {PCIC_NETWORK, PCIS_NETWORK_FDDI, 1, "fddi"}, + {PCIC_NETWORK, PCIS_NETWORK_ATM, 1, "ATM"}, + {PCIC_NETWORK, PCIS_NETWORK_ISDN, 1, "ISDN"}, + {PCIC_DISPLAY, -1, 1, "display"}, + {PCIC_DISPLAY, PCIS_DISPLAY_VGA, 1, "VGA"}, + {PCIC_DISPLAY, PCIS_DISPLAY_XGA, 1, "XGA"}, + {PCIC_DISPLAY, PCIS_DISPLAY_3D, 1, "3D"}, + {PCIC_MULTIMEDIA, -1, 1, "multimedia"}, + {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_VIDEO, 1, "video"}, + {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_AUDIO, 1, "audio"}, + {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_TELE, 1, "telephony"}, + {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_HDA, 1, "HDA"}, + {PCIC_MEMORY, -1, 1, "memory"}, + {PCIC_MEMORY, PCIS_MEMORY_RAM, 1, "RAM"}, + {PCIC_MEMORY, PCIS_MEMORY_FLASH, 1, "flash"}, + {PCIC_BRIDGE, -1, 1, "bridge"}, + {PCIC_BRIDGE, PCIS_BRIDGE_HOST, 1, "HOST-PCI"}, + {PCIC_BRIDGE, PCIS_BRIDGE_ISA, 1, "PCI-ISA"}, + {PCIC_BRIDGE, PCIS_BRIDGE_EISA, 1, "PCI-EISA"}, + {PCIC_BRIDGE, PCIS_BRIDGE_MCA, 1, "PCI-MCA"}, + {PCIC_BRIDGE, PCIS_BRIDGE_PCI, 1, "PCI-PCI"}, + {PCIC_BRIDGE, PCIS_BRIDGE_PCMCIA, 1, "PCI-PCMCIA"}, + {PCIC_BRIDGE, PCIS_BRIDGE_NUBUS, 1, "PCI-NuBus"}, + {PCIC_BRIDGE, PCIS_BRIDGE_CARDBUS, 1, "PCI-CardBus"}, + {PCIC_BRIDGE, PCIS_BRIDGE_RACEWAY, 1, "PCI-RACEway"}, + {PCIC_SIMPLECOMM, -1, 1, "simple comms"}, + {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_UART, 1, "UART"}, /* could detect 16550 */ + {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_PAR, 1, "parallel port"}, + {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MULSER, 1, "multiport serial"}, + {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MODEM, 1, "generic modem"}, + {PCIC_BASEPERIPH, -1, 0, "base peripheral"}, + {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PIC, 1, "interrupt controller"}, + {PCIC_BASEPERIPH, PCIS_BASEPERIPH_DMA, 1, "DMA controller"}, + {PCIC_BASEPERIPH, PCIS_BASEPERIPH_TIMER, 1, "timer"}, + {PCIC_BASEPERIPH, PCIS_BASEPERIPH_RTC, 1, "realtime clock"}, + {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PCIHOT, 1, "PCI hot-plug controller"}, + {PCIC_BASEPERIPH, PCIS_BASEPERIPH_SDHC, 1, "SD host controller"}, + {PCIC_INPUTDEV, -1, 1, "input device"}, + {PCIC_INPUTDEV, PCIS_INPUTDEV_KEYBOARD, 1, "keyboard"}, + {PCIC_INPUTDEV, PCIS_INPUTDEV_DIGITIZER,1, "digitizer"}, + {PCIC_INPUTDEV, PCIS_INPUTDEV_MOUSE, 1, "mouse"}, + {PCIC_INPUTDEV, PCIS_INPUTDEV_SCANNER, 1, "scanner"}, + {PCIC_INPUTDEV, PCIS_INPUTDEV_GAMEPORT, 1, "gameport"}, + {PCIC_DOCKING, -1, 1, "docking station"}, + {PCIC_PROCESSOR, -1, 1, "processor"}, + {PCIC_SERIALBUS, -1, 1, "serial bus"}, + {PCIC_SERIALBUS, PCIS_SERIALBUS_FW, 1, "FireWire"}, + {PCIC_SERIALBUS, PCIS_SERIALBUS_ACCESS, 1, "AccessBus"}, + {PCIC_SERIALBUS, PCIS_SERIALBUS_SSA, 1, "SSA"}, + {PCIC_SERIALBUS, PCIS_SERIALBUS_USB, 1, "USB"}, + {PCIC_SERIALBUS, PCIS_SERIALBUS_FC, 1, "Fibre Channel"}, + {PCIC_SERIALBUS, PCIS_SERIALBUS_SMBUS, 0, "SMBus"}, + {PCIC_WIRELESS, -1, 1, "wireless controller"}, + {PCIC_WIRELESS, PCIS_WIRELESS_IRDA, 1, "iRDA"}, + {PCIC_WIRELESS, PCIS_WIRELESS_IR, 1, "IR"}, + {PCIC_WIRELESS, PCIS_WIRELESS_RF, 1, "RF"}, + {PCIC_INTELLIIO, -1, 1, "intelligent I/O controller"}, + {PCIC_INTELLIIO, PCIS_INTELLIIO_I2O, 1, "I2O"}, + {PCIC_SATCOM, -1, 1, "satellite communication"}, + {PCIC_SATCOM, PCIS_SATCOM_TV, 1, "sat TV"}, + {PCIC_SATCOM, PCIS_SATCOM_AUDIO, 1, "sat audio"}, + {PCIC_SATCOM, PCIS_SATCOM_VOICE, 1, "sat voice"}, + {PCIC_SATCOM, PCIS_SATCOM_DATA, 1, "sat data"}, + {PCIC_CRYPTO, -1, 1, "encrypt/decrypt"}, + {PCIC_CRYPTO, PCIS_CRYPTO_NETCOMP, 1, "network/computer crypto"}, + {PCIC_CRYPTO, PCIS_CRYPTO_ENTERTAIN, 1, "entertainment crypto"}, + {PCIC_DASP, -1, 0, "dasp"}, + {PCIC_DASP, PCIS_DASP_DPIO, 1, "DPIO module"}, + {0, 0, 0, NULL} }; void pci_probe_nomatch(device_t dev, device_t child) { - int i; + int i, report; const char *cp, *scp; char *device; /* * Look for a listing for this device in a loaded device database. */ + report = 1; if ((device = pci_describe_device(child)) != NULL) { device_printf(dev, "<%s>", device); free(device, M_DEVBUF); @@ -3763,19 +3784,25 @@ pci_probe_nomatch(device_t dev, device_t child) if (pci_nomatch_tab[i].class == pci_get_class(child)) { if (pci_nomatch_tab[i].subclass == -1) { cp = pci_nomatch_tab[i].desc; + report = pci_nomatch_tab[i].report; } else if (pci_nomatch_tab[i].subclass == pci_get_subclass(child)) { scp = pci_nomatch_tab[i].desc; + report = pci_nomatch_tab[i].report; } } } - device_printf(dev, "<%s%s%s>", - cp ? cp : "", - ((cp != NULL) && (scp != NULL)) ? ", " : "", - scp ? scp : ""); + if (report || bootverbose) { + device_printf(dev, "<%s%s%s>", + cp ? cp : "", + ((cp != NULL) && (scp != NULL)) ? ", " : "", + scp ? scp : ""); + } + } + if (report || bootverbose) { + printf(" at device %d.%d (no driver attached)\n", + pci_get_slot(child), pci_get_function(child)); } - printf(" at device %d.%d (no driver attached)\n", - pci_get_slot(child), pci_get_function(child)); pci_cfg_save(child, device_get_ivars(child), 1); } @@ -4078,7 +4105,6 @@ pci_reserve_map(device_t dev, device_t child, int type, int *rid, { 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; @@ -4151,23 +4177,16 @@ pci_reserve_map(device_t dev, device_t child, int type, int *rid, * 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", @@ -4182,11 +4201,11 @@ struct resource * pci_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { - struct pci_devinfo *dinfo = device_get_ivars(child); - struct resource_list *rl = &dinfo->resources; + struct pci_devinfo *dinfo; + struct resource_list *rl; struct resource_list_entry *rle; struct resource *res; - pcicfgregs *cfg = &dinfo->cfg; + pcicfgregs *cfg; if (device_get_parent(child) != dev) return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, @@ -4195,6 +4214,9 @@ pci_alloc_resource(device_t dev, device_t child, int type, int *rid, /* * Perform lazy resource allocation */ + dinfo = device_get_ivars(child); + rl = &dinfo->resources; + cfg = &dinfo->cfg; switch (type) { case SYS_RES_IRQ: /* @@ -4250,6 +4272,41 @@ pci_alloc_resource(device_t dev, device_t child, int type, int *rid, } int +pci_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + struct pci_devinfo *dinfo; + struct resource_list *rl; + pcicfgregs *cfg; + + if (device_get_parent(child) != dev) + return (BUS_RELEASE_RESOURCE(device_get_parent(dev), child, + type, rid, r)); + + dinfo = device_get_ivars(child); + cfg = &dinfo->cfg; +#ifdef NEW_PCIB + /* + * PCI-PCI bridge I/O window resources are not BARs. For + * those allocations just pass the request up the tree. + */ + if (cfg->hdrtype == PCIM_HDRTYPE_BRIDGE && + (type == SYS_RES_IOPORT || type == SYS_RES_MEMORY)) { + switch (rid) { + case PCIR_IOBASEL_1: + case PCIR_MEMBASE_1: + case PCIR_PMBASEL_1: + return (bus_generic_release_resource(dev, child, type, + rid, r)); + } + } +#endif + + rl = &dinfo->resources; + return (resource_list_release(rl, dev, child, type, rid, r)); +} + +int pci_activate_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { diff --git a/freebsd/sys/dev/pci/pci_pci.c b/freebsd/sys/dev/pci/pci_pci.c index bfaabf35..6c159aec 100644 --- a/freebsd/sys/dev/pci/pci_pci.c +++ b/freebsd/sys/dev/pci/pci_pci.c @@ -105,13 +105,12 @@ DEFINE_CLASS_0(pcib, pcib_driver, pcib_methods, sizeof(struct pcib_softc)); DRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, NULL, NULL); #ifdef NEW_PCIB -/* - * XXX Todo: - * - properly handle the ISA enable bit. If it is set, we should change - * the behavior of the I/O window resource and rman to not allocate the - * blocked ranges (upper 768 bytes of each 1K in the first 64k of the - * I/O port address space). - */ +SYSCTL_DECL(_hw_pci); + +static int pci_clear_pcib; +TUNABLE_INT("hw.pci.clear_pcib", &pci_clear_pcib); +SYSCTL_INT(_hw_pci, OID_AUTO, clear_pcib, CTLFLAG_RDTUN, &pci_clear_pcib, 0, + "Clear firmware-assigned resources for PCI-PCI bridge I/O windows."); /* * Is a resource from a child device sub-allocated from one of our @@ -191,10 +190,183 @@ pcib_write_windows(struct pcib_softc *sc, int mask) } } +/* + * This is used to reject I/O port allocations that conflict with an + * ISA alias range. + */ +static int +pcib_is_isa_range(struct pcib_softc *sc, u_long start, u_long end, u_long count) +{ + u_long next_alias; + + if (!(sc->bridgectl & PCIB_BCR_ISA_ENABLE)) + return (0); + + /* Only check fixed ranges for overlap. */ + if (start + count - 1 != end) + return (0); + + /* ISA aliases are only in the lower 64KB of I/O space. */ + if (start >= 65536) + return (0); + + /* Check for overlap with 0x000 - 0x0ff as a special case. */ + if (start < 0x100) + goto alias; + + /* + * If the start address is an alias, the range is an alias. + * Otherwise, compute the start of the next alias range and + * check if it is before the end of the candidate range. + */ + if ((start & 0x300) != 0) + goto alias; + next_alias = (start & ~0x3fful) | 0x100; + if (next_alias <= end) + goto alias; + return (0); + +alias: + if (bootverbose) + device_printf(sc->dev, + "I/O range %#lx-%#lx overlaps with an ISA alias\n", start, + end); + return (1); +} + +static void +pcib_add_window_resources(struct pcib_window *w, struct resource **res, + int count) +{ + struct resource **newarray; + int error, i; + + newarray = malloc(sizeof(struct resource *) * (w->count + count), + M_DEVBUF, M_WAITOK); + if (w->res != NULL) + bcopy(w->res, newarray, sizeof(struct resource *) * w->count); + bcopy(res, newarray + w->count, sizeof(struct resource *) * count); + free(w->res, M_DEVBUF); + w->res = newarray; + w->count += count; + + for (i = 0; i < count; i++) { + error = rman_manage_region(&w->rman, rman_get_start(res[i]), + rman_get_end(res[i])); + if (error) + panic("Failed to add resource to rman"); + } +} + +typedef void (nonisa_callback)(u_long start, u_long end, void *arg); + +static void +pcib_walk_nonisa_ranges(u_long start, u_long end, nonisa_callback *cb, + void *arg) +{ + u_long next_end; + + /* + * If start is within an ISA alias range, move up to the start + * of the next non-alias range. As a special case, addresses + * in the range 0x000 - 0x0ff should also be skipped since + * those are used for various system I/O devices in ISA + * systems. + */ + if (start <= 65535) { + if (start < 0x100 || (start & 0x300) != 0) { + start &= ~0x3ff; + start += 0x400; + } + } + + /* ISA aliases are only in the lower 64KB of I/O space. */ + while (start <= MIN(end, 65535)) { + next_end = MIN(start | 0xff, end); + cb(start, next_end, arg); + start += 0x400; + } + + if (start <= end) + cb(start, end, arg); +} + +static void +count_ranges(u_long start, u_long end, void *arg) +{ + int *countp; + + countp = arg; + (*countp)++; +} + +struct alloc_state { + struct resource **res; + struct pcib_softc *sc; + int count, error; +}; + +static void +alloc_ranges(u_long start, u_long end, void *arg) +{ + struct alloc_state *as; + struct pcib_window *w; + int rid; + + as = arg; + if (as->error != 0) + return; + + w = &as->sc->io; + rid = w->reg; + if (bootverbose) + device_printf(as->sc->dev, + "allocating non-ISA range %#lx-%#lx\n", start, end); + as->res[as->count] = bus_alloc_resource(as->sc->dev, SYS_RES_IOPORT, + &rid, start, end, end - start + 1, 0); + if (as->res[as->count] == NULL) + as->error = ENXIO; + else + as->count++; +} + +static int +pcib_alloc_nonisa_ranges(struct pcib_softc *sc, u_long start, u_long end) +{ + struct alloc_state as; + int i, new_count; + + /* First, see how many ranges we need. */ + new_count = 0; + pcib_walk_nonisa_ranges(start, end, count_ranges, &new_count); + + /* Second, allocate the ranges. */ + as.res = malloc(sizeof(struct resource *) * new_count, M_DEVBUF, + M_WAITOK); + as.sc = sc; + as.count = 0; + as.error = 0; + pcib_walk_nonisa_ranges(start, end, alloc_ranges, &as); + if (as.error != 0) { + for (i = 0; i < as.count; i++) + bus_release_resource(sc->dev, SYS_RES_IOPORT, + sc->io.reg, as.res[i]); + free(as.res, M_DEVBUF); + return (as.error); + } + KASSERT(as.count == new_count, ("%s: count mismatch", __func__)); + + /* Third, add the ranges to the window. */ + pcib_add_window_resources(&sc->io, as.res, as.count); + free(as.res, M_DEVBUF); + return (0); +} + static void pcib_alloc_window(struct pcib_softc *sc, struct pcib_window *w, int type, int flags, pci_addr_t max_address) { + struct resource *res; char buf[64]; int error, rid; @@ -219,9 +391,15 @@ pcib_alloc_window(struct pcib_softc *sc, struct pcib_window *w, int type, "initial %s window has too many bits, ignoring\n", w->name); return; } - rid = w->reg; - w->res = bus_alloc_resource(sc->dev, type, &rid, w->base, w->limit, - w->limit - w->base + 1, flags); + if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE) + (void)pcib_alloc_nonisa_ranges(sc, w->base, w->limit); + else { + rid = w->reg; + res = bus_alloc_resource(sc->dev, type, &rid, w->base, w->limit, + w->limit - w->base + 1, flags); + if (res != NULL) + pcib_add_window_resources(w, &res, 1); + } if (w->res == NULL) { device_printf(sc->dev, "failed to allocate initial %s window: %#jx-%#jx\n", @@ -232,11 +410,6 @@ pcib_alloc_window(struct pcib_softc *sc, struct pcib_window *w, int type, return; } pcib_activate_window(sc, type); - - error = rman_manage_region(&w->rman, rman_get_start(w->res), - rman_get_end(w->res)); - if (error) - panic("Failed to initialize rman with resource"); } /* @@ -251,6 +424,19 @@ pcib_probe_windows(struct pcib_softc *sc) dev = sc->dev; + if (pci_clear_pcib) { + pci_write_config(dev, PCIR_IOBASEL_1, 0xff, 1); + pci_write_config(dev, PCIR_IOBASEH_1, 0xffff, 2); + pci_write_config(dev, PCIR_IOLIMITL_1, 0, 1); + pci_write_config(dev, PCIR_IOLIMITH_1, 0, 2); + pci_write_config(dev, PCIR_MEMBASE_1, 0xffff, 2); + pci_write_config(dev, PCIR_MEMLIMIT_1, 0, 2); + pci_write_config(dev, PCIR_PMBASEL_1, 0xffff, 2); + pci_write_config(dev, PCIR_PMBASEH_1, 0xffffffff, 4); + pci_write_config(dev, PCIR_PMLIMITL_1, 0, 2); + pci_write_config(dev, PCIR_PMLIMITH_1, 0, 4); + } + /* Determine if the I/O port window is implemented. */ val = pci_read_config(dev, PCIR_IOBASEL_1, 1); if (val == 0) { @@ -543,6 +729,7 @@ pcib_attach_common(device_t dev) struct pcib_softc *sc; struct sysctl_ctx_list *sctx; struct sysctl_oid *soid; + int comma; sc = device_get_softc(dev); sc->dev = dev; @@ -671,10 +858,22 @@ pcib_attach_common(device_t dev) device_printf(dev, " prefetched decode 0x%jx-0x%jx\n", (uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit); #endif - else - device_printf(dev, " no prefetched decode\n"); - if (sc->flags & PCIB_SUBTRACTIVE) - device_printf(dev, " Subtractively decoded bridge.\n"); + if (sc->bridgectl & (PCIB_BCR_ISA_ENABLE | PCIB_BCR_VGA_ENABLE) || + sc->flags & PCIB_SUBTRACTIVE) { + device_printf(dev, " special decode "); + comma = 0; + if (sc->bridgectl & PCIB_BCR_ISA_ENABLE) { + printf("ISA"); + comma = 1; + } + if (sc->bridgectl & PCIB_BCR_VGA_ENABLE) { + printf("%sVGA", comma ? ", " : ""); + comma = 1; + } + if (sc->flags & PCIB_SUBTRACTIVE) + printf("%ssubtractive", comma ? ", " : ""); + printf("\n"); + } } /* @@ -821,23 +1020,197 @@ pcib_suballoc_resource(struct pcib_softc *sc, struct pcib_window *w, return (res); } +/* Allocate a fresh resource range for an unconfigured window. */ +static int +pcib_alloc_new_window(struct pcib_softc *sc, struct pcib_window *w, int type, + u_long start, u_long end, u_long count, u_int flags) +{ + struct resource *res; + u_long base, limit, wmask; + int rid; + + /* + * If this is an I/O window on a bridge with ISA enable set + * and the start address is below 64k, then try to allocate an + * initial window of 0x1000 bytes long starting at address + * 0xf000 and walking down. Note that if the original request + * was larger than the non-aliased range size of 0x100 our + * caller would have raised the start address up to 64k + * already. + */ + if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE && + start < 65536) { + for (base = 0xf000; (long)base >= 0; base -= 0x1000) { + limit = base + 0xfff; + + /* + * Skip ranges that wouldn't work for the + * original request. Note that the actual + * window that overlaps are the non-alias + * ranges within [base, limit], so this isn't + * quite a simple comparison. + */ + if (start + count > limit - 0x400) + continue; + if (base == 0) { + /* + * The first open region for the window at + * 0 is 0x400-0x4ff. + */ + if (end - count + 1 < 0x400) + continue; + } else { + if (end - count + 1 < base) + continue; + } + + if (pcib_alloc_nonisa_ranges(sc, base, limit) == 0) { + w->base = base; + w->limit = limit; + return (0); + } + } + return (ENOSPC); + } + + wmask = (1ul << w->step) - 1; + if (RF_ALIGNMENT(flags) < w->step) { + flags &= ~RF_ALIGNMENT_MASK; + flags |= RF_ALIGNMENT_LOG2(w->step); + } + start &= ~wmask; + end |= wmask; + count = roundup2(count, 1ul << w->step); + rid = w->reg; + res = bus_alloc_resource(sc->dev, type, &rid, start, end, count, + flags & ~RF_ACTIVE); + if (res == NULL) + return (ENOSPC); + pcib_add_window_resources(w, &res, 1); + pcib_activate_window(sc, type); + w->base = rman_get_start(res); + w->limit = rman_get_end(res); + return (0); +} + +/* Try to expand an existing window to the requested base and limit. */ +static int +pcib_expand_window(struct pcib_softc *sc, struct pcib_window *w, int type, + u_long base, u_long limit) +{ + struct resource *res; + int error, i, force_64k_base; + + KASSERT(base <= w->base && limit >= w->limit, + ("attempting to shrink window")); + + /* + * XXX: pcib_grow_window() doesn't try to do this anyway and + * the error handling for all the edge cases would be tedious. + */ + KASSERT(limit == w->limit || base == w->base, + ("attempting to grow both ends of a window")); + + /* + * Yet more special handling for requests to expand an I/O + * window behind an ISA-enabled bridge. Since I/O windows + * have to grow in 0x1000 increments and the end of the 0xffff + * range is an alias, growing a window below 64k will always + * result in allocating new resources and never adjusting an + * existing resource. + */ + if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE && + (limit <= 65535 || (base <= 65535 && base != w->base))) { + KASSERT(limit == w->limit || limit <= 65535, + ("attempting to grow both ends across 64k ISA alias")); + + if (base != w->base) + error = pcib_alloc_nonisa_ranges(sc, base, w->base - 1); + else + error = pcib_alloc_nonisa_ranges(sc, w->limit + 1, + limit); + if (error == 0) { + w->base = base; + w->limit = limit; + } + return (error); + } + + /* + * Find the existing resource to adjust. Usually there is only one, + * but for an ISA-enabled bridge we might be growing the I/O window + * above 64k and need to find the existing resource that maps all + * of the area above 64k. + */ + for (i = 0; i < w->count; i++) { + if (rman_get_end(w->res[i]) == w->limit) + break; + } + KASSERT(i != w->count, ("did not find existing resource")); + res = w->res[i]; + + /* + * Usually the resource we found should match the window's + * existing range. The one exception is the ISA-enabled case + * mentioned above in which case the resource should start at + * 64k. + */ + if (type == SYS_RES_IOPORT && sc->bridgectl & PCIB_BCR_ISA_ENABLE && + w->base <= 65535) { + KASSERT(rman_get_start(res) == 65536, + ("existing resource mismatch")); + force_64k_base = 1; + } else { + KASSERT(w->base == rman_get_start(res), + ("existing resource mismatch")); + force_64k_base = 0; + } + + error = bus_adjust_resource(sc->dev, type, res, force_64k_base ? + rman_get_start(res) : base, limit); + if (error) + return (error); + + /* Add the newly allocated region to the resource manager. */ + if (w->base != base) { + error = rman_manage_region(&w->rman, base, w->base - 1); + w->base = base; + } else { + error = rman_manage_region(&w->rman, w->limit + 1, limit); + w->limit = limit; + } + if (error) { + if (bootverbose) + device_printf(sc->dev, + "failed to expand %s resource manager\n", w->name); + (void)bus_adjust_resource(sc->dev, type, res, force_64k_base ? + rman_get_start(res) : w->base, w->limit); + } + return (error); +} + /* * Attempt to grow a window to make room for a given resource request. - * The 'step' parameter is log_2 of the desired I/O window's alignment. */ static int pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type, u_long start, u_long end, u_long count, u_int flags) { u_long align, start_free, end_free, front, back, wmask; - int error, rid; + int error; /* * Clamp the desired resource range to the maximum address * this window supports. Reject impossible requests. + * + * For I/O port requests behind a bridge with the ISA enable + * bit set, force large allocations to start above 64k. */ if (!w->valid) return (EINVAL); + if (sc->bridgectl & PCIB_BCR_ISA_ENABLE && count > 0x100 && + start < 65536) + start = 65536; if (end > w->rman.rm_end) end = w->rman.rm_end; if (start + count - 1 > end || start + count < start) @@ -849,40 +1222,19 @@ pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type, * aligned space for this resource. */ if (w->res == NULL) { - if (RF_ALIGNMENT(flags) < w->step) { - flags &= ~RF_ALIGNMENT_MASK; - flags |= RF_ALIGNMENT_LOG2(w->step); - } - start &= ~wmask; - end |= wmask; - count = roundup2(count, 1ul << w->step); - rid = w->reg; - w->res = bus_alloc_resource(sc->dev, type, &rid, start, end, - count, flags & ~RF_ACTIVE); - if (w->res == NULL) { + error = pcib_alloc_new_window(sc, w, type, start, end, count, + flags); + if (error) { if (bootverbose) device_printf(sc->dev, "failed to allocate initial %s window (%#lx-%#lx,%#lx)\n", w->name, start, end, count); - return (ENXIO); + return (error); } if (bootverbose) device_printf(sc->dev, - "allocated initial %s window of %#lx-%#lx\n", - w->name, rman_get_start(w->res), - rman_get_end(w->res)); - error = rman_manage_region(&w->rman, rman_get_start(w->res), - rman_get_end(w->res)); - if (error) { - if (bootverbose) - device_printf(sc->dev, - "failed to add initial %s window to rman\n", - w->name); - bus_release_resource(sc->dev, type, w->reg, w->res); - w->res = NULL; - return (error); - } - pcib_activate_window(sc, type); + "allocated initial %s window of %#jx-%#jx\n", + w->name, (uintmax_t)w->base, (uintmax_t)w->limit); goto updatewin; } @@ -896,6 +1248,11 @@ pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type, * edge of the window, grow from the inner edge of the free * region. Otherwise grow from the window boundary. * + * Growing an I/O window below 64k for a bridge with the ISA + * enable bit doesn't require any special magic as the step + * size of an I/O window (1k) always includes multiple + * non-alias ranges when it is grown in either direction. + * * XXX: Special case: if w->res is completely empty and the * request size is larger than w->res, we should find the * optimal aligned buffer containing w->res and allocate that. @@ -905,10 +1262,10 @@ pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type, "attempting to grow %s window for (%#lx-%#lx,%#lx)\n", w->name, start, end, count); align = 1ul << RF_ALIGNMENT(flags); - if (start < rman_get_start(w->res)) { + if (start < w->base) { if (rman_first_free_region(&w->rman, &start_free, &end_free) != - 0 || start_free != rman_get_start(w->res)) - end_free = rman_get_start(w->res); + 0 || start_free != w->base) + end_free = w->base; if (end_free > end) end_free = end + 1; @@ -929,15 +1286,15 @@ pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type, printf("\tfront candidate range: %#lx-%#lx\n", front, end_free); front &= ~wmask; - front = rman_get_start(w->res) - front; + front = w->base - front; } else front = 0; } else front = 0; - if (end > rman_get_end(w->res)) { + if (end > w->limit) { if (rman_last_free_region(&w->rman, &start_free, &end_free) != - 0 || end_free != rman_get_end(w->res)) - start_free = rman_get_end(w->res) + 1; + 0 || end_free != w->limit) + start_free = w->limit + 1; if (start_free < start) start_free = start; @@ -957,7 +1314,7 @@ pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type, printf("\tback candidate range: %#lx-%#lx\n", start_free, back); back |= wmask; - back -= rman_get_end(w->res); + back -= w->limit; } else back = 0; } else @@ -970,16 +1327,14 @@ pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type, error = ENOSPC; while (front != 0 || back != 0) { if (front != 0 && (front <= back || back == 0)) { - error = bus_adjust_resource(sc->dev, type, w->res, - rman_get_start(w->res) - front, - rman_get_end(w->res)); + error = pcib_expand_window(sc, w, type, w->base - front, + w->limit); if (error == 0) break; front = 0; } else { - error = bus_adjust_resource(sc->dev, type, w->res, - rman_get_start(w->res), - rman_get_end(w->res) + back); + error = pcib_expand_window(sc, w, type, w->base, + w->limit + back); if (error == 0) break; back = 0; @@ -989,32 +1344,11 @@ pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type, if (error) return (error); if (bootverbose) - device_printf(sc->dev, "grew %s window to %#lx-%#lx\n", - w->name, rman_get_start(w->res), rman_get_end(w->res)); - - /* Add the newly allocated region to the resource manager. */ - if (w->base != rman_get_start(w->res)) { - KASSERT(w->limit == rman_get_end(w->res), ("both ends moved")); - error = rman_manage_region(&w->rman, rman_get_start(w->res), - w->base - 1); - } else { - KASSERT(w->limit != rman_get_end(w->res), - ("neither end moved")); - error = rman_manage_region(&w->rman, w->limit + 1, - rman_get_end(w->res)); - } - if (error) { - if (bootverbose) - device_printf(sc->dev, - "failed to expand %s resource manager\n", w->name); - bus_adjust_resource(sc->dev, type, w->res, w->base, w->limit); - return (error); - } + device_printf(sc->dev, "grew %s window to %#jx-%#jx\n", + w->name, (uintmax_t)w->base, (uintmax_t)w->limit); updatewin: - /* Save the new window. */ - w->base = rman_get_start(w->res); - w->limit = rman_get_end(w->res); + /* Write the new window. */ KASSERT((w->base & wmask) == 0, ("start address is not aligned")); KASSERT((w->limit & wmask) == wmask, ("end address is not aligned")); pcib_write_windows(sc, w->mask); @@ -1050,6 +1384,8 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, switch (type) { case SYS_RES_IOPORT: + if (pcib_is_isa_range(sc, start, end, count)) + return (NULL); r = pcib_suballoc_resource(sc, &sc->io, child, type, rid, start, end, count, flags); if (r != NULL || (sc->flags & PCIB_SUBTRACTIVE) != 0) diff --git a/freebsd/sys/dev/pci/pci_private.h b/freebsd/sys/dev/pci/pci_private.h index b8e446ea..92f36d5c 100644 --- a/freebsd/sys/dev/pci/pci_private.h +++ b/freebsd/sys/dev/pci/pci_private.h @@ -91,6 +91,8 @@ int pci_msix_count_method(device_t dev, device_t child); struct resource *pci_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags); +int pci_release_resource(device_t dev, device_t child, int type, + int rid, struct resource *r); int pci_activate_resource(device_t dev, device_t child, int type, int rid, struct resource *r); int pci_deactivate_resource(device_t dev, device_t child, int type, diff --git a/freebsd/sys/dev/pci/pci_user.c b/freebsd/sys/dev/pci/pci_user.c index 63d64c39..dc22106c 100644 --- a/freebsd/sys/dev/pci/pci_user.c +++ b/freebsd/sys/dev/pci/pci_user.c @@ -409,6 +409,89 @@ pci_conf_match_old32(struct pci_match_conf_old32 *matches, int num_matches, #endif /* PRE7_COMPAT */ static int +pci_list_vpd(device_t dev, struct pci_list_vpd_io *lvio) +{ + struct pci_vpd_element vpd_element, *vpd_user; + struct pcicfg_vpd *vpd; + size_t len; + int error, i; + + vpd = pci_fetch_vpd_list(dev); + if (vpd->vpd_reg == 0 || vpd->vpd_ident == NULL) + return (ENXIO); + + /* + * Calculate the amount of space needed in the data buffer. An + * identifier element is always present followed by the read-only + * and read-write keywords. + */ + len = sizeof(struct pci_vpd_element) + strlen(vpd->vpd_ident); + for (i = 0; i < vpd->vpd_rocnt; i++) + len += sizeof(struct pci_vpd_element) + vpd->vpd_ros[i].len; + for (i = 0; i < vpd->vpd_wcnt; i++) + len += sizeof(struct pci_vpd_element) + vpd->vpd_w[i].len; + + if (lvio->plvi_len == 0) { + lvio->plvi_len = len; + return (0); + } + if (lvio->plvi_len < len) { + lvio->plvi_len = len; + return (ENOMEM); + } + + /* + * Copyout the identifier string followed by each keyword and + * value. + */ + vpd_user = lvio->plvi_data; + vpd_element.pve_keyword[0] = '\0'; + vpd_element.pve_keyword[1] = '\0'; + vpd_element.pve_flags = PVE_FLAG_IDENT; + vpd_element.pve_datalen = strlen(vpd->vpd_ident); + error = copyout(&vpd_element, vpd_user, sizeof(vpd_element)); + if (error) + return (error); + error = copyout(vpd->vpd_ident, vpd_user->pve_data, + strlen(vpd->vpd_ident)); + if (error) + return (error); + vpd_user = PVE_NEXT(vpd_user); + vpd_element.pve_flags = 0; + for (i = 0; i < vpd->vpd_rocnt; i++) { + vpd_element.pve_keyword[0] = vpd->vpd_ros[i].keyword[0]; + vpd_element.pve_keyword[1] = vpd->vpd_ros[i].keyword[1]; + vpd_element.pve_datalen = vpd->vpd_ros[i].len; + error = copyout(&vpd_element, vpd_user, sizeof(vpd_element)); + if (error) + return (error); + error = copyout(vpd->vpd_ros[i].value, vpd_user->pve_data, + vpd->vpd_ros[i].len); + if (error) + return (error); + vpd_user = PVE_NEXT(vpd_user); + } + vpd_element.pve_flags = PVE_FLAG_RW; + for (i = 0; i < vpd->vpd_wcnt; i++) { + vpd_element.pve_keyword[0] = vpd->vpd_w[i].keyword[0]; + vpd_element.pve_keyword[1] = vpd->vpd_w[i].keyword[1]; + vpd_element.pve_datalen = vpd->vpd_w[i].len; + error = copyout(&vpd_element, vpd_user, sizeof(vpd_element)); + if (error) + return (error); + error = copyout(vpd->vpd_w[i].value, vpd_user->pve_data, + vpd->vpd_w[i].len); + if (error) + return (error); + vpd_user = PVE_NEXT(vpd_user); + } + KASSERT((char *)vpd_user - (char *)lvio->plvi_data == len, + ("length mismatch")); + lvio->plvi_len = len; + return (0); +} + +static int pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) { device_t pcidev, brdev; @@ -419,6 +502,7 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t struct pci_devinfo *dinfo; struct pci_io *io; struct pci_bar_io *bio; + struct pci_list_vpd_io *lvio; struct pci_match_conf *pattern_buf; struct pci_map *pm; size_t confsz, iolen, pbufsz; @@ -435,19 +519,29 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t struct pci_match_conf_old *pattern_buf_old = NULL; io_old = NULL; +#endif - if (!(flag & FWRITE) && cmd != PCIOCGETBAR && - cmd != PCIOCGETCONF && cmd != PCIOCGETCONF_OLD) - return EPERM; -#else - if (!(flag & FWRITE) && cmd != PCIOCGETBAR && cmd != PCIOCGETCONF) - return EPERM; + if (!(flag & FWRITE)) { + switch (cmd) { +#ifdef PRE7_COMPAT +#ifdef COMPAT_FREEBSD32 + case PCIOCGETCONF_OLD32: #endif + case PCIOCGETCONF_OLD: +#endif + case PCIOCGETCONF: + case PCIOCGETBAR: + case PCIOCLISTVPD: + break; + default: + return (EPERM); + } + } - switch(cmd) { + switch (cmd) { #ifdef PRE7_COMPAT #ifdef COMPAT_FREEBSD32 - case PCIOCGETCONF_OLD32: + case PCIOCGETCONF_OLD32: cio32 = (struct pci_conf_io32 *)data; cio = malloc(sizeof(struct pci_conf_io), M_TEMP, M_WAITOK); cio->pat_buf_len = cio32->pat_buf_len; @@ -468,7 +562,7 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t cio = (struct pci_conf_io *)data; } - switch(cmd) { + switch (cmd) { #ifdef PRE7_COMPAT #ifdef COMPAT_FREEBSD32 case PCIOCGETCONF_OLD32: @@ -914,6 +1008,22 @@ getconfexit: else error = ENODEV; break; + case PCIOCLISTVPD: + lvio = (struct pci_list_vpd_io *)data; + + /* + * Assume that the user-level bus number is + * in fact the physical PCI bus number. + */ + pcidev = pci_find_dbsf(lvio->plvi_sel.pc_domain, + lvio->plvi_sel.pc_bus, lvio->plvi_sel.pc_dev, + lvio->plvi_sel.pc_func); + if (pcidev == NULL) { + error = ENODEV; + break; + } + error = pci_list_vpd(pcidev, lvio); + break; default: error = ENOTTY; break; diff --git a/freebsd/sys/dev/pci/pcib_private.h b/freebsd/sys/dev/pci/pcib_private.h index 79135afa..e9d4c4bf 100644 --- a/freebsd/sys/dev/pci/pcib_private.h +++ b/freebsd/sys/dev/pci/pcib_private.h @@ -73,7 +73,8 @@ struct pcib_window { pci_addr_t base; /* base address */ pci_addr_t limit; /* topmost address */ struct rman rman; - struct resource *res; + struct resource **res; + int count; /* size of 'res' array */ int reg; /* resource id from parent */ int valid; int mask; /* WIN_* bitmask of this window */ diff --git a/freebsd/sys/dev/pci/pcireg.h b/freebsd/sys/dev/pci/pcireg.h index ef351356..f2d1ccbe 100644 --- a/freebsd/sys/dev/pci/pcireg.h +++ b/freebsd/sys/dev/pci/pcireg.h @@ -752,8 +752,17 @@ #define PCIEM_SLOT_STA_EIS 0x0080 #define PCIEM_SLOT_STA_DLLSC 0x0100 #define PCIER_ROOT_CTL 0x1c +#define PCIEM_ROOT_CTL_SERR_CORR 0x0001 +#define PCIEM_ROOT_CTL_SERR_NONFATAL 0x0002 +#define PCIEM_ROOT_CTL_SERR_FATAL 0x0004 +#define PCIEM_ROOT_CTL_PME 0x0008 +#define PCIEM_ROOT_CTL_CRS_VIS 0x0010 #define PCIER_ROOT_CAP 0x1e +#define PCIEM_ROOT_CAP_CRS_VIS 0x0001 #define PCIER_ROOT_STA 0x20 +#define PCIEM_ROOT_STA_PME_REQID_MASK 0x0000ffff +#define PCIEM_ROOT_STA_PME_STATUS 0x00010000 +#define PCIEM_ROOT_STA_PME_PEND 0x00020000 #define PCIER_DEVICE_CAP2 0x24 #define PCIER_DEVICE_CTL2 0x28 #define PCIEM_CTL2_COMP_TIMEOUT_VAL 0x000f diff --git a/freebsd/sys/dev/pci/pcivar.h b/freebsd/sys/dev/pci/pcivar.h index 84e7c871..a951ca66 100644 --- a/freebsd/sys/dev/pci/pcivar.h +++ b/freebsd/sys/dev/pci/pcivar.h @@ -57,6 +57,7 @@ struct pci_map { struct vpd_readonly { char keyword[2]; char *value; + int len; }; struct vpd_write { @@ -491,5 +492,13 @@ extern uint32_t pci_generation; struct pci_map *pci_find_bar(device_t dev, int reg); int pci_bar_enabled(device_t dev, struct pci_map *pm); +struct pcicfg_vpd *pci_fetch_vpd_list(device_t dev); + +#define VGA_PCI_BIOS_SHADOW_ADDR 0xC0000 +#define VGA_PCI_BIOS_SHADOW_SIZE 131072 + +int vga_pci_is_boot_display(device_t dev); +void * vga_pci_map_bios(device_t dev, size_t *size); +void vga_pci_unmap_bios(device_t dev, void *bios); #endif /* _PCIVAR_H_ */ |