For those that have problems with (acpi) suspend/resume that can be
fixed by setting pci_dopm to 0, please test the diff below.  This
fixes a flaw in the powermanagement code where we would disable
devices (and in particular PCI-PCI bridges) even if those devices
don't support powermanagement.

Also, it would be interesting if people with working apm
suspend/resume could test this diff and set pci_dopm to 1.

Thanks,

Mark


Index: pci.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/pci.c,v
retrieving revision 1.87
diff -u -p -r1.87 pci.c
--- pci.c       4 Dec 2010 17:08:20 -0000       1.87
+++ pci.c       29 Dec 2010 23:02:29 -0000
@@ -215,7 +215,7 @@ void
 pci_suspend(struct pci_softc *sc)
 {
        struct pci_dev *pd;
-       pcireg_t bhlc, csr;
+       pcireg_t bhlc;
        int i;
 
        LIST_FOREACH(pd, &sc->sc_devs, pd_next) {
@@ -240,18 +240,7 @@ pci_suspend(struct pci_softc *sc)
                    PCI_INTERRUPT_REG);
 
                if (pci_dopm) {
-                       /*
-                        * Place the device into D3.  The PCI Power
-                        * Management spec says we should disable I/O
-                        * and memory space as well as bus mastering
-                        * before we do so.
-                        */
-                       csr = pd->pd_csr;
-                       csr &= ~PCI_COMMAND_IO_ENABLE;
-                       csr &= ~PCI_COMMAND_MEM_ENABLE;
-                       csr &= ~PCI_COMMAND_MASTER_ENABLE;
-                       pci_conf_write(sc->sc_pc, pd->pd_tag,
-                           PCI_COMMAND_STATUS_REG, csr);
+                       /* Place the device into D3. */
                        pd->pd_pmcsr_state = pci_get_powerstate(sc->sc_pc,
                            pd->pd_tag);
                        pci_set_powerstate(sc->sc_pc, pd->pd_tag,
@@ -567,6 +556,19 @@ pci_set_powerstate(pci_chipset_tag_t pc,
        int offset;
 
        if (pci_get_capability(pc, tag, PCI_CAP_PWRMGMT, &offset, 0)) {
+               if (state == PCI_PMCSR_STATE_D3) {
+                       /*
+                        * The PCI Power Management spec says we
+                        * should disable I/O and memory space as well
+                        * as bus mastering before we place the device
+                        * into D3.
+                        */
+                       reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
+                       reg &= ~PCI_COMMAND_IO_ENABLE;
+                       reg &= ~PCI_COMMAND_MEM_ENABLE;
+                       reg &= ~PCI_COMMAND_MASTER_ENABLE;
+                       pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, reg);
+               }
                reg = pci_conf_read(pc, tag, offset + PCI_PMCSR);
                if ((reg & PCI_PMCSR_STATE_MASK) != state) {
                        pci_conf_write(pc, tag, offset + PCI_PMCSR,
Index: ppb.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/ppb.c,v
retrieving revision 1.46
diff -u -p -r1.46 ppb.c
--- ppb.c       25 Sep 2010 19:23:39 -0000      1.46
+++ ppb.c       29 Dec 2010 23:02:29 -0000
@@ -346,7 +346,7 @@ ppbactivate(struct device *self, int act
        struct ppb_softc *sc = (void *)self;
        pci_chipset_tag_t pc = sc->sc_pc;
        pcitag_t tag = sc->sc_tag;
-       pcireg_t blr, csr, reg;
+       pcireg_t blr, reg;
        int rv = 0;
 
        switch (act) {
@@ -367,17 +367,7 @@ ppbactivate(struct device *self, int act
                            sc->sc_cap_off + PCI_PCIE_SLCSR);
 
                if (pci_dopm) { 
-                       /*
-                        * Place the bridge into D3.  The PCI Power
-                        * Management spec says we should disable I/O
-                        * and memory space as well as bus mastering
-                        * before we do so.
-                        */
-                       csr = sc->sc_csr;
-                       csr &= ~PCI_COMMAND_IO_ENABLE;
-                       csr &= ~PCI_COMMAND_MEM_ENABLE;
-                       csr &= ~PCI_COMMAND_MASTER_ENABLE;
-                       pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
+                       /* Place the bridge into D3. */
                        sc->sc_pmcsr_state = pci_get_powerstate(pc, tag);
                        pci_set_powerstate(pc, tag, PCI_PMCSR_STATE_D3);
                }

Reply via email to