Index: dev/cardbus/cardbus_cis.c =================================================================== --- dev/cardbus/cardbus_cis.c (revision 201256) +++ dev/cardbus/cardbus_cis.c (working copy) @@ -435,9 +435,6 @@ { 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); } } @@ -482,14 +480,11 @@ 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) { bus_space_tag_t bt; bus_space_handle_t bh; uint32_t imagesize; uint32_t imagebase = 0; uint32_t pcidata; Index: dev/pci/pci_private.h =================================================================== --- dev/pci/pci_private.h (revision 201277) +++ dev/pci/pci_private.h (working copy) @@ -84,6 +84,8 @@ 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); Index: dev/pci/pci.c =================================================================== --- dev/pci/pci.c (revision 201277) +++ dev/pci/pci.c (working copy) @@ -80,6 +80,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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_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 @@ * 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 @@ /* 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 @@ 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) {