Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 9 Oct 2012 18:45:08 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r241378 - in stable/8/sys/dev: cardbus pci
Message-ID:  <201210091845.q99Ij88H054570@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Tue Oct  9 18:45:08 2012
New Revision: 241378
URL: http://svn.freebsd.org/changeset/base/241378

Log:
  MFC 201279,201280,201286,213907,214146,220195,222753,223371,225515,235833:
  Various fixes to managing PCI BARs including proper support for managing
  PCI ROM BARs:
  - Teach the PCI bus driver to handle PCIR_BIOS BARs properly and remove
    special handling for the PCIR_BIOS decoding enable bit from the cardbus
    driver.  The PCIR_BIOS BAR does include type bits like other BARs.
    Instead, it is always a 32-bit non-prefetchable memory BAR where the low
    bit is used as a flag to enable decoding.
  - Explicitly track the state of all known BARs for each PCI device.  The PCI
    bus driver will now remember the size of a BAR obtained during the initial
    bus scan and use that size when doing lazy resource allocation rather than
    resizing the BAR.  The bus driver will now also report unallocated BARs to
    userland for display by 'pciconf -lb'.
  - Add a constant for the offset of the ROM BIOS BAR in PCI-PCI bridges and
    properly handle ROM BIOS BARs in PCI-PCI bridges.  The PCI bus now also
    properly handles the lack of a ROM BIOS BAR in a PCI-Cardbus bridge.
  
  Tested by:	John Kozubik  john kozubik com

Modified:
  stable/8/sys/dev/cardbus/cardbus_cis.c
  stable/8/sys/dev/pci/pci.c
  stable/8/sys/dev/pci/pci_private.h
  stable/8/sys/dev/pci/pci_user.c
  stable/8/sys/dev/pci/pcireg.h
  stable/8/sys/dev/pci/pcivar.h
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/dev/   (props changed)
  stable/8/sys/dev/cardbus/   (props changed)
  stable/8/sys/dev/pci/   (props changed)

Modified: stable/8/sys/dev/cardbus/cardbus_cis.c
==============================================================================
--- stable/8/sys/dev/cardbus/cardbus_cis.c	Tue Oct  9 18:02:09 2012	(r241377)
+++ stable/8/sys/dev/cardbus/cardbus_cis.c	Tue Oct  9 18:45:08 2012	(r241378)
@@ -324,7 +324,7 @@ decode_tuple_bar(device_t cbdev, device_
 		 * hint when the cardbus bridge is a child of pci0 (the main
 		 * bus).  The PC Card spec seems to indicate that this should
 		 * only be done on x86 based machines, which suggests that on
-		 * non-x86 machines the adddresses can be anywhere.  Since the
+		 * non-x86 machines the addresses can be anywhere.  Since the
 		 * hardware can do it on non-x86 machines, it should be able
 		 * to do it on x86 machines too.  Therefore, we can and should
 		 * ignore this hint.  Furthermore, the PC Card spec recommends
@@ -435,9 +435,7 @@ cardbus_read_tuple_finish(device_t cbdev
 {
 	if (res != CIS_CONFIG_SPACE) {
 		bus_release_resource(child, SYS_RES_MEMORY, rid, res);
-		if (rid == PCIM_CIS_ASI_ROM)
-			pci_write_config(child, rid, pci_read_config(child,
-			    rid, 4) & ~PCIR_BIOS, 4);
+		bus_delete_resource(child, SYS_RES_MEMORY, rid);
 	}
 }
 
@@ -474,7 +472,7 @@ cardbus_read_tuple_init(device_t cbdev, 
 	}
 
 	/* allocate the memory space to read CIS */
-	res = bus_alloc_resource(child, SYS_RES_MEMORY, rid, 0, ~0, 1,
+	res = bus_alloc_resource_any(child, SYS_RES_MEMORY, rid,
 	    rman_make_alignment_flags(4096) | RF_ACTIVE);
 	if (res == NULL) {
 		device_printf(cbdev, "Unable to allocate resource "
@@ -482,9 +480,6 @@ cardbus_read_tuple_init(device_t cbdev, 
 		return (NULL);
 	}
 	DEVPRINTF((cbdev, "CIS Mapped to %#lx\n", rman_get_start(res)));
-	if (*rid == PCIR_BIOS)
-		pci_write_config(child, *rid,
-		    rman_get_start(res) | PCIM_BIOS_ENABLE, 4);
 
 	/* Flip to the right ROM image if CIS is in ROM */
 	if (space == PCIM_CIS_ASI_ROM) {
@@ -508,8 +503,8 @@ cardbus_read_tuple_init(device_t cbdev, 
 				device_printf(cbdev, "Bad header in rom %d: "
 				    "[%x] %04x\n", romnum, imagebase +
 				    CARDBUS_EXROM_SIGNATURE, romsig);
-				bus_release_resource(child, SYS_RES_MEMORY,
-				    *rid, res);
+				cardbus_read_tuple_finish(cbdev, child, *rid,
+				    res);
 				*rid = 0;
 				return (NULL);
 			}
@@ -545,8 +540,8 @@ cardbus_read_tuple_init(device_t cbdev, 
 			    CARDBUS_EXROM_DATA_INDICATOR) & 0x80) != 0) {
 				device_printf(cbdev, "Cannot find CIS in "
 				    "Option ROM\n");
-				bus_release_resource(child, SYS_RES_MEMORY,
-				    *rid, res);
+				cardbus_read_tuple_finish(cbdev, child, *rid,
+				    res);
 				*rid = 0;
 				return (NULL);
 			}

Modified: stable/8/sys/dev/pci/pci.c
==============================================================================
--- stable/8/sys/dev/pci/pci.c	Tue Oct  9 18:02:09 2012	(r241377)
+++ stable/8/sys/dev/pci/pci.c	Tue Oct  9 18:45:08 2012	(r241378)
@@ -91,10 +91,16 @@ __FBSDID("$FreeBSD$");
 #endif
 #endif
 
+#define	PCIR_IS_BIOS(cfg, reg)						\
+	(((cfg)->hdrtype == PCIM_HDRTYPE_NORMAL && reg == PCIR_BIOS) ||	\
+	 ((cfg)->hdrtype == PCIM_HDRTYPE_BRIDGE && reg == PCIR_BIOS_1))
+
 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 pci_addr_t	pci_rombase(uint64_t mapreg);
+static int		pci_romsize(uint64_t testval);
 static void		pci_fixancient(pcicfgregs *cfg);
 static int		pci_printf(pcicfgregs *cfg, const char *fmt, ...);
 
@@ -162,7 +168,7 @@ static device_method_t pci_methods[] = {
 	DEVMETHOD(bus_adjust_resource,	bus_generic_adjust_resource),
 	DEVMETHOD(bus_release_resource,	bus_generic_rl_release_resource),
 	DEVMETHOD(bus_activate_resource, pci_activate_resource),
-	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+	DEVMETHOD(bus_deactivate_resource, pci_deactivate_resource),
 	DEVMETHOD(bus_child_pnpinfo_str, pci_child_pnpinfo_str_method),
 	DEVMETHOD(bus_child_location_str, pci_child_location_str_method),
 	DEVMETHOD(bus_remap_intr,	pci_remap_intr_method),
@@ -324,7 +330,7 @@ static int pci_usb_takeover = 1;
 static int pci_usb_takeover = 0;
 #endif
 TUNABLE_INT("hw.pci.usb_early_takeover", &pci_usb_takeover);
-SYSCTL_INT(_hw_pci, OID_AUTO, usb_early_takeover, CTLFLAG_RD | CTLFLAG_TUN,
+SYSCTL_INT(_hw_pci, OID_AUTO, usb_early_takeover, CTLFLAG_RDTUN,
     &pci_usb_takeover, 1, "Enable early takeover of USB controllers.\n\
 Disable this if you depend on BIOS emulation of USB devices, that is\n\
 you use USB devices (like keyboard or mouse) but do not load USB drivers");
@@ -447,6 +453,34 @@ pci_mapsize(uint64_t testval)
 	return (ln2size);
 }
 
+/* return base address of device ROM */
+
+static pci_addr_t
+pci_rombase(uint64_t mapreg)
+{
+
+	return (mapreg & PCIM_BIOS_ADDR_MASK);
+}
+
+/* return log2 of map size decided for device ROM */
+
+static int
+pci_romsize(uint64_t testval)
+{
+	int ln2size;
+
+	testval = pci_rombase(testval);
+	ln2size = 0;
+	if (testval != 0) {
+		while ((testval & 1) == 0)
+		{
+			ln2size++;
+			testval >>= 1;
+		}
+	}
+	return (ln2size);
+}
+	
 /* return log2 of address range supported by map register */
 
 static int
@@ -551,6 +585,7 @@ pci_read_device(device_t pcib, int d, in
 
 		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);
@@ -2124,6 +2159,7 @@ int
 pci_freecfg(struct pci_devinfo *dinfo)
 {
 	struct devlist *devlist_head;
+	struct pci_map *pm, *next;
 	int i;
 
 	devlist_head = &pci_devq;
@@ -2137,6 +2173,9 @@ pci_freecfg(struct pci_devinfo *dinfo)
 			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);
 
@@ -2411,10 +2450,27 @@ pci_memen(device_t dev)
 static void
 pci_read_bar(device_t dev, int reg, pci_addr_t *mapp, pci_addr_t *testvalp)
 {
+	struct pci_devinfo *dinfo;
 	pci_addr_t map, testval;
 	int ln2range;
 	uint16_t cmd;
 
+	/*
+	 * The device ROM BAR is special.  It is always a 32-bit
+	 * memory BAR.  Bit 0 is special and should not be set when
+	 * sizing the BAR.
+	 */
+	dinfo = device_get_ivars(dev);
+	if (PCIR_IS_BIOS(&dinfo->cfg, reg)) {
+		map = pci_read_config(dev, reg, 4);
+		pci_write_config(dev, reg, 0xfffffffe, 4);
+		testval = pci_read_config(dev, reg, 4);
+		pci_write_config(dev, reg, map, 4);
+		*mapp = map;
+		*testvalp = testval;
+		return;
+	}
+
 	map = pci_read_config(dev, reg, 4);
 	ln2range = pci_maprange(map);
 	if (ln2range == 64)
@@ -2456,16 +2512,100 @@ pci_read_bar(device_t dev, int reg, pci_
 }
 
 static void
-pci_write_bar(device_t dev, int reg, pci_addr_t base)
+pci_write_bar(device_t dev, struct pci_map *pm, pci_addr_t base)
 {
-	pci_addr_t map;
+	struct pci_devinfo *dinfo;
 	int ln2range;
 
-	map = pci_read_config(dev, reg, 4);
-	ln2range = pci_maprange(map);
-	pci_write_config(dev, reg, base, 4);
+	/* The device ROM BAR is always a 32-bit memory BAR. */
+	dinfo = device_get_ivars(dev);
+	if (PCIR_IS_BIOS(&dinfo->cfg, pm->pm_reg))
+		ln2range = 32;
+	else
+		ln2range = pci_maprange(pm->pm_value);
+	pci_write_config(dev, pm->pm_reg, base, 4);
 	if (ln2range == 64)
-		pci_write_config(dev, reg + 4, base >> 32, 4);
+		pci_write_config(dev, pm->pm_reg + 4, base >> 32, 4);
+	pm->pm_value = pci_read_config(dev, pm->pm_reg, 4);
+	if (ln2range == 64)
+		pm->pm_value |= (pci_addr_t)pci_read_config(dev,
+		    pm->pm_reg + 4, 4) << 32;
+}
+
+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 == reg)
+			return (pm);
+	}
+	return (NULL);
+}
+
+int
+pci_bar_enabled(device_t dev, struct pci_map *pm)
+{
+	struct pci_devinfo *dinfo;
+	uint16_t cmd;
+
+	dinfo = device_get_ivars(dev);
+	if (PCIR_IS_BIOS(&dinfo->cfg, pm->pm_reg) &&
+	    !(pm->pm_value & PCIM_BIOS_ENABLE))
+		return (0);
+	cmd = pci_read_config(dev, PCIR_COMMAND, 2);
+	if (PCIR_IS_BIOS(&dinfo->cfg, pm->pm_reg) || PCI_BAR_MEM(pm->pm_value))
+		return ((cmd & PCIM_CMD_MEMEN) != 0);
+	else
+		return ((cmd & PCIM_CMD_PORTEN) != 0);
+}
+
+static struct pci_map *
+pci_add_bar(device_t dev, int reg, pci_addr_t value, pci_addr_t size)
+{
+	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;
+	pm->pm_value = value;
+	pm->pm_size = size;
+	STAILQ_FOREACH(prev, &dinfo->cfg.maps, pm_link) {
+		KASSERT(prev->pm_reg != pm->pm_reg, ("duplicate map %02x",
+		    reg));
+		if (STAILQ_NEXT(prev, pm_link) == NULL ||
+		    STAILQ_NEXT(prev, pm_link)->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);
+}
+
+static void
+pci_restore_bars(device_t dev)
+{
+	struct pci_devinfo *dinfo;
+	struct pci_map *pm;
+	int ln2range;
+
+	dinfo = device_get_ivars(dev);
+	STAILQ_FOREACH(pm, &dinfo->cfg.maps, pm_link) {
+		if (PCIR_IS_BIOS(&dinfo->cfg, pm->pm_reg))
+			ln2range = 32;
+		else
+			ln2range = pci_maprange(pm->pm_value);
+		pci_write_config(dev, pm->pm_reg, pm->pm_value, 4);
+		if (ln2range == 64)
+			pci_write_config(dev, pm->pm_reg + 4,
+			    pm->pm_value >> 32, 4);
+	}
 }
 
 /*
@@ -2476,12 +2616,24 @@ static int
 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;
 
+	/*
+	 * The BAR may already exist if the device is a CardBus card
+	 * whose CIS is stored in this BAR.
+	 */
+	pm = pci_find_bar(dev, reg);
+	if (pm != NULL) {
+		maprange = pci_maprange(pm->pm_value);
+		barlen = maprange == 64 ? 2 : 1;
+		return (barlen);
+	}
+
 	pci_read_bar(dev, reg, &map, &testval);
 	if (PCI_BAR_MEM(map)) {
 		type = SYS_RES_MEMORY;
@@ -2512,6 +2664,8 @@ pci_add_map(device_t bus, device_t dev, 
 	    (type == SYS_RES_IOPORT && mapsize < 2))
 		return (barlen);
 
+	/* Save a record of this BAR. */
+	pm = pci_add_bar(dev, reg, map, mapsize);
 	if (bootverbose) {
 		printf("\tmap[%02x]: type %s, range %2d, base %#jx, size %2d",
 		    reg, pci_maptype(map), maprange, (uintmax_t)base, mapsize);
@@ -2573,7 +2727,7 @@ pci_add_map(device_t bus, device_t dev, 
 	count = (pci_addr_t)1 << mapsize;
 	if (basezero || base == pci_mapbase(testval)) {
 		start = 0;	/* Let the parent decide. */
-		end = ~0ULL;
+		end = ~0ul;
 	} else {
 		start = base;
 		end = base + count - 1;
@@ -2601,7 +2755,7 @@ pci_add_map(device_t bus, device_t dev, 
 		start = rman_get_start(res);
 		rman_set_device(res, bus);
 	}
-	pci_write_bar(dev, reg, start);
+	pci_write_bar(dev, pm, start);
 	return (barlen);
 }
 
@@ -3037,7 +3191,7 @@ pci_suspend(device_t dev)
 		return (error);
 	for (i = 0; i < numdevs; i++) {
 		child = devlist[i];
-		dinfo = (struct pci_devinfo *) device_get_ivars(child);
+		dinfo = device_get_ivars(child);
 		pci_cfg_save(child, dinfo, 0);
 	}
 
@@ -3454,7 +3608,7 @@ pci_probe_nomatch(device_t dev, device_t
 	}
 	printf(" at device %d.%d (no driver attached)\n",
 	    pci_get_slot(child), pci_get_function(child));
-	pci_cfg_save(child, (struct pci_devinfo *)device_get_ivars(child), 1);
+	pci_cfg_save(child, device_get_ivars(child), 1);
 	return;
 }
 
@@ -3759,24 +3913,41 @@ pci_alloc_map(device_t dev, device_t chi
 	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(child, *rid);
+	if (pm != NULL) {
+		/* This is a BAR that we failed to allocate earlier. */
+		mapsize = pm->pm_size;
+		map = pm->pm_value;
+	} 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_read_bar(child, *rid, &map, &testval);
 
-	/* Ignore a BAR with a base of 0. */
-	if (pci_mapbase(testval) == 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 (PCIR_IS_BIOS(&dinfo->cfg, *rid))
+			mapsize = pci_romsize(testval);
+		else
+			mapsize = pci_mapsize(testval);
+		if (mapsize == 0)
+			goto out;
+		pm = pci_add_bar(child, *rid, map, mapsize);
+	}
 
-	if (PCI_BAR_MEM(testval)) {
+	if (PCI_BAR_MEM(map) || PCIR_IS_BIOS(&dinfo->cfg, *rid)) {
 		if (type != SYS_RES_MEMORY) {
 			if (bootverbose)
 				device_printf(dev,
@@ -3803,16 +3974,15 @@ pci_alloc_map(device_t dev, device_t chi
 	 * situation where we might allocate the excess to
 	 * another driver, which won't work.
 	 */
-	mapsize = pci_mapsize(testval);
 	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);
@@ -3836,7 +4006,7 @@ 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);
+	pci_write_bar(child, pm, map);
 out:;
 	return (res);
 }
@@ -3968,6 +4138,7 @@ int
 pci_activate_resource(device_t dev, device_t child, int type, int rid,
     struct resource *r)
 {
+	struct pci_devinfo *dinfo;
 	int error;
 
 	error = bus_generic_activate_resource(dev, child, type, rid, r);
@@ -3976,6 +4147,11 @@ pci_activate_resource(device_t dev, devi
 
 	/* Enable decoding in the command register when activating BARs. */
 	if (device_get_parent(child) == dev) {
+		/* Device ROMs need their decoding explicitly enabled. */
+		dinfo = device_get_ivars(child);
+		if (type == SYS_RES_MEMORY && PCIR_IS_BIOS(&dinfo->cfg, rid))
+			pci_write_bar(child, pci_find_bar(child, rid),
+			    rman_get_start(r) | PCIM_BIOS_ENABLE);
 		switch (type) {
 		case SYS_RES_IOPORT:
 		case SYS_RES_MEMORY:
@@ -3986,6 +4162,27 @@ pci_activate_resource(device_t dev, devi
 	return (error);
 }
 
+int
+pci_deactivate_resource(device_t dev, device_t child, int type,
+    int rid, struct resource *r)
+{
+	struct pci_devinfo *dinfo;
+	int error;
+
+	error = bus_generic_deactivate_resource(dev, child, type, rid, r);
+	if (error)
+		return (error);
+
+	/* Disable decoding for device ROMs. */	
+	if (device_get_parent(child) == dev) {
+		dinfo = device_get_ivars(child);
+		if (type == SYS_RES_MEMORY && PCIR_IS_BIOS(&dinfo->cfg, rid))
+			pci_write_bar(child, pci_find_bar(child, rid),
+			    rman_get_start(r));
+	}
+	return (0);
+}
+
 void
 pci_delete_resource(device_t dev, device_t child, int type, int rid)
 {
@@ -4021,7 +4218,7 @@ pci_delete_resource(device_t dev, device
 		switch (type) {
 		case SYS_RES_IOPORT:
 		case SYS_RES_MEMORY:
-			pci_write_bar(child, rid, 0);
+			pci_write_bar(child, pci_find_bar(child, rid), 0);
 			break;
 		}
 #endif
@@ -4128,7 +4325,6 @@ pci_modevent(module_t mod, int what, voi
 void
 pci_cfg_restore(device_t dev, struct pci_devinfo *dinfo)
 {
-	int i;
 
 	/*
 	 * Only do header type 0 devices.  Type 1 devices are bridges,
@@ -4148,12 +4344,9 @@ pci_cfg_restore(device_t dev, struct pci
 	 * the noise on boot by doing nothing if we are already in
 	 * state D0.
 	 */
-	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
+	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0)
 		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
-	}
-	for (i = 0; i < dinfo->cfg.nummaps; i++)
-		pci_write_config(dev, PCIR_BAR(i), dinfo->cfg.bar[i], 4);
-	pci_write_config(dev, PCIR_BIOS, dinfo->cfg.bios, 4);
+	pci_restore_bars(dev);
 	pci_write_config(dev, PCIR_COMMAND, dinfo->cfg.cmdreg, 2);
 	pci_write_config(dev, PCIR_INTLINE, dinfo->cfg.intline, 1);
 	pci_write_config(dev, PCIR_INTPIN, dinfo->cfg.intpin, 1);
@@ -4174,7 +4367,6 @@ pci_cfg_restore(device_t dev, struct pci
 void
 pci_cfg_save(device_t dev, struct pci_devinfo *dinfo, int setstate)
 {
-	int i;
 	uint32_t cls;
 	int ps;
 
@@ -4187,9 +4379,6 @@ pci_cfg_save(device_t dev, struct pci_de
 	 */
 	if (dinfo->cfg.hdrtype != 0)
 		return;
-	for (i = 0; i < dinfo->cfg.nummaps; i++)
-		dinfo->cfg.bar[i] = pci_read_config(dev, PCIR_BAR(i), 4);
-	dinfo->cfg.bios = pci_read_config(dev, PCIR_BIOS, 4);
 
 	/*
 	 * Some drivers apparently write to these registers w/o updating our

Modified: stable/8/sys/dev/pci/pci_private.h
==============================================================================
--- stable/8/sys/dev/pci/pci_private.h	Tue Oct  9 18:02:09 2012	(r241377)
+++ stable/8/sys/dev/pci/pci_private.h	Tue Oct  9 18:45:08 2012	(r241378)
@@ -91,6 +91,8 @@ int		pci_release_resource(device_t dev, 
 		    int rid, struct resource *r);
 int		pci_activate_resource(device_t dev, device_t child, int type,
 		    int rid, struct resource *r);
+int		pci_deactivate_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/8/sys/dev/pci/pci_user.c
==============================================================================
--- stable/8/sys/dev/pci/pci_user.c	Tue Oct  9 18:02:09 2012	(r241377)
+++ stable/8/sys/dev/pci/pci_user.c	Tue Oct  9 18:45:08 2012	(r241378)
@@ -309,8 +309,7 @@ pci_ioctl(struct cdev *dev, u_long cmd, 
 	struct pci_io *io;
 	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 +684,14 @@ getconfexit:
 			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, bio->pbi_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 = pci_bar_enabled(pcidev, pm);
 		error = 0;
 		break;
 	default:

Modified: stable/8/sys/dev/pci/pcireg.h
==============================================================================
--- stable/8/sys/dev/pci/pcireg.h	Tue Oct  9 18:02:09 2012	(r241377)
+++ stable/8/sys/dev/pci/pcireg.h	Tue Oct  9 18:45:08 2012	(r241378)
@@ -213,6 +213,7 @@
 #define	PCIM_BRPM_64		0x1
 #define	PCIM_BRPM_MASK		0xf
 
+#define	PCIR_BIOS_1	0x38
 #define	PCIR_BRIDGECTL_1 0x3e
 
 /* config registers for header type 2 (CardBus) devices */

Modified: stable/8/sys/dev/pci/pcivar.h
==============================================================================
--- stable/8/sys/dev/pci/pcivar.h	Tue Oct  9 18:02:09 2012	(r241377)
+++ stable/8/sys/dev/pci/pcivar.h	Tue Oct  9 18:45:08 2012	(r241378)
@@ -46,7 +46,14 @@ struct pcicfg_pp {
     uint8_t	pp_pmcsr;	/* config space address of PMCSR reg */
     uint8_t	pp_data;	/* config space address of PCI power data reg */
 };
- 
+
+struct pci_map {
+    pci_addr_t	pm_value;	/* Raw BAR value */
+    pci_addr_t	pm_size;
+    uint8_t	pm_reg;
+    STAILQ_ENTRY(pci_map) pm_link;
+};
+
 struct vpd_readonly {
     char	keyword[2];
     char	*value;
@@ -120,8 +127,7 @@ struct pcicfg_ht {
 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 */
@@ -480,4 +486,7 @@ STAILQ_HEAD(devlist, pci_devinfo);
 extern struct devlist	pci_devq;
 extern uint32_t	pci_generation;
 
+struct pci_map *pci_find_bar(device_t dev, int reg);
+int	pci_bar_enabled(device_t dev, struct pci_map *pm);
+
 #endif /* _PCIVAR_H_ */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201210091845.q99Ij88H054570>