svn commit: r201279 - in head/sys/dev: cardbus pci

John Baldwin jhb at FreeBSD.org
Wed Dec 30 20:47:14 UTC 2009


Author: jhb
Date: Wed Dec 30 20:47:14 2009
New Revision: 201279
URL: http://svn.freebsd.org/changeset/base/201279

Log:
  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.
  
  Reviewed by:	imp

Modified:
  head/sys/dev/cardbus/cardbus_cis.c
  head/sys/dev/pci/pci.c
  head/sys/dev/pci/pci_private.h

Modified: head/sys/dev/cardbus/cardbus_cis.c
==============================================================================
--- head/sys/dev/cardbus/cardbus_cis.c	Wed Dec 30 20:42:07 2009	(r201278)
+++ head/sys/dev/cardbus/cardbus_cis.c	Wed Dec 30 20:47:14 2009	(r201279)
@@ -430,9 +430,6 @@ 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);
 	}
 }
 
@@ -477,9 +474,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) {

Modified: head/sys/dev/pci/pci.c
==============================================================================
--- head/sys/dev/pci/pci.c	Wed Dec 30 20:42:07 2009	(r201278)
+++ head/sys/dev/pci/pci.c	Wed Dec 30 20:47:14 2009	(r201279)
@@ -80,6 +80,8 @@ static pci_addr_t	pci_mapbase(uint64_t m
 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, ...);
 
@@ -142,7 +144,7 @@ static device_method_t pci_methods[] = {
 	DEVMETHOD(bus_alloc_resource,	pci_alloc_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),
 
@@ -388,6 +390,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
@@ -2280,6 +2310,21 @@ pci_read_bar(device_t dev, int reg, pci_
 	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.
+	 */
+	if (reg == PCIR_BIOS) {
+		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)
@@ -2327,6 +2372,10 @@ pci_write_bar(device_t dev, int reg, pci
 	int ln2range;
 
 	map = pci_read_config(dev, reg, 4);
+
+	/* The device ROM BAR is always 32-bits. */
+	if (reg == PCIR_BIOS)
+		return;
 	ln2range = pci_maprange(map);
 	pci_write_config(dev, reg, base, 4);
 	if (ln2range == 64)
@@ -3579,10 +3628,11 @@ pci_reserve_map(device_t dev, device_t c
 	pci_read_bar(child, *rid, &map, &testval);
 
 	/* Ignore a BAR with a base of 0. */
-	if (pci_mapbase(testval) == 0)
+	if ((*rid == PCIR_BIOS && pci_rombase(testval) == 0) ||
+	    pci_mapbase(testval) == 0)
 		goto out;
 
-	if (PCI_BAR_MEM(testval)) {
+	if (PCI_BAR_MEM(testval) || *rid == PCIR_BIOS) {
 		if (type != SYS_RES_MEMORY) {
 			if (bootverbose)
 				device_printf(dev,
@@ -3608,8 +3658,13 @@ pci_reserve_map(device_t dev, device_t c
 	 * actually uses and we would otherwise have a
 	 * situation where we might allocate the excess to
 	 * another driver, which won't work.
+	 *
+	 * Device ROM BARs use a different mask value.
 	 */
-	mapsize = pci_mapsize(testval);
+	if (*rid == PCIR_BIOS)
+		mapsize = pci_romsize(testval);
+	else
+		mapsize = pci_mapsize(testval);
 	count = 1UL << mapsize;
 	if (RF_ALIGNMENT(flags) < mapsize)
 		flags = (flags & ~RF_ALIGNMENT_MASK) | RF_ALIGNMENT_LOG2(mapsize);
@@ -3711,6 +3766,10 @@ 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. */
+		if (rid == PCIR_BIOS)
+			pci_write_config(child, rid, rman_get_start(r) |
+			    PCIM_BIOS_ENABLE, 4);
 		switch (type) {
 		case SYS_RES_IOPORT:
 		case SYS_RES_MEMORY:
@@ -3721,6 +3780,22 @@ 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)
+{
+	int error;
+
+	error = bus_generic_deactivate_resource(dev, child, type, rid, r);
+	if (error)
+		return (error);
+
+	/* Disable decoding for device ROMs. */
+	if (rid == PCIR_BIOS)
+		pci_write_config(child, rid, rman_get_start(r), 4);
+	return (0);
+}
+
 void
 pci_delete_resource(device_t dev, device_t child, int type, int rid)
 {

Modified: head/sys/dev/pci/pci_private.h
==============================================================================
--- head/sys/dev/pci/pci_private.h	Wed Dec 30 20:42:07 2009	(r201278)
+++ head/sys/dev/pci/pci_private.h	Wed Dec 30 20:47:14 2009	(r201279)
@@ -84,6 +84,8 @@ struct resource	*pci_alloc_resource(devi
 		    u_int flags);
 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);


More information about the svn-src-all mailing list