diff options
author | jhb <jhb@FreeBSD.org> | 2009-12-09 21:52:53 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2009-12-09 21:52:53 +0000 |
commit | 2f9d87159f5d613da2c056aaac7bd15b0ff65321 (patch) | |
tree | 78b5b1cc0d0ca2bef712c38d3b03a18d90c486b4 /sys/dev/pci/pci.c | |
parent | 406b6e267438bc964488f714b956cfc3a8de788f (diff) | |
download | FreeBSD-src-2f9d87159f5d613da2c056aaac7bd15b0ff65321.zip FreeBSD-src-2f9d87159f5d613da2c056aaac7bd15b0ff65321.tar.gz |
For some buses, devices may have active resources assigned even though they
are not allocated by the device driver. These resources should still appear
allocated from the system's perspective so that their assigned ranges are
not reused by other resource requests. The PCI bus driver has used a hack
to effect this for a while now where it uses rman_set_device() to assign
devices to the PCI bus when they are first encountered and later assigns
them to the actual device when a driver allocates a BAR. A few downsides of
this approach is that it results in somewhat confusing devinfo -r output as
well as not being very easily portable to other bus drivers.
This commit adds generic support for "reserved" resources to the resource
list API used by many bus drivers to manage the resources of child devices.
A resource may be reserved via resource_list_reserve(). This will allocate
the resource from the bus' parent without activating it.
resource_list_alloc() recognizes an attempt to allocate a reserved resource.
When this happens it activates the resource (if requested) and then returns
the reserved resource. Similarly, when a reserved resource is released via
resource_list_release(), it is deactivated (if it is active) and the
resource is then marked reserved again, but is left allocated from the
bus' parent. To completely remove a reserved resource, a bus driver may
use resource_list_unreserve(). A bus driver may use resource_list_busy()
to determine if a reserved resource is allocated by a child device or if
it can be unreserved.
The PCI bus driver has been changed to use this framework instead of
abusing rman_set_device() to keep track of reserved vs allocated resources.
Submitted by: imp (an older version many moons ago)
MFC after: 1 month
Diffstat (limited to 'sys/dev/pci/pci.c')
-rw-r--r-- | sys/dev/pci/pci.c | 84 |
1 files changed, 22 insertions, 62 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index b8a2dab..1bf5130 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -2451,7 +2451,7 @@ pci_add_map(device_t bus, device_t dev, int reg, struct resource_list *rl, * driver for this device will later inherit this resource in * pci_alloc_resource(). */ - res = resource_list_alloc(rl, bus, dev, type, ®, start, end, count, + res = resource_list_reserve(rl, bus, dev, type, ®, start, end, count, prefetch ? RF_PREFETCHABLE : 0); if (res == NULL) { /* @@ -2462,10 +2462,8 @@ pci_add_map(device_t bus, device_t dev, int reg, struct resource_list *rl, */ resource_list_delete(rl, type, reg); start = 0; - } else { + } else start = rman_get_start(res); - rman_set_device(res, bus); - } pci_write_bar(dev, reg, start); return (barlen); } @@ -2504,14 +2502,12 @@ pci_ata_maps(device_t bus, device_t dev, struct resource_list *rl, int force, } else { rid = PCIR_BAR(0); resource_list_add(rl, type, rid, 0x1f0, 0x1f7, 8); - r = resource_list_alloc(rl, bus, dev, type, &rid, 0x1f0, 0x1f7, - 8, 0); - rman_set_device(r, bus); + r = resource_list_reserve(rl, bus, dev, type, &rid, 0x1f0, + 0x1f7, 8, 0); rid = PCIR_BAR(1); resource_list_add(rl, type, rid, 0x3f6, 0x3f6, 1); - r = resource_list_alloc(rl, bus, dev, type, &rid, 0x3f6, 0x3f6, - 1, 0); - rman_set_device(r, bus); + r = resource_list_reserve(rl, bus, dev, type, &rid, 0x3f6, + 0x3f6, 1, 0); } if (progif & PCIP_STORAGE_IDE_MODESEC) { pci_add_map(bus, dev, PCIR_BAR(2), rl, force, @@ -2521,14 +2517,12 @@ pci_ata_maps(device_t bus, device_t dev, struct resource_list *rl, int force, } else { rid = PCIR_BAR(2); resource_list_add(rl, type, rid, 0x170, 0x177, 8); - r = resource_list_alloc(rl, bus, dev, type, &rid, 0x170, 0x177, - 8, 0); - rman_set_device(r, bus); + r = resource_list_reserve(rl, bus, dev, type, &rid, 0x170, + 0x177, 8, 0); rid = PCIR_BAR(3); resource_list_add(rl, type, rid, 0x376, 0x376, 1); - r = resource_list_alloc(rl, bus, dev, type, &rid, 0x376, 0x376, - 1, 0); - rman_set_device(r, bus); + r = resource_list_reserve(rl, bus, dev, type, &rid, 0x376, + 0x376, 1, 0); } pci_add_map(bus, dev, PCIR_BAR(4), rl, force, prefetchmask & (1 << 4)); @@ -3564,7 +3558,7 @@ DB_SHOW_COMMAND(pciregs, db_pci_dump) #endif /* DDB */ static struct resource * -pci_alloc_map(device_t dev, device_t child, int type, int *rid, +pci_reserve_map(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct pci_devinfo *dinfo = device_get_ivars(child); @@ -3634,15 +3628,15 @@ pci_alloc_map(device_t dev, device_t child, int type, int *rid, 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) - panic("pci_alloc_map: unexpectedly can't find resource."); + panic("pci_reserve_map: unexpectedly can't find resource."); rle->res = res; rle->start = rman_get_start(res); rle->end = rman_get_end(res); rle->count = count; + rle->flags = RLE_RESERVED; if (bootverbose) device_printf(child, "Lazy allocation of %#lx bytes rid %#x type %d at %#lx\n", @@ -3692,34 +3686,13 @@ pci_alloc_resource(device_t dev, device_t child, int type, int *rid, break; case SYS_RES_IOPORT: case SYS_RES_MEMORY: - /* Allocate resources for this BAR if needed. */ + /* Reserve 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, + res = pci_reserve_map(dev, child, type, rid, start, end, count, flags); if (res == NULL) return (NULL); - rle = resource_list_find(rl, type, *rid); - } - - /* - * 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. - */ - 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_activate_resource(child, type, *rid, - rle->res) != 0) - return (NULL); - return (rle->res); } } return (resource_list_alloc(rl, dev, child, type, rid, @@ -3730,7 +3703,6 @@ 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, @@ -3739,21 +3711,10 @@ pci_release_resource(device_t dev, device_t child, int type, int rid, /* * 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. + * ownership of the BAR back to the bus. This is handled for us + * in resource_list_release() since we use resource_list_reserve() + * for BARs. */ - 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)); } @@ -3796,13 +3757,12 @@ pci_delete_resource(device_t dev, device_t child, int type, int rid) return; if (rle->res) { - if (rman_get_device(rle->res) != dev || - rman_get_flags(rle->res) & RF_ACTIVE) { + if (rman_get_flags(rle->res) & RF_ACTIVE || + resource_list_busy(rl, type, rid)) { 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)); + type, rid, rman_get_start(rle->res)); return; } @@ -3818,7 +3778,7 @@ pci_delete_resource(device_t dev, device_t child, int type, int rid) break; } #endif - bus_release_resource(dev, type, rid, rle->res); + resource_list_unreserve(rl, dev, child, type, rid); } resource_list_delete(rl, type, rid); } |