summaryrefslogtreecommitdiff
path: root/sys/dev/pci/ppb.c
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2010-08-17 19:14:53 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2010-08-17 19:14:53 +0000
commit5268c49d0fb645ef2cbc307c2a6d81bfa902a58b (patch)
tree1e674868071627714098692976474431f9ba29d1 /sys/dev/pci/ppb.c
parent7f00f673b9f13763b9642e62566597f9551ddff7 (diff)
Power management for PCI devices. For now just put everything in the D3
(deepest sleep) state upon suspend, and restore power upon resume. ok deraadt@
Diffstat (limited to 'sys/dev/pci/ppb.c')
-rw-r--r--sys/dev/pci/ppb.c26
1 files changed, 22 insertions, 4 deletions
diff --git a/sys/dev/pci/ppb.c b/sys/dev/pci/ppb.c
index c51aa8d8119..39e9a8c4a36 100644
--- a/sys/dev/pci/ppb.c
+++ b/sys/dev/pci/ppb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ppb.c,v 1.43 2010/08/02 03:22:26 deraadt Exp $ */
+/* $OpenBSD: ppb.c,v 1.44 2010/08/17 19:14:52 kettenis Exp $ */
/* $NetBSD: ppb.c,v 1.16 1997/06/06 23:48:05 thorpej Exp $ */
/*
@@ -81,8 +81,8 @@ struct ppb_softc {
pcireg_t sc_bir;
pcireg_t sc_bcr;
pcireg_t sc_int;
-
pcireg_t sc_slcsr;
+ int sc_pmcsr_state;
};
int ppbmatch(struct device *, void *, void *);
@@ -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;
+ pcireg_t blr, csr, reg;
int rv = 0;
switch (act) {
@@ -362,8 +362,24 @@ ppbactivate(struct device *self, int act)
if (sc->sc_cap_off)
sc->sc_slcsr = pci_conf_read(pc, tag,
sc->sc_cap_off + PCI_PCIE_SLCSR);
+
+ /*
+ * 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);
+ sc->sc_pmcsr_state = pci_get_powerstate(pc, tag);
+ pci_set_powerstate(pc, tag, PCI_PMCSR_STATE_D3);
break;
case DVACT_RESUME:
+ /* Restore power. */
+ pci_set_powerstate(pc, tag, sc->sc_pmcsr_state);
+
/* Restore the registers saved above. */
pci_conf_write(pc, tag, PCI_BHLC_REG, sc->sc_bhlcr);
pci_conf_write(pc, tag, PPB_REG_BUSINFO, sc->sc_bir);
@@ -403,7 +419,9 @@ ppbactivate(struct device *self, int act)
* Restore command register last to avoid exposing
* uninitialised windows.
*/
- pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, sc->sc_csr);
+ reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
+ pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
+ (reg & 0xffff0000) | (sc->sc_csr & 0x0000ffff));
rv = config_activate_children(self, act);
break;