Date: Mon, 4 May 2009 20:36:00 +0000 (UTC) From: John Baldwin <jhb@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org Subject: svn commit: r191795 - in stable/7/sys: . contrib/pf dev/ath/ath_hal dev/cxgb dev/pci Message-ID: <200905042036.n44Ka08v056369@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: jhb Date: Mon May 4 20:35:59 2009 New Revision: 191795 URL: http://svn.freebsd.org/changeset/base/191795 Log: MFC: Various fixes to the PCI resource allocation code: - Disabling decoding of BARs via the PCI command register before writing to the BARs to size them. - Don't free resources decoded by a BAR when the device driver releases a BAR. Instead, the PCI bus now owns unclaimed BARs and gives them to drivers on demand. When a driver releases a BAR, the PCI bus reclaims it and leaves the resource range allocated. This also prevents drivers from allocating the same resource multiple times. - Move the activation of BARs by enabling decoding in the PCI command register into bus_activate_resource() so that it always happens after the BAR is fully programmed. - Always read/write the full 64-bit value of 64-bit BARs. - Consolidate duplicated code for reading and sizing BARs and writing base address to BARs. Modified: stable/7/sys/ (props changed) stable/7/sys/contrib/pf/ (props changed) stable/7/sys/dev/ath/ath_hal/ (props changed) stable/7/sys/dev/cxgb/ (props changed) stable/7/sys/dev/pci/pci.c stable/7/sys/dev/pci/pci_private.h stable/7/sys/dev/pci/pcireg.h Modified: stable/7/sys/dev/pci/pci.c ============================================================================== --- stable/7/sys/dev/pci/pci.c Mon May 4 20:25:56 2009 (r191794) +++ stable/7/sys/dev/pci/pci.c Mon May 4 20:35:59 2009 (r191795) @@ -71,18 +71,17 @@ __FBSDID("$FreeBSD$"); #define ACPI_PWR_FOR_SLEEP(x, y, z) #endif -static uint32_t pci_mapbase(unsigned mapreg); -static const char *pci_maptype(unsigned mapreg); -static int pci_mapsize(unsigned testval); -static int pci_maprange(unsigned mapreg); +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 void pci_fixancient(pcicfgregs *cfg); -static int pci_porten(device_t pcib, int b, int s, int f); -static int pci_memen(device_t pcib, int b, int s, int f); +static int pci_porten(device_t dev); +static int pci_memen(device_t dev); static void pci_assign_interrupt(device_t bus, device_t dev, int force_route); -static int pci_add_map(device_t pcib, device_t bus, device_t dev, - int b, int s, int f, int reg, +static int pci_add_map(device_t bus, device_t dev, int reg, struct resource_list *rl, int force, int prefetch); static int pci_probe(device_t dev); static int pci_attach(device_t dev); @@ -136,7 +135,7 @@ static device_method_t pci_methods[] = { DEVMETHOD(bus_delete_resource, pci_delete_resource), DEVMETHOD(bus_alloc_resource, pci_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), - DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_activate_resource, pci_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_child_pnpinfo_str, pci_child_pnpinfo_str_method), DEVMETHOD(bus_child_location_str, pci_child_location_str_method), @@ -316,8 +315,8 @@ pci_find_device(uint16_t vendor, uint16_ /* return base address of memory or port map */ -static uint32_t -pci_mapbase(uint32_t mapreg) +static pci_addr_t +pci_mapbase(uint64_t mapreg) { if (PCI_BAR_MEM(mapreg)) @@ -329,7 +328,7 @@ pci_mapbase(uint32_t mapreg) /* return map type of memory or port map */ static const char * -pci_maptype(unsigned mapreg) +pci_maptype(uint64_t mapreg) { if (PCI_BAR_IO(mapreg)) @@ -342,7 +341,7 @@ pci_maptype(unsigned mapreg) /* return log2 of map size decoded for memory or port map */ static int -pci_mapsize(uint32_t testval) +pci_mapsize(uint64_t testval) { int ln2size; @@ -361,7 +360,7 @@ pci_mapsize(uint32_t testval) /* return log2 of address range supported by map register */ static int -pci_maprange(unsigned mapreg) +pci_maprange(uint64_t mapreg) { int ln2range = 0; @@ -2257,17 +2256,75 @@ pci_print_verbose(struct pci_devinfo *di } static int -pci_porten(device_t pcib, int b, int s, int f) +pci_porten(device_t dev) { - return (PCIB_READ_CONFIG(pcib, b, s, f, PCIR_COMMAND, 2) - & PCIM_CMD_PORTEN) != 0; + return (pci_read_config(dev, PCIR_COMMAND, 2) & PCIM_CMD_PORTEN) != 0; } static int -pci_memen(device_t pcib, int b, int s, int f) +pci_memen(device_t dev) { - return (PCIB_READ_CONFIG(pcib, b, s, f, PCIR_COMMAND, 2) - & PCIM_CMD_MEMEN) != 0; + return (pci_read_config(dev, PCIR_COMMAND, 2) & PCIM_CMD_MEMEN) != 0; +} + +static void +pci_read_bar(device_t dev, int reg, pci_addr_t *mapp, pci_addr_t *testvalp) +{ + pci_addr_t map, testval; + int ln2range; + uint16_t cmd; + + map = pci_read_config(dev, reg, 4); + ln2range = pci_maprange(map); + if (ln2range == 64) + map |= (pci_addr_t)pci_read_config(dev, reg + 4, 4) << 32; + + /* + * Disable decoding via the command register before + * determining the BAR's length since we will be placing it in + * a weird state. + */ + cmd = pci_read_config(dev, PCIR_COMMAND, 2); + pci_write_config(dev, PCIR_COMMAND, + cmd & ~(PCI_BAR_MEM(map) ? PCIM_CMD_MEMEN : PCIM_CMD_PORTEN), 2); + + /* + * Determine the BAR's length by writing all 1's. The bottom + * log_2(size) bits of the BAR will stick as 0 when we read + * the value back. + */ + pci_write_config(dev, reg, 0xffffffff, 4); + testval = pci_read_config(dev, reg, 4); + if (ln2range == 64) { + pci_write_config(dev, reg + 4, 0xffffffff, 4); + testval |= (pci_addr_t)pci_read_config(dev, reg + 4, 4) << 32; + } + + /* + * Restore the original value of the BAR. We may have reprogrammed + * the BAR of the low-level console device and when booting verbose, + * we need the console device addressable. + */ + pci_write_config(dev, reg, map, 4); + if (ln2range == 64) + pci_write_config(dev, reg + 4, map >> 32, 4); + pci_write_config(dev, PCIR_COMMAND, cmd, 2); + + *mapp = map; + *testvalp = testval; +} + +static void +pci_write_bar(device_t dev, int reg, pci_addr_t base) +{ + pci_addr_t map; + int ln2range; + + map = pci_read_config(dev, reg, 4); + ln2range = pci_maprange(map); + pci_write_config(dev, reg, base, 4); + if (ln2range == 64) + pci_write_config(dev, reg + 4, base >> 32, 4); } /* @@ -2275,36 +2332,26 @@ pci_memen(device_t pcib, int b, int s, i * register is a 32bit map register or 2 if it is a 64bit register. */ static int -pci_add_map(device_t pcib, device_t bus, device_t dev, - int b, int s, int f, int reg, struct resource_list *rl, int force, - int prefetch) +pci_add_map(device_t bus, device_t dev, int reg, struct resource_list *rl, + int force, int prefetch) { - uint32_t map; - pci_addr_t base; + pci_addr_t base, map, testval; pci_addr_t start, end, count; - uint8_t ln2size; - uint8_t ln2range; - uint32_t testval; + int barlen, maprange, mapsize, type; uint16_t cmd; - int type; - int barlen; struct resource *res; - map = PCIB_READ_CONFIG(pcib, b, s, f, reg, 4); - PCIB_WRITE_CONFIG(pcib, b, s, f, reg, 0xffffffff, 4); - testval = PCIB_READ_CONFIG(pcib, b, s, f, reg, 4); - PCIB_WRITE_CONFIG(pcib, b, s, f, reg, map, 4); - + pci_read_bar(dev, reg, &map, &testval); if (PCI_BAR_MEM(map)) { type = SYS_RES_MEMORY; if (map & PCIM_BAR_MEM_PREFETCH) prefetch = 1; } else type = SYS_RES_IOPORT; - ln2size = pci_mapsize(testval); - ln2range = pci_maprange(testval); + mapsize = pci_mapsize(testval); base = pci_mapbase(map); - barlen = ln2range == 64 ? 2 : 1; + maprange = pci_maprange(map); + barlen = maprange == 64 ? 2 : 1; /* * For I/O registers, if bottom bit is set, and the next bit up @@ -2315,19 +2362,16 @@ pci_add_map(device_t pcib, device_t bus, */ if (PCI_BAR_IO(testval) && (testval & PCIM_BAR_IO_RESERVED) != 0) return (barlen); - if ((type == SYS_RES_MEMORY && ln2size < 4) || - (type == SYS_RES_IOPORT && ln2size < 2)) + if ((type == SYS_RES_MEMORY && mapsize < 4) || + (type == SYS_RES_IOPORT && mapsize < 2)) return (barlen); - if (ln2range == 64) - /* Read the other half of a 64bit map register */ - base |= (uint64_t) PCIB_READ_CONFIG(pcib, b, s, f, reg + 4, 4) << 32; if (bootverbose) { printf("\tmap[%02x]: type %s, range %2d, base %#jx, size %2d", - reg, pci_maptype(map), ln2range, (uintmax_t)base, ln2size); - if (type == SYS_RES_IOPORT && !pci_porten(pcib, b, s, f)) + reg, pci_maptype(map), maprange, (uintmax_t)base, mapsize); + if (type == SYS_RES_IOPORT && !pci_porten(dev)) printf(", port disabled\n"); - else if (type == SYS_RES_MEMORY && !pci_memen(pcib, b, s, f)) + else if (type == SYS_RES_MEMORY && !pci_memen(dev)) printf(", memory disabled\n"); else printf(", enabled\n"); @@ -2349,7 +2393,8 @@ pci_add_map(device_t pcib, device_t bus, if ((u_long)base != base) { device_printf(bus, "pci%d:%d:%d:%d bar %#x too many address bits", - pci_get_domain(dev), b, s, f, reg); + pci_get_domain(dev), pci_get_bus(dev), pci_get_slot(dev), + pci_get_function(dev), reg); return (barlen); } @@ -2362,30 +2407,30 @@ pci_add_map(device_t pcib, device_t bus, */ if (pci_enable_io_modes) { /* Turn on resources that have been left off by a lazy BIOS */ - if (type == SYS_RES_IOPORT && !pci_porten(pcib, b, s, f)) { - cmd = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_COMMAND, 2); + if (type == SYS_RES_IOPORT && !pci_porten(dev)) { + cmd = pci_read_config(dev, PCIR_COMMAND, 2); cmd |= PCIM_CMD_PORTEN; - PCIB_WRITE_CONFIG(pcib, b, s, f, PCIR_COMMAND, cmd, 2); + pci_write_config(dev, PCIR_COMMAND, cmd, 2); } - if (type == SYS_RES_MEMORY && !pci_memen(pcib, b, s, f)) { - cmd = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_COMMAND, 2); + if (type == SYS_RES_MEMORY && !pci_memen(dev)) { + cmd = pci_read_config(dev, PCIR_COMMAND, 2); cmd |= PCIM_CMD_MEMEN; - PCIB_WRITE_CONFIG(pcib, b, s, f, PCIR_COMMAND, cmd, 2); + pci_write_config(dev, PCIR_COMMAND, cmd, 2); } } else { - if (type == SYS_RES_IOPORT && !pci_porten(pcib, b, s, f)) + if (type == SYS_RES_IOPORT && !pci_porten(dev)) return (barlen); - if (type == SYS_RES_MEMORY && !pci_memen(pcib, b, s, f)) + if (type == SYS_RES_MEMORY && !pci_memen(dev)) return (barlen); } - count = 1 << ln2size; + count = 1 << mapsize; if (base == 0 || base == pci_mapbase(testval)) { start = 0; /* Let the parent decide. */ end = ~0ULL; } else { start = base; - end = base + (1 << ln2size) - 1; + end = base + (1 << mapsize) - 1; } resource_list_add(rl, type, reg, start, end, count); @@ -2406,11 +2451,11 @@ pci_add_map(device_t pcib, device_t bus, */ resource_list_delete(rl, type, reg); start = 0; - } else + } else { start = rman_get_start(res); - pci_write_config(dev, reg, start, 4); - if (ln2range == 64) - pci_write_config(dev, reg + 4, start >> 32, 4); + rman_set_device(res, bus); + } + pci_write_bar(dev, reg, start); return (barlen); } @@ -2422,9 +2467,10 @@ pci_add_map(device_t pcib, device_t bus, * addressing mode. */ static void -pci_ata_maps(device_t pcib, device_t bus, device_t dev, int b, - int s, int f, struct resource_list *rl, int force, uint32_t prefetchmask) +pci_ata_maps(device_t bus, device_t dev, struct resource_list *rl, int force, + uint32_t prefetchmask) { + struct resource *r; int rid, type, progif; #if 0 /* if this device supports PCI native addressing use it */ @@ -2440,38 +2486,42 @@ pci_ata_maps(device_t pcib, device_t bus progif = pci_read_config(dev, PCIR_PROGIF, 1); type = SYS_RES_IOPORT; if (progif & PCIP_STORAGE_IDE_MODEPRIM) { - pci_add_map(pcib, bus, dev, b, s, f, PCIR_BAR(0), rl, force, + pci_add_map(bus, dev, PCIR_BAR(0), rl, force, prefetchmask & (1 << 0)); - pci_add_map(pcib, bus, dev, b, s, f, PCIR_BAR(1), rl, force, + pci_add_map(bus, dev, PCIR_BAR(1), rl, force, prefetchmask & (1 << 1)); } else { rid = PCIR_BAR(0); resource_list_add(rl, type, rid, 0x1f0, 0x1f7, 8); - resource_list_alloc(rl, bus, dev, type, &rid, 0x1f0, 0x1f7, 8, - 0); + r = resource_list_alloc(rl, bus, dev, type, &rid, 0x1f0, 0x1f7, + 8, 0); + rman_set_device(r, bus); rid = PCIR_BAR(1); resource_list_add(rl, type, rid, 0x3f6, 0x3f6, 1); - resource_list_alloc(rl, bus, dev, type, &rid, 0x3f6, 0x3f6, 1, - 0); + r = resource_list_alloc(rl, bus, dev, type, &rid, 0x3f6, 0x3f6, + 1, 0); + rman_set_device(r, bus); } if (progif & PCIP_STORAGE_IDE_MODESEC) { - pci_add_map(pcib, bus, dev, b, s, f, PCIR_BAR(2), rl, force, + pci_add_map(bus, dev, PCIR_BAR(2), rl, force, prefetchmask & (1 << 2)); - pci_add_map(pcib, bus, dev, b, s, f, PCIR_BAR(3), rl, force, + pci_add_map(bus, dev, PCIR_BAR(3), rl, force, prefetchmask & (1 << 3)); } else { rid = PCIR_BAR(2); resource_list_add(rl, type, rid, 0x170, 0x177, 8); - resource_list_alloc(rl, bus, dev, type, &rid, 0x170, 0x177, 8, - 0); + r = resource_list_alloc(rl, bus, dev, type, &rid, 0x170, 0x177, + 8, 0); + rman_set_device(r, bus); rid = PCIR_BAR(3); resource_list_add(rl, type, rid, 0x376, 0x376, 1); - resource_list_alloc(rl, bus, dev, type, &rid, 0x376, 0x376, 1, - 0); + r = resource_list_alloc(rl, bus, dev, type, &rid, 0x376, 0x376, + 1, 0); + rman_set_device(r, bus); } - pci_add_map(pcib, bus, dev, b, s, f, PCIR_BAR(4), rl, force, + pci_add_map(bus, dev, PCIR_BAR(4), rl, force, prefetchmask & (1 << 4)); - pci_add_map(pcib, bus, dev, b, s, f, PCIR_BAR(5), rl, force, + pci_add_map(bus, dev, PCIR_BAR(5), rl, force, prefetchmask & (1 << 5)); } @@ -2526,18 +2576,11 @@ pci_assign_interrupt(device_t bus, devic void pci_add_resources(device_t bus, device_t dev, int force, uint32_t prefetchmask) { - device_t pcib; struct pci_devinfo *dinfo = device_get_ivars(dev); pcicfgregs *cfg = &dinfo->cfg; struct resource_list *rl = &dinfo->resources; struct pci_quirk *q; - int b, i, f, s; - - pcib = device_get_parent(bus); - - b = cfg->bus; - s = cfg->slot; - f = cfg->func; + int i; /* ATA devices needs special map treatment */ if ((pci_get_class(dev) == PCIC_STORAGE) && @@ -2545,11 +2588,11 @@ pci_add_resources(device_t bus, device_t ((pci_get_progif(dev) & PCIP_STORAGE_IDE_MASTERDEV) || (!pci_read_config(dev, PCIR_BAR(0), 4) && !pci_read_config(dev, PCIR_BAR(2), 4))) ) - pci_ata_maps(pcib, bus, dev, b, s, f, rl, force, prefetchmask); + pci_ata_maps(bus, dev, rl, force, prefetchmask); else for (i = 0; i < cfg->nummaps;) - i += pci_add_map(pcib, bus, dev, b, s, f, PCIR_BAR(i), - rl, force, prefetchmask & (1 << i)); + i += pci_add_map(bus, dev, PCIR_BAR(i), rl, force, + prefetchmask & (1 << i)); /* * Add additional, quirked resources. @@ -2557,8 +2600,7 @@ pci_add_resources(device_t bus, device_t for (q = &pci_quirks[0]; q->devid; q++) { if (q->devid == ((cfg->device << 16) | cfg->vendor) && q->type == PCI_QUIRK_MAP_REG) - pci_add_map(pcib, bus, dev, b, s, f, q->arg1, rl, - force, 0); + pci_add_map(bus, dev, q->arg1, rl, force, 0); } if (cfg->intpin > 0 && PCI_INTERRUPT_VALID(cfg->intline)) { @@ -3401,21 +3443,12 @@ pci_alloc_map(device_t dev, device_t chi * it fails here, that other code is broken. */ res = NULL; - map = pci_read_config(child, *rid, 4); - pci_write_config(child, *rid, 0xffffffff, 4); - testval = pci_read_config(child, *rid, 4); - if (pci_maprange(testval) == 64) - map |= (pci_addr_t)pci_read_config(child, *rid + 4, 4) << 32; + pci_read_bar(child, *rid, &map, &testval); + + /* Ignore a BAR with a base of 0. */ if (pci_mapbase(testval) == 0) goto out; - /* - * Restore the original value of the BAR. We may have reprogrammed - * the BAR of the low-level console device and when booting verbose, - * we need the console device addressable. - */ - pci_write_config(child, *rid, map, 4); - if (PCI_BAR_MEM(testval)) { if (type != SYS_RES_MEMORY) { if (bootverbose) @@ -3435,6 +3468,7 @@ pci_alloc_map(device_t dev, device_t chi goto out; } } + /* * For real BARs, we need to override the size that * the driver requests, because that's what the BAR @@ -3454,13 +3488,14 @@ pci_alloc_map(device_t dev, device_t chi * appropriate bar for that resource. */ res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, type, rid, - start, end, count, flags); + start, end, count, flags & ~RF_ACTIVE); if (res == NULL) { device_printf(child, "%#lx bytes of rid %#x res %d failed (%#lx, %#lx).\n", count, *rid, type, start, end); goto out; } + rman_set_device(res, dev); resource_list_add(rl, type, *rid, start, end, count); rle = resource_list_find(rl, type, *rid); if (rle == NULL) @@ -3474,10 +3509,8 @@ 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); out:; - pci_write_config(child, *rid, map, 4); - if (pci_maprange(testval) == 64) - pci_write_config(child, *rid + 4, map >> 32, 4); return (res); } @@ -3489,68 +3522,63 @@ pci_alloc_resource(device_t dev, device_ struct pci_devinfo *dinfo = device_get_ivars(child); struct resource_list *rl = &dinfo->resources; struct resource_list_entry *rle; + struct resource *res; pcicfgregs *cfg = &dinfo->cfg; + if (device_get_parent(child) != dev) + return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, + type, rid, start, end, count, flags)); + /* * Perform lazy resource allocation */ - if (device_get_parent(child) == dev) { - switch (type) { - case SYS_RES_IRQ: - /* - * Can't alloc legacy interrupt once MSI messages - * have been allocated. - */ - if (*rid == 0 && (cfg->msi.msi_alloc > 0 || - cfg->msix.msix_alloc > 0)) + switch (type) { + case SYS_RES_IRQ: + /* + * Can't alloc legacy interrupt once MSI messages have + * been allocated. + */ + if (*rid == 0 && (cfg->msi.msi_alloc > 0 || + cfg->msix.msix_alloc > 0)) + return (NULL); + + /* + * If the child device doesn't have an interrupt + * routed and is deserving of an interrupt, try to + * assign it one. + */ + if (*rid == 0 && !PCI_INTERRUPT_VALID(cfg->intline) && + (cfg->intpin != 0)) + pci_assign_interrupt(dev, child, 0); + break; + case SYS_RES_IOPORT: + case SYS_RES_MEMORY: + /* Allocate resources for this BAR if needed. */ + rle = resource_list_find(rl, type, *rid); + if (rle == NULL) { + res = pci_alloc_map(dev, child, type, rid, start, end, + count, flags); + if (res == NULL) return (NULL); - /* - * If the child device doesn't have an - * interrupt routed and is deserving of an - * interrupt, try to assign it one. - */ - if (*rid == 0 && !PCI_INTERRUPT_VALID(cfg->intline) && - (cfg->intpin != 0)) - pci_assign_interrupt(dev, child, 0); - break; - case SYS_RES_IOPORT: - case SYS_RES_MEMORY: - if (*rid < PCIR_BAR(cfg->nummaps)) { - /* - * Enable the I/O mode. We should - * also be assigning resources too - * when none are present. The - * resource_list_alloc kind of sorta does - * this... - */ - if (PCI_ENABLE_IO(dev, child, type)) - return (NULL); - } rle = resource_list_find(rl, type, *rid); - if (rle == NULL) - return (pci_alloc_map(dev, child, type, rid, - start, end, count, flags)); - break; } + /* - * If we've already allocated the resource, then - * return it now. But first we may need to activate - * it, since we don't allocate the resource as active - * above. Normally this would be done down in the - * nexus, but since we short-circuit that path we have - * to do its job here. Not sure if we should free the - * resource if it fails to activate. + * If the resource belongs to the bus, then give it to + * the child. We need to activate it if requested + * since the bus always allocates inactive resources. */ - rle = resource_list_find(rl, type, *rid); - if (rle != NULL && rle->res != NULL) { + if (rle != NULL && rle->res != NULL && + rman_get_device(rle->res) == dev) { if (bootverbose) device_printf(child, "Reserved %#lx bytes for rid %#x type %d at %#lx\n", rman_get_size(rle->res), *rid, type, rman_get_start(rle->res)); + rman_set_device(rle->res, child); if ((flags & RF_ACTIVE) && - bus_generic_activate_resource(dev, child, type, - *rid, rle->res) != 0) + bus_activate_resource(child, type, *rid, + rle->res) != 0) return (NULL); return (rle->res); } @@ -3559,6 +3587,59 @@ pci_alloc_resource(device_t dev, device_ start, end, count, flags)); } +int +pci_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + int error; + + if (device_get_parent(child) != dev) + return (BUS_RELEASE_RESOURCE(device_get_parent(dev), child, + type, rid, r)); + + /* + * For BARs we don't actually want to release the resource. + * Instead, we deactivate the resource if needed and then give + * ownership of the BAR back to the bus. + */ + switch (type) { + case SYS_RES_IOPORT: + case SYS_RES_MEMORY: + if (rman_get_device(r) != child) + return (EINVAL); + if (rman_get_flags(r) & RF_ACTIVE) { + error = bus_deactivate_resource(child, type, rid, r); + if (error) + return (error); + } + rman_set_device(r, dev); + return (0); + } + return (bus_generic_rl_release_resource(dev, child, type, rid, r)); +} + +int +pci_activate_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + int error; + + error = bus_generic_activate_resource(dev, child, type, rid, r); + if (error) + return (error); + + /* Enable decoding in the command register when activating BARs. */ + if (device_get_parent(child) == dev) { + switch (type) { + case SYS_RES_IOPORT: + case SYS_RES_MEMORY: + error = PCI_ENABLE_IO(dev, child, type); + break; + } + } + return (error); +} + void pci_delete_resource(device_t dev, device_t child, int type, int rid) { @@ -3572,27 +3653,33 @@ pci_delete_resource(device_t dev, device dinfo = device_get_ivars(child); rl = &dinfo->resources; rle = resource_list_find(rl, type, rid); - if (rle) { - if (rle->res) { - if (rman_get_device(rle->res) != dev || - rman_get_flags(rle->res) & RF_ACTIVE) { - device_printf(dev, "delete_resource: " - "Resource still owned by child, oops. " - "(type=%d, rid=%d, addr=%lx)\n", - rle->type, rle->rid, - rman_get_start(rle->res)); - return; - } - bus_release_resource(dev, type, rid, rle->res); + if (rle == NULL) + return; + + if (rle->res) { + if (rman_get_device(rle->res) != dev || + rman_get_flags(rle->res) & RF_ACTIVE) { + device_printf(dev, "delete_resource: " + "Resource still owned by child, oops. " + "(type=%d, rid=%d, addr=%lx)\n", + rle->type, rle->rid, + rman_get_start(rle->res)); + return; } - resource_list_delete(rl, type, rid); + + /* + * If this is a BAR, clear the BAR so it stops + * decoding before releasing the resource. + */ + switch (type) { + case SYS_RES_IOPORT: + case SYS_RES_MEMORY: + pci_write_bar(child, rid, 0); + break; + } + bus_release_resource(dev, type, rid, rle->res); } - /* - * Why do we turn off the PCI configuration BAR when we delete a - * resource? -- imp - */ - pci_write_config(child, rid, 0, 4); - BUS_DELETE_RESOURCE(device_get_parent(dev), child, type, rid); + resource_list_delete(rl, type, rid); } struct resource_list * Modified: stable/7/sys/dev/pci/pci_private.h ============================================================================== --- stable/7/sys/dev/pci/pci_private.h Mon May 4 20:25:56 2009 (r191794) +++ stable/7/sys/dev/pci/pci_private.h Mon May 4 20:35:59 2009 (r191795) @@ -82,6 +82,10 @@ int pci_msix_count_method(device_t dev, 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); 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/7/sys/dev/pci/pcireg.h ============================================================================== --- stable/7/sys/dev/pci/pcireg.h Mon May 4 20:25:56 2009 (r191794) +++ stable/7/sys/dev/pci/pcireg.h Mon May 4 20:35:59 2009 (r191795) @@ -130,7 +130,7 @@ #define PCIM_BAR_MEM_1MB 2 /* Locate below 1MB in PCI <= 2.1 */ #define PCIM_BAR_MEM_64 4 #define PCIM_BAR_MEM_PREFETCH 0x00000008 -#define PCIM_BAR_MEM_BASE 0xfffffff0 +#define PCIM_BAR_MEM_BASE 0xfffffffffffffff0ULL #define PCIM_BAR_IO_RESERVED 0x00000002 #define PCIM_BAR_IO_BASE 0xfffffffc #define PCIR_CIS 0x28
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200905042036.n44Ka08v056369>