PERFORCE change 189478 for review
John Baldwin
jhb at FreeBSD.org
Fri Mar 4 04:13:13 UTC 2011
http://p4web.freebsd.org/@@189478?ac=10
Change 189478 by jhb at jhb_kavik on 2011/03/04 04:12:13
Checkpoint work to track BARs explicitly so we can report all BARs
to userland. There is room here for consolidating some more
duplicated code. This isn't quite finished as pm_enabled isn't
correct yet for "lazy" allocations.
Affected files ...
.. //depot/projects/pci/sys/dev/pci/pci.c#2 edit
.. //depot/projects/pci/sys/dev/pci/pci_private.h#2 edit
.. //depot/projects/pci/sys/dev/pci/pci_user.c#2 edit
.. //depot/projects/pci/sys/dev/pci/pcivar.h#2 edit
Differences ...
==== //depot/projects/pci/sys/dev/pci/pci.c#2 (text+ko) ====
@@ -531,6 +531,7 @@
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);
@@ -2084,6 +2085,7 @@
pci_freecfg(struct pci_devinfo *dinfo)
{
struct devlist *devlist_head;
+ struct pci_map *pm, *next;
int i;
devlist_head = &pci_devq;
@@ -2097,6 +2099,9 @@
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);
@@ -2368,8 +2373,25 @@
return (pci_read_config(dev, PCIR_COMMAND, 2) & PCIM_CMD_MEMEN) != 0;
}
+static pci_addr_t
+pci_read_bar(device_t dev, int reg)
+{
+ pci_addr_t map;
+ int ln2range;
+
+ /* The device ROM BAR is always a 32-bit memory BAR. */
+ if (reg == PCIR_BIOS)
+ return (pci_read_config(dev, PCIR_BIOS, 4));
+
+ 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;
+ return (map);
+}
+
static void
-pci_read_bar(device_t dev, int reg, pci_addr_t *mapp, pci_addr_t *testvalp)
+pci_size_bar(device_t dev, int reg, pci_addr_t *mapp, pci_addr_t *testvalp)
{
pci_addr_t map, testval;
int ln2range;
@@ -2447,6 +2469,43 @@
pci_write_config(dev, reg + 4, base >> 32, 4);
}
+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 == bio->pbi_reg)
+ return (pm);
+ }
+ return (NULL);
+}
+
+struct pci_map *
+pci_add_bar(device_t dev, int reg)
+{
+ 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;
+ STAILQ_FOREACH(prev, &dinfo->cfg.maps, pm_link) {
+ KASSERT(prev->pm_reg != pm->pm_reg, ("duplicate map %02x",
+ reg));
+ if (STAILQ_NEXT(prev) == NULL || STAILQ_NEXT(prev)->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);
+}
+
/*
* Add a resource based on a pci map register. Return 1 if the map
* register is a 32bit map register or 2 if it is a 64bit register.
@@ -2455,13 +2514,14 @@
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;
- pci_read_bar(dev, reg, &map, &testval);
+ pci_size_bar(dev, reg, &map, &testval);
if (PCI_BAR_MEM(map)) {
type = SYS_RES_MEMORY;
if (map & PCIM_BAR_MEM_PREFETCH)
@@ -2491,6 +2551,10 @@
(type == SYS_RES_IOPORT && mapsize < 2))
return (barlen);
+ /* Save a record of this BAR. */
+ pm = pci_add_bar(dev, reg);
+ pm->pm_value = map;
+ pm->pm_size = mapsize;
if (bootverbose) {
printf("\tmap[%02x]: type %s, range %2d, base %#jx, size %2d",
reg, pci_maptype(map), maprange, (uintmax_t)base, mapsize);
@@ -2576,9 +2640,12 @@
*/
resource_list_delete(rl, type, reg);
start = 0;
- } else
+ } else {
start = rman_get_start(res);
+ pm->pm_enabled = 1;
+ }
pci_write_bar(dev, reg, start);
+ pm->pm_value = pm_read_bar(dev, reg);
return (barlen);
}
@@ -3713,31 +3780,44 @@
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(dev, *rid);
+ if (pm != NULL) {
+ /* This is a BAR that we failed to allocate earlier. */
+ mapsize = pm->pm_size;
+ map = pci_read_bar(child, *rid);
+ } 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_size_bar(child, *rid, &map, &testval);
- /*
- * Determine the size of the BAR and ignore BARs with a size
- * of 0. Device ROM BARs use a different mask value.
- */
- if (*rid == PCIR_BIOS)
- mapsize = pci_romsize(testval);
- else
- mapsize = pci_mapsize(testval);
- if (mapsize == 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 (*rid == PCIR_BIOS)
+ mapsize = pci_romsize(testval);
+ else
+ mapsize = pci_mapsize(testval);
+ if (mapsize == 0)
+ goto out;
+ pm = pci_add_bar(child, *rid);
+ pm->pm_value = map;
+ pm->pm_size = mapsize;
+ }
- if (PCI_BAR_MEM(testval) || *rid == PCIR_BIOS) {
+ if (PCI_BAR_MEM(map) || *rid == PCIR_BIOS) {
if (type != SYS_RES_MEMORY) {
if (bootverbose)
device_printf(dev,
@@ -3767,12 +3847,12 @@
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);
@@ -3797,6 +3877,7 @@
count, *rid, type, rman_get_start(res));
map = rman_get_start(res);
pci_write_bar(child, *rid, map);
+ pm->pm_value = pci_read_bar(child, *rid);
out:;
return (res);
}
==== //depot/projects/pci/sys/dev/pci/pci_private.h#2 (text+ko) ====
@@ -104,6 +104,7 @@
int pci_assign_interrupt_method(device_t dev, device_t child);
int pci_resume(device_t dev);
int pci_suspend(device_t dev);
+struct pci_map *pci_find_bar(device_t dev, int reg);
/** Restore the config register state. The state must be previously
* saved with pci_cfg_save. However, the pci bus driver takes care of
==== //depot/projects/pci/sys/dev/pci/pci_user.c#2 (text+ko) ====
@@ -310,7 +310,7 @@
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 +685,14 @@
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, 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 = pm->pm_enabled;
error = 0;
break;
case PCIOCATTACHED:
==== //depot/projects/pci/sys/dev/pci/pcivar.h#2 (text+ko) ====
@@ -46,7 +46,15 @@
uint8_t pp_bse; /* conf. space addr. of PM BSE reg */
uint8_t pp_data; /* conf. space addr. of PM data reg */
};
-
+
+struct pci_map {
+ pci_addr_t pm_value; /* Raw BAR value */
+ pci_addr_t pm_size;
+ uint8_t pm_reg;
+ uint8_t pm_enabled;
+ STAILQ_ENTRY(pci_map) pm_link;
+};
+
struct vpd_readonly {
char keyword[2];
char *value;
@@ -119,8 +127,7 @@
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 */
More information about the p4-projects
mailing list