From owner-svn-src-all@FreeBSD.ORG Tue Oct 9 18:45:09 2012 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 2EBE28FA; Tue, 9 Oct 2012 18:45:09 +0000 (UTC) (envelope-from jhb@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 150D18FC1A; Tue, 9 Oct 2012 18:45:09 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q99Ij9Lj054577; Tue, 9 Oct 2012 18:45:09 GMT (envelope-from jhb@svn.freebsd.org) Received: (from jhb@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q99Ij88H054570; Tue, 9 Oct 2012 18:45:08 GMT (envelope-from jhb@svn.freebsd.org) Message-Id: <201210091845.q99Ij88H054570@svn.freebsd.org> From: John Baldwin Date: Tue, 9 Oct 2012 18:45:08 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org Subject: svn commit: r241378 - in stable/8/sys/dev: cardbus pci X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Oct 2012 18:45:09 -0000 Author: jhb Date: Tue Oct 9 18:45:08 2012 New Revision: 241378 URL: http://svn.freebsd.org/changeset/base/241378 Log: MFC 201279,201280,201286,213907,214146,220195,222753,223371,225515,235833: Various fixes to managing PCI BARs including proper support for managing PCI ROM BARs: - 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. - Explicitly track the state of all known BARs for each PCI device. The PCI bus driver will now remember the size of a BAR obtained during the initial bus scan and use that size when doing lazy resource allocation rather than resizing the BAR. The bus driver will now also report unallocated BARs to userland for display by 'pciconf -lb'. - Add a constant for the offset of the ROM BIOS BAR in PCI-PCI bridges and properly handle ROM BIOS BARs in PCI-PCI bridges. The PCI bus now also properly handles the lack of a ROM BIOS BAR in a PCI-Cardbus bridge. Tested by: John Kozubik john kozubik com Modified: stable/8/sys/dev/cardbus/cardbus_cis.c stable/8/sys/dev/pci/pci.c stable/8/sys/dev/pci/pci_private.h stable/8/sys/dev/pci/pci_user.c stable/8/sys/dev/pci/pcireg.h stable/8/sys/dev/pci/pcivar.h Directory Properties: stable/8/sys/ (props changed) stable/8/sys/dev/ (props changed) stable/8/sys/dev/cardbus/ (props changed) stable/8/sys/dev/pci/ (props changed) Modified: stable/8/sys/dev/cardbus/cardbus_cis.c ============================================================================== --- stable/8/sys/dev/cardbus/cardbus_cis.c Tue Oct 9 18:02:09 2012 (r241377) +++ stable/8/sys/dev/cardbus/cardbus_cis.c Tue Oct 9 18:45:08 2012 (r241378) @@ -324,7 +324,7 @@ decode_tuple_bar(device_t cbdev, device_ * hint when the cardbus bridge is a child of pci0 (the main * bus). The PC Card spec seems to indicate that this should * only be done on x86 based machines, which suggests that on - * non-x86 machines the adddresses can be anywhere. Since the + * non-x86 machines the addresses can be anywhere. Since the * hardware can do it on non-x86 machines, it should be able * to do it on x86 machines too. Therefore, we can and should * ignore this hint. Furthermore, the PC Card spec recommends @@ -435,9 +435,7 @@ cardbus_read_tuple_finish(device_t cbdev { 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); + bus_delete_resource(child, SYS_RES_MEMORY, rid); } } @@ -474,7 +472,7 @@ cardbus_read_tuple_init(device_t cbdev, } /* allocate the memory space to read CIS */ - res = bus_alloc_resource(child, SYS_RES_MEMORY, rid, 0, ~0, 1, + res = bus_alloc_resource_any(child, SYS_RES_MEMORY, rid, rman_make_alignment_flags(4096) | RF_ACTIVE); if (res == NULL) { device_printf(cbdev, "Unable to allocate resource " @@ -482,9 +480,6 @@ cardbus_read_tuple_init(device_t cbdev, 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) { @@ -508,8 +503,8 @@ cardbus_read_tuple_init(device_t cbdev, device_printf(cbdev, "Bad header in rom %d: " "[%x] %04x\n", romnum, imagebase + CARDBUS_EXROM_SIGNATURE, romsig); - bus_release_resource(child, SYS_RES_MEMORY, - *rid, res); + cardbus_read_tuple_finish(cbdev, child, *rid, + res); *rid = 0; return (NULL); } @@ -545,8 +540,8 @@ cardbus_read_tuple_init(device_t cbdev, CARDBUS_EXROM_DATA_INDICATOR) & 0x80) != 0) { device_printf(cbdev, "Cannot find CIS in " "Option ROM\n"); - bus_release_resource(child, SYS_RES_MEMORY, - *rid, res); + cardbus_read_tuple_finish(cbdev, child, *rid, + res); *rid = 0; return (NULL); } Modified: stable/8/sys/dev/pci/pci.c ============================================================================== --- stable/8/sys/dev/pci/pci.c Tue Oct 9 18:02:09 2012 (r241377) +++ stable/8/sys/dev/pci/pci.c Tue Oct 9 18:45:08 2012 (r241378) @@ -91,10 +91,16 @@ __FBSDID("$FreeBSD$"); #endif #endif +#define PCIR_IS_BIOS(cfg, reg) \ + (((cfg)->hdrtype == PCIM_HDRTYPE_NORMAL && reg == PCIR_BIOS) || \ + ((cfg)->hdrtype == PCIM_HDRTYPE_BRIDGE && reg == PCIR_BIOS_1)) + 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, ...); @@ -162,7 +168,7 @@ static device_method_t pci_methods[] = { DEVMETHOD(bus_adjust_resource, bus_generic_adjust_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), DEVMETHOD(bus_remap_intr, pci_remap_intr_method), @@ -324,7 +330,7 @@ static int pci_usb_takeover = 1; static int pci_usb_takeover = 0; #endif TUNABLE_INT("hw.pci.usb_early_takeover", &pci_usb_takeover); -SYSCTL_INT(_hw_pci, OID_AUTO, usb_early_takeover, CTLFLAG_RD | CTLFLAG_TUN, +SYSCTL_INT(_hw_pci, OID_AUTO, usb_early_takeover, CTLFLAG_RDTUN, &pci_usb_takeover, 1, "Enable early takeover of USB controllers.\n\ 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"); @@ -447,6 +453,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 @@ -551,6 +585,7 @@ pci_read_device(device_t pcib, int d, in cfg->mfdev = (cfg->hdrtype & PCIM_MFDEV) != 0; cfg->hdrtype &= ~PCIM_MFDEV; + STAILQ_INIT(&cfg->maps); pci_fixancient(cfg); pci_hdrtypedata(pcib, b, s, f, cfg); @@ -2124,6 +2159,7 @@ int pci_freecfg(struct pci_devinfo *dinfo) { struct devlist *devlist_head; + struct pci_map *pm, *next; int i; devlist_head = &pci_devq; @@ -2137,6 +2173,9 @@ pci_freecfg(struct pci_devinfo *dinfo) free(dinfo->cfg.vpd.vpd_w[i].value, M_DEVBUF); free(dinfo->cfg.vpd.vpd_w, M_DEVBUF); } + STAILQ_FOREACH_SAFE(pm, &dinfo->cfg.maps, pm_link, next) { + free(pm, M_DEVBUF); + } STAILQ_REMOVE(devlist_head, dinfo, pci_devinfo, pci_links); free(dinfo, M_DEVBUF); @@ -2411,10 +2450,27 @@ pci_memen(device_t dev) static void pci_read_bar(device_t dev, int reg, pci_addr_t *mapp, pci_addr_t *testvalp) { + struct pci_devinfo *dinfo; pci_addr_t map, testval; 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. + */ + dinfo = device_get_ivars(dev); + if (PCIR_IS_BIOS(&dinfo->cfg, reg)) { + 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) @@ -2456,16 +2512,100 @@ pci_read_bar(device_t dev, int reg, pci_ } static void -pci_write_bar(device_t dev, int reg, pci_addr_t base) +pci_write_bar(device_t dev, struct pci_map *pm, pci_addr_t base) { - pci_addr_t map; + struct pci_devinfo *dinfo; int ln2range; - map = pci_read_config(dev, reg, 4); - ln2range = pci_maprange(map); - pci_write_config(dev, reg, base, 4); + /* The device ROM BAR is always a 32-bit memory BAR. */ + dinfo = device_get_ivars(dev); + if (PCIR_IS_BIOS(&dinfo->cfg, pm->pm_reg)) + ln2range = 32; + else + ln2range = pci_maprange(pm->pm_value); + pci_write_config(dev, pm->pm_reg, base, 4); if (ln2range == 64) - pci_write_config(dev, reg + 4, base >> 32, 4); + pci_write_config(dev, pm->pm_reg + 4, base >> 32, 4); + pm->pm_value = pci_read_config(dev, pm->pm_reg, 4); + if (ln2range == 64) + pm->pm_value |= (pci_addr_t)pci_read_config(dev, + pm->pm_reg + 4, 4) << 32; +} + +struct pci_map * +pci_find_bar(device_t dev, int reg) +{ + struct pci_devinfo *dinfo; + struct pci_map *pm; + + dinfo = device_get_ivars(dev); + STAILQ_FOREACH(pm, &dinfo->cfg.maps, pm_link) { + if (pm->pm_reg == reg) + return (pm); + } + return (NULL); +} + +int +pci_bar_enabled(device_t dev, struct pci_map *pm) +{ + struct pci_devinfo *dinfo; + uint16_t cmd; + + dinfo = device_get_ivars(dev); + if (PCIR_IS_BIOS(&dinfo->cfg, pm->pm_reg) && + !(pm->pm_value & PCIM_BIOS_ENABLE)) + return (0); + cmd = pci_read_config(dev, PCIR_COMMAND, 2); + if (PCIR_IS_BIOS(&dinfo->cfg, pm->pm_reg) || PCI_BAR_MEM(pm->pm_value)) + return ((cmd & PCIM_CMD_MEMEN) != 0); + else + return ((cmd & PCIM_CMD_PORTEN) != 0); +} + +static struct pci_map * +pci_add_bar(device_t dev, int reg, pci_addr_t value, pci_addr_t size) +{ + struct pci_devinfo *dinfo; + struct pci_map *pm, *prev; + + dinfo = device_get_ivars(dev); + pm = malloc(sizeof(*pm), M_DEVBUF, M_WAITOK | M_ZERO); + pm->pm_reg = reg; + pm->pm_value = value; + pm->pm_size = size; + STAILQ_FOREACH(prev, &dinfo->cfg.maps, pm_link) { + KASSERT(prev->pm_reg != pm->pm_reg, ("duplicate map %02x", + reg)); + if (STAILQ_NEXT(prev, pm_link) == NULL || + STAILQ_NEXT(prev, pm_link)->pm_reg > pm->pm_reg) + break; + } + if (prev != NULL) + STAILQ_INSERT_AFTER(&dinfo->cfg.maps, prev, pm, pm_link); + else + STAILQ_INSERT_TAIL(&dinfo->cfg.maps, pm, pm_link); + return (pm); +} + +static void +pci_restore_bars(device_t dev) +{ + struct pci_devinfo *dinfo; + struct pci_map *pm; + int ln2range; + + dinfo = device_get_ivars(dev); + STAILQ_FOREACH(pm, &dinfo->cfg.maps, pm_link) { + if (PCIR_IS_BIOS(&dinfo->cfg, pm->pm_reg)) + ln2range = 32; + else + ln2range = pci_maprange(pm->pm_value); + pci_write_config(dev, pm->pm_reg, pm->pm_value, 4); + if (ln2range == 64) + pci_write_config(dev, pm->pm_reg + 4, + pm->pm_value >> 32, 4); + } } /* @@ -2476,12 +2616,24 @@ static int pci_add_map(device_t bus, device_t dev, int reg, struct resource_list *rl, int force, int prefetch) { + struct pci_map *pm; pci_addr_t base, map, testval; pci_addr_t start, end, count; int barlen, basezero, maprange, mapsize, type; uint16_t cmd; struct resource *res; + /* + * The BAR may already exist if the device is a CardBus card + * whose CIS is stored in this BAR. + */ + pm = pci_find_bar(dev, reg); + if (pm != NULL) { + maprange = pci_maprange(pm->pm_value); + barlen = maprange == 64 ? 2 : 1; + return (barlen); + } + pci_read_bar(dev, reg, &map, &testval); if (PCI_BAR_MEM(map)) { type = SYS_RES_MEMORY; @@ -2512,6 +2664,8 @@ pci_add_map(device_t bus, device_t dev, (type == SYS_RES_IOPORT && mapsize < 2)) return (barlen); + /* Save a record of this BAR. */ + pm = pci_add_bar(dev, reg, map, mapsize); if (bootverbose) { printf("\tmap[%02x]: type %s, range %2d, base %#jx, size %2d", reg, pci_maptype(map), maprange, (uintmax_t)base, mapsize); @@ -2573,7 +2727,7 @@ pci_add_map(device_t bus, device_t dev, count = (pci_addr_t)1 << mapsize; if (basezero || base == pci_mapbase(testval)) { start = 0; /* Let the parent decide. */ - end = ~0ULL; + end = ~0ul; } else { start = base; end = base + count - 1; @@ -2601,7 +2755,7 @@ pci_add_map(device_t bus, device_t dev, start = rman_get_start(res); rman_set_device(res, bus); } - pci_write_bar(dev, reg, start); + pci_write_bar(dev, pm, start); return (barlen); } @@ -3037,7 +3191,7 @@ pci_suspend(device_t dev) return (error); for (i = 0; i < numdevs; i++) { child = devlist[i]; - dinfo = (struct pci_devinfo *) device_get_ivars(child); + dinfo = device_get_ivars(child); pci_cfg_save(child, dinfo, 0); } @@ -3454,7 +3608,7 @@ pci_probe_nomatch(device_t dev, device_t } printf(" at device %d.%d (no driver attached)\n", pci_get_slot(child), pci_get_function(child)); - pci_cfg_save(child, (struct pci_devinfo *)device_get_ivars(child), 1); + pci_cfg_save(child, device_get_ivars(child), 1); return; } @@ -3759,24 +3913,41 @@ pci_alloc_map(device_t dev, device_t chi struct resource_list *rl = &dinfo->resources; struct resource_list_entry *rle; struct resource *res; + struct pci_map *pm; pci_addr_t map, testval; int mapsize; - /* - * Weed out the bogons, and figure out how large the BAR/map - * is. Bars that read back 0 here are bogus and unimplemented. - * Note: atapci in legacy mode are special and handled elsewhere - * in the code. If you have a atapci device in legacy mode and - * it fails here, that other code is broken. - */ res = NULL; - pci_read_bar(child, *rid, &map, &testval); + pm = pci_find_bar(child, *rid); + if (pm != NULL) { + /* This is a BAR that we failed to allocate earlier. */ + mapsize = pm->pm_size; + map = pm->pm_value; + } else { + /* + * Weed out the bogons, and figure out how large the + * BAR/map is. BARs that read back 0 here are bogus + * and unimplemented. Note: atapci in legacy mode are + * special and handled elsewhere in the code. If you + * have a atapci device in legacy mode and it fails + * here, that other code is broken. + */ + pci_read_bar(child, *rid, &map, &testval); - /* Ignore a BAR with a base of 0. */ - if (pci_mapbase(testval) == 0) - goto out; + /* + * Determine the size of the BAR and ignore BARs with a size + * of 0. Device ROM BARs use a different mask value. + */ + if (PCIR_IS_BIOS(&dinfo->cfg, *rid)) + mapsize = pci_romsize(testval); + else + mapsize = pci_mapsize(testval); + if (mapsize == 0) + goto out; + pm = pci_add_bar(child, *rid, map, mapsize); + } - if (PCI_BAR_MEM(testval)) { + if (PCI_BAR_MEM(map) || PCIR_IS_BIOS(&dinfo->cfg, *rid)) { if (type != SYS_RES_MEMORY) { if (bootverbose) device_printf(dev, @@ -3803,16 +3974,15 @@ pci_alloc_map(device_t dev, device_t chi * situation where we might allocate the excess to * another driver, which won't work. */ - mapsize = pci_mapsize(testval); count = (pci_addr_t)1 << mapsize; if (RF_ALIGNMENT(flags) < mapsize) flags = (flags & ~RF_ALIGNMENT_MASK) | RF_ALIGNMENT_LOG2(mapsize); - if (PCI_BAR_MEM(testval) && (testval & PCIM_BAR_MEM_PREFETCH)) + if (PCI_BAR_MEM(map) && (map & PCIM_BAR_MEM_PREFETCH)) flags |= RF_PREFETCHABLE; /* * Allocate enough resource, and then write back the - * appropriate bar for that resource. + * appropriate BAR for that resource. */ res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, type, rid, start, end, count, flags & ~RF_ACTIVE); @@ -3836,7 +4006,7 @@ pci_alloc_map(device_t dev, device_t chi "Lazy allocation of %#lx bytes rid %#x type %d at %#lx\n", count, *rid, type, rman_get_start(res)); map = rman_get_start(res); - pci_write_bar(child, *rid, map); + pci_write_bar(child, pm, map); out:; return (res); } @@ -3968,6 +4138,7 @@ int pci_activate_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { + struct pci_devinfo *dinfo; int error; error = bus_generic_activate_resource(dev, child, type, rid, r); @@ -3976,6 +4147,11 @@ pci_activate_resource(device_t dev, devi /* Enable decoding in the command register when activating BARs. */ if (device_get_parent(child) == dev) { + /* Device ROMs need their decoding explicitly enabled. */ + dinfo = device_get_ivars(child); + if (type == SYS_RES_MEMORY && PCIR_IS_BIOS(&dinfo->cfg, rid)) + pci_write_bar(child, pci_find_bar(child, rid), + rman_get_start(r) | PCIM_BIOS_ENABLE); switch (type) { case SYS_RES_IOPORT: case SYS_RES_MEMORY: @@ -3986,6 +4162,27 @@ pci_activate_resource(device_t dev, devi return (error); } +int +pci_deactivate_resource(device_t dev, device_t child, int type, + int rid, struct resource *r) +{ + struct pci_devinfo *dinfo; + int error; + + error = bus_generic_deactivate_resource(dev, child, type, rid, r); + if (error) + return (error); + + /* Disable decoding for device ROMs. */ + if (device_get_parent(child) == dev) { + dinfo = device_get_ivars(child); + if (type == SYS_RES_MEMORY && PCIR_IS_BIOS(&dinfo->cfg, rid)) + pci_write_bar(child, pci_find_bar(child, rid), + rman_get_start(r)); + } + return (0); +} + void pci_delete_resource(device_t dev, device_t child, int type, int rid) { @@ -4021,7 +4218,7 @@ pci_delete_resource(device_t dev, device switch (type) { case SYS_RES_IOPORT: case SYS_RES_MEMORY: - pci_write_bar(child, rid, 0); + pci_write_bar(child, pci_find_bar(child, rid), 0); break; } #endif @@ -4128,7 +4325,6 @@ pci_modevent(module_t mod, int what, voi void pci_cfg_restore(device_t dev, struct pci_devinfo *dinfo) { - int i; /* * Only do header type 0 devices. Type 1 devices are bridges, @@ -4148,12 +4344,9 @@ pci_cfg_restore(device_t dev, struct pci * the noise on boot by doing nothing if we are already in * state D0. */ - if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { + if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) pci_set_powerstate(dev, PCI_POWERSTATE_D0); - } - for (i = 0; i < dinfo->cfg.nummaps; i++) - pci_write_config(dev, PCIR_BAR(i), dinfo->cfg.bar[i], 4); - pci_write_config(dev, PCIR_BIOS, dinfo->cfg.bios, 4); + pci_restore_bars(dev); pci_write_config(dev, PCIR_COMMAND, dinfo->cfg.cmdreg, 2); pci_write_config(dev, PCIR_INTLINE, dinfo->cfg.intline, 1); pci_write_config(dev, PCIR_INTPIN, dinfo->cfg.intpin, 1); @@ -4174,7 +4367,6 @@ pci_cfg_restore(device_t dev, struct pci void pci_cfg_save(device_t dev, struct pci_devinfo *dinfo, int setstate) { - int i; uint32_t cls; int ps; @@ -4187,9 +4379,6 @@ pci_cfg_save(device_t dev, struct pci_de */ if (dinfo->cfg.hdrtype != 0) return; - for (i = 0; i < dinfo->cfg.nummaps; i++) - dinfo->cfg.bar[i] = pci_read_config(dev, PCIR_BAR(i), 4); - dinfo->cfg.bios = pci_read_config(dev, PCIR_BIOS, 4); /* * Some drivers apparently write to these registers w/o updating our Modified: stable/8/sys/dev/pci/pci_private.h ============================================================================== --- stable/8/sys/dev/pci/pci_private.h Tue Oct 9 18:02:09 2012 (r241377) +++ stable/8/sys/dev/pci/pci_private.h Tue Oct 9 18:45:08 2012 (r241378) @@ -91,6 +91,8 @@ int pci_release_resource(device_t dev, 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, + 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); Modified: stable/8/sys/dev/pci/pci_user.c ============================================================================== --- stable/8/sys/dev/pci/pci_user.c Tue Oct 9 18:02:09 2012 (r241377) +++ stable/8/sys/dev/pci/pci_user.c Tue Oct 9 18:45:08 2012 (r241378) @@ -309,8 +309,7 @@ pci_ioctl(struct cdev *dev, u_long cmd, struct pci_io *io; struct pci_bar_io *bio; struct pci_match_conf *pattern_buf; - struct resource_list_entry *rle; - uint32_t value; + struct pci_map *pm; size_t confsz, iolen, pbufsz; int error, ionum, i, num_patterns; #ifdef PRE7_COMPAT @@ -685,54 +684,14 @@ getconfexit: error = ENODEV; break; } - dinfo = device_get_ivars(pcidev); - - /* - * Look for a resource list entry matching the requested BAR. - * - * XXX: This will not find BARs that are not initialized, but - * maybe that is ok? - */ - rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY, - bio->pbi_reg); - if (rle == NULL) - rle = resource_list_find(&dinfo->resources, - SYS_RES_IOPORT, bio->pbi_reg); - if (rle == NULL || rle->res == NULL) { + pm = pci_find_bar(pcidev, bio->pbi_reg); + if (pm == NULL) { error = EINVAL; break; } - - /* - * Ok, we have a resource for this BAR. Read the lower - * 32 bits to get any flags. - */ - value = pci_read_config(pcidev, bio->pbi_reg, 4); - if (PCI_BAR_MEM(value)) { - if (rle->type != SYS_RES_MEMORY) { - error = EINVAL; - break; - } - value &= ~PCIM_BAR_MEM_BASE; - } else { - if (rle->type != SYS_RES_IOPORT) { - error = EINVAL; - break; - } - value &= ~PCIM_BAR_IO_BASE; - } - bio->pbi_base = rman_get_start(rle->res) | value; - bio->pbi_length = rman_get_size(rle->res); - - /* - * Check the command register to determine if this BAR - * is enabled. - */ - value = pci_read_config(pcidev, PCIR_COMMAND, 2); - if (rle->type == SYS_RES_MEMORY) - bio->pbi_enabled = (value & PCIM_CMD_MEMEN) != 0; - else - bio->pbi_enabled = (value & PCIM_CMD_PORTEN) != 0; + bio->pbi_base = pm->pm_value; + bio->pbi_length = (pci_addr_t)1 << pm->pm_size; + bio->pbi_enabled = pci_bar_enabled(pcidev, pm); error = 0; break; default: Modified: stable/8/sys/dev/pci/pcireg.h ============================================================================== --- stable/8/sys/dev/pci/pcireg.h Tue Oct 9 18:02:09 2012 (r241377) +++ stable/8/sys/dev/pci/pcireg.h Tue Oct 9 18:45:08 2012 (r241378) @@ -213,6 +213,7 @@ #define PCIM_BRPM_64 0x1 #define PCIM_BRPM_MASK 0xf +#define PCIR_BIOS_1 0x38 #define PCIR_BRIDGECTL_1 0x3e /* config registers for header type 2 (CardBus) devices */ Modified: stable/8/sys/dev/pci/pcivar.h ============================================================================== --- stable/8/sys/dev/pci/pcivar.h Tue Oct 9 18:02:09 2012 (r241377) +++ stable/8/sys/dev/pci/pcivar.h Tue Oct 9 18:45:08 2012 (r241378) @@ -46,7 +46,14 @@ struct pcicfg_pp { uint8_t pp_pmcsr; /* config space address of PMCSR reg */ uint8_t pp_data; /* config space address of PCI power data reg */ }; - + +struct pci_map { + pci_addr_t pm_value; /* Raw BAR value */ + pci_addr_t pm_size; + uint8_t pm_reg; + STAILQ_ENTRY(pci_map) pm_link; +}; + struct vpd_readonly { char keyword[2]; char *value; @@ -120,8 +127,7 @@ struct pcicfg_ht { typedef struct pcicfg { struct device *dev; /* device which owns this */ - uint32_t bar[PCI_MAXMAPS_0]; /* BARs */ - uint32_t bios; /* BIOS mapping */ + STAILQ_HEAD(, pci_map) maps; /* BARs */ uint16_t subvendor; /* card vendor ID */ uint16_t subdevice; /* card device ID, assigned by card vendor */ @@ -480,4 +486,7 @@ STAILQ_HEAD(devlist, pci_devinfo); extern struct devlist pci_devq; 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); + #endif /* _PCIVAR_H_ */