Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/pci If the chip supports ACPI power management:



details:   https://anonhg.NetBSD.org/src/rev/5eca0e8a9b9b
branches:  trunk
changeset: 533082:5eca0e8a9b9b
user:      thorpej <thorpej%NetBSD.org@localhost>
date:      Thu Jun 20 20:17:04 2002 +0000

description:
If the chip supports ACPI power management:
* Go to D3 if IFF_UP == 0.
* Go to D0 if IFF_UP == 1.

Saves battery life on my T21, mmm.

diffstat:

 sys/dev/pci/if_ex_pci.c |  109 ++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 100 insertions(+), 9 deletions(-)

diffs (186 lines):

diff -r 9fb9b337765e -r 5eca0e8a9b9b sys/dev/pci/if_ex_pci.c
--- a/sys/dev/pci/if_ex_pci.c   Thu Jun 20 20:06:20 2002 +0000
+++ b/sys/dev/pci/if_ex_pci.c   Thu Jun 20 20:17:04 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_ex_pci.c,v 1.20 2002/02/07 01:32:19 christos Exp $  */
+/*     $NetBSD: if_ex_pci.c,v 1.21 2002/06/20 20:17:04 thorpej Exp $   */
 
 /*-
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -38,7 +38,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_ex_pci.c,v 1.20 2002/02/07 01:32:19 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_ex_pci.c,v 1.21 2002/06/20 20:17:04 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -78,6 +78,12 @@
        bus_space_tag_t sc_funct;
        bus_space_handle_t sc_funch;
 
+       pci_chipset_tag_t psc_pc;       /* pci chipset tag */
+       pcireg_t psc_regs[0x20>>2];     /* saved PCI config regs (sparse) */
+       pcitag_t psc_tag;               /* pci device tag */
+
+       int psc_pwrmgmt_csr_reg;        /* ACPI power management register */
+       pcireg_t psc_pwrmgmt_csr;       /* ...and the contents at D0 */
 };
 
 /*
@@ -96,6 +102,11 @@
 void ex_pci_attach __P((struct device *, struct device *, void *));
 void ex_pci_intr_ack __P((struct ex_softc *));
 
+int ex_pci_enable __P((struct ex_softc *));
+void ex_pci_disable __P((struct ex_softc *));
+
+void ex_pci_confreg_restore __P((struct ex_pci_softc *));
+
 struct cfattach ex_pci_ca = {
        sizeof(struct ex_pci_softc), ex_pci_match, ex_pci_attach
 };
@@ -229,10 +240,6 @@
        rev = PCI_REVISION(pci_conf_read(pc, pa->pa_tag, PCI_CLASS_REG));
        printf(": 3Com %s (rev. 0x%x)\n", epp->epp_name, rev);
 
-       sc->enable = NULL;
-       sc->disable = NULL;
-       sc->enabled = 1;
-
        sc->sc_dmat = pa->pa_dmat;
 
        sc->ex_bustype = EX_BUS_PCI;
@@ -243,6 +250,15 @@
            pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) |
            PCI_COMMAND_MASTER_ENABLE);
 
+       psc->psc_pc = pc;
+       psc->psc_tag = pa->pa_tag;
+       psc->psc_regs[PCI_COMMAND_STATUS_REG>>2] = 
+           pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
+       psc->psc_regs[PCI_BHLC_REG>>2] =
+           pci_conf_read(pc, pa->pa_tag, PCI_BHLC_REG); 
+       psc->psc_regs[PCI_CBIO>>2] =
+           pci_conf_read(pc, pa->pa_tag, PCI_CBIO);
+
        if (sc->ex_conf & EX_CONF_PCI_FUNCREG) {
                /* Map PCI function status window. */
                if (pci_mapreg_map(pa, PCI_FUNCMEM, PCI_MAPREG_TYPE_MEM, 0,
@@ -252,12 +268,24 @@
                        return;
                }
                sc->intr_ack = ex_pci_intr_ack;
+
+               psc->psc_regs[PCI_FUNCMEM>>2] =
+                   pci_conf_read(pc, pa->pa_tag, PCI_FUNCMEM);
        }
                
        /* Get it out of power save mode if needed (BIOS bugs) */
        if (pci_get_capability(pc, pa->pa_tag, PCI_CAP_PWRMGMT, &pmreg, 0)) {
-               reg = pci_conf_read(pc, pa->pa_tag, pmreg + 4) & 0x3;
-               if (reg == 3) {
+               sc->enable = ex_pci_enable;
+               sc->disable = ex_pci_disable;
+
+               psc->psc_pwrmgmt_csr_reg = pmreg + 4;
+               reg = pci_conf_read(pc, pa->pa_tag,
+                   psc->psc_pwrmgmt_csr_reg) & 0x3;
+
+               psc->psc_pwrmgmt_csr = (reg & ~PCI_PMCSR_STATE_MASK) |
+                   PCI_PMCSR_STATE_D0;
+
+               if (reg == PCI_PMCSR_STATE_D3) {
                        /*
                         * The card has lost all configuration data in
                         * this state, so punt.
@@ -266,13 +294,15 @@
                            sc->sc_dev.dv_xname);
                        return;
                }
-               if (reg != 0) {
+               if (reg != PCI_PMCSR_STATE_D0) {
                        printf("%s: waking up from power state D%d\n",
                            sc->sc_dev.dv_xname, reg);
                        pci_conf_write(pc, pa->pa_tag, pmreg + 4, 0);
                }
        }
 
+       sc->enabled = 1;
+
        /* Map and establish the interrupt. */
        if (pci_intr_map(pa, &ih)) {
                printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
@@ -296,6 +326,9 @@
        if (sc->ex_conf & EX_CONF_PCI_FUNCREG)
                bus_space_write_4(psc->sc_funct, psc->sc_funch, PCI_INTR, 
                    PCI_INTRACK);
+
+       if (sc->disable != NULL)
+               ex_disable(sc);
 }
 
 void            
@@ -307,3 +340,61 @@
        bus_space_write_4(psc->sc_funct, psc->sc_funch, PCI_INTR,
            PCI_INTRACK);
 }
+
+void
+ex_pci_confreg_restore(psc)
+       struct ex_pci_softc *psc;
+{
+       struct ex_softc *sc = (void *) psc;
+       pcireg_t reg;
+
+       reg = pci_conf_read(psc->psc_pc, psc->psc_tag, PCI_COMMAND_STATUS_REG);
+
+       pci_conf_write(psc->psc_pc, psc->psc_tag,
+           PCI_COMMAND_STATUS_REG,
+           (reg & 0xffff0000) |
+           (psc->psc_regs[PCI_COMMAND_STATUS_REG>>2] & 0xffff));
+       pci_conf_write(psc->psc_pc, psc->psc_tag, PCI_BHLC_REG,
+           psc->psc_regs[PCI_BHLC_REG>>2]);
+       pci_conf_write(psc->psc_pc, psc->psc_tag, PCI_CBIO,
+           psc->psc_regs[PCI_CBIO>>2]);
+       if (sc->ex_conf & EX_CONF_PCI_FUNCREG)
+               pci_conf_write(psc->psc_pc, psc->psc_tag, PCI_FUNCMEM,
+                   psc->psc_regs[PCI_FUNCMEM>>2]);
+}
+
+int
+ex_pci_enable(sc)
+       struct ex_softc *sc;
+{
+       struct ex_pci_softc *psc = (void *) sc;
+
+#if 0
+       printf("%s: going to power state D0\n", sc->sc_dev.dv_xname);
+#endif
+
+       /* Bring the device into D0 power state. */
+       pci_conf_write(psc->psc_pc, psc->psc_tag,
+           psc->psc_pwrmgmt_csr_reg, psc->psc_pwrmgmt_csr);
+
+       /* Now restore the configuration registers. */
+       ex_pci_confreg_restore(psc);
+
+       return (0);
+}
+
+void
+ex_pci_disable(sc)
+       struct ex_softc *sc;
+{
+       struct ex_pci_softc *psc = (void *) sc;
+
+#if 0
+       printf("%s: going to power state D3\n", sc->sc_dev.dv_xname);
+#endif
+
+       /* Put the device into D3 state. */
+       pci_conf_write(psc->psc_pc, psc->psc_tag,
+           psc->psc_pwrmgmt_csr_reg, (psc->psc_pwrmgmt_csr &
+           ~PCI_PMCSR_STATE_MASK) | PCI_PMCSR_STATE_D3);
+}



Home | Main Index | Thread Index | Old Index