Re: HEADS UP: PCI Chnages

From: M. Warner Losh <imp_at_bsdimp.com>
Date: Sat, 10 Apr 2004 20:23:42 -0600 (MDT)
In message: <3320000.1081643496_at_lerlaptop.lerctr.org>
            Larry Rosenman <ler_at_lerctr.org> writes:
: 
: 
: --On Saturday, April 10, 2004 14:27:52 -0700 Kevin Oberman <oberman_at_es.net> 
: wrote:
: 
: s.  Thanks
: >
: > I can now confirm that this one breaks my laptop. It's an IBM T30 (1.8
: > GHz P4M). If I back out this set of commits (and a few since this one),
: > things work. With the commit, the ATA disk is not seen and I can't boot
: > up.
: >
: > I already posted the output of the boot in response to another current
: > post with the subject "Re: Recent -CURRENT doesn't find ata
: > controller". It actually odes, but it does not manage to talk to it (or
: > even seem to try to.)  The ports are the significant difference I see.
: >
: I see a similar failure on my Fujitsu C6651 (interestingly, also a ICH3).
: 
: What can I supply to help here?

Working patches :-P.

Seriously, I think I need access to ICH3 hardware for a little bit to
sort out what's going on.  I'll go rummage around in my bounce box
collection to see if I can find one that fits the bill.  The hardware
is common enough that I don't think there will be a problem.  I do
have one fix pending in my p4 tree, which I've attached.  You can try
it, but it didn't work for Andrew Gallatin.  He has a ServerWorks CSB5
UDMA100 controller, however.

hw.pci.do_powerstate is also added by this patch.  set it to 0 to turn
off the power setting stuff.  That likely has nothing to do with this
problem.

I suspect multiple issues...

Warner

Index: pci.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/pci/pci.c,v
retrieving revision 1.239
diff -u -r1.239 pci.c
--- pci.c	9 Apr 2004 20:41:18 -0000	1.239
+++ pci.c	11 Apr 2004 02:21:12 -0000
_at__at_ -176,6 +176,14 _at__at_
 enable these bits correctly.  We'd like to do this all the time, but there\n\
 are some peripherals that this causes problems with.");
 
+static int pci_do_powerstate = 1;
+TUNABLE_INT("hw.pci.do_powerstate", (int *)&pci_do_powerstate);
+SYSCTL_INT(_hw_pci, OID_AUTO, do_powerstate, CTLFLAG_RW,
+    &pci_do_powerstate, 1,
+    "Enable setting the power states of the PCI devices.  This means that we\n\
+set devices into D0 before probe/attach, and D3 if they fail to attach.  It\n\
+also means we set devices into D3 state before shutdown.");
+
 /* Find a device_t by bus/slot/function */
 
 device_t
_at__at_ -484,6 +492,12 _at__at_
 	uint16_t status;
 	int result;
 
+	/*
+	 * Dx -> Dx is a nop always.
+	 */
+	if (pci_get_powerstate(dev) == state)
+		return (0);
+
 	if (cfg->pp.pp_cap != 0) {
 		status = PCI_READ_CONFIG(dev, child, cfg->pp.pp_status, 2)
 		    & ~PCIM_PSTAT_DMASK;
_at__at_ -752,13 +766,14 _at__at_
 	 * 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.
+	 * areas to the type of memory involved.  Memory must be at least
+	 * 32 bytes in size, while I/O ranges must be at least 4.
 	 */
 	if ((testval & 0x1) == 0x1 &&
 	    (testval & 0x2) != 0)
 		return (1);
 	if ((type == SYS_RES_MEMORY && ln2size < 5) ||
-	    (type == SYS_RES_IOPORT && ln2size < 3))
+	    (type == SYS_RES_IOPORT && ln2size < 2))
 		return (1);
 
 	if (ln2range == 64)
_at__at_ -1696,16 +1711,26 _at__at_
 	int i;
 
 	/*
-	 * Only do header type 0 devices.  Type 1 devices are bridges, which
-	 * we know need special treatment.  Type 2 devices are cardbus bridges
-	 * which also require special treatment.  Other types are unknown, and
-	 * we err on the side of safety by ignoring them.
+	 * Only do header type 0 devices.  Type 1 devices are bridges,
+	 * which we know need special treatment.  Type 2 devices are
+	 * cardbus bridges which also require special treatment.
+	 * Other types are unknown, and we err on the side of safety
+	 * by ignoring them.
 	 */
 	if (dinfo->cfg.hdrtype != 0)
 		return;
-	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
-		printf("pci%d:%d:%d: setting power state D0\n", dinfo->cfg.bus,
-		    dinfo->cfg.slot, dinfo->cfg.func);
+	/*
+	 * Restore the device to full power mode.  We must do this
+	 * before we restore the registers because moving from D3 to
+	 * D0 will cause the chip's BARs and some other registers to
+	 * be reset to some unknown power on reset values.  Cut down
+	 * the noise on boot by doing nothing if we are already in
+	 * state D0.
+	 */
+	if (pci_do_powerstate && (pci_get_powerstate(dev) != PCI_POWERSTATE_D0)) {
+		printf("pci%d:%d:%d: Transition from D%d to D0\n", dinfo->cfg.bus,
+		    dinfo->cfg.slot, dinfo->cfg.func,
+		    pci_get_powerstate(dev));
 		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
 	}
 	for (i = 0; i < dinfo->cfg.nummaps; i++)
_at__at_ -1725,6 +1750,7 _at__at_
 {
 	int i;
 	uint32_t cls;
+	int ps;
 
 	/*
 	 * Only do header type 0 devices.  Type 1 devices are bridges, which
_at__at_ -1763,15 +1789,22 _at__at_
 	 * detach and (b) use generic drivers for these devices so that some
 	 * device actually attaches.  We need to make sure that when we
 	 * implement (a) we don't power the device down on a reattach.
-	 *
-	 * John and Nate also tell me that we should be running the power up
-	 * and power down hooks when we change power state for those nodes
-	 * that have ACPI hooks in the tree.
 	 */
 	cls = pci_get_class(dev);
-	if (setstate && cls != PCIC_DISPLAY && cls != PCIC_MEMORY) {
+	if (pci_do_powerstate && setstate && cls != PCIC_DISPLAY && cls != PCIC_MEMORY) {
+		/*
+		 * PCI spec is clear that we can only go into D3 state from
+		 * D0 state.  Transition from D[12] into D0 before going
+		 * to D3 state.
+		 */
+		ps = pci_get_powerstate(dev);
+		if (ps != PCI_POWERSTATE_D0 && ps != PCI_POWERSTATE_D3) {
+			printf("pci%d:%d:%d: Transition from D%d to D0\n", dinfo->cfg.bus,
+			    dinfo->cfg.slot, dinfo->cfg.func, ps);
+			pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+		}
 		if (pci_get_powerstate(dev) != PCI_POWERSTATE_D3) {
-			printf("pci%d:%d:%d: setting power state D3\n", dinfo->cfg.bus,
+			printf("pci%d:%d:%d: Transition from D0 to D3\n", dinfo->cfg.bus,
 			    dinfo->cfg.slot, dinfo->cfg.func);
 			pci_set_powerstate(dev, PCI_POWERSTATE_D3);
 		}
Received on Sat Apr 10 2004 - 17:25:30 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:37:50 UTC