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