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
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to