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.
This commit is contained in:
dyoung 2008-03-12 18:02:21 +00:00
parent 15bb494e45
commit 3df2b2feb5
18 changed files with 548 additions and 588 deletions

View File

@ -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 <sys/cdefs.h>
__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;

View File

@ -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 <sys/cdefs.h>
__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);

View File

@ -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 <sys/cdefs.h>
__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;

View File

@ -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 <sys/cdefs.h>
__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;
}

View File

@ -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 <ichiro@ichiro.org>.
@ -36,7 +36,7 @@
*/
#include <sys/cdefs.h>
__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);
}

View File

@ -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 <sys/cdefs.h>
__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, &regs->r_bt, &regs->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,
&regs->r_bt, &regs->r_bh, &adr, &regs->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, &regs->r_bt, &regs->r_bh, &adr,
&csc->sc_mapsize) == 0) {
} else if (Cardbus_mapreg_map(ct, RTW_PCI_IOBA, CARDBUS_MAPREG_TYPE_IO,
0, &regs->r_bt, &regs->r_bh, &adr, &regs->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);
}

View File

@ -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);

View File

@ -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<<i))
int ath_attach(u_int16_t, struct ath_softc *);
int ath_detach(struct ath_softc *);
int ath_activate(struct device *, enum devact);
void ath_resume(struct ath_softc *);
bool ath_resume(struct ath_softc *);
void ath_suspend(struct ath_softc *);
int ath_intr(void *);
int ath_reset(struct ifnet *);
void ath_sysctlattach(struct ath_softc *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: rtw.c,v 1.100 2008/03/12 15:47:49 dyoung Exp $ */
/* $NetBSD: rtw.c,v 1.101 2008/03/12 18:02:21 dyoung Exp $ */
/*-
* Copyright (c) 2004, 2005, 2006, 2007 David Young. All rights
* reserved.
@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
__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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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 <sys/cdefs.h>
__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 <sys/param.h>
#include <sys/systm.h>
@ -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");
&regs->r_bt, &regs->r_bh, NULL, &regs->r_sz) == 0)
;
else if (pci_mapreg_map(pa, RTW_PCI_IOBA, PCI_MAPREG_TYPE_IO, 0,
&regs->r_bt, &regs->r_bh, NULL, &regs->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;
}

View File

@ -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 <sys/cdefs.h>
__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 "

View File

@ -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 <sys/cdefs.h>
__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 <sys/param.h>
#include <sys/systm.h>
@ -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;
}

View File

@ -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 <jmcneill@invisible.ca>
@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
__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 <sys/types.h>
#include <sys/param.h>
@ -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;

View File

@ -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 <sys/cdefs.h>
__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;

View File

@ -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),

View File

@ -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 <jmcneill@invisible.ca>
@ -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);