summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/dev/pci
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2015-02-02 14:27:13 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2015-02-13 10:34:19 +0100
commit7eeb079d84bc4abe9897be0047fc28a754e46ecd (patch)
tree9b47ac7055ce0cb1e2d86c684a2a7a1cd20c0c4d /freebsd/sys/dev/pci
parentfreebsd-to-rtems.py: Fix revert includes (diff)
downloadrtems-libbsd-7eeb079d84bc4abe9897be0047fc28a754e46ecd.tar.bz2
Update to FreeBSD 9.3
Diffstat (limited to 'freebsd/sys/dev/pci')
-rw-r--r--freebsd/sys/dev/pci/pci.c283
-rw-r--r--freebsd/sys/dev/pci/pci_pci.c508
-rw-r--r--freebsd/sys/dev/pci/pci_private.h2
-rw-r--r--freebsd/sys/dev/pci/pci_user.c128
-rw-r--r--freebsd/sys/dev/pci/pcib_private.h3
-rw-r--r--freebsd/sys/dev/pci/pcireg.h9
-rw-r--r--freebsd/sys/dev/pci/pcivar.h9
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, &reg, 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, &reg, 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_ */