diff options
author | jhb <jhb@FreeBSD.org> | 2009-12-30 20:47:14 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2009-12-30 20:47:14 +0000 |
commit | 9b53c8050d11d206fc12ee51b23d56389bd41bd3 (patch) | |
tree | 2e18981b24feef6425f28326218e699e93b7e1d7 | |
parent | 8c20c2b016bbf46383564d9219cd1f96c9d02af5 (diff) | |
download | FreeBSD-src-9b53c8050d11d206fc12ee51b23d56389bd41bd3.zip FreeBSD-src-9b53c8050d11d206fc12ee51b23d56389bd41bd3.tar.gz |
Teach the PCI bus driver to handle PCIR_BIOS BARs properly and remove special
handling for the PCIR_BIOS decoding enable bit from the cardbus driver.
The PCIR_BIOS BAR does include type bits like other BARs. Instead, it is
always a 32-bit non-prefetchable memory BAR where the low bit is used as a
flag to enable decoding.
Reviewed by: imp
-rw-r--r-- | sys/dev/cardbus/cardbus_cis.c | 6 | ||||
-rw-r--r-- | sys/dev/pci/pci.c | 83 | ||||
-rw-r--r-- | sys/dev/pci/pci_private.h | 2 |
3 files changed, 81 insertions, 10 deletions
diff --git a/sys/dev/cardbus/cardbus_cis.c b/sys/dev/cardbus/cardbus_cis.c index 9d443b2..5e52c3b 100644 --- a/sys/dev/cardbus/cardbus_cis.c +++ b/sys/dev/cardbus/cardbus_cis.c @@ -430,9 +430,6 @@ cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid, { if (res != CIS_CONFIG_SPACE) { bus_release_resource(child, SYS_RES_MEMORY, rid, res); - if (rid == PCIM_CIS_ASI_ROM) - pci_write_config(child, rid, pci_read_config(child, - rid, 4) & ~PCIR_BIOS, 4); } } @@ -477,9 +474,6 @@ cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start, return (NULL); } DEVPRINTF((cbdev, "CIS Mapped to %#lx\n", rman_get_start(res))); - if (*rid == PCIR_BIOS) - pci_write_config(child, *rid, - rman_get_start(res) | PCIM_BIOS_ENABLE, 4); /* Flip to the right ROM image if CIS is in ROM */ if (space == PCIM_CIS_ASI_ROM) { diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index b4b4051..008377a 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -80,6 +80,8 @@ static pci_addr_t pci_mapbase(uint64_t mapreg); static const char *pci_maptype(uint64_t mapreg); static int pci_mapsize(uint64_t testval); static int pci_maprange(uint64_t mapreg); +static pci_addr_t pci_rombase(uint64_t mapreg); +static int pci_romsize(uint64_t testval); static void pci_fixancient(pcicfgregs *cfg); static int pci_printf(pcicfgregs *cfg, const char *fmt, ...); @@ -142,7 +144,7 @@ static device_method_t pci_methods[] = { DEVMETHOD(bus_alloc_resource, pci_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), DEVMETHOD(bus_activate_resource, pci_activate_resource), - DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_deactivate_resource, pci_deactivate_resource), DEVMETHOD(bus_child_pnpinfo_str, pci_child_pnpinfo_str_method), DEVMETHOD(bus_child_location_str, pci_child_location_str_method), @@ -388,6 +390,34 @@ pci_mapsize(uint64_t testval) return (ln2size); } +/* return base address of device ROM */ + +static pci_addr_t +pci_rombase(uint64_t mapreg) +{ + + return (mapreg & PCIM_BIOS_ADDR_MASK); +} + +/* return log2 of map size decided for device ROM */ + +static int +pci_romsize(uint64_t testval) +{ + int ln2size; + + testval = pci_rombase(testval); + ln2size = 0; + if (testval != 0) { + while ((testval & 1) == 0) + { + ln2size++; + testval >>= 1; + } + } + return (ln2size); +} + /* return log2 of address range supported by map register */ static int @@ -2280,6 +2310,21 @@ pci_read_bar(device_t dev, int reg, pci_addr_t *mapp, pci_addr_t *testvalp) int ln2range; uint16_t cmd; + /* + * The device ROM BAR is special. It is always a 32-bit + * memory BAR. Bit 0 is special and should not be set when + * sizing the BAR. + */ + if (reg == PCIR_BIOS) { + map = pci_read_config(dev, reg, 4); + pci_write_config(dev, reg, 0xfffffffe, 4); + testval = pci_read_config(dev, reg, 4); + pci_write_config(dev, reg, map, 4); + *mapp = map; + *testvalp = testval; + return; + } + map = pci_read_config(dev, reg, 4); ln2range = pci_maprange(map); if (ln2range == 64) @@ -2327,6 +2372,10 @@ pci_write_bar(device_t dev, int reg, pci_addr_t base) int ln2range; map = pci_read_config(dev, reg, 4); + + /* The device ROM BAR is always 32-bits. */ + if (reg == PCIR_BIOS) + return; ln2range = pci_maprange(map); pci_write_config(dev, reg, base, 4); if (ln2range == 64) @@ -3579,10 +3628,11 @@ pci_reserve_map(device_t dev, device_t child, int type, int *rid, pci_read_bar(child, *rid, &map, &testval); /* Ignore a BAR with a base of 0. */ - if (pci_mapbase(testval) == 0) + if ((*rid == PCIR_BIOS && pci_rombase(testval) == 0) || + pci_mapbase(testval) == 0) goto out; - if (PCI_BAR_MEM(testval)) { + if (PCI_BAR_MEM(testval) || *rid == PCIR_BIOS) { if (type != SYS_RES_MEMORY) { if (bootverbose) device_printf(dev, @@ -3608,8 +3658,13 @@ pci_reserve_map(device_t dev, device_t child, int type, int *rid, * actually uses and we would otherwise have a * situation where we might allocate the excess to * another driver, which won't work. + * + * Device ROM BARs use a different mask value. */ - mapsize = pci_mapsize(testval); + if (*rid == PCIR_BIOS) + mapsize = pci_romsize(testval); + else + mapsize = pci_mapsize(testval); count = 1UL << mapsize; if (RF_ALIGNMENT(flags) < mapsize) flags = (flags & ~RF_ALIGNMENT_MASK) | RF_ALIGNMENT_LOG2(mapsize); @@ -3711,6 +3766,10 @@ pci_activate_resource(device_t dev, device_t child, int type, int rid, /* Enable decoding in the command register when activating BARs. */ if (device_get_parent(child) == dev) { + /* Device ROMs need their decoding explicitly enabled. */ + if (rid == PCIR_BIOS) + pci_write_config(child, rid, rman_get_start(r) | + PCIM_BIOS_ENABLE, 4); switch (type) { case SYS_RES_IOPORT: case SYS_RES_MEMORY: @@ -3721,6 +3780,22 @@ pci_activate_resource(device_t dev, device_t child, int type, int rid, return (error); } +int +pci_deactivate_resource(device_t dev, device_t child, int type, + int rid, struct resource *r) +{ + int error; + + error = bus_generic_deactivate_resource(dev, child, type, rid, r); + if (error) + return (error); + + /* Disable decoding for device ROMs. */ + if (rid == PCIR_BIOS) + pci_write_config(child, rid, rman_get_start(r), 4); + return (0); +} + void pci_delete_resource(device_t dev, device_t child, int type, int rid) { diff --git a/sys/dev/pci/pci_private.h b/sys/dev/pci/pci_private.h index d75e457..1cb28e9 100644 --- a/sys/dev/pci/pci_private.h +++ b/sys/dev/pci/pci_private.h @@ -84,6 +84,8 @@ struct resource *pci_alloc_resource(device_t dev, device_t child, u_int flags); 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, + int rid, struct resource *r); void pci_delete_resource(device_t dev, device_t child, int type, int rid); struct resource_list *pci_get_resource_list (device_t dev, device_t child); |