From 3df2b2feb5ec81dbf34ffb230078ff45e416489a Mon Sep 17 00:00:00 2001 From: dyoung Date: Wed, 12 Mar 2008 18:02:21 +0000 Subject: [PATCH] Use device_t and its accessors throughout. Use aprint_*_dev(). Improve PMF-ability. Add a 'flags' argument to suspend/resume handlers and callers such as pmf_system_suspend(). Define a flag, PMF_F_SELF, which indicates to PMF that a device is suspending/resuming itself. Add helper routines, pmf_device_suspend_self(dev) and pmf_device_resume_self(dev), that call pmf_device_suspend(dev, PMF_F_SELF) and pmf_device_resume(dev, PMF_F_SELF), respectively. Use PMF_F_SELF to suspend/resume self in ath(4), audio(4), rtw(4), and sip(4). In ath(4) and in rtw(4), replace the icky sc_enable/sc_disable callbacks, provided by the bus front-end, with self-suspension/resumption. Also, clean up the bus front-ends. Make sure that the interrupt handler is disestablished during suspension. Get rid of driver-private flags (e.g., RTW_F_ENABLED, ath_softc->sc_invalid); use device_is_active()/device_has_power() calls, instead. In the network-class suspend handler, call if_stop(, 0) instead of if_stop(, 1), because the latter is superfluous (bus- and driver-suspension hooks will 'disable' the NIC), and it may cause recursion. In the network-class resume handler, prevent infinite recursion through if_init() by getting out early if we are self-suspending (PMF_F_SELF). rtw(4) improvements: Destroy rtw(4) callouts when we detach it. Make rtw at pci detachable. Print some more information with the "rx frame too long" warning. Remove activate() methods: Get rid of rtw_activate() and ath_activate(). The device activate() methods are not good for much these days. Make ath at cardbus resume with crypto functions intact: Introduce a boolean device property, "pmf-powerdown". If pmf-powerdown is present and false, it indicates that a bus back-end should not remove power from a device. Honor this property in cardbus_child_suspend(). Set this property to 'false' in ath_attach(), since removing power from an ath at cardbus seems to lobotomize the WPA crypto engine. XXX Should the pmf-powerdown property propagate toward the root of the device tree? Miscellaneous ath(4) changes: Warn if ath(4) tries to write crypto keys to suspended hardware. Reduce differences between FreeBSD and NetBSD in ath(4) multicast filter setup. Make ath_printrxbuf() print an rx descriptor's status & key index, to help debug crypto errors. Shorten a staircase in ath_ioctl(). Don't check for ieee80211_ioctl() return code ERESTART, it never happens. --- sys/dev/acpi/acpi.c | 10 +- sys/dev/apm/apm.c | 10 +- sys/dev/audio.c | 22 +-- sys/dev/cardbus/cardbus.c | 9 +- sys/dev/cardbus/if_ath_cardbus.c | 197 +++++++++-------------- sys/dev/cardbus/if_rtw_cardbus.c | 122 ++++++--------- sys/dev/ic/ath.c | 257 ++++++++++++------------------- sys/dev/ic/athvar.h | 13 +- sys/dev/ic/rtw.c | 162 ++++++++++--------- sys/dev/ic/rtwvar.h | 20 +-- sys/dev/pci/if_ath_pci.c | 70 ++++++--- sys/dev/pci/if_rtw_pci.c | 95 +++++++----- sys/dev/pci/if_sip.c | 36 +++-- sys/kern/kern_drvctl.c | 17 +- sys/kern/kern_pmf.c | 26 +++- sys/kern/subr_autoconf.c | 38 ++++- sys/sys/device.h | 8 +- sys/sys/pmf.h | 24 ++- 18 files changed, 548 insertions(+), 588 deletions(-) diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c index dff318cf7648..d8903626858a 100644 --- a/sys/dev/acpi/acpi.c +++ b/sys/dev/acpi/acpi.c @@ -1,4 +1,4 @@ -/* $NetBSD: acpi.c,v 1.111 2008/03/10 20:58:38 dyoung Exp $ */ +/* $NetBSD: acpi.c,v 1.112 2008/03/12 18:02:21 dyoung Exp $ */ /*- * Copyright (c) 2003, 2007 The NetBSD Foundation, Inc. @@ -77,7 +77,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.111 2008/03/10 20:58:38 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.112 2008/03/12 18:02:21 dyoung Exp $"); #include "opt_acpi.h" #include "opt_pcifixup.h" @@ -1198,7 +1198,7 @@ acpi_enter_sleep_state(struct acpi_softc *sc, int state) break; } - if (state != ACPI_STATE_S1 && !pmf_system_suspend()) { + if (state != ACPI_STATE_S1 && !pmf_system_suspend(PMF_F_NONE)) { aprint_error_dev(&sc->sc_dev, "aborting suspend\n"); break; } @@ -1221,9 +1221,9 @@ acpi_enter_sleep_state(struct acpi_softc *sc, int state) err = acpi_md_sleep(state); if (state == ACPI_STATE_S4) AcpiEnable(); - pmf_system_bus_resume(); + pmf_system_bus_resume(PMF_F_NONE); AcpiLeaveSleepState((UINT8)state); - pmf_system_resume(); + pmf_system_resume(PMF_F_NONE); } break; diff --git a/sys/dev/apm/apm.c b/sys/dev/apm/apm.c index be6ee1de858a..f3981ba2fa38 100644 --- a/sys/dev/apm/apm.c +++ b/sys/dev/apm/apm.c @@ -1,4 +1,4 @@ -/* $NetBSD: apm.c,v 1.19 2008/03/07 21:45:08 cube Exp $ */ +/* $NetBSD: apm.c,v 1.20 2008/03/12 18:02:21 dyoung Exp $ */ /*- * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. @@ -40,7 +40,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: apm.c,v 1.19 2008/03/07 21:45:08 cube Exp $"); +__KERNEL_RCSID(0, "$NetBSD: apm.c,v 1.20 2008/03/12 18:02:21 dyoung Exp $"); #include "opt_apm.h" @@ -316,7 +316,7 @@ apm_suspend(struct apm_softc *sc) sc->sc_power_state = PWR_SUSPEND; if (!(sc->sc_hwflags & APM_F_DONT_RUN_HOOKS)) { - pmf_system_suspend(); + pmf_system_suspend(PMF_F_NONE); apm_spl = splhigh(); } @@ -342,7 +342,7 @@ apm_standby(struct apm_softc *sc) sc->sc_power_state = PWR_STANDBY; if (!(sc->sc_hwflags & APM_F_DONT_RUN_HOOKS)) { - pmf_system_suspend(); + pmf_system_suspend(PMF_F_NONE); apm_spl = splhigh(); } error = (*sc->sc_ops->aa_set_powstate)(sc->sc_cookie, APM_DEV_ALLDEVS, @@ -373,7 +373,7 @@ apm_resume(struct apm_softc *sc, u_int event_type, u_int event_info) inittodr(time_second); if (!(sc->sc_hwflags & APM_F_DONT_RUN_HOOKS)) { splx(apm_spl); - pmf_system_resume(); + pmf_system_resume(PMF_F_NONE); } apm_record_event(sc, event_type); diff --git a/sys/dev/audio.c b/sys/dev/audio.c index 62f7b525b1dd..90214df0d2b5 100644 --- a/sys/dev/audio.c +++ b/sys/dev/audio.c @@ -1,4 +1,4 @@ -/* $NetBSD: audio.c,v 1.236 2008/03/04 18:23:44 cube Exp $ */ +/* $NetBSD: audio.c,v 1.237 2008/03/12 18:02:21 dyoung Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -61,7 +61,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.236 2008/03/04 18:23:44 cube Exp $"); +__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.237 2008/03/12 18:02:21 dyoung Exp $"); #include "audio.h" #if NAUDIO > 0 @@ -183,8 +183,8 @@ static void audio_idle(void *); static void audio_activity(device_t, devactive_t); #endif -static bool audio_suspend(device_t dv); -static bool audio_resume(device_t dv); +static bool audio_suspend(device_t dv PMF_FN_PROTO); +static bool audio_resume(device_t dv PMF_FN_PROTO); static void audio_volume_down(device_t); static void audio_volume_up(device_t); static void audio_volume_toggle(device_t); @@ -3993,11 +3993,11 @@ audio_idle(void *arg) sc->sc_idle = true; /* XXX joerg Make pmf_device_suspend handle children? */ - if (!pmf_device_suspend(dv)) + if (!pmf_device_suspend(dv, PMF_F_SELF)) return; - if (!pmf_device_suspend(sc->sc_dev)) - pmf_device_resume(dv); + if (!pmf_device_suspend(sc->sc_dev, PMF_F_SELF)) + pmf_device_resume(dv, PMF_F_SELF); } static void @@ -4013,14 +4013,14 @@ audio_activity(device_t dv, devactive_t type) sc->sc_idle = false; if (!device_is_active(dv)) { /* XXX joerg How to deal with a failing resume... */ - pmf_device_resume(sc->sc_dev); - pmf_device_resume(dv); + pmf_device_resume(sc->sc_dev, PMF_F_SELF); + pmf_device_resume(dv, PMF_F_SELF); } } #endif static bool -audio_suspend(device_t dv) +audio_suspend(device_t dv PMF_FN_ARGS) { struct audio_softc *sc = device_private(dv); const struct audio_hw_if *hwp = sc->hw_if; @@ -4041,7 +4041,7 @@ audio_suspend(device_t dv) } static bool -audio_resume(device_t dv) +audio_resume(device_t dv PMF_FN_ARGS) { struct audio_softc *sc = device_private(dv); int s; diff --git a/sys/dev/cardbus/cardbus.c b/sys/dev/cardbus/cardbus.c index f795e0036f9f..1582d919618a 100644 --- a/sys/dev/cardbus/cardbus.c +++ b/sys/dev/cardbus/cardbus.c @@ -1,4 +1,4 @@ -/* $NetBSD: cardbus.c,v 1.90 2008/02/28 14:25:12 drochner Exp $ */ +/* $NetBSD: cardbus.c,v 1.91 2008/03/12 18:02:21 dyoung Exp $ */ /* * Copyright (c) 1997, 1998, 1999 and 2000 @@ -33,7 +33,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: cardbus.c,v 1.90 2008/02/28 14:25:12 drochner Exp $"); +__KERNEL_RCSID(0, "$NetBSD: cardbus.c,v 1.91 2008/03/12 18:02:21 dyoung Exp $"); #include "opt_cardbus.h" @@ -1167,6 +1167,7 @@ struct cardbus_child_power { static bool cardbus_child_suspend(device_t dv PMF_FN_ARGS) { + bool powerdown; struct cardbus_child_power *priv = device_pmf_bus_private(dv); cardbus_conf_capture(priv->p_cc, priv->p_cf, priv->p_tag, @@ -1179,7 +1180,9 @@ cardbus_child_suspend(device_t dv PMF_FN_ARGS) return false; } - Cardbus_function_disable(priv->p_ct); + if (!prop_dictionary_get_bool(device_properties(dv), "pmf-powerdown", + &powerdown) || powerdown) + Cardbus_function_disable(priv->p_ct); return true; } diff --git a/sys/dev/cardbus/if_ath_cardbus.c b/sys/dev/cardbus/if_ath_cardbus.c index 75e4a3e5e916..819a2ec468fd 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.25 2007/12/22 00:39:47 dyoung Exp $ */ +/* $NetBSD: if_ath_cardbus.c,v 1.26 2008/03/12 18:02:21 dyoung Exp $ */ /* * Copyright (c) 2003 * Ichiro FUKUHARA . @@ -36,7 +36,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_ath_cardbus.c,v 1.25 2007/12/22 00:39:47 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_ath_cardbus.c,v 1.26 2008/03/12 18:02:21 dyoung Exp $"); #include "opt_inet.h" #include "bpfilter.h" @@ -109,70 +109,72 @@ struct ath_cardbus_softc { bus_space_handle_t sc_ioh; }; -int ath_cardbus_match(struct device *, struct cfdata *, void *); -void ath_cardbus_attach(struct device *, struct device *, void *); -int ath_cardbus_detach(struct device *, int); +int ath_cardbus_match(device_t, struct cfdata *, void *); +void ath_cardbus_attach(device_t, device_t, void *); +int ath_cardbus_detach(device_t, int); CFATTACH_DECL(ath_cardbus, sizeof(struct ath_cardbus_softc), - ath_cardbus_match, ath_cardbus_attach, ath_cardbus_detach, ath_activate); + ath_cardbus_match, ath_cardbus_attach, ath_cardbus_detach, NULL); void ath_cardbus_setup(struct ath_cardbus_softc *); -int ath_cardbus_enable(struct ath_softc *); -void ath_cardbus_disable(struct ath_softc *); - static bool -ath_cardbus_resume(device_t dv) +ath_cardbus_suspend(device_t self PMF_FN_ARGS) { - struct ath_cardbus_softc *csc = device_private(dv); - - /* Insofar as I understand what the PCI retry timeout is - * (it does not appear to be documented in any PCI standard, - * and we don't have any Atheros documentation), disabling - * it on resume does not seem to be justified. - * - * Taking a guess, the DMA engine counts down from the - * retry timeout to 0 while it retries a delayed PCI - * transaction. When it reaches 0, it ceases retrying. - * A PCI master is *never* supposed to stop retrying a - * delayed transaction, though. - * - * Incidentally, while I am hopeful that cardbus_disable_retry() - * does disable retries, because that would help to explain - * some ath(4) lossage, I suspect that writing 0 to the - * register does not disable *retries*, but it disables - * the timeout. That is, the device will *never* timeout. - */ -#if 0 - cardbus_devfunc_t ct = csc->sc_ct; - cardbus_chipset_tag_t cc = ct->ct_cc; - cardbus_function_tag_t cf = ct->ct_cf; - cardbus_disable_retry(cc, cf, csc->sc_tag); -#endif - ath_resume(&csc->sc_ath); + struct ath_cardbus_softc *csc = device_private(self); + ath_suspend(&csc->sc_ath); + if (csc->sc_ih != NULL) { + cardbus_intr_disestablish(csc->sc_ct->ct_cc, csc->sc_ct->ct_cf, + csc->sc_ih); + csc->sc_ih = NULL; + } return true; } +static bool +ath_cardbus_resume(device_t self PMF_FN_ARGS) +{ + struct ath_cardbus_softc *csc = device_private(self); + +#if 1 + ath_cardbus_setup(csc); +#else + int rc; + rc = cardbus_set_powerstate(csc->sc_ct, csc->sc_tag, PCI_PWR_D0); + if (rc != 0) + aprint_debug("%s: cardbus_set_powerstate %d\n", __func__, rc); +#endif + + csc->sc_ih = cardbus_intr_establish(csc->sc_ct->ct_cc, + csc->sc_ct->ct_cf, csc->sc_intrline, IPL_NET, ath_intr, + &csc->sc_ath); + + if (csc->sc_ih == NULL) { + aprint_error_dev(self, + "unable to establish interrupt at %d\n", csc->sc_intrline); + return false; + } + + return ath_resume(&csc->sc_ath); +} + int -ath_cardbus_match(struct device *parent, struct cfdata *match, - void *aux) +ath_cardbus_match(device_t parent, struct cfdata *match, void *aux) { struct cardbus_attach_args *ca = aux; - const char* devname; + const char *devname; - devname = ath_hal_probe(PCI_VENDOR(ca->ca_id), - PCI_PRODUCT(ca->ca_id)); + devname = ath_hal_probe(PCI_VENDOR(ca->ca_id), PCI_PRODUCT(ca->ca_id)); if (devname) - return (1); + return 1; - return (0); + return 0; } void -ath_cardbus_attach(struct device *parent, struct device *self, - void *aux) +ath_cardbus_attach(device_t parent, device_t self, void *aux) { struct ath_cardbus_softc *csc = device_private(self); struct ath_softc *sc = &csc->sc_ath; @@ -184,29 +186,20 @@ ath_cardbus_attach(struct device *parent, struct device *self, csc->sc_ct = ct; csc->sc_tag = ca->ca_tag; - printf("\n"); - - /* - * Power management hooks. - */ - sc->sc_enable = ath_cardbus_enable; - sc->sc_disable = ath_cardbus_disable; + aprint_normal("\n"); /* * Map the device. */ - if (Cardbus_mapreg_map(ct, ATH_PCI_MMBA, CARDBUS_MAPREG_TYPE_MEM, 0, + if (Cardbus_mapreg_map(ct, ATH_PCI_MMBA, PCI_MAPREG_TYPE_MEM, 0, &csc->sc_iot, &csc->sc_ioh, &adr, &csc->sc_mapsize) == 0) { #if rbus #else (*ct->ct_cf->cardbus_mem_open)(cc, 0, adr, adr+csc->sc_mapsize); #endif - csc->sc_bar_val = adr | CARDBUS_MAPREG_TYPE_MEM; - } - - else { - printf("%s: unable to map device registers\n", - sc->sc_dev.dv_xname); + csc->sc_bar_val = adr | PCI_MAPREG_TYPE_MEM; + } else { + aprint_error_dev(self, "unable to map device registers\n"); return; } @@ -223,19 +216,22 @@ ath_cardbus_attach(struct device *parent, struct device *self, ATH_LOCK_INIT(sc); - if (!pmf_device_register(self, NULL, ath_cardbus_resume)) - aprint_error_dev(self, "couldn't establish power handler\n"); - else - pmf_class_network_register(self, &sc->sc_if); - /* * Finish off the attach. */ - ath_attach(PCI_PRODUCT(ca->ca_id), sc); + if (ath_attach(PCI_PRODUCT(ca->ca_id), sc) != 0) + return; + + if (!pmf_device_register(self, ath_cardbus_suspend, ath_cardbus_resume)) + aprint_error_dev(self, "couldn't establish power handler\n"); + else { + pmf_class_network_register(self, &sc->sc_if); + pmf_device_suspend_self(self); + } } int -ath_cardbus_detach(struct device *self, int flags) +ath_cardbus_detach(device_t self, int flags) { struct ath_cardbus_softc *csc = device_private(self); struct ath_softc *sc = &csc->sc_ath; @@ -272,79 +268,24 @@ ath_cardbus_detach(struct device *self, int flags) return (0); } -int -ath_cardbus_enable(struct ath_softc *sc) -{ - struct ath_cardbus_softc *csc = (void *) sc; - cardbus_devfunc_t ct = csc->sc_ct; - cardbus_chipset_tag_t cc = ct->ct_cc; - cardbus_function_tag_t cf = ct->ct_cf; - - /* - * Power on the socket. - */ - Cardbus_function_enable(ct); - - /* - * Set up the PCI configuration registers. - */ - ath_cardbus_setup(csc); - - /* - * Map and establish the interrupt. - */ - csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET, - ath_intr, sc); - if (csc->sc_ih == NULL) { - printf("%s: unable to establish interrupt at %d\n", - sc->sc_dev.dv_xname, csc->sc_intrline); - Cardbus_function_disable(csc->sc_ct); - return (1); - } - printf("%s: interrupting at %d\n", sc->sc_dev.dv_xname, - csc->sc_intrline); - - return (0); -} - -void -ath_cardbus_disable(struct ath_softc *sc) -{ - struct ath_cardbus_softc *csc = (void *) sc; - cardbus_devfunc_t ct = csc->sc_ct; - cardbus_chipset_tag_t cc = ct->ct_cc; - cardbus_function_tag_t cf = ct->ct_cf; - - /* Unhook the interrupt handler. */ - cardbus_intr_disestablish(cc, cf, csc->sc_ih); - csc->sc_ih = NULL; -} - void ath_cardbus_setup(struct ath_cardbus_softc *csc) { cardbus_devfunc_t ct = csc->sc_ct; cardbus_chipset_tag_t cc = ct->ct_cc; cardbus_function_tag_t cf = ct->ct_cf; - int error; + int rc; pcireg_t reg; - if ((error = cardbus_set_powerstate(ct, csc->sc_tag, - PCI_PWR_D0)) != 0) - aprint_debug("%s: cardbus_set_powerstate %d\n", __func__, error); + if ((rc = cardbus_set_powerstate(ct, csc->sc_tag, PCI_PWR_D0)) != 0) + aprint_debug("%s: cardbus_set_powerstate %d\n", __func__, rc); /* Program the BAR. */ - cardbus_conf_write(cc, cf, csc->sc_tag, ATH_PCI_MMBA, - csc->sc_bar_val); - - /* Make sure the right access type is on the CardBus bridge. */ - (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE); - (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); + cardbus_conf_write(cc, cf, csc->sc_tag, ATH_PCI_MMBA, csc->sc_bar_val); /* Enable the appropriate bits in the PCI CSR. */ reg = cardbus_conf_read(cc, cf, csc->sc_tag, - CARDBUS_COMMAND_STATUS_REG); - reg |= CARDBUS_COMMAND_MASTER_ENABLE | CARDBUS_COMMAND_MEM_ENABLE; - cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_COMMAND_STATUS_REG, - reg); + PCI_COMMAND_STATUS_REG); + reg |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE; + cardbus_conf_write(cc, cf, csc->sc_tag, PCI_COMMAND_STATUS_REG, reg); } diff --git a/sys/dev/cardbus/if_rtw_cardbus.c b/sys/dev/cardbus/if_rtw_cardbus.c index 5d9e407e92f4..1f82719a2b5e 100644 --- a/sys/dev/cardbus/if_rtw_cardbus.c +++ b/sys/dev/cardbus/if_rtw_cardbus.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_rtw_cardbus.c,v 1.22 2008/01/08 18:26:09 dyoung Exp $ */ +/* $NetBSD: if_rtw_cardbus.c,v 1.23 2008/03/12 18:02:21 dyoung Exp $ */ /*- * Copyright (c) 2004, 2005 David Young. All rights reserved. @@ -74,7 +74,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_rtw_cardbus.c,v 1.22 2008/01/08 18:26:09 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_rtw_cardbus.c,v 1.23 2008/03/12 18:02:21 dyoung Exp $"); #include "opt_inet.h" #include "bpfilter.h" @@ -141,14 +141,10 @@ struct rtw_cardbus_softc { * region */ - int sc_cben; /* CardBus enables */ int sc_bar_reg; /* which BAR to use */ pcireg_t sc_bar_val; /* value of the BAR */ int sc_intrline; /* interrupt line */ -#if 0 - struct cardbus_conf_state sc_conf; /* configuration regs */ -#endif }; int rtw_cardbus_match(device_t, struct cfdata *, void *); @@ -156,13 +152,12 @@ void rtw_cardbus_attach(device_t, device_t, void *); int rtw_cardbus_detach(device_t, int); CFATTACH_DECL_NEW(rtw_cardbus, sizeof(struct rtw_cardbus_softc), - rtw_cardbus_match, rtw_cardbus_attach, rtw_cardbus_detach, rtw_activate); + rtw_cardbus_match, rtw_cardbus_attach, rtw_cardbus_detach, NULL); void rtw_cardbus_setup(struct rtw_cardbus_softc *); -int rtw_cardbus_enable(struct rtw_softc *); -void rtw_cardbus_disable(struct rtw_softc *); -void rtw_cardbus_power(struct rtw_softc *, int); +bool rtw_cardbus_resume(device_t PMF_FN_PROTO); +bool rtw_cardbus_suspend(device_t PMF_FN_PROTO); const struct rtw_cardbus_product *rtw_cardbus_lookup( const struct cardbus_attach_args *); @@ -250,12 +245,6 @@ rtw_cardbus_attach(device_t parent, device_t self, void *aux) panic("rtw_cardbus_attach: impossible"); } - /* - * Power management hooks. - */ - sc->sc_enable = rtw_cardbus_enable; - sc->sc_disable = rtw_cardbus_disable; - sc->sc_intr_ack = rtw_cardbus_intr_ack; /* Get revision info. */ @@ -264,47 +253,42 @@ rtw_cardbus_attach(device_t parent, device_t self, void *aux) printf(": %s\n", rcp->rcp_product_name); RTW_DPRINTF(RTW_DEBUG_ATTACH, - ("%s: pass %d.%d signature %08x\n", device_xname(sc->sc_dev), + ("%s: pass %d.%d signature %08x\n", device_xname(self), (rev >> 4) & 0xf, rev & 0xf, cardbus_conf_read(ct->ct_cc, ct->ct_cf, csc->sc_tag, 0x80))); /* * Map the device. */ - csc->sc_csr = CARDBUS_COMMAND_MASTER_ENABLE; - if (Cardbus_mapreg_map(ct, RTW_PCI_MMBA, - CARDBUS_MAPREG_TYPE_MEM, 0, ®s->r_bt, ®s->r_bh, &adr, - &csc->sc_mapsize) == 0) { + csc->sc_csr = CARDBUS_COMMAND_MASTER_ENABLE | + CARDBUS_COMMAND_PARITY_ENABLE | + CARDBUS_COMMAND_SERR_ENABLE; + if (Cardbus_mapreg_map(ct, RTW_PCI_MMBA, CARDBUS_MAPREG_TYPE_MEM, 0, + ®s->r_bt, ®s->r_bh, &adr, ®s->r_sz) == 0) { RTW_DPRINTF(RTW_DEBUG_ATTACH, - ("%s: %s mapped %lu bytes mem space\n", - device_xname(sc->sc_dev), __func__, - (long)csc->sc_mapsize)); + ("%s: %s mapped %" PRIuMAX " bytes mem space\n", + device_xname(self), __func__, regs->r_sz)); #if rbus #else (*ct->ct_cf->cardbus_mem_open)(cc, 0, adr, adr+csc->sc_mapsize); #endif - csc->sc_cben = CARDBUS_MEM_ENABLE; csc->sc_csr |= CARDBUS_COMMAND_MEM_ENABLE; csc->sc_bar_reg = RTW_PCI_MMBA; csc->sc_bar_val = adr | CARDBUS_MAPREG_TYPE_MEM; - } else if (Cardbus_mapreg_map(ct, RTW_PCI_IOBA, - CARDBUS_MAPREG_TYPE_IO, 0, ®s->r_bt, ®s->r_bh, &adr, - &csc->sc_mapsize) == 0) { + } else if (Cardbus_mapreg_map(ct, RTW_PCI_IOBA, CARDBUS_MAPREG_TYPE_IO, + 0, ®s->r_bt, ®s->r_bh, &adr, ®s->r_sz) == 0) { RTW_DPRINTF(RTW_DEBUG_ATTACH, - ("%s: %s mapped %lu bytes I/O space\n", - device_xname(sc->sc_dev), __func__, - (long)csc->sc_mapsize)); + ("%s: %s mapped %" PRIuMAX " bytes I/O space\n", + device_xname(self), __func__, regs->r_sz)); #if rbus #else (*ct->ct_cf->cardbus_io_open)(cc, 0, adr, adr+csc->sc_mapsize); #endif - csc->sc_cben = CARDBUS_IO_ENABLE; csc->sc_csr |= CARDBUS_COMMAND_IO_ENABLE; csc->sc_bar_reg = RTW_PCI_IOBA; csc->sc_bar_val = adr | CARDBUS_MAPREG_TYPE_IO; } else { - aprint_error_dev(sc->sc_dev, - "unable to map device registers\n"); + aprint_error_dev(self, "unable to map device registers\n"); return; } @@ -317,7 +301,7 @@ rtw_cardbus_attach(device_t parent, device_t self, void *aux) /* Remember which interrupt line. */ csc->sc_intrline = ca->ca_intrline; - aprint_normal_dev(sc->sc_dev, "interrupting at %d\n", csc->sc_intrline); + aprint_normal_dev(self, "interrupting at %d\n", csc->sc_intrline); /* * Finish off the attach. */ @@ -328,14 +312,15 @@ rtw_cardbus_attach(device_t parent, device_t self, void *aux) RTW_WRITE(regs, RTW_FEMR, RTW_FEMR_INTR); RTW_WRITE(regs, RTW_FER, RTW_FER_INTR); -#if 0 - cardbus_conf_capture(ct->ct_cc, ct->ct_cf, csc->sc_tag, &csc->sc_conf); -#endif - - /* - * Power down the socket. - */ - Cardbus_function_disable(csc->sc_ct); + if (!pmf_device_register(self, rtw_cardbus_suspend, rtw_cardbus_resume)) + aprint_error_dev(self, "couldn't establish power handler\n"); + else { + pmf_class_network_register(self, &sc->sc_if); + /* + * Power down the socket. + */ + pmf_device_suspend_self(self); + } } int @@ -366,33 +351,20 @@ rtw_cardbus_detach(device_t self, int flags) */ if (csc->sc_bar_reg != 0) Cardbus_mapreg_unmap(ct, csc->sc_bar_reg, - regs->r_bt, regs->r_bh, csc->sc_mapsize); + regs->r_bt, regs->r_bh, regs->r_sz); return 0; } -int -rtw_cardbus_enable(struct rtw_softc *sc) +bool +rtw_cardbus_resume(device_t self PMF_FN_ARGS) { - struct rtw_cardbus_softc *csc = (void *) sc; + struct rtw_cardbus_softc *csc = device_private(self); + struct rtw_softc *sc = &csc->sc_rtw; cardbus_devfunc_t ct = csc->sc_ct; cardbus_chipset_tag_t cc = ct->ct_cc; cardbus_function_tag_t cf = ct->ct_cf; - /* - * Power on the socket. - */ - Cardbus_function_enable(ct); - -#if 0 - cardbus_conf_restore(cc, cf, csc->sc_tag, &csc->sc_conf); -#endif - - /* - * Set up the PCI configuration registers. - */ - rtw_cardbus_setup(csc); - /* * Map and establish the interrupt. */ @@ -401,8 +373,7 @@ rtw_cardbus_enable(struct rtw_softc *sc) if (csc->sc_ih == NULL) { aprint_error_dev(sc->sc_dev, "unable to establish interrupt at %d\n", csc->sc_intrline); - Cardbus_function_disable(csc->sc_ct); - return 1; + return false; } rtw_cardbus_funcregen(&sc->sc_regs, 1); @@ -410,17 +381,21 @@ rtw_cardbus_enable(struct rtw_softc *sc) RTW_WRITE(&sc->sc_regs, RTW_FEMR, RTW_FEMR_INTR); RTW_WRITE(&sc->sc_regs, RTW_FER, RTW_FER_INTR); - return 0; + return rtw_resume(self, flags); } -void -rtw_cardbus_disable(struct rtw_softc *sc) +bool +rtw_cardbus_suspend(device_t self PMF_FN_ARGS) { - struct rtw_cardbus_softc *csc = (void *) sc; + struct rtw_cardbus_softc *csc = device_private(self); + struct rtw_softc *sc = &csc->sc_rtw; cardbus_devfunc_t ct = csc->sc_ct; cardbus_chipset_tag_t cc = ct->ct_cc; cardbus_function_tag_t cf = ct->ct_cf; + if (!rtw_suspend(self, flags)) + return false; + RTW_WRITE(&sc->sc_regs, RTW_FEMR, RTW_READ(&sc->sc_regs, RTW_FEMR) & ~RTW_FEMR_INTR); @@ -429,13 +404,7 @@ rtw_cardbus_disable(struct rtw_softc *sc) /* Unhook the interrupt handler. */ cardbus_intr_disestablish(cc, cf, csc->sc_ih); csc->sc_ih = NULL; - -#if 0 - cardbus_conf_capture(cc, cf, csc->sc_tag, &csc->sc_conf); -#endif - - /* Power down the socket. */ - Cardbus_function_disable(ct); + return true; } void @@ -463,14 +432,9 @@ rtw_cardbus_setup(struct rtw_cardbus_softc *csc) /* Program the BAR. */ cardbus_conf_write(cc, cf, tag, csc->sc_bar_reg, csc->sc_bar_val); - /* Make sure the right access type is on the CardBus bridge. */ - (*ct->ct_cf->cardbus_ctrl)(cc, csc->sc_cben); - (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); - /* Enable the appropriate bits in the PCI CSR. */ csr = cardbus_conf_read(cc, cf, tag, PCI_COMMAND_STATUS_REG); csr &= ~(PCI_COMMAND_IO_ENABLE|PCI_COMMAND_MEM_ENABLE); csr |= csc->sc_csr; - csr |= CARDBUS_COMMAND_PARITY_ENABLE | CARDBUS_COMMAND_SERR_ENABLE; cardbus_conf_write(cc, cf, tag, PCI_COMMAND_STATUS_REG, csr); } diff --git a/sys/dev/ic/ath.c b/sys/dev/ic/ath.c index bc91b6a5e0e6..8097a7fab57d 100644 --- a/sys/dev/ic/ath.c +++ b/sys/dev/ic/ath.c @@ -1,4 +1,4 @@ -/* $NetBSD: ath.c,v 1.98 2008/01/04 21:17:54 ad Exp $ */ +/* $NetBSD: ath.c,v 1.99 2008/03/12 18:02:21 dyoung Exp $ */ /*- * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting @@ -41,7 +41,7 @@ __FBSDID("$FreeBSD: src/sys/dev/ath/if_ath.c,v 1.104 2005/09/16 10:09:23 ru Exp $"); #endif #ifdef __NetBSD__ -__KERNEL_RCSID(0, "$NetBSD: ath.c,v 1.98 2008/01/04 21:17:54 ad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ath.c,v 1.99 2008/03/12 18:02:21 dyoung Exp $"); #endif /* @@ -199,11 +199,6 @@ static void ath_restore_diversity(struct ath_softc *); static int ath_rate_setup(struct ath_softc *, u_int mode); static void ath_setcurmode(struct ath_softc *, enum ieee80211_phymode); -#ifdef __NetBSD__ -int ath_enable(struct ath_softc *); -void ath_disable(struct ath_softc *); -#endif - #if NBPFILTER > 0 static void ath_bpfattach(struct ath_softc *); #endif @@ -264,51 +259,6 @@ static void ath_printtxbuf(struct ath_buf *bf, int); #define KEYPRINTF(sc, k, ix, mac) #endif -#ifdef __NetBSD__ -int -ath_activate(struct device *self, enum devact act) -{ - struct ath_softc *sc = (struct ath_softc *)self; - int rv = 0, s; - - s = splnet(); - switch (act) { - case DVACT_ACTIVATE: - rv = EOPNOTSUPP; - break; - case DVACT_DEACTIVATE: - if_deactivate(&sc->sc_if); - break; - } - splx(s); - return rv; -} - -int -ath_enable(struct ath_softc *sc) -{ - if (ATH_IS_ENABLED(sc) == 0) { - if (sc->sc_enable != NULL && (*sc->sc_enable)(sc) != 0) { - printf("%s: device enable failed\n", - device_xname(&sc->sc_dev)); - return (EIO); - } - sc->sc_flags |= ATH_ENABLED; - } - return (0); -} - -void -ath_disable(struct ath_softc *sc) -{ - if (!ATH_IS_ENABLED(sc)) - return; - if (sc->sc_disable != NULL) - (*sc->sc_disable)(sc); - sc->sc_flags &= ~ATH_ENABLED; -} -#endif /* __NetBSD__ */ - MALLOC_DEFINE(M_ATHDEV, "athdev", "ath driver dma buffers"); int @@ -339,7 +289,10 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) goto bad; } sc->sc_ah = ah; - sc->sc_invalid = 0; /* ready to go, enable interrupt handling */ + + if (!prop_dictionary_set_bool(device_properties(&sc->sc_dev), + "pmf-powerdown", false)) + goto bad; /* * Check if the MAC has multi-rate retry support. @@ -655,7 +608,8 @@ bad2: bad: if (ah) ath_hal_detach(ah); - sc->sc_invalid = 1; + /* XXX don't get under the abstraction like this */ + sc->sc_dev.dv_flags &= ~DVF_ACTIVE; return error; } @@ -705,12 +659,45 @@ ath_detach(struct ath_softc *sc) } void +ath_suspend(struct ath_softc *sc) +{ + /* + * Set the chip in full sleep mode. Note that we are + * careful to do this only when bringing the interface + * completely to a stop. When the chip is in this state + * it must be carefully woken up or references to + * registers in the PCI clock domain may freeze the bus + * (and system). This varies by chip and is mostly an + * issue with newer parts that go to sleep more quickly. + */ + ath_hal_setpower(sc->sc_ah, HAL_PM_FULL_SLEEP); +} + +bool ath_resume(struct ath_softc *sc) { + int i; + struct ath_hal *ah = sc->sc_ah; + + ath_hal_setpower(ah, HAL_PM_AWAKE); + + /* + * Reset the key cache since some parts do not + * reset the contents on initial power up. + */ + for (i = 0; i < sc->sc_keymax; i++) + ath_hal_keyreset(ah, i); + + ath_hal_resettxqueue(ah, sc->sc_bhalq); + for (i = 0; i < HAL_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) + ath_hal_resettxqueue(ah, i); + if (sc->sc_softled) { ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin); ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !sc->sc_ledon); } + return true; } /* @@ -724,7 +711,7 @@ ath_intr(void *arg) struct ath_hal *ah = sc->sc_ah; HAL_INT status; - if (sc->sc_invalid) { + if (!device_is_active(&sc->sc_dev)) { /* * The hardware is not ready/present, don't touch anything. * Note this can happen early on if the IRQ is shared. @@ -946,15 +933,12 @@ ath_init(struct ath_softc *sc) DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags 0x%x\n", __func__, ifp->if_flags); - if (!device_has_power(&sc->sc_dev)) - return EBUSY; - - ATH_LOCK(sc); - - if ((error = ath_enable(sc)) != 0) { - ATH_UNLOCK(sc); - return error; - } + if (device_is_active(&sc->sc_dev)) { + ATH_LOCK(sc); + } else if (!pmf_device_resume_self(&sc->sc_dev)) + return ENXIO; + else + ATH_LOCK(sc); /* * Stop anything previously setup. This is safe @@ -1048,8 +1032,8 @@ ath_stop_locked(struct ifnet *ifp, int disable) struct ieee80211com *ic = &sc->sc_ic; struct ath_hal *ah = sc->sc_ah; - DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid %u if_flags 0x%x\n", - __func__, sc->sc_invalid, ifp->if_flags); + DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid %d if_flags 0x%x\n", + __func__, !device_is_enabled(&sc->sc_dev), ifp->if_flags); ATH_LOCK_ASSERT(sc); if (ifp->if_flags & IFF_RUNNING) { @@ -1075,7 +1059,7 @@ ath_stop_locked(struct ifnet *ifp, int disable) ieee80211_new_state(ic, IEEE80211_S_INIT, -1); ifp->if_flags &= ~IFF_RUNNING; ifp->if_timer = 0; - if (!sc->sc_invalid) { + if (device_is_enabled(&sc->sc_dev)) { if (sc->sc_softled) { callout_stop(&sc->sc_ledtimer); ath_hal_gpioset(ah, sc->sc_ledpin, @@ -1085,7 +1069,7 @@ ath_stop_locked(struct ifnet *ifp, int disable) ath_hal_intrset(ah, 0); } ath_draintxq(sc); - if (!sc->sc_invalid) { + if (device_is_enabled(&sc->sc_dev)) { ath_stoprecv(sc); ath_hal_phydisable(ah); } else @@ -1093,7 +1077,7 @@ ath_stop_locked(struct ifnet *ifp, int disable) IF_PURGE(&ifp->if_snd); ath_beacon_free(sc); if (disable) - ath_disable(sc); + pmf_device_suspend_self(&sc->sc_dev); } } @@ -1104,18 +1088,6 @@ ath_stop(struct ifnet *ifp, int disable) ATH_LOCK(sc); ath_stop_locked(ifp, disable); - if (!sc->sc_invalid) { - /* - * Set the chip in full sleep mode. Note that we are - * careful to do this only when bringing the interface - * completely to a stop. When the chip is in this state - * it must be carefully woken up or references to - * registers in the PCI clock domain may freeze the bus - * (and system). This varies by chip and is mostly an - * issue with newer parts that go to sleep more quickly. - */ - ath_hal_setpower(sc->sc_ah, HAL_PM_FULL_SLEEP); - } ATH_UNLOCK(sc); } @@ -1249,7 +1221,8 @@ ath_start(struct ifnet *ifp) struct ether_header *eh; ath_bufhead frags; - if ((ifp->if_flags & IFF_RUNNING) == 0 || sc->sc_invalid) + if ((ifp->if_flags & IFF_RUNNING) == 0 || + !device_is_active(&sc->sc_dev)) return; for (;;) { /* @@ -1730,6 +1703,11 @@ ath_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k) DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: delete key %u\n", __func__, keyix); + if (!device_has_power(&sc->sc_dev)) { + aprint_error_dev(&sc->sc_dev, "deleting keyix %d w/o power\n", + k->wk_keyix); + } + ath_hal_keyreset(ah, keyix); /* * Handle split tx/rx keying required for TKIP with h/w MIC. @@ -1764,6 +1742,10 @@ ath_key_set(struct ieee80211com *ic, const struct ieee80211_key *k, { struct ath_softc *sc = ic->ic_ifp->if_softc; + if (!device_has_power(&sc->sc_dev)) { + aprint_error_dev(&sc->sc_dev, "setting keyix %d w/o power\n", + k->wk_keyix); + } return ath_keyset(sc, k, mac, ic->ic_bss); } @@ -1838,50 +1820,17 @@ ath_calcrxfilter(struct ath_softc *sc, enum ieee80211_state state) return rfilt; } -static void -ath_mcastfilter_accum(void *dl, u_int32_t *mfilt) -{ - u_int32_t val; - u_int8_t pos; - - /* calculate XOR of eight 6bit values */ - val = LE_READ_4((char *)dl + 0); - pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; - val = LE_READ_4((char *)dl + 3); - pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; - pos &= 0x3f; - mfilt[pos / 32] |= (1 << (pos % 32)); -} - -static void -ath_mcastfilter_compute(struct ath_softc *sc, u_int32_t *mfilt) -{ - struct ifnet *ifp = &sc->sc_if; - struct ether_multi *enm; - struct ether_multistep estep; - - mfilt[0] = mfilt[1] = 0; - ETHER_FIRST_MULTI(estep, &sc->sc_ec, enm); - while (enm != NULL) { - /* XXX Punt on ranges. */ - if (!IEEE80211_ADDR_EQ(enm->enm_addrlo, enm->enm_addrhi)) { - mfilt[0] = mfilt[1] = ~((u_int32_t)0); - ifp->if_flags |= IFF_ALLMULTI; - return; - } - ath_mcastfilter_accum(enm->enm_addrlo, mfilt); - ETHER_NEXT_MULTI(estep, enm); - } - ifp->if_flags &= ~IFF_ALLMULTI; -} - static void ath_mode_init(struct ath_softc *sc) { + struct ifnet *ifp = &sc->sc_if; struct ieee80211com *ic = &sc->sc_ic; struct ath_hal *ah = sc->sc_ah; - u_int32_t rfilt, mfilt[2]; + struct ether_multi *enm; + struct ether_multistep estep; + u_int32_t rfilt, mfilt[2], val; int i; + uint8_t pos; /* configure rx filter */ rfilt = ath_calcrxfilter(sc, ic->ic_state); @@ -1911,30 +1860,28 @@ ath_mode_init(struct ath_softc *sc) ath_hal_setmac(ah, ic->ic_myaddr); /* calculate and install multicast filter */ -#ifdef __FreeBSD__ - if ((ifp->if_flags & IFF_ALLMULTI) == 0) { - mfilt[0] = mfilt[1] = 0; - IF_ADDR_LOCK(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - void *dl; - - /* calculate XOR of eight 6bit values */ - dl = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); - val = LE_READ_4((char *)dl + 0); - pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; - val = LE_READ_4((char *)dl + 3); - pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; - pos &= 0x3f; - mfilt[pos / 32] |= (1 << (pos % 32)); + ifp->if_flags &= ~IFF_ALLMULTI; + mfilt[0] = mfilt[1] = 0; + ETHER_FIRST_MULTI(estep, &sc->sc_ec, enm); + while (enm != NULL) { + void *dl; + /* XXX Punt on ranges. */ + if (!IEEE80211_ADDR_EQ(enm->enm_addrlo, enm->enm_addrhi)) { + mfilt[0] = mfilt[1] = 0xffffffff; + ifp->if_flags |= IFF_ALLMULTI; + break; } - IF_ADDR_UNLOCK(ifp); - } else { - mfilt[0] = mfilt[1] = ~0; + dl = enm->enm_addrlo; + val = LE_READ_4((char *)dl + 0); + pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; + val = LE_READ_4((char *)dl + 3); + pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; + pos &= 0x3f; + mfilt[pos / 32] |= (1 << (pos % 32)); + + ETHER_NEXT_MULTI(estep, enm); } -#endif -#ifdef __NetBSD__ - ath_mcastfilter_compute(sc, mfilt); -#endif + ath_hal_setmcastfilter(ah, mfilt[0], mfilt[1]); DPRINTF(sc, ATH_DEBUG_MODE, "%s: RX filter 0x%x, MC filter %08x:%08x\n", __func__, rfilt, mfilt[0], mfilt[1]); @@ -4216,7 +4163,7 @@ ath_draintxq(struct ath_softc *sc) int i; /* XXX return value */ - if (!sc->sc_invalid) { + if (device_is_active(&sc->sc_dev)) { /* don't touch the hardware if marked invalid */ (void) ath_hal_stoptxdma(ah, sc->sc_bhalq); DPRINTF(sc, ATH_DEBUG_RESET, @@ -5051,11 +4998,12 @@ ath_printrxbuf(struct ath_buf *bf, int done) for (i = 0, ds = bf->bf_desc; i < bf->bf_nseg; i++, ds++) { printf("R%d (%p %" PRIx64 - ") %08x %08x %08x %08x %08x %08x %c\n", i, ds, + ") %08x %08x %08x %08x %08x %08x %02x %02x %c\n", i, ds, (uint64_t)bf->bf_daddr + sizeof (struct ath_desc) * i, ds->ds_link, ds->ds_data, ds->ds_ctl0, ds->ds_ctl1, ds->ds_hw[0], ds->ds_hw[1], + ds->ds_rxstat.rs_status, ds->ds_rxstat.rs_keyix, !done ? ' ' : (ds->ds_rxstat.rs_status == 0) ? '*' : '!'); } } @@ -5088,7 +5036,8 @@ ath_watchdog(struct ifnet *ifp) int i; ifp->if_timer = 0; - if ((ifp->if_flags & IFF_RUNNING) == 0 || sc->sc_invalid) + if ((ifp->if_flags & IFF_RUNNING) == 0 || + !device_is_active(&sc->sc_dev)) return; for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { if (!ATH_TXQ_SETUP(sc, i)) @@ -5202,9 +5151,8 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, void *data) * torn down much of our state. There's * probably a better way to deal with this. */ - if (!sc->sc_invalid && ic->ic_bss != NULL) - ath_init(sc); /* XXX lose error */ - } else + error = ath_init(sc); + } else if (device_is_active(&sc->sc_dev)) ath_stop_locked(ifp, 1); break; case SIOCADDMULTI: @@ -5234,14 +5182,13 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, void *data) break; default: error = ieee80211_ioctl(ic, cmd, data); - if (error == ENETRESET) { - if (IS_RUNNING(ifp) && - ic->ic_roaming != IEEE80211_ROAMING_MANUAL) - ath_init(sc); /* XXX lose error */ + if (error != ENETRESET) + ; + else if (IS_RUNNING(ifp) && + ic->ic_roaming != IEEE80211_ROAMING_MANUAL) + error = ath_init(sc); + else error = 0; - } - if (error == ERESTART) - error = IS_RUNNING(ifp) ? ath_reset(ifp) : 0; break; } ATH_UNLOCK(sc); diff --git a/sys/dev/ic/athvar.h b/sys/dev/ic/athvar.h index 84f47ecf859a..13b2a1f03535 100644 --- a/sys/dev/ic/athvar.h +++ b/sys/dev/ic/athvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: athvar.h,v 1.23 2007/12/22 00:41:02 dyoung Exp $ */ +/* $NetBSD: athvar.h,v 1.24 2008/03/12 18:02:21 dyoung Exp $ */ /*- * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting @@ -170,8 +170,6 @@ struct ath_softc { struct ethercom sc_ec; /* interface common */ struct ath_stats sc_stats; /* interface statistics */ struct ieee80211com sc_ic; /* IEEE 802.11 common */ - int (*sc_enable)(struct ath_softc *); - void (*sc_disable)(struct ath_softc *); void (*sc_power)(struct ath_softc *, int); int sc_regdomain; int sc_countrycode; @@ -192,8 +190,7 @@ struct ath_softc { struct ath_ratectrl *sc_rc; /* tx rate control support */ struct ath_tx99 *sc_tx99; /* tx99 adjunct state */ void (*sc_setdefantenna)(struct ath_softc *, u_int); - unsigned int sc_invalid : 1, /* disable hardware accesses */ - sc_mrretry : 1, /* multi-rate retry support */ + unsigned int sc_mrretry : 1, /* multi-rate retry support */ sc_softled : 1, /* enable LED gpio status */ sc_splitmic: 1, /* split TKIP MIC keys */ sc_needmib : 1, /* enable MIB stats intr */ @@ -297,16 +294,14 @@ struct ath_softc { #define sc_rx_th u_rx_rt.th #define ATH_ATTACHED 0x0001 /* attach has succeeded */ -#define ATH_ENABLED 0x0002 /* chip is enabled */ - -#define ATH_IS_ENABLED(sc) ((sc)->sc_flags & ATH_ENABLED) #define ATH_TXQ_SETUP(sc, i) ((sc)->sc_txqsetup & (1< -__KERNEL_RCSID(0, "$NetBSD: rtw.c,v 1.100 2008/03/12 15:47:49 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: rtw.c,v 1.101 2008/03/12 18:02:21 dyoung Exp $"); #include "bpfilter.h" @@ -92,6 +92,11 @@ static int rtw_rxbufs_limit = RTW_RXQLEN; int rtw_dwelltime = 200; /* milliseconds */ static struct ieee80211_cipher rtw_cipher_wep; +static void rtw_disable_interrupts(struct rtw_regs *); +static void rtw_enable_interrupts(struct rtw_softc *); + +static int rtw_init(struct ifnet *); + static void rtw_start(struct ifnet *); static void rtw_reset_oactive(struct rtw_softc *); static struct mbuf *rtw_beacon_alloc(struct rtw_softc *, @@ -108,6 +113,7 @@ static int rtw_wep_decap(struct ieee80211_key *, struct mbuf *, int); static void rtw_wep_setkeys(struct rtw_softc *, struct ieee80211_key *, int); static void rtw_led_attach(struct rtw_led_state *, void *); +static void rtw_led_detach(struct rtw_led_state *); static void rtw_led_init(struct rtw_regs *); static void rtw_led_slowblink(void *); static void rtw_led_fastblink(void *); @@ -599,8 +605,7 @@ rtw_key_update_end(struct ieee80211com *ic) DPRINTF(sc, RTW_DEBUG_KEY, ("%s:\n", __func__)); if ((sc->sc_flags & RTW_F_DK_VALID) != 0 || - (sc->sc_flags & RTW_F_ENABLED) == 0 || - (sc->sc_flags & RTW_F_INVALID) != 0) + !device_is_active(sc->sc_dev)) return; rtw_io_enable(sc, RTW_CR_RE | RTW_CR_TE, 0); @@ -1518,7 +1523,10 @@ rtw_intr_rx(struct rtw_softc *sc, uint16_t isr) goto next; } if (len > rs->rs_mbuf->m_len) { - aprint_error_dev(sc->sc_dev, "rx frame too long\n"); + aprint_error_dev(sc->sc_dev, + "rx frame too long, %d > %d, %08" PRIx32 + ", desc %d\n", + len, rs->rs_mbuf->m_len, hstat, next); ifp->if_ierrors++; goto next; } @@ -2107,8 +2115,7 @@ rtw_intr(void *arg) * If the interface isn't running, the interrupt couldn't * possibly have come from us. */ - if ((sc->sc_flags & RTW_F_ENABLED) == 0 || - (ifp->if_flags & IFF_RUNNING) == 0 || + if ((ifp->if_flags & IFF_RUNNING) == 0 || !device_is_active(sc->sc_dev)) { RTW_DPRINTF(RTW_DEBUG_INTR, ("%s: stray interrupt\n", device_xname(sc->sc_dev))); @@ -2189,14 +2196,11 @@ rtw_stop(struct ifnet *ifp, int disable) struct ieee80211com *ic = &sc->sc_ic; struct rtw_regs *regs = &sc->sc_regs; - if ((sc->sc_flags & RTW_F_ENABLED) == 0) - return; - rtw_suspend_ticks(sc); ieee80211_new_state(ic, IEEE80211_S_INIT, -1); - if ((sc->sc_flags & RTW_F_INVALID) == 0) { + if (device_has_power(sc->sc_dev)) { /* Disable interrupts. */ RTW_WRITE16(regs, RTW_IMR, 0); @@ -2219,13 +2223,13 @@ rtw_stop(struct ifnet *ifp, int disable) rtw_rxbufs_release(sc->sc_dmat, &sc->sc_rxsoft[0]); - if (disable) - rtw_disable(sc); - /* Mark the interface as not running. Cancel the watchdog timer. */ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); ifp->if_timer = 0; + if (disable) + pmf_device_suspend_self(sc->sc_dev); + return; } @@ -2448,7 +2452,7 @@ rtw_tune(struct rtw_softc *sc) /* TBD wait for Tx to complete */ - KASSERT((sc->sc_flags & RTW_F_ENABLED) != 0); + KASSERT(device_has_power(sc->sc_dev)); if ((rc = rtw_phy_init(&sc->sc_regs, sc->sc_rf, rtw_chan2txpower(&sc->sc_srom, ic, ic->ic_curchan), sc->sc_csthr, @@ -2466,43 +2470,39 @@ rtw_tune(struct rtw_softc *sc) return rc; } -void -rtw_disable(struct rtw_softc *sc) +bool +rtw_suspend(device_t self PMF_FN_ARGS) { int rc; + struct rtw_softc *sc = device_private(self); - if ((sc->sc_flags & RTW_F_ENABLED) == 0) - return; + sc->sc_flags &= ~RTW_F_DK_VALID; + + if (!device_has_power(self)) + return false; /* turn off PHY */ - if ((sc->sc_flags & RTW_F_INVALID) == 0 && - (rc = rtw_pwrstate(sc, RTW_OFF)) != 0) { - aprint_error_dev(sc->sc_dev, - "failed to turn off PHY (%d)\n", rc); + if ((rc = rtw_pwrstate(sc, RTW_OFF)) != 0) { + aprint_error_dev(self, "failed to turn off PHY (%d)\n", rc); + return false; } - if (sc->sc_disable != NULL) - (*sc->sc_disable)(sc); + rtw_disable_interrupts(&sc->sc_regs); - sc->sc_flags &= ~RTW_F_ENABLED; + return true; } -int -rtw_enable(struct rtw_softc *sc) +bool +rtw_resume(device_t self PMF_FN_ARGS) { - if ((sc->sc_flags & RTW_F_ENABLED) == 0) { - if (sc->sc_enable != NULL && (*sc->sc_enable)(sc) != 0) { - aprint_error_dev(sc->sc_dev, - "device enable failed\n"); - return (EIO); - } - sc->sc_flags |= RTW_F_ENABLED; - /* Power may have been removed, and WEP keys thus - * reset. - */ - sc->sc_flags &= ~RTW_F_DK_VALID; - } - return (0); + struct rtw_softc *sc = device_private(self); + + /* Power may have been removed, resetting WEP keys. + */ + sc->sc_flags &= ~RTW_F_DK_VALID; + rtw_enable_interrupts(sc); + + return true; } static void @@ -2529,7 +2529,16 @@ rtw_transmit_config(struct rtw_regs *regs) RTW_SYNC(regs, RTW_TCR, RTW_TCR); } -static inline void +static void +rtw_disable_interrupts(struct rtw_regs *regs) +{ + RTW_WRITE16(regs, RTW_IMR, 0); + RTW_WBW(regs, RTW_IMR, RTW_ISR); + RTW_WRITE16(regs, RTW_ISR, 0xffff); + RTW_SYNC(regs, RTW_IMR, RTW_ISR); +} + +static void rtw_enable_interrupts(struct rtw_softc *sc) { struct rtw_regs *regs = &sc->sc_regs; @@ -2685,13 +2694,13 @@ rtw_init(struct ifnet *ifp) struct rtw_softc *sc = (struct rtw_softc *)ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; struct rtw_regs *regs = &sc->sc_regs; - int rc = 0; + int rc; - if ((rc = rtw_enable(sc)) != 0) - goto out; - - /* Cancel pending I/O and reset. */ - rtw_stop(ifp, 0); + if (device_is_active(sc->sc_dev)) { + /* Cancel pending I/O and reset. */ + rtw_stop(ifp, 0); + } else if (!pmf_device_resume_self(sc->sc_dev)) + return 0; /* XXX error? */ DPRINTF(sc, RTW_DEBUG_TUNE, ("%s: channel %d freq %d flags 0x%04x\n", __func__, ieee80211_chan2ieee(ic, ic->ic_curchan), @@ -2800,6 +2809,7 @@ rtw_led_newstate(struct rtw_softc *sc, enum ieee80211_state nstate) switch (nstate) { case IEEE80211_S_INIT: rtw_led_init(&sc->sc_regs); + aprint_debug_dev(sc->sc_dev, "stopping blink\n"); callout_stop(&ls->ls_slow_ch); callout_stop(&ls->ls_fast_ch); ls->ls_slowblink = 0; @@ -2807,6 +2817,7 @@ rtw_led_newstate(struct rtw_softc *sc, enum ieee80211_state nstate) ls->ls_default = 0; break; case IEEE80211_S_SCAN: + aprint_debug_dev(sc->sc_dev, "scheduling blink\n"); callout_schedule(&ls->ls_slow_ch, RTW_LED_SLOW_TICKS); callout_schedule(&ls->ls_fast_ch, RTW_LED_FAST_TICKS); /*FALLTHROUGH*/ @@ -2896,6 +2907,7 @@ rtw_led_fastblink(void *arg) rtw_led_set(ls, &sc->sc_regs, sc->sc_hwverid); splx(s); + aprint_debug_dev(sc->sc_dev, "scheduling fast blink\n"); callout_schedule(&ls->ls_fast_ch, RTW_LED_FAST_TICKS); } @@ -2910,10 +2922,18 @@ rtw_led_slowblink(void *arg) ls->ls_state ^= RTW_LED_S_SLOW; rtw_led_set(ls, &sc->sc_regs, sc->sc_hwverid); splx(s); + aprint_debug_dev(sc->sc_dev, "scheduling slow blink\n"); callout_schedule(&ls->ls_slow_ch, RTW_LED_SLOW_TICKS); } -static inline void +static void +rtw_led_detach(struct rtw_led_state *ls) +{ + callout_destroy(&ls->ls_fast_ch); + callout_destroy(&ls->ls_slow_ch); +} + +static void rtw_led_attach(struct rtw_led_state *ls, void *arg) { callout_init(&ls->ls_fast_ch, 0); @@ -2931,12 +2951,12 @@ rtw_ioctl(struct ifnet *ifp, u_long cmd, void *data) s = splnet(); if (cmd == SIOCSIFFLAGS) { if ((ifp->if_flags & IFF_UP) != 0) { - if ((sc->sc_flags & RTW_F_ENABLED) != 0) + if (device_is_active(sc->sc_dev)) rtw_pktfilt_load(sc); else rc = rtw_init(ifp); RTW_PRINT_REGS(&sc->sc_regs, ifp->if_xname, __func__); - } else if ((sc->sc_flags & RTW_F_ENABLED) != 0) { + } else if (device_is_active(sc->sc_dev)) { RTW_PRINT_REGS(&sc->sc_regs, ifp->if_xname, __func__); rtw_stop(ifp, 1); } @@ -2947,8 +2967,7 @@ rtw_ioctl(struct ifnet *ifp, u_long cmd, void *data) if (ifp->if_flags & IFF_RUNNING) rtw_pktfilt_load(sc); rc = 0; - } else if ((sc->sc_flags & RTW_F_ENABLED) != 0) - /* reinitialize h/w if activated */ + } else if ((ifp->if_flags & IFF_UP) != 0) rc = rtw_init(ifp); else rc = 0; @@ -3463,7 +3482,7 @@ rtw_watchdog(struct ifnet *ifp) ifp->if_timer = 0; - if ((sc->sc_flags & RTW_F_ENABLED) == 0) + if (!device_is_active(sc->sc_dev)) return; for (pri = 0; pri < RTW_NTXPRI; pri++) { @@ -3554,8 +3573,10 @@ rtw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) ostate = ic->ic_state; + aprint_debug_dev(sc->sc_dev, "%s: l.%d\n", __func__, __LINE__); rtw_led_newstate(sc, nstate); + aprint_debug_dev(sc->sc_dev, "%s: l.%d\n", __func__, __LINE__); if (nstate == IEEE80211_S_INIT) { callout_stop(&sc->sc_scan_ch); sc->sc_cur_chan = IEEE80211_CHAN_ANY; @@ -3636,7 +3657,8 @@ rtw_recv_mgmt(struct ieee80211com *ic, struct mbuf *m, case IEEE80211_FC0_SUBTYPE_PROBE_RESP: case IEEE80211_FC0_SUBTYPE_BEACON: if (ic->ic_opmode == IEEE80211_M_IBSS && - ic->ic_state == IEEE80211_S_RUN) { + ic->ic_state == IEEE80211_S_RUN && + device_is_active(sc->sc_dev)) { uint64_t tsf = rtw_tsf_extend(&sc->sc_regs, rstamp); if (le64toh(ni->ni_tstamp.tsf) >= tsf) (void)ieee80211_ibss_merge(ni); @@ -3693,7 +3715,7 @@ rtw_media_status(struct ifnet *ifp, struct ifmediareq *imr) { struct rtw_softc *sc = ifp->if_softc; - if ((sc->sc_flags & RTW_F_ENABLED) == 0) { + if (!device_is_active(sc->sc_dev)) { imr->ifm_active = IFM_IEEE80211 | IFM_NONE; imr->ifm_status = 0; return; @@ -4131,12 +4153,6 @@ rtw_attach(struct rtw_softc *sc) sizeof(struct ieee80211_frame) + 64, &sc->sc_radiobpf); #endif - if (!pmf_device_register(sc->sc_dev, NULL, NULL)) { - aprint_error_dev(sc->sc_dev, - "couldn't establish power handler\n"); - } else - pmf_class_network_register(sc->sc_dev, &sc->sc_if); - NEXT_ATTACH_STATE(sc, FINISHED); ieee80211_announce(ic); @@ -4153,7 +4169,6 @@ rtw_detach(struct rtw_softc *sc) int pri, s; s = splnet(); - sc->sc_flags |= RTW_F_INVALID; switch (sc->sc_attach_state) { case FINISHED: @@ -4163,6 +4178,7 @@ rtw_detach(struct rtw_softc *sc) callout_stop(&sc->sc_scan_ch); ieee80211_ifdetach(&sc->sc_ic); if_detach(ifp); + rtw_led_detach(&sc->sc_led_state); /*FALLTHROUGH*/ case FINISH_ID_STA: case FINISH_RF_ATTACH: @@ -4210,23 +4226,3 @@ rtw_detach(struct rtw_softc *sc) splx(s); return 0; } - -int -rtw_activate(device_t self, enum devact act) -{ - struct rtw_softc *sc = device_private(self); - int rc = 0, s; - - s = splnet(); - switch (act) { - case DVACT_ACTIVATE: - rc = EOPNOTSUPP; - break; - - case DVACT_DEACTIVATE: - if_deactivate(&sc->sc_if); - break; - } - splx(s); - return rc; -} diff --git a/sys/dev/ic/rtwvar.h b/sys/dev/ic/rtwvar.h index c5e6a217faf2..f83971f2d26a 100644 --- a/sys/dev/ic/rtwvar.h +++ b/sys/dev/ic/rtwvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: rtwvar.h,v 1.36 2007/12/25 18:33:39 perry Exp $ */ +/* $NetBSD: rtwvar.h,v 1.37 2008/03/12 18:02:21 dyoung Exp $ */ /*- * Copyright (c) 2004, 2005 David Young. All rights reserved. * @@ -94,18 +94,14 @@ enum rtw_rfchipid { RTW_RFCHIPID_MAXIM = 4, RTW_RFCHIPID_GCT = 5 }; - /* sc_flags */ -#define RTW_F_ENABLED 0x00000001 /* chip is enabled */ #define RTW_F_DIGPHY 0x00000002 /* digital PHY */ #define RTW_F_DFLANTB 0x00000004 /* B antenna is default */ #define RTW_F_ANTDIV 0x00000010 /* h/w antenna diversity */ #define RTW_F_9356SROM 0x00000020 /* 93c56 SROM */ -#define RTW_F_SLEEP 0x00000040 /* chip is asleep */ -#define RTW_F_INVALID 0x00000080 /* chip is absent */ -#define RTW_F_DK_VALID 0x00000100 /* keys in DK0-DK3 are valid */ -#define RTW_C_RXWEP_40 0x00000200 /* h/w decrypts 40-bit WEP */ -#define RTW_C_RXWEP_104 0x00000400 /* h/w decrypts 104-bit WEP */ +#define RTW_F_DK_VALID 0x00000040 /* keys in DK0-DK3 are valid */ +#define RTW_C_RXWEP_40 0x00000080 /* h/w decrypts 40-bit WEP */ +#define RTW_C_RXWEP_104 0x00000100 /* h/w decrypts 104-bit WEP */ /* all PHY flags */ #define RTW_F_ALLPHY (RTW_F_DIGPHY|RTW_F_DFLANTB|RTW_F_ANTDIV) enum rtw_access {RTW_ACCESS_NONE = 0, @@ -115,6 +111,7 @@ enum rtw_access {RTW_ACCESS_NONE = 0, struct rtw_regs { bus_space_tag_t r_bt; bus_space_handle_t r_bh; + bus_size_t r_sz; enum rtw_access r_access; }; @@ -459,8 +456,6 @@ struct rtw_softc { /* interrupt acknowledge hook */ void (*sc_intr_ack)(struct rtw_regs *); - int (*sc_enable)(struct rtw_softc *); - void (*sc_disable)(struct rtw_softc *); struct rtw_mtbl sc_mtbl; void * sc_radiobpf; @@ -507,11 +502,10 @@ void rtw_attach(struct rtw_softc *); int rtw_detach(struct rtw_softc *); int rtw_intr(void *); -void rtw_disable(struct rtw_softc *); -int rtw_enable(struct rtw_softc *); +bool rtw_suspend(device_t PMF_FN_PROTO); +bool rtw_resume(device_t PMF_FN_PROTO); int rtw_activate(device_t, enum devact); -void rtw_shutdown(void *); const char *rtw_pwrstate_string(enum rtw_pwrstate); diff --git a/sys/dev/pci/if_ath_pci.c b/sys/dev/pci/if_ath_pci.c index ed793f19a914..9750be549b74 100644 --- a/sys/dev/pci/if_ath_pci.c +++ b/sys/dev/pci/if_ath_pci.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_ath_pci.c,v 1.29 2008/03/07 22:17:03 dyoung Exp $ */ +/* $NetBSD: if_ath_pci.c,v 1.30 2008/03/12 18:02:21 dyoung Exp $ */ /*- * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting @@ -41,7 +41,7 @@ __FBSDID("$FreeBSD: src/sys/dev/ath/if_ath_pci.c,v 1.11 2005/01/18 18:08:16 sam Exp $"); #endif #ifdef __NetBSD__ -__KERNEL_RCSID(0, "$NetBSD: if_ath_pci.c,v 1.29 2008/03/07 22:17:03 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_ath_pci.c,v 1.30 2008/03/12 18:02:21 dyoung Exp $"); #endif /* @@ -84,6 +84,7 @@ struct ath_pci_softc { struct ath_softc sc_sc; pci_chipset_tag_t sc_pc; pcitag_t sc_pcitag; + pci_intr_handle_t sc_pih; void *sc_ih; /* interrupt handler */ bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; @@ -92,10 +93,10 @@ struct ath_pci_softc { #define BS_BAR 0x10 -static void ath_pci_attach(struct device *, struct device *, void *); -static int ath_pci_detach(struct device *, int); -static int ath_pci_match(struct device *, struct cfdata *, void *); -static int ath_pci_detach(struct device *, int); +static void ath_pci_attach(device_t, device_t, void *); +static int ath_pci_detach(device_t, int); +static int ath_pci_match(device_t, struct cfdata *, void *); +static int ath_pci_detach(device_t, int); CFATTACH_DECL(ath_pci, sizeof(struct ath_pci_softc), @@ -105,7 +106,7 @@ CFATTACH_DECL(ath_pci, NULL); static int -ath_pci_match(struct device *parent, struct cfdata *match, void *aux) +ath_pci_match(device_t parent, struct cfdata *match, void *aux) { const char* devname; struct pci_attach_args *pa = aux; @@ -117,10 +118,28 @@ ath_pci_match(struct device *parent, struct cfdata *match, void *aux) } static bool -ath_pci_resume(device_t dv) +ath_pci_suspend(device_t self PMF_FN_ARGS) { - struct ath_pci_softc *sc = device_private(dv); + struct ath_pci_softc *sc = device_private(self); + ath_suspend(&sc->sc_sc); + pci_intr_disestablish(sc->sc_pc, sc->sc_ih); + sc->sc_ih = NULL; + + return true; +} + +static bool +ath_pci_resume(device_t self PMF_FN_ARGS) +{ + struct ath_pci_softc *sc = device_private(self); + + sc->sc_ih = pci_intr_establish(sc->sc_pc, sc->sc_pih, IPL_NET, ath_intr, + &sc->sc_sc); + if (sc->sc_ih == NULL) { + aprint_error_dev(self, "couldn't map interrupt\n"); + return false; + } ath_resume(&sc->sc_sc); return true; @@ -180,13 +199,12 @@ ath_pci_setup(struct ath_pci_softc *sc) } static void -ath_pci_attach(struct device *parent, struct device *self, void *aux) +ath_pci_attach(device_t parent, device_t self, void *aux) { - struct ath_pci_softc *psc = (struct ath_pci_softc *)self; + struct ath_pci_softc *psc = device_private(self); struct ath_softc *sc = &psc->sc_sc; struct pci_attach_args *pa = aux; pci_chipset_tag_t pc = pa->pa_pc; - pci_intr_handle_t ih; pcireg_t mem_type; const char *intrstr = NULL; @@ -215,37 +233,39 @@ ath_pci_attach(struct device *parent, struct device *self, void *aux) sc->sc_st = HALTAG(psc->sc_iot); sc->sc_sh = HALHANDLE(psc->sc_ioh); - sc->sc_invalid = 1; - /* * Arrange interrupt line. */ - if (pci_intr_map(pa, &ih)) { + if (pci_intr_map(pa, &psc->sc_pih)) { aprint_error("couldn't map interrupt\n"); goto bad1; } - intrstr = pci_intr_string(pc, ih); - psc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, ath_intr, sc); + intrstr = pci_intr_string(pc, psc->sc_pih); + psc->sc_ih = pci_intr_establish(pc, psc->sc_pih, IPL_NET, ath_intr, sc); if (psc->sc_ih == NULL) { aprint_error("couldn't map interrupt\n"); goto bad2; } - printf("\n"); - printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); + aprint_normal("\n"); + aprint_verbose_dev(self, "interrupting at %s\n", intrstr); sc->sc_dmat = pa->pa_dmat; ATH_LOCK_INIT(sc); - if (!pmf_device_register(self, NULL, ath_pci_resume)) - aprint_error_dev(self, "couldn't establish power handler\n"); + if (ath_attach(PCI_PRODUCT(pa->pa_id), sc) != 0) + goto bad3; - if (ath_attach(PCI_PRODUCT(pa->pa_id), sc) == 0) { + if (!pmf_device_register(self, ath_pci_suspend, ath_pci_resume)) + aprint_error_dev(self, "couldn't establish power handler\n"); + else { pmf_class_network_register(self, &sc->sc_if); - return; + pmf_device_suspend_self(self); } + return; +bad3: ATH_LOCK_DESTROY(sc); pci_intr_disestablish(pc, psc->sc_ih); @@ -257,9 +277,9 @@ bad: /* XXX */ } static int -ath_pci_detach(struct device *self, int flags) +ath_pci_detach(device_t self, int flags) { - struct ath_pci_softc *psc = (struct ath_pci_softc *)self; + struct ath_pci_softc *psc = device_private(self); ath_detach(&psc->sc_sc); pmf_device_deregister(self); diff --git a/sys/dev/pci/if_rtw_pci.c b/sys/dev/pci/if_rtw_pci.c index edb540c4aabb..04bf431831fd 100644 --- a/sys/dev/pci/if_rtw_pci.c +++ b/sys/dev/pci/if_rtw_pci.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_rtw_pci.c,v 1.9 2007/12/21 18:22:44 dyoung Exp $ */ +/* $NetBSD: if_rtw_pci.c,v 1.10 2008/03/12 18:02:21 dyoung Exp $ */ /*- * Copyright (c) 1998, 1999, 2000, 2002 The NetBSD Foundation, Inc. @@ -46,7 +46,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_rtw_pci.c,v 1.9 2007/12/21 18:22:44 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_rtw_pci.c,v 1.10 2008/03/12 18:02:21 dyoung Exp $"); #include #include @@ -98,9 +98,10 @@ struct rtw_pci_softc { static int rtw_pci_match(device_t, struct cfdata *, void *); static void rtw_pci_attach(device_t, device_t, void *); +static int rtw_pci_detach(device_t, int); CFATTACH_DECL_NEW(rtw_pci, sizeof(struct rtw_pci_softc), - rtw_pci_match, rtw_pci_attach, NULL, NULL); + rtw_pci_match, rtw_pci_attach, rtw_pci_detach, NULL); static const struct rtw_pci_product { u_int32_t app_vendor; /* PCI vendor ID */ @@ -141,30 +142,35 @@ rtw_pci_match(device_t parent, struct cfdata *match, void *aux) return (0); } -static int -rtw_pci_enable(struct rtw_softc *sc) +static bool +rtw_pci_resume(device_t self PMF_FN_ARGS) { - struct rtw_pci_softc *psc = (void *)sc; + struct rtw_pci_softc *psc = device_private(self); + struct rtw_softc *sc = &psc->psc_rtw; /* Establish the interrupt. */ psc->psc_intrcookie = pci_intr_establish(psc->psc_pc, psc->psc_ih, IPL_NET, rtw_intr, sc); if (psc->psc_intrcookie == NULL) { aprint_error_dev(sc->sc_dev, "unable to establish interrupt\n"); - return (1); + return false; } - return (0); + return rtw_resume(self, flags); } -static void -rtw_pci_disable(struct rtw_softc *sc) +static bool +rtw_pci_suspend(device_t self PMF_FN_ARGS) { - struct rtw_pci_softc *psc = (void *)sc; + struct rtw_pci_softc *psc = device_private(self); + + if (!rtw_suspend(self, flags)) + return false; /* Unhook the interrupt handler. */ pci_intr_disestablish(psc->psc_pc, psc->psc_intrcookie); psc->psc_intrcookie = NULL; + return true; } static void @@ -176,9 +182,6 @@ rtw_pci_attach(device_t parent, device_t self, void *aux) struct pci_attach_args *pa = aux; pci_chipset_tag_t pc = pa->pa_pc; const char *intrstr = NULL; - bus_space_tag_t iot, memt; - bus_space_handle_t ioh, memh; - int ioh_valid, memh_valid; const struct rtw_pci_product *app; int error; @@ -192,12 +195,6 @@ rtw_pci_attach(device_t parent, device_t self, void *aux) panic("rtw_pci_attach: impossible"); } - /* - * No power management hooks. - * XXX Maybe we should add some! - */ - sc->sc_flags |= RTW_F_ENABLED; - /* * Get revision info, and set some chip-specific variables. */ @@ -206,8 +203,8 @@ rtw_pci_attach(device_t parent, device_t self, void *aux) (sc->sc_rev >> 4) & 0xf, sc->sc_rev & 0xf); /* power up chip */ - if ((error = pci_activate(pa->pa_pc, pa->pa_tag, sc, - NULL)) && error != EOPNOTSUPP) { + if ((error = pci_activate(pa->pa_pc, pa->pa_tag, sc, NULL)) != 0 && + error != EOPNOTSUPP) { aprint_error_dev(self, "cannot activate %d\n", error); return; } @@ -215,21 +212,15 @@ rtw_pci_attach(device_t parent, device_t self, void *aux) /* * Map the device. */ - ioh_valid = (pci_mapreg_map(pa, RTW_PCI_IOBA, - PCI_MAPREG_TYPE_IO, 0, - &iot, &ioh, NULL, NULL) == 0); - memh_valid = (pci_mapreg_map(pa, RTW_PCI_MMBA, + if (pci_mapreg_map(pa, RTW_PCI_MMBA, PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0, - &memt, &memh, NULL, NULL) == 0); - - if (memh_valid) { - regs->r_bt = memt; - regs->r_bh = memh; - } else if (ioh_valid) { - regs->r_bt = iot; - regs->r_bh = ioh; - } else { - aprint_error(": unable to map device registers\n"); + ®s->r_bt, ®s->r_bh, NULL, ®s->r_sz) == 0) + ; + else if (pci_mapreg_map(pa, RTW_PCI_IOBA, PCI_MAPREG_TYPE_IO, 0, + ®s->r_bt, ®s->r_bh, NULL, ®s->r_sz) == 0) + ; + else { + aprint_error_dev(self, "unable to map device registers\n"); return; } @@ -262,11 +253,37 @@ rtw_pci_attach(device_t parent, device_t self, void *aux) aprint_normal_dev(self, "interrupting at %s\n", intrstr); - sc->sc_enable = rtw_pci_enable; - sc->sc_disable = rtw_pci_disable; - /* * Finish off the attach. */ rtw_attach(sc); + + if (!pmf_device_register(sc->sc_dev, rtw_pci_suspend, + rtw_pci_resume)) { + aprint_error_dev(sc->sc_dev, + "couldn't establish power handler\n"); + } else { + pmf_class_network_register(self, &sc->sc_if); + /* + * Power down the socket. + */ + pmf_device_suspend_self(self); + } +} + +static int +rtw_pci_detach(device_t self, int flags) +{ + struct rtw_pci_softc *psc = device_private(self); + struct rtw_softc *sc = &psc->psc_rtw; + struct rtw_regs *regs = &sc->sc_regs; + int rc; + + if ((rc = rtw_detach(sc)) != 0) + return rc; + if (psc->psc_intrcookie != NULL) + pci_intr_disestablish(psc->psc_pc, psc->psc_intrcookie); + bus_space_unmap(regs->r_bt, regs->r_bh, regs->r_sz); + + return 0; } diff --git a/sys/dev/pci/if_sip.c b/sys/dev/pci/if_sip.c index 853b23bbee34..21f5f6b31e0e 100644 --- a/sys/dev/pci/if_sip.c +++ b/sys/dev/pci/if_sip.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_sip.c,v 1.129 2008/03/11 22:26:14 dyoung Exp $ */ +/* $NetBSD: if_sip.c,v 1.130 2008/03/12 18:02:21 dyoung Exp $ */ /*- * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc. @@ -80,7 +80,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_sip.c,v 1.129 2008/03/11 22:26:14 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_sip.c,v 1.130 2008/03/12 18:02:21 dyoung Exp $"); #include "bpfilter.h" #include "rnd.h" @@ -614,6 +614,7 @@ static void sipcom_attach(device_t, device_t, void *); static void sipcom_do_detach(device_t, enum sip_attach_stage); static int sipcom_detach(device_t, int); static bool sipcom_resume(device_t PMF_FN_PROTO); +static bool sipcom_suspend(device_t PMF_FN_PROTO); int gsip_copy_small = 0; int sip_copy_small = 0; @@ -972,6 +973,15 @@ sipcom_resume(device_t self PMF_FN_ARGS) return sipcom_reset(sc); } +static bool +sipcom_suspend(device_t self PMF_FN_ARGS) +{ + struct sip_softc *sc = device_private(self); + + sipcom_rxdrain(sc); + return true; +} + static void sipcom_attach(device_t parent, device_t self, void *aux) { @@ -1363,7 +1373,7 @@ sipcom_attach(device_t parent, device_t self, void *aux) } #endif /* SIP_EVENT_COUNTERS */ - if (!pmf_device_register(self, NULL, sipcom_resume)) + if (!pmf_device_register(self, sipcom_suspend, sipcom_resume)) aprint_error_dev(self, "couldn't establish power handler\n"); else pmf_class_network_register(self, ifp); @@ -2551,13 +2561,13 @@ sipcom_init(struct ifnet *ifp) struct sip_desc *sipd; int i, error = 0; - if (!device_has_power(&sc->sc_dev)) - return EBUSY; - - /* - * Cancel any pending I/O. - */ - sipcom_stop(ifp, 0); + if (device_is_active(&sc->sc_dev)) { + /* + * Cancel any pending I/O. + */ + sipcom_stop(ifp, 0); + } else if (!pmf_device_resume_self(&sc->sc_dev)) + return 0; /* * Reset the chip to a known state. @@ -2877,15 +2887,15 @@ sipcom_stop(struct ifnet *ifp, int disable) SIMPLEQ_INSERT_TAIL(&sc->sc_txfreeq, txs, txs_q); } - if (disable) - sipcom_rxdrain(sc); - /* * Mark the interface down and cancel the watchdog timer. */ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); ifp->if_timer = 0; + if (disable) + pmf_device_suspend_self(&sc->sc_dev); + if ((ifp->if_flags & IFF_DEBUG) != 0 && (cmdsts & CMDSTS_INTR) == 0 && sc->sc_txfree != sc->sc_ntxdesc) printf("%s: sip_stop: no INTR bits set in dirty tx " diff --git a/sys/kern/kern_drvctl.c b/sys/kern/kern_drvctl.c index d2dd32a5cfc4..190851601c76 100644 --- a/sys/kern/kern_drvctl.c +++ b/sys/kern/kern_drvctl.c @@ -1,4 +1,4 @@ -/* $NetBSD: kern_drvctl.c,v 1.15 2008/03/05 07:09:18 dyoung Exp $ */ +/* $NetBSD: kern_drvctl.c,v 1.16 2008/03/12 18:02:21 dyoung Exp $ */ /* * Copyright (c) 2004 @@ -27,7 +27,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: kern_drvctl.c,v 1.15 2008/03/05 07:09:18 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_drvctl.c,v 1.16 2008/03/12 18:02:21 dyoung Exp $"); #include #include @@ -63,12 +63,15 @@ pmdevbyname(int cmd, struct devpmargs *a) switch (cmd) { case DRVSUSPENDDEV: - return pmf_device_recursive_suspend(d) ? 0 : EBUSY; + return pmf_device_recursive_suspend(d, PMF_F_NONE) ? 0 : EBUSY; case DRVRESUMEDEV: - if (a->flags & DEVPM_F_SUBTREE) - return pmf_device_resume_subtree(d) ? 0 : EBUSY; - else - return pmf_device_recursive_resume(d) ? 0 : EBUSY; + if (a->flags & DEVPM_F_SUBTREE) { + return pmf_device_resume_subtree(d, PMF_F_NONE) + ? 0 : EBUSY; + } else { + return pmf_device_recursive_resume(d, PMF_F_NONE) + ? 0 : EBUSY; + } default: return EPASSTHROUGH; } diff --git a/sys/kern/kern_pmf.c b/sys/kern/kern_pmf.c index cb38f87c7f1b..52b2df2a4169 100644 --- a/sys/kern/kern_pmf.c +++ b/sys/kern/kern_pmf.c @@ -1,4 +1,4 @@ -/* $NetBSD: kern_pmf.c,v 1.16 2008/03/07 07:03:06 dyoung Exp $ */ +/* $NetBSD: kern_pmf.c,v 1.17 2008/03/12 18:02:22 dyoung Exp $ */ /*- * Copyright (c) 2007 Jared D. McNeill @@ -33,7 +33,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: kern_pmf.c,v 1.16 2008/03/07 07:03:06 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_pmf.c,v 1.17 2008/03/12 18:02:22 dyoung Exp $"); #include #include @@ -375,6 +375,12 @@ pmf_device_deregister(device_t dev) device_pmf_driver_deregister(dev); } +bool +pmf_device_suspend_self(device_t dev) +{ + return pmf_device_suspend(dev, PMF_F_SELF); +} + bool pmf_device_suspend(device_t dev PMF_FN_ARGS) { @@ -398,6 +404,8 @@ pmf_device_suspend(device_t dev PMF_FN_ARGS) static bool pmf_device_suspend_locked(device_t dev PMF_FN_ARGS) { + PMF_TRANSITION_PRINTF2(1, ("%s: self suspend\n", device_xname(dev))); + device_pmf_self_suspend(dev, flags); PMF_TRANSITION_PRINTF2(1, ("%s: class suspend\n", device_xname(dev))); if (!device_pmf_class_suspend(dev PMF_FN_CALL)) return false; @@ -411,6 +419,12 @@ pmf_device_suspend_locked(device_t dev PMF_FN_ARGS) return true; } +bool +pmf_device_resume_self(device_t dev) +{ + return pmf_device_resume(dev, PMF_F_SELF); +} + bool pmf_device_resume(device_t dev PMF_FN_ARGS) { @@ -443,6 +457,9 @@ pmf_device_resume_locked(device_t dev PMF_FN_ARGS) PMF_TRANSITION_PRINTF2(1, ("%s: class resume\n", device_xname(dev))); if (!device_pmf_class_resume(dev PMF_FN_CALL)) return false; + PMF_TRANSITION_PRINTF2(1, ("%s: self resume\n", device_xname(dev))); + device_pmf_self_resume(dev, flags); + return true; } @@ -519,7 +536,7 @@ pmf_class_network_suspend(device_t dev PMF_FN_ARGS) int s; s = splnet(); - (*ifp->if_stop)(ifp, 1); + (*ifp->if_stop)(ifp, 0); splx(s); return true; @@ -531,6 +548,9 @@ pmf_class_network_resume(device_t dev PMF_FN_ARGS) struct ifnet *ifp = device_pmf_class_private(dev); int s; + if ((flags & PMF_F_SELF) != 0) + return true; + s = splnet(); if (ifp->if_flags & IFF_UP) { ifp->if_flags &= ~IFF_RUNNING; diff --git a/sys/kern/subr_autoconf.c b/sys/kern/subr_autoconf.c index 653f67dab34a..790e9ecca1e5 100644 --- a/sys/kern/subr_autoconf.c +++ b/sys/kern/subr_autoconf.c @@ -1,4 +1,4 @@ -/* $NetBSD: subr_autoconf.c,v 1.140 2008/03/11 02:42:41 matt Exp $ */ +/* $NetBSD: subr_autoconf.c,v 1.141 2008/03/12 18:02:22 dyoung Exp $ */ /* * Copyright (c) 1996, 2000 Christopher G. Demetriou @@ -77,7 +77,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.140 2008/03/11 02:42:41 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.141 2008/03/12 18:02:22 dyoung Exp $"); #include "opt_multiprocessor.h" #include "opt_ddb.h" @@ -1952,6 +1952,8 @@ device_pmf_driver_resume(device_t dev PMF_FN_ARGS) return true; if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0) return false; + if ((flags & PMF_F_SELF) != 0 && !device_is_self_suspended(dev)) + return false; if (*dev->dv_driver_resume != NULL && !(*dev->dv_driver_resume)(dev PMF_FN_CALL)) return false; @@ -2047,6 +2049,36 @@ device_pmf_driver_set_child_register(device_t dev, dev->dv_driver_child_register = child_register; } +void +device_pmf_self_resume(device_t dev PMF_FN_ARGS) +{ + pmflock_debug_with_flags(dev, __func__, __LINE__ PMF_FN_CALL); + if ((dev->dv_flags & DVF_SELF_SUSPENDED) != 0) + dev->dv_flags &= ~DVF_SELF_SUSPENDED; + pmflock_debug_with_flags(dev, __func__, __LINE__ PMF_FN_CALL); +} + +bool +device_is_self_suspended(device_t dev) +{ + return (dev->dv_flags & DVF_SELF_SUSPENDED) != 0; +} + +void +device_pmf_self_suspend(device_t dev PMF_FN_ARGS) +{ + bool self = (flags & PMF_F_SELF) != 0; + + pmflock_debug_with_flags(dev, __func__, __LINE__ PMF_FN_CALL); + + if (!self) + dev->dv_flags &= ~DVF_SELF_SUSPENDED; + else if (device_is_active(dev)) + dev->dv_flags |= DVF_SELF_SUSPENDED; + + pmflock_debug_with_flags(dev, __func__, __LINE__ PMF_FN_CALL); +} + static void pmflock_debug(device_t dev, const char *func, int line) { @@ -2154,6 +2186,8 @@ device_pmf_bus_resume(device_t dev PMF_FN_ARGS) { if ((dev->dv_flags & DVF_BUS_SUSPENDED) == 0) return true; + if ((flags & PMF_F_SELF) != 0 && !device_is_self_suspended(dev)) + return false; if (*dev->dv_bus_resume != NULL && !(*dev->dv_bus_resume)(dev PMF_FN_CALL)) return false; diff --git a/sys/sys/device.h b/sys/sys/device.h index ee1124a55661..40b26fc2ff72 100644 --- a/sys/sys/device.h +++ b/sys/sys/device.h @@ -1,4 +1,4 @@ -/* $NetBSD: device.h,v 1.108 2008/03/11 02:42:41 matt Exp $ */ +/* $NetBSD: device.h,v 1.109 2008/03/12 18:02:22 dyoung Exp $ */ /* * Copyright (c) 1996, 2000 Christopher G. Demetriou @@ -166,6 +166,7 @@ struct device { #define DVF_CLASS_SUSPENDED 0x0008 /* device class suspend was called */ #define DVF_DRIVER_SUSPENDED 0x0010 /* device driver suspend was called */ #define DVF_BUS_SUSPENDED 0x0020 /* device bus suspend was called */ +#define DVF_SELF_SUSPENDED 0x0040 /* device suspended itself */ TAILQ_HEAD(devicelist, device); @@ -499,6 +500,11 @@ void *device_pmf_private(device_t); void device_pmf_unlock(device_t PMF_FN_PROTO); bool device_pmf_lock(device_t PMF_FN_PROTO); +bool device_is_self_suspended(device_t); +void device_pmf_self_suspend(device_t PMF_FN_PROTO); +void device_pmf_self_resume(device_t PMF_FN_PROTO); +bool device_pmf_self_wait(device_t PMF_FN_PROTO); + void device_pmf_bus_register(device_t, void *, bool (*)(device_t PMF_FN_PROTO), bool (*)(device_t PMF_FN_PROTO), diff --git a/sys/sys/pmf.h b/sys/sys/pmf.h index cbfe8017c660..1d3897cecfb0 100644 --- a/sys/sys/pmf.h +++ b/sys/sys/pmf.h @@ -1,4 +1,4 @@ -/* $NetBSD: pmf.h,v 1.9 2008/03/07 07:03:06 dyoung Exp $ */ +/* $NetBSD: pmf.h,v 1.10 2008/03/12 18:02:22 dyoung Exp $ */ /*- * Copyright (c) 2007 Jared D. McNeill @@ -54,14 +54,21 @@ typedef enum { PMFE_CHASSIS_LID_OPEN } pmf_generic_event_t; -#define PMF_FN_PROTO1 void /* pmf_flags_t */ -#define PMF_FN_ARGS1 void /* pmf_flags_t flags */ +enum pmf_flags { + PMF_F_NONE = 0x0 + , PMF_F_SELF = 0x1 +}; -#define PMF_FN_PROTO /* , pmf_flags_t */ -#define PMF_FN_ARGS /* , pmf_flags_t flags */ -#define PMF_FN_CALL /* , flags */ +typedef enum pmf_flags pmf_flags_t; -#define PMF_FLAGS_FMT "n/a" /* "%x" */ +#define PMF_FN_PROTO1 pmf_flags_t +#define PMF_FN_ARGS1 pmf_flags_t flags + +#define PMF_FN_PROTO , pmf_flags_t +#define PMF_FN_ARGS , pmf_flags_t flags +#define PMF_FN_CALL , flags + +#define PMF_FLAGS_FMT "%x" /* "n/a" */ void pmf_init(void); @@ -91,6 +98,9 @@ void pmf_device_deregister(device_t); bool pmf_device_suspend(device_t PMF_FN_PROTO); bool pmf_device_resume(device_t PMF_FN_PROTO); +bool pmf_device_suspend_self(device_t); +bool pmf_device_resume_self(device_t); + bool pmf_device_recursive_suspend(device_t PMF_FN_PROTO); bool pmf_device_recursive_resume(device_t PMF_FN_PROTO); bool pmf_device_resume_subtree(device_t PMF_FN_PROTO);