svn commit: r191795 - in stable/7/sys: . contrib/pf dev/ath/ath_hal
dev/cxgb dev/pci
John Baldwin
jhb at FreeBSD.org
Mon May 4 20:36:01 UTC 2009
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
More information about the svn-src-stable
mailing list