Date: Sat, 10 Apr 2004 20:23:42 -0600 (MDT) From: "M. Warner Losh" <imp@bsdimp.com> To: ler@lerctr.org Cc: current@freebsd.org Subject: Re: HEADS UP: PCI Chnages Message-ID: <20040410.202342.23011094.imp@bsdimp.com> In-Reply-To: <3320000.1081643496@lerlaptop.lerctr.org> References: <20040410212752.A996B5D07@ptavv.es.net> <3320000.1081643496@lerlaptop.lerctr.org>
next in thread | previous in thread | raw e-mail | index | archive | help
In message: <3320000.1081643496@lerlaptop.lerctr.org> Larry Rosenman <ler@lerctr.org> writes: : : : --On Saturday, April 10, 2004 14:27:52 -0700 Kevin Oberman <oberman@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 @@ -176,6 +176,14 @@ 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 @@ -484,6 +492,12 @@ 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; @@ -752,13 +766,14 @@ * 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) @@ -1696,16 +1711,26 @@ 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++) @@ -1725,6 +1750,7 @@ { int i; uint32_t cls; + int ps; /* * Only do header type 0 devices. Type 1 devices are bridges, which @@ -1763,15 +1789,22 @@ * 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); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20040410.202342.23011094.imp>