diff --git a/sys/dev/cardbus/cardbus.c b/sys/dev/cardbus/cardbus.c index 006cd8d90adc..c1445696d582 100644 --- a/sys/dev/cardbus/cardbus.c +++ b/sys/dev/cardbus/cardbus.c @@ -1,4 +1,4 @@ -/* $NetBSD: cardbus.c,v 1.48 2004/04/23 21:13:07 itojun Exp $ */ +/* $NetBSD: cardbus.c,v 1.49 2004/05/08 23:40:01 christos Exp $ */ /* * Copyright (c) 1997, 1998, 1999 and 2000 @@ -33,7 +33,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: cardbus.c,v 1.48 2004/04/23 21:13:07 itojun Exp $"); +__KERNEL_RCSID(0, "$NetBSD: cardbus.c,v 1.49 2004/05/08 23:40:01 christos Exp $"); #include "opt_cardbus.h" @@ -857,6 +857,121 @@ decode_tuple(u_int8_t *tuple, tuple_decode_func func, void *data) return (tuple + len); } +/* + * XXX: this is another reason why this code should be shared with PCI. + */ +int +cardbus_powerstate(cardbus_devfunc_t ct, pcitag_t tag, const int *newstate, + int *oldstate) +{ + cardbus_chipset_tag_t cc = ct->ct_cc; + cardbus_function_tag_t cf = ct->ct_cf; + + int offset; + pcireg_t value, cap, now; + + if (!cardbus_get_capability(cc, cf, tag, PCI_CAP_PWRMGMT, &offset, + &value)) + return EOPNOTSUPP; + + cap = value >> 16; + value = cardbus_conf_read(cc, cf, tag, offset + PCI_PMCSR); + now = value & PCI_PMCSR_STATE_MASK; + value &= ~PCI_PMCSR_STATE_MASK; + if (oldstate) { + switch (now) { + case PCI_PMCSR_STATE_D0: + *oldstate = PCI_PWR_D0; + break; + case PCI_PMCSR_STATE_D1: + *oldstate = PCI_PWR_D1; + break; + case PCI_PMCSR_STATE_D2: + *oldstate = PCI_PWR_D2; + break; + case PCI_PMCSR_STATE_D3: + *oldstate = PCI_PWR_D3; + break; + default: + return EINVAL; + } + } + if (newstate == NULL) + return 0; + switch (*newstate) { + case PCI_PWR_D0: + if (now == PCI_PMCSR_STATE_D0) + return 0; + value |= PCI_PMCSR_STATE_D0; + break; + case PCI_PWR_D1: + if (now == PCI_PMCSR_STATE_D1) + return 0; + if (now == PCI_PMCSR_STATE_D2 || now == PCI_PMCSR_STATE_D3) + return EINVAL; + if (!(cap & PCI_PMCR_D1SUPP)) + return EOPNOTSUPP; + value |= PCI_PMCSR_STATE_D1; + break; + case PCI_PWR_D2: + if (now == PCI_PMCSR_STATE_D2) + return 0; + if (now == PCI_PMCSR_STATE_D3) + return EINVAL; + if (!(cap & PCI_PMCR_D2SUPP)) + return EOPNOTSUPP; + value |= PCI_PMCSR_STATE_D2; + break; + case PCI_PWR_D3: + if (now == PCI_PMCSR_STATE_D3) + return 0; + value |= PCI_PMCSR_STATE_D3; + break; + default: + return EINVAL; + } + cardbus_conf_write(cc, cf, tag, offset + PCI_PMCSR, value); + DELAY(1000); + + return 0; +} + +int +cardbus_setpowerstate(const char *dvname, cardbus_devfunc_t ct, pcitag_t tag, + int newpwr) +{ + int oldpwr, error; + + if ((error = cardbus_powerstate(ct, tag, &newpwr, &oldpwr)) != 0) + return error; + + if (oldpwr == newpwr) + return 0; + + if (oldpwr > newpwr) { + printf("%s: sleeping to power state D%d\n", dvname, oldpwr); + return 0; + } + + /* oldpwr < newpwr */ + switch (oldpwr) { + case PCI_PWR_D3: + /* + * XXX: This is because none of the devices do + * the necessary song and dance for now to wakeup + * Once this + */ + printf("%s: cannot wake up from power state D%d\n", + dvname, oldpwr); + return EINVAL; + default: + printf("%s: waking up from power state D%d\n", + dvname, oldpwr); + return 0; + } +} + + #ifdef CARDBUS_DEBUG static const char *tuple_name(int); static const char *tuple_names[] = { diff --git a/sys/dev/cardbus/cardbusvar.h b/sys/dev/cardbus/cardbusvar.h index 83edd06494ca..ad9c9a92ca16 100644 --- a/sys/dev/cardbus/cardbusvar.h +++ b/sys/dev/cardbus/cardbusvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: cardbusvar.h,v 1.25 2003/07/08 10:06:29 itojun Exp $ */ +/* $NetBSD: cardbusvar.h,v 1.26 2004/05/08 23:40:01 christos Exp $ */ /* * Copyright (c) 1998, 1999 and 2000 @@ -338,6 +338,8 @@ int cardbus_function_disable __P((struct cardbus_softc *, int)); int cardbus_get_capability __P((cardbus_chipset_tag_t, cardbus_function_tag_t, cardbustag_t, int, int *, cardbusreg_t *)); +int cardbus_powerstate __P((cardbus_devfunc_t, pcitag_t, const int *, int *)); +int cardbus_setpowerstate __P((const char *, cardbus_devfunc_t, pcitag_t, int)); #define Cardbus_function_enable(ct) cardbus_function_enable((ct)->ct_sc, (ct)->ct_func) #define Cardbus_function_disable(ct) cardbus_function_disable((ct)->ct_sc, (ct)->ct_func) diff --git a/sys/dev/cardbus/if_ath_cardbus.c b/sys/dev/cardbus/if_ath_cardbus.c index 82f94f69133f..3851a2185e60 100644 --- a/sys/dev/cardbus/if_ath_cardbus.c +++ b/sys/dev/cardbus/if_ath_cardbus.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_ath_cardbus.c,v 1.1 2003/10/14 17:47:03 ichiro Exp $ */ +/* $NetBSD: if_ath_cardbus.c,v 1.2 2004/05/08 23:40:01 christos Exp $ */ /* * Copyright (c) 2003 * Ichiro FUKUHARA . @@ -36,7 +36,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_ath_cardbus.c,v 1.1 2003/10/14 17:47:03 ichiro Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_ath_cardbus.c,v 1.2 2004/05/08 23:40:01 christos Exp $"); #include "opt_inet.h" #include "opt_ns.h" @@ -311,29 +311,9 @@ ath_cardbus_setup(struct ath_cardbus_softc *csc) cardbus_chipset_tag_t cc = ct->ct_cc; cardbus_function_tag_t cf = ct->ct_cf; pcireg_t reg; - int pmreg; - if (cardbus_get_capability(cc, cf, csc->sc_tag, - PCI_CAP_PWRMGMT, &pmreg, 0)) { - reg = cardbus_conf_read(cc, cf, csc->sc_tag, pmreg + 4); -#if 1 /* XXX Probably not right for CardBus. */ - if (reg & 0x03) { - /* - * The card has lost all configuration data in - * this state, so punt. - */ - printf("%s: unable to wake up from power state D3\n", - sc->sc_dev.dv_xname); - return; - } -#endif - if (reg != 0) { - printf("%s: waking up from power state D%d\n", - sc->sc_dev.dv_xname, reg); - cardbus_conf_write(cc, cf, csc->sc_tag, - pmreg + 4, 0); - } - } + (void)cardbus_setpowerstate(sc->sc_dev.dv_xname, ct, csc->sc_tag, + PCI_PWR_D0); /* Make sure the right access type is on the CardBus bridge. */ (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE); diff --git a/sys/dev/cardbus/if_atw_cardbus.c b/sys/dev/cardbus/if_atw_cardbus.c index bcdac224063f..4f53ebbea685 100644 --- a/sys/dev/cardbus/if_atw_cardbus.c +++ b/sys/dev/cardbus/if_atw_cardbus.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_atw_cardbus.c,v 1.6 2004/02/17 21:20:55 dyoung Exp $ */ +/* $NetBSD: if_atw_cardbus.c,v 1.7 2004/05/08 23:40:01 christos Exp $ */ /*- * Copyright (c) 1999, 2000, 2003 The NetBSD Foundation, Inc. @@ -43,7 +43,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_atw_cardbus.c,v 1.6 2004/02/17 21:20:55 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_atw_cardbus.c,v 1.7 2004/05/08 23:40:01 christos Exp $"); #include "opt_inet.h" #include "opt_ns.h" @@ -408,29 +408,9 @@ atw_cardbus_setup(struct atw_cardbus_softc *csc) cardbus_chipset_tag_t cc = ct->ct_cc; cardbus_function_tag_t cf = ct->ct_cf; pcireg_t reg; - int pmreg; - if (cardbus_get_capability(cc, cf, csc->sc_tag, - PCI_CAP_PWRMGMT, &pmreg, 0)) { - reg = cardbus_conf_read(cc, cf, csc->sc_tag, pmreg + 4) & 0x03; -#if 1 /* XXX Probably not right for CardBus. */ - if (reg == 3) { - /* - * The card has lost all configuration data in - * this state, so punt. - */ - printf("%s: unable to wake up from power state D3\n", - sc->sc_dev.dv_xname); - return; - } -#endif - if (reg != 0) { - printf("%s: waking up from power state D%d\n", - sc->sc_dev.dv_xname, reg); - cardbus_conf_write(cc, cf, csc->sc_tag, - pmreg + 4, 0); - } - } + (void)cardbus_setpowerstate(sc->sc_dev.dv_xname, ct, csc->sc_tag, + PCI_PWR_D0); /* Make sure the right access type is on the CardBus bridge. */ (*ct->ct_cf->cardbus_ctrl)(cc, csc->sc_cben); diff --git a/sys/dev/cardbus/if_ex_cardbus.c b/sys/dev/cardbus/if_ex_cardbus.c index af34fa4a8852..2bfebb6d00e8 100644 --- a/sys/dev/cardbus/if_ex_cardbus.c +++ b/sys/dev/cardbus/if_ex_cardbus.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_ex_cardbus.c,v 1.28 2003/11/02 09:56:38 wiz Exp $ */ +/* $NetBSD: if_ex_cardbus.c,v 1.29 2004/05/08 23:40:01 christos Exp $ */ /* * CardBus specific routines for 3Com 3C575-family CardBus ethernet adapter @@ -37,7 +37,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_ex_cardbus.c,v 1.28 2003/11/02 09:56:38 wiz Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_ex_cardbus.c,v 1.29 2004/05/08 23:40:01 christos Exp $"); /* #define EX_DEBUG 4 */ /* define to report information for debugging */ @@ -400,30 +400,9 @@ ex_cardbus_setup(csc) cardbus_chipset_tag_t cc = ct->ct_cc; cardbus_function_tag_t cf = ct->ct_cf; cardbusreg_t reg; - int pmreg; - /* Get it out of power save mode if needed (BIOS bugs). */ - if (cardbus_get_capability(cc, cf, csc->sc_tag, - PCI_CAP_PWRMGMT, &pmreg, 0)) { - reg = cardbus_conf_read(cc, cf, csc->sc_tag, pmreg + 4) & 0x03; -#if 1 /* XXX Probably not right for CardBus. */ - if (reg == 3) { - /* - * The card has lost all configuration data in - * this state, so punt. - */ - printf("%s: unable to wake up from power state D3\n", - sc->sc_dev.dv_xname); - return; - } -#endif - if (reg != 0) { - printf("%s: waking up from power state D%d\n", - sc->sc_dev.dv_xname, reg); - cardbus_conf_write(cc, cf, csc->sc_tag, - pmreg + 4, 0); - } - } + (void)cardbus_setpowerstate(sc->sc_dev.dv_xname, ct, csc->sc_tag, + PCI_PWR_D0); /* Make sure the right access type is on the CardBus bridge. */ (ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_IO_ENABLE); diff --git a/sys/dev/cardbus/if_tlp_cardbus.c b/sys/dev/cardbus/if_tlp_cardbus.c index e6728c3f9ef0..666f15115f08 100644 --- a/sys/dev/cardbus/if_tlp_cardbus.c +++ b/sys/dev/cardbus/if_tlp_cardbus.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_tlp_cardbus.c,v 1.39 2003/10/24 17:04:35 mycroft Exp $ */ +/* $NetBSD: if_tlp_cardbus.c,v 1.40 2004/05/08 23:40:01 christos Exp $ */ /*- * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. @@ -43,7 +43,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_tlp_cardbus.c,v 1.39 2003/10/24 17:04:35 mycroft Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_tlp_cardbus.c,v 1.40 2004/05/08 23:40:01 christos Exp $"); #include "opt_inet.h" #include "opt_ns.h" @@ -621,27 +621,8 @@ tlp_cardbus_setup(csc) break; } - if (cardbus_get_capability(cc, cf, csc->sc_tag, - PCI_CAP_PWRMGMT, &pmreg, 0)) { - reg = cardbus_conf_read(cc, cf, csc->sc_tag, pmreg + 4) & 0x03; -#if 1 /* XXX Probably not right for CardBus. */ - if (reg == 3) { - /* - * The card has lost all configuration data in - * this state, so punt. - */ - printf("%s: unable to wake up from power state D3\n", - sc->sc_dev.dv_xname); - return; - } -#endif - if (reg != 0) { - printf("%s: waking up from power state D%d\n", - sc->sc_dev.dv_xname, reg); - cardbus_conf_write(cc, cf, csc->sc_tag, - pmreg + 4, 0); - } - } + (void)cardbus_setpowerstate(sc->sc_dev.dv_xname, ct, csc->sc_tag, + PCI_PWR_D0); /* Make sure the right access type is on the CardBus bridge. */ (*ct->ct_cf->cardbus_ctrl)(cc, csc->sc_cben);