diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2010-08-17 19:14:53 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2010-08-17 19:14:53 +0000 |
commit | 5268c49d0fb645ef2cbc307c2a6d81bfa902a58b (patch) | |
tree | 1e674868071627714098692976474431f9ba29d1 /sys/dev/pci/ppb.c | |
parent | 7f00f673b9f13763b9642e62566597f9551ddff7 (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.c | 26 |
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; |