From 2c903bf2c0a82ebe96ad61bcec9a4992a8ade554 Mon Sep 17 00:00:00 2001 From: haya Date: Fri, 2 Nov 2001 03:32:33 +0000 Subject: [PATCH] Add PCI power management control. If the power state of a bridge is not D0 at device attaching or resuming, set the bridge D0 mode. --- sys/dev/pci/pccbb.c | 47 ++++++++++++++++++++++++++++++++++++++++-- sys/dev/pci/pccbbvar.h | 4 +++- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/sys/dev/pci/pccbb.c b/sys/dev/pci/pccbb.c index f3a4db9f92a7..f746138d4750 100644 --- a/sys/dev/pci/pccbb.c +++ b/sys/dev/pci/pccbb.c @@ -1,4 +1,4 @@ -/* $NetBSD: pccbb.c,v 1.69 2001/10/17 10:25:51 haya Exp $ */ +/* $NetBSD: pccbb.c,v 1.70 2001/11/02 03:32:33 haya Exp $ */ /* * Copyright (c) 1998, 1999 and 2000 @@ -422,6 +422,7 @@ pccbbattach(parent, self, aux) bus_addr_t sockbase; char devinfo[256]; int flags; + int pwrmgt_offs; sc->sc_chipset = cb_chipset(pa->pa_id, &flags); @@ -447,6 +448,22 @@ pccbbattach(parent, self, aux) sc->sc_base_memh = 0; + /* power management: set D0 state */ + sc->sc_pwrmgt_offs = 0; + if (pci_get_capability(pc, pa->pa_tag, PCI_CAP_PWRMGMT, + &pwrmgt_offs, 0)) { + reg = pci_conf_read(pc, pa->pa_tag, pwrmgt_offs + 4); + if ((reg & PCI_PMCSR_STATE_MASK) != PCI_PMCSR_STATE_D0 || + reg & 0x100 /* PCI_PMCSR_PME_EN */) { + reg &= ~PCI_PMCSR_STATE_MASK; + reg |= PCI_PMCSR_STATE_D0; + reg &= ~(0x100 /* PCI_PMCSR_PME_EN */); + pci_conf_write(pc, pa->pa_tag, pwrmgt_offs + 4, reg); + } + + sc->sc_pwrmgt_offs = pwrmgt_offs; + } + /* * MAP socket registers and ExCA registers on memory-space * When no valid address is set on socket base registers (on pci @@ -3253,7 +3270,7 @@ pccbb_powerhook(why, arg) void *arg; { struct pccbb_softc *sc = arg; - u_int32_t reg; + pcireg_t reg; bus_space_tag_t base_memt = sc->sc_base_memt; /* socket regs memory */ bus_space_handle_t base_memh = sc->sc_base_memh; @@ -3271,6 +3288,32 @@ pccbb_powerhook(why, arg) } if (why == PWR_RESUME) { + if (sc->sc_pwrmgt_offs != 0) { + reg = pci_conf_read(sc->sc_pc, sc->sc_tag, + sc->sc_pwrmgt_offs + 4); + if ((reg & PCI_PMCSR_STATE_MASK) != PCI_PMCSR_STATE_D0 || + reg & 0x100) { + /* powrstate != D0 */ + + printf("%s going back to D0 mode\n", + sc->sc_dev.dv_xname); + reg &= ~PCI_PMCSR_STATE_MASK; + reg |= PCI_PMCSR_STATE_D0; + reg &= ~(0x100 /* PCI_PMCSR_PME_EN */); + pci_conf_write(sc->sc_pc, sc->sc_tag, + sc->sc_pwrmgt_offs + 4, reg); + + pci_conf_write(sc->sc_pc, sc->sc_tag, + PCI_SOCKBASE, sc->sc_sockbase); + pci_conf_write(sc->sc_pc, sc->sc_tag, + PCI_BUSNUM, sc->sc_busnum); + pccbb_chipinit(sc); + /* setup memory and io space window for CB */ + pccbb_winset(0x1000, sc, sc->sc_memt); + pccbb_winset(0x04, sc, sc->sc_iot); + } + } + if (pci_conf_read (sc->sc_pc, sc->sc_tag, PCI_SOCKBASE) == 0) /* BIOS did not recover this register */ pci_conf_write (sc->sc_pc, sc->sc_tag, diff --git a/sys/dev/pci/pccbbvar.h b/sys/dev/pci/pccbbvar.h index 913108ac478d..29daab567ac2 100644 --- a/sys/dev/pci/pccbbvar.h +++ b/sys/dev/pci/pccbbvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: pccbbvar.h,v 1.16 2001/07/06 18:07:00 mcr Exp $ */ +/* $NetBSD: pccbbvar.h,v 1.17 2001/11/02 03:32:34 haya Exp $ */ /* * Copyright (c) 1999 HAYAKAWA Koichi. All rights reserved. * @@ -160,6 +160,8 @@ struct pccbb_softc { /* interrupt handler list on the bridge */ struct pccbb_intrhand_list *sc_pil; int sc_pil_intr_enable; /* can i call intr handler for child device? */ + + int sc_pwrmgt_offs; /* Offset for power management capability */ }; /*