Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 13 Sep 2003 14:34:27 -0700 (PDT)
From:      Warner Losh <imp@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 38012 for review
Message-ID:  <200309132134.h8DLYRM3067166@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=38012

Change 38012 by imp@imp_koguchi on 2003/09/13 14:34:06

	Integrate these from newcard.  This is the basis for much of
	power management stuff that I've added to the pci bus.  Extra
	files integrated because I'm too lame to revert them.

Affected files ...

.. //depot/projects/power/sys/dev/pci/eisa_pci.c#2 integrate
.. //depot/projects/power/sys/dev/pci/fixup_pci.c#2 integrate
.. //depot/projects/power/sys/dev/pci/ignore_pci.c#2 integrate
.. //depot/projects/power/sys/dev/pci/isa_pci.c#2 integrate
.. //depot/projects/power/sys/dev/pci/pci.c#2 integrate
.. //depot/projects/power/sys/dev/pci/pci_if.m#2 integrate
.. //depot/projects/power/sys/dev/pci/pci_pci.c#2 integrate
.. //depot/projects/power/sys/dev/pci/pci_private.h#2 integrate
.. //depot/projects/power/sys/dev/pci/pci_user.c#2 integrate
.. //depot/projects/power/sys/dev/pci/pcib_if.m#2 integrate
.. //depot/projects/power/sys/dev/pci/pcib_private.h#2 integrate
.. //depot/projects/power/sys/dev/pci/pcireg.h#2 integrate
.. //depot/projects/power/sys/dev/pci/pcivar.h#2 integrate

Differences ...

==== //depot/projects/power/sys/dev/pci/eisa_pci.c#2 (text+ko) ====


==== //depot/projects/power/sys/dev/pci/fixup_pci.c#2 (text+ko) ====


==== //depot/projects/power/sys/dev/pci/ignore_pci.c#2 (text+ko) ====


==== //depot/projects/power/sys/dev/pci/isa_pci.c#2 (text+ko) ====


==== //depot/projects/power/sys/dev/pci/pci.c#2 (text+ko) ====

@@ -68,35 +68,39 @@
 
 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_add_map(device_t pcib, int b, int s, int f, int reg, 
-				    struct resource_list *rl);
+static int		pci_add_map(device_t pcib, int b, int s, int f,
+			    int reg, struct resource_list *rl);
 static void		pci_add_resources(device_t pcib, device_t bus,
-					  device_t dev);
+			    device_t dev);
 static int		pci_probe(device_t dev);
 static int		pci_attach(device_t dev);
+static int		pci_suspend(device_t dev);
+static int		pci_resume(device_t dev);
 static void		pci_load_vendor_data(void);
 static int		pci_describe_parse_line(char **ptr, int *vendor, 
-						int *device, char **desc);
+			    int *device, char **desc);
 static char		*pci_describe_device(device_t dev);
 static int		pci_modevent(module_t mod, int what, void *arg);
 static void		pci_hdrtypedata(device_t pcib, int b, int s, int f, 
-					pcicfgregs *cfg);
+			    pcicfgregs *cfg);
 static void		pci_read_extcap(device_t pcib, pcicfgregs *cfg);
+static void		pci_cfg_restore(device_t, struct pci_devinfo *);
+static void		pci_cfg_save(device_t, struct pci_devinfo *, int);
 
 static device_method_t pci_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		pci_probe),
 	DEVMETHOD(device_attach,	pci_attach),
 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
-	DEVMETHOD(device_suspend,	bus_generic_suspend),
-	DEVMETHOD(device_resume,	bus_generic_resume),
+	DEVMETHOD(device_suspend,	pci_suspend),
+	DEVMETHOD(device_resume,	pci_resume),
 
 	/* Bus interface */
 	DEVMETHOD(bus_print_child,	pci_print_child),
 	DEVMETHOD(bus_probe_nomatch,	pci_probe_nomatch),
 	DEVMETHOD(bus_read_ivar,	pci_read_ivar),
 	DEVMETHOD(bus_write_ivar,	pci_write_ivar),
-	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
+	DEVMETHOD(bus_driver_added,	pci_driver_added),
 	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
 	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
 
@@ -716,20 +720,31 @@
 
 	map = PCIB_READ_CONFIG(pcib, b, s, f, reg, 4);
 
-	if (map == 0 || map == 0xffffffff)
-		return (1); /* skip invalid entry */
-
 	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);
 
-	base = pci_mapbase(map);
 	if (pci_maptype(map) & PCI_MAPMEM)
 		type = SYS_RES_MEMORY;
 	else
 		type = SYS_RES_IOPORT;
 	ln2size = pci_mapsize(testval);
 	ln2range = pci_maprange(testval);
+	base = pci_mapbase(map);
+
+	/*
+	 * For I/O registers, if bottom bit is set, and the next bit up
+	 * isn't clear, we know we have a BAR that doesn't conform to the
+	 * spec, so ignore it.  Also, sanity check the size of the data
+	 * areas to the type of memory involved.
+	 */
+	if ((testval & 0x1) == 0x1 &&
+	    (testval & 0x2) != 0)
+		return (1);
+	if ((type == SYS_RES_MEMORY && ln2size < 5) ||
+	    (type == SYS_RES_IOPORT && ln2size < 3))
+		return (1);
+
 	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;
@@ -771,6 +786,12 @@
 		if (type == SYS_RES_MEMORY && !pci_memen(pcib, b, s, f))
 			return (1);
 	}
+	/*
+	 * If base is 0, then we have problems.  It is best to ignore
+	 * such entires for the moment. XXX
+	 */
+	if (base == 0)
+		return 1;
 	resource_list_add(rl, type, reg, base, base + (1 << ln2size) - 1,
 	    (1 << ln2size));
 
@@ -857,6 +878,7 @@
 	pcib = device_get_parent(bus);
 	dinfo->cfg.dev = device_add_child(bus, NULL, -1);
 	device_set_ivars(dinfo->cfg.dev, dinfo);
+	pci_cfg_restore(dinfo->cfg.dev, dinfo);
 	pci_add_resources(pcib, bus, dinfo->cfg.dev);
 	pci_print_verbose(dinfo);
 }
@@ -891,6 +913,52 @@
 	return (bus_generic_attach(dev));
 }
 
+static int
+pci_suspend(device_t dev)
+{
+	int numdevs;
+	device_t *devlist;
+	device_t child;
+	struct pci_devinfo *dinfo;
+	int i;
+
+	/*
+	 * Save the pci configuration space for each child.  We don't need
+	 * to do this, unless the BIOS suspend code powers down the bus and
+	 * the devices on the bus.
+	 */
+	device_get_children(dev, &devlist, &numdevs);
+	for (i = 0; i < numdevs; i++) {
+		child = devlist[i];
+		dinfo = (struct pci_devinfo *) device_get_ivars(child);
+		pci_cfg_save(child, dinfo, 0);
+	}
+	free(devlist, M_TEMP);
+	return (bus_generic_suspend(dev));
+}
+
+static int
+pci_resume(device_t dev)
+{
+	int numdevs;
+	device_t *devlist;
+	device_t child;
+	struct pci_devinfo *dinfo;
+	int i;
+
+	/*
+	 * Restore the pci configuration space for each child.
+	 */
+	device_get_children(dev, &devlist, &numdevs);
+	for (i = 0; i < numdevs; i++) {
+		child = devlist[i];
+		dinfo = (struct pci_devinfo *) device_get_ivars(child);
+		pci_cfg_restore(child, dinfo);
+	}
+	free(devlist, M_TEMP);
+	return (bus_generic_resume(dev));
+}
+
 static void
 pci_load_vendor_data(void)
 {
@@ -906,6 +974,34 @@
 	}
 }
 
+void
+pci_driver_added(device_t dev, driver_t *driver)
+{
+	int numdevs;
+	device_t *devlist;
+	device_t child;
+	struct pci_devinfo *dinfo;
+	int i;
+
+	device_printf(dev, "driver added\n");
+	DEVICE_IDENTIFY(driver, dev);
+	device_get_children(dev, &devlist, &numdevs);
+	for (i = 0; i < numdevs; i++) {
+		child = devlist[i];
+		if (device_get_state(child) != DS_NOTPRESENT)
+			continue;
+		dinfo = device_get_ivars(child);
+		pci_print_verbose(dinfo);
+/*XXX???*/	/* resource_list_init(&dinfo->cfg.resources); */
+		printf("pci%d:%d:%d: reprobing on driver added\n",
+		    dinfo->cfg.bus, dinfo->cfg.slot, dinfo->cfg.func);
+		pci_cfg_restore(child, dinfo);
+		if (device_probe_and_attach(child) != 0)
+			pci_cfg_save(child, dinfo, 1);
+	}
+	free(devlist, M_TEMP);
+}
+
 int
 pci_print_child(device_t dev, device_t child)
 {
@@ -1031,6 +1127,7 @@
 	}
 	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);
 	return;
 }
 
@@ -1431,7 +1528,7 @@
 }
 
 int
-pci_child_location_str_method(device_t cbdev, device_t child, char *buf,
+pci_child_location_str_method(device_t dev, device_t child, char *buf,
     size_t buflen)
 {
 	struct pci_devinfo *dinfo;
@@ -1443,7 +1540,7 @@
 }
 
 int
-pci_child_pnpinfo_str_method(device_t cbdev, device_t child, char *buf,
+pci_child_pnpinfo_str_method(device_t dev, device_t child, char *buf,
     size_t buflen)
 {
 	struct pci_devinfo *dinfo;
@@ -1489,3 +1586,40 @@
 
 	return (0);
 }
+
+static void
+pci_cfg_restore(device_t dev, struct pci_devinfo *dinfo)
+{
+#define NBAR 7
+	int i;
+	uint32_t bar[NBAR];
+
+	if (dinfo->cfg.hdrtype != 0)
+		return;
+	for (i = 0; i < NBAR; i++)
+		bar[i] = pci_read_config(dev, PCIR_MAPS + i * 4, 4);
+	printf("pci%d:%d:%d: setting power state D0\n", dinfo->cfg.bus,
+	    dinfo->cfg.slot, dinfo->cfg.func);
+	pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+	for (i = 0; i < NBAR; i++)
+		pci_write_config(dev, PCIR_MAPS + i * 4, bar[i], 4);
+	pci_write_config(dev, PCIR_INTLINE, dinfo->cfg.intline, 1);
+	pci_write_config(dev, PCIR_INTPIN, dinfo->cfg.intpin, 1);
+	pci_write_config(dev, PCIR_MINGNT, dinfo->cfg.mingnt, 1);
+	pci_write_config(dev, PCIR_MAXLAT, dinfo->cfg.maxlat, 1);
+}
+
+static void
+pci_cfg_save(device_t dev, struct pci_devinfo *dinfo, int setstate)
+{
+	uint32_t cls;
+
+	if (dinfo->cfg.hdrtype != 0)
+		return;
+	cls = pci_get_class(dev);
+	if (setstate && cls != PCIC_DISPLAY && cls != PCIC_MEMORY) {
+		pci_set_powerstate(dev, PCI_POWERSTATE_D3);
+		printf("pci%d:%d:%d: setting power state D3\n", dinfo->cfg.bus,
+		    dinfo->cfg.slot, dinfo->cfg.func);
+	}
+}

==== //depot/projects/power/sys/dev/pci/pci_if.m#2 (text+ko) ====


==== //depot/projects/power/sys/dev/pci/pci_pci.c#2 (text+ko) ====


==== //depot/projects/power/sys/dev/pci/pci_private.h#2 (text+ko) ====

@@ -41,6 +41,7 @@
 
 void		pci_add_children(device_t dev, int busno, size_t dinfo_size);
 void		pci_add_child(device_t bus, struct pci_devinfo *dinfo);
+void		pci_driver_added(device_t dev, driver_t *driver);
 int		pci_print_child(device_t dev, device_t child);
 void		pci_probe_nomatch(device_t dev, device_t child);
 int		pci_read_ivar(device_t dev, device_t child, int which,

==== //depot/projects/power/sys/dev/pci/pci_user.c#2 (text+ko) ====


==== //depot/projects/power/sys/dev/pci/pcib_if.m#2 (text+ko) ====


==== //depot/projects/power/sys/dev/pci/pcib_private.h#2 (text+ko) ====


==== //depot/projects/power/sys/dev/pci/pcireg.h#2 (text+ko) ====


==== //depot/projects/power/sys/dev/pci/pcivar.h#2 (text+ko) ====

@@ -51,8 +51,13 @@
 typedef uint32_t pci_addr_t;	/* uint64_t for system with 64bit addresses */
 #endif
 
+/* Additional data saved on power events */
+struct pci_save 
+{
+    uint32_t   bar[7];		/* 7 bars to save */
+};
+
 /* config header information common to all header types */
-
 typedef struct pcicfg {
     struct device *dev;		/* device which owns this */
 


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