summaryrefslogtreecommitdiffstats
path: root/sys/dev/ath
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ath')
-rw-r--r--sys/dev/ath/ah_osdep.c49
-rw-r--r--sys/dev/ath/ath_dfs/null/dfs_null.c2
-rw-r--r--sys/dev/ath/ath_hal/ah.c52
-rw-r--r--sys/dev/ath/ath_hal/ah.h64
-rw-r--r--sys/dev/ath/ath_hal/ah_decode.h3
-rw-r--r--sys/dev/ath/ath_hal/ah_devid.h1
-rw-r--r--sys/dev/ath/ath_hal/ah_internal.h28
-rw-r--r--sys/dev/ath/ath_hal/ah_regdomain.c5
-rw-r--r--sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regenum.h1
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210.h3
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210_attach.c4
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210_misc.c1
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210_power.c12
-rw-r--r--sys/dev/ath/ath_hal/ar5210/ar5210_reset.c4
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211.h1
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211_attach.c2
-rw-r--r--sys/dev/ath/ath_hal/ar5211/ar5211_power.c12
-rw-r--r--sys/dev/ath/ath_hal/ar5212/ar5212.h11
-rw-r--r--sys/dev/ath/ath_hal/ar5212/ar5212_ani.c13
-rw-r--r--sys/dev/ath/ath_hal/ar5212/ar5212_attach.c2
-rw-r--r--sys/dev/ath/ath_hal/ar5212/ar5212_misc.c18
-rw-r--r--sys/dev/ath/ath_hal/ar5212/ar5212_power.c10
-rw-r--r--sys/dev/ath/ath_hal/ar5212/ar5212_reset.c3
-rw-r--r--sys/dev/ath/ath_hal/ar5312/ar5312_attach.c2
-rw-r--r--sys/dev/ath/ath_hal/ar5312/ar5312_power.c5
-rw-r--r--sys/dev/ath/ath_hal/ar5416/ar5416_ani.c13
-rw-r--r--sys/dev/ath/ath_hal/ar5416/ar5416_attach.c7
-rw-r--r--sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c26
-rw-r--r--sys/dev/ath/ath_hal/ar5416/ar5416_cal.c3
-rw-r--r--sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c3
-rw-r--r--sys/dev/ath/ath_hal/ar5416/ar5416_power.c13
-rw-r--r--sys/dev/ath/ath_hal/ar5416/ar5416_reset.c3
-rw-r--r--sys/dev/ath/ath_hal/ar5416/ar5416reg.h4
-rw-r--r--sys/dev/ath/ath_hal/ar9001/ar9130_attach.c4
-rw-r--r--sys/dev/ath/ath_hal/ar9001/ar9160_attach.c1
-rw-r--r--sys/dev/ath/ath_hal/ar9002/ar9280_attach.c1
-rw-r--r--sys/dev/ath/ath_hal/ar9002/ar9285_attach.c1
-rw-r--r--sys/dev/ath/ath_hal/ar9002/ar9287_attach.c1
-rw-r--r--sys/dev/ath/ath_rate/sample/sample.c6
-rw-r--r--sys/dev/ath/ath_rate/sample/sample.h2
-rw-r--r--sys/dev/ath/if_ath.c937
-rw-r--r--sys/dev/ath/if_ath_ahb.c24
-rw-r--r--sys/dev/ath/if_ath_beacon.c93
-rw-r--r--sys/dev/ath/if_ath_beacon.h2
-rw-r--r--sys/dev/ath/if_ath_btcoex.c70
-rw-r--r--sys/dev/ath/if_ath_debug.c3
-rw-r--r--sys/dev/ath/if_ath_debug.h1
-rw-r--r--sys/dev/ath/if_ath_keycache.c17
-rw-r--r--sys/dev/ath/if_ath_led.c9
-rw-r--r--sys/dev/ath/if_ath_lna_div.c6
-rw-r--r--sys/dev/ath/if_ath_misc.h13
-rw-r--r--sys/dev/ath/if_ath_pci.c138
-rw-r--r--sys/dev/ath/if_ath_pci_devlist.h669
-rw-r--r--sys/dev/ath/if_ath_rx.c250
-rw-r--r--sys/dev/ath/if_ath_rx_edma.c175
-rw-r--r--sys/dev/ath/if_ath_spectral.c2
-rw-r--r--sys/dev/ath/if_ath_sysctl.c36
-rw-r--r--sys/dev/ath/if_ath_tdma.c16
-rw-r--r--sys/dev/ath/if_ath_tx.c422
-rw-r--r--sys/dev/ath/if_ath_tx_edma.c15
-rw-r--r--sys/dev/ath/if_athvar.h48
61 files changed, 2904 insertions, 438 deletions
diff --git a/sys/dev/ath/ah_osdep.c b/sys/dev/ath/ah_osdep.c
index 043ebed..fe4a657 100644
--- a/sys/dev/ath/ah_osdep.c
+++ b/sys/dev/ath/ah_osdep.c
@@ -96,9 +96,8 @@ static SYSCTL_NODE(_hw_ath, OID_AUTO, hal, CTLFLAG_RD, 0,
#ifdef AH_DEBUG
int ath_hal_debug = 0;
-SYSCTL_INT(_hw_ath_hal, OID_AUTO, debug, CTLFLAG_RW, &ath_hal_debug,
+SYSCTL_INT(_hw_ath_hal, OID_AUTO, debug, CTLFLAG_RWTUN, &ath_hal_debug,
0, "Atheros HAL debugging printfs");
-TUNABLE_INT("hw.ath.hal.debug", &ath_hal_debug);
#endif /* AH_DEBUG */
static MALLOC_DEFINE(M_ATH_HAL, "ath_hal", "ath hal data");
@@ -138,6 +137,24 @@ ath_hal_ether_sprintf(const u_int8_t *mac)
#ifdef AH_DEBUG
+/*
+ * XXX This is highly relevant only for the AR5416 and later
+ * PCI/PCIe NICs. It'll need adjustment for other hardware
+ * variations.
+ */
+static int
+ath_hal_reg_whilst_asleep(struct ath_hal *ah, uint32_t reg)
+{
+
+ if (reg >= 0x4000 && reg < 0x5000)
+ return (1);
+ if (reg >= 0x6000 && reg < 0x7000)
+ return (1);
+ if (reg >= 0x7000 && reg < 0x8000)
+ return (1);
+ return (0);
+}
+
void
DO_HALDEBUG(struct ath_hal *ah, u_int mask, const char* fmt, ...)
{
@@ -253,6 +270,13 @@ ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val)
bus_space_tag_t tag = BUSTAG(ah);
bus_space_handle_t h = ah->ah_sh;
+ /* Debug - complain if we haven't fully waken things up */
+ if (! ath_hal_reg_whilst_asleep(ah, reg) &&
+ ah->ah_powerMode != HAL_PM_AWAKE) {
+ ath_hal_printf(ah, "%s: reg=0x%08x, val=0x%08x, pm=%d\n",
+ __func__, reg, val, ah->ah_powerMode);
+ }
+
if (ath_hal_alq) {
struct ale *ale = ath_hal_alq_get(ah);
if (ale) {
@@ -278,6 +302,13 @@ ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg)
bus_space_handle_t h = ah->ah_sh;
u_int32_t val;
+ /* Debug - complain if we haven't fully waken things up */
+ if (! ath_hal_reg_whilst_asleep(ah, reg) &&
+ ah->ah_powerMode != HAL_PM_AWAKE) {
+ ath_hal_printf(ah, "%s: reg=0x%08x, pm=%d\n",
+ __func__, reg, ah->ah_powerMode);
+ }
+
if (ah->ah_config.ah_serialise_reg_war)
mtx_lock_spin(&ah_regser_mtx);
val = bus_space_read_4(tag, h, reg);
@@ -330,6 +361,13 @@ ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val)
bus_space_tag_t tag = BUSTAG(ah);
bus_space_handle_t h = ah->ah_sh;
+ /* Debug - complain if we haven't fully waken things up */
+ if (! ath_hal_reg_whilst_asleep(ah, reg) &&
+ ah->ah_powerMode != HAL_PM_AWAKE) {
+ ath_hal_printf(ah, "%s: reg=0x%08x, val=0x%08x, pm=%d\n",
+ __func__, reg, val, ah->ah_powerMode);
+ }
+
if (ah->ah_config.ah_serialise_reg_war)
mtx_lock_spin(&ah_regser_mtx);
bus_space_write_4(tag, h, reg, val);
@@ -344,6 +382,13 @@ ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg)
bus_space_handle_t h = ah->ah_sh;
u_int32_t val;
+ /* Debug - complain if we haven't fully waken things up */
+ if (! ath_hal_reg_whilst_asleep(ah, reg) &&
+ ah->ah_powerMode != HAL_PM_AWAKE) {
+ ath_hal_printf(ah, "%s: reg=0x%08x, pm=%d\n",
+ __func__, reg, ah->ah_powerMode);
+ }
+
if (ah->ah_config.ah_serialise_reg_war)
mtx_lock_spin(&ah_regser_mtx);
val = bus_space_read_4(tag, h, reg);
diff --git a/sys/dev/ath/ath_dfs/null/dfs_null.c b/sys/dev/ath/ath_dfs/null/dfs_null.c
index 36b2042..c980a79 100644
--- a/sys/dev/ath/ath_dfs/null/dfs_null.c
+++ b/sys/dev/ath/ath_dfs/null/dfs_null.c
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <sys/kernel.h>
#include <sys/lock.h>
+#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/errno.h>
@@ -53,6 +54,7 @@ __FBSDID("$FreeBSD$");
#include <sys/socket.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_media.h>
#include <net/if_arp.h>
#include <net/ethernet.h> /* XXX for ether_sprintf */
diff --git a/sys/dev/ath/ath_hal/ah.c b/sys/dev/ath/ath_hal/ah.c
index 7187d57..4eb7fb6 100644
--- a/sys/dev/ath/ath_hal/ah.c
+++ b/sys/dev/ath/ath_hal/ah.c
@@ -55,7 +55,9 @@ ath_hal_probe(uint16_t vendorid, uint16_t devid)
*/
struct ath_hal*
ath_hal_attach(uint16_t devid, HAL_SOFTC sc,
- HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_STATUS *error)
+ HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata,
+ HAL_OPS_CONFIG *ah_config,
+ HAL_STATUS *error)
{
struct ath_hal_chip * const *pchip;
@@ -66,7 +68,8 @@ ath_hal_attach(uint16_t devid, HAL_SOFTC sc,
/* XXX don't have vendorid, assume atheros one works */
if (chip->probe(ATHEROS_VENDOR_ID, devid) == AH_NULL)
continue;
- ah = chip->attach(devid, sc, st, sh, eepromdata, error);
+ ah = chip->attach(devid, sc, st, sh, eepromdata, ah_config,
+ error);
if (ah != AH_NULL) {
/* copy back private state to public area */
ah->ah_devid = AH_PRIVATE(ah)->ah_devid;
@@ -786,6 +789,8 @@ ath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
return HAL_OK;
case HAL_CAP_RX_LNA_MIXING: /* Hardware uses an RX LNA mixer to map 2 antennas to a 1 stream receiver */
return pCap->halRxUsingLnaMixing ? HAL_OK : HAL_ENOTSUPP;
+ case HAL_CAP_DO_MYBEACON: /* Hardware supports filtering my-beacons */
+ return pCap->halRxDoMyBeacon ? HAL_OK : HAL_ENOTSUPP;
default:
return HAL_EINVAL;
}
@@ -848,10 +853,11 @@ ath_hal_getregdump(struct ath_hal *ah, const HAL_REGRANGE *regs,
int i;
for (i = 0; space >= 2*sizeof(uint32_t); i++) {
- u_int r = regs[i].start;
- u_int e = regs[i].end;
- *dp++ = (r<<16) | e;
- space -= sizeof(uint32_t);
+ uint32_t r = regs[i].start;
+ uint32_t e = regs[i].end;
+ *dp++ = r;
+ *dp++ = e;
+ space -= 2*sizeof(uint32_t);
do {
*dp++ = OS_REG_READ(ah, r);
r += sizeof(uint32_t);
@@ -875,6 +881,7 @@ ath_hal_getdiagstate(struct ath_hal *ah, int request,
const void *args, uint32_t argsize,
void **result, uint32_t *resultsize)
{
+
switch (request) {
case HAL_DIAG_REVS:
*result = &AH_PRIVATE(ah)->ah_devid;
@@ -932,6 +939,10 @@ ath_hal_getdiagstate(struct ath_hal *ah, int request,
} else
return AH_FALSE;
return AH_TRUE;
+ case HAL_DIAG_CHANSURVEY:
+ *result = &AH_PRIVATE(ah)->ah_chansurvey;
+ *resultsize = sizeof(HAL_CHANNEL_SURVEY);
+ return AH_TRUE;
}
return AH_FALSE;
}
@@ -1427,3 +1438,32 @@ ath_hal_mhz2ieee_2ghz(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan)
else
return 15 + ((ichan->channel - 2512) / 20);
}
+
+/*
+ * Clear the current survey data.
+ *
+ * This should be done during a channel change.
+ */
+void
+ath_hal_survey_clear(struct ath_hal *ah)
+{
+
+ OS_MEMZERO(&AH_PRIVATE(ah)->ah_chansurvey,
+ sizeof(AH_PRIVATE(ah)->ah_chansurvey));
+}
+
+/*
+ * Add a sample to the channel survey.
+ */
+void
+ath_hal_survey_add_sample(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hs)
+{
+ HAL_CHANNEL_SURVEY *cs;
+
+ cs = &AH_PRIVATE(ah)->ah_chansurvey;
+
+ OS_MEMCPY(&cs->samples[cs->cur_sample], hs, sizeof(*hs));
+ cs->samples[cs->cur_sample].seq_num = cs->cur_seq;
+ cs->cur_sample = (cs->cur_sample + 1) % CHANNEL_SURVEY_SAMPLE_COUNT;
+ cs->cur_seq++;
+}
diff --git a/sys/dev/ath/ath_hal/ah.h b/sys/dev/ath/ath_hal/ah.h
index 2480803..facfceb1 100644
--- a/sys/dev/ath/ath_hal/ah.h
+++ b/sys/dev/ath/ath_hal/ah.h
@@ -199,6 +199,7 @@ typedef enum {
HAL_CAP_SERIALISE_WAR = 245, /* serialise register access on PCI */
HAL_CAP_ENFORCE_TXOP = 246, /* Enforce TXOP if supported */
HAL_CAP_RX_LNA_MIXING = 247, /* RX hardware uses LNA mixing */
+ HAL_CAP_DO_MYBEACON = 248, /* Supports HAL_RX_FILTER_MYBEACON */
} HAL_CAPABILITY_TYPE;
/*
@@ -404,6 +405,7 @@ typedef enum {
HAL_RX_FILTER_PROM = 0x00000020, /* Promiscuous mode */
HAL_RX_FILTER_PROBEREQ = 0x00000080, /* Allow probe request frames */
HAL_RX_FILTER_PHYERR = 0x00000100, /* Allow phy errors */
+ HAL_RX_FILTER_MYBEACON = 0x00000200, /* Filter beacons other than mine */
HAL_RX_FILTER_COMPBAR = 0x00000400, /* Allow compressed BAR */
HAL_RX_FILTER_COMP_BA = 0x00000800, /* Allow compressed blockack */
HAL_RX_FILTER_PHYRADAR = 0x00002000, /* Allow phy radar errors */
@@ -538,6 +540,7 @@ typedef enum {
typedef struct {
u_int32_t cyclecnt_diff; /* delta cycle count */
u_int32_t rxclr_cnt; /* rx clear count */
+ u_int32_t extrxclr_cnt; /* ext chan rx clear count */
u_int32_t txframecnt_diff; /* delta tx frame count */
u_int32_t rxframecnt_diff; /* delta rx frame count */
u_int32_t listen_time; /* listen time in msec - time for which ch is free */
@@ -847,6 +850,48 @@ typedef struct {
#define HAL_RSSI_EP_MULTIPLIER (1<<7) /* pow2 to optimize out * and / */
+/*
+ * This is the ANI state and MIB stats.
+ *
+ * It's used by the HAL modules to keep state /and/ by the debug ioctl
+ * to fetch ANI information.
+ */
+typedef struct {
+ uint32_t ast_ani_niup; /* ANI increased noise immunity */
+ uint32_t ast_ani_nidown; /* ANI decreased noise immunity */
+ uint32_t ast_ani_spurup; /* ANI increased spur immunity */
+ uint32_t ast_ani_spurdown;/* ANI descreased spur immunity */
+ uint32_t ast_ani_ofdmon; /* ANI OFDM weak signal detect on */
+ uint32_t ast_ani_ofdmoff;/* ANI OFDM weak signal detect off */
+ uint32_t ast_ani_cckhigh;/* ANI CCK weak signal threshold high */
+ uint32_t ast_ani_ccklow; /* ANI CCK weak signal threshold low */
+ uint32_t ast_ani_stepup; /* ANI increased first step level */
+ uint32_t ast_ani_stepdown;/* ANI decreased first step level */
+ uint32_t ast_ani_ofdmerrs;/* ANI cumulative ofdm phy err count */
+ uint32_t ast_ani_cckerrs;/* ANI cumulative cck phy err count */
+ uint32_t ast_ani_reset; /* ANI parameters zero'd for non-STA */
+ uint32_t ast_ani_lzero; /* ANI listen time forced to zero */
+ uint32_t ast_ani_lneg; /* ANI listen time calculated < 0 */
+ HAL_MIB_STATS ast_mibstats; /* MIB counter stats */
+ HAL_NODE_STATS ast_nodestats; /* Latest rssi stats from driver */
+} HAL_ANI_STATS;
+
+typedef struct {
+ uint8_t noiseImmunityLevel;
+ uint8_t spurImmunityLevel;
+ uint8_t firstepLevel;
+ uint8_t ofdmWeakSigDetectOff;
+ uint8_t cckWeakSigThreshold;
+ uint32_t listenTime;
+
+ /* NB: intentionally ordered so data exported to user space is first */
+ uint32_t txFrameCount; /* Last txFrameCount */
+ uint32_t rxFrameCount; /* Last rx Frame count */
+ uint32_t cycleCount; /* Last cycleCount
+ (to detect wrap-around) */
+ uint32_t ofdmPhyErrCount;/* OFDM err count since last reset */
+ uint32_t cckPhyErrCount; /* CCK err count since last reset */
+} HAL_ANI_STATE;
struct ath_desc;
struct ath_tx_status;
@@ -1262,6 +1307,7 @@ typedef struct
int ath_hal_show_bb_panic;
int ath_hal_ant_ctrl_comm2g_switch_enable;
int ath_hal_ext_atten_margin_cfg;
+ int ath_hal_min_gainidx;
int ath_hal_war70c;
uint32_t ath_hal_mci_config;
} HAL_OPS_CONFIG;
@@ -1297,6 +1343,9 @@ struct ath_hal {
uint32_t ah_intrstate[8]; /* last int state */
uint32_t ah_syncstate; /* last sync intr state */
+ /* Current powerstate from HAL calls */
+ HAL_POWER_MODE ah_powerMode;
+
HAL_OPS_CONFIG ah_config;
const HAL_RATE_TABLE *__ahdecl(*ah_getRateTable)(struct ath_hal *,
u_int mode);
@@ -1583,6 +1632,18 @@ struct ath_hal {
void __ahdecl(*ah_btCoexDisable)(struct ath_hal *);
int __ahdecl(*ah_btCoexEnable)(struct ath_hal *);
+ /* Bluetooth MCI methods */
+ void __ahdecl(*ah_btMciSetup)(struct ath_hal *,
+ uint32_t, void *, uint16_t, uint32_t);
+ HAL_BOOL __ahdecl(*ah_btMciSendMessage)(struct ath_hal *,
+ uint8_t, uint32_t, uint32_t *, uint8_t,
+ HAL_BOOL, HAL_BOOL);
+ uint32_t __ahdecl(*ah_btMciGetInterrupt)(struct ath_hal *,
+ uint32_t *, uint32_t *);
+ uint32_t __ahdecl(*ah_btMciGetState)(struct ath_hal *,
+ uint32_t, uint32_t *);
+ void __ahdecl(*ah_btMciDetach)(struct ath_hal *);
+
/* LNA diversity configuration */
void __ahdecl(*ah_divLnaConfGet)(struct ath_hal *,
HAL_ANT_COMB_CONFIG *);
@@ -1611,7 +1672,8 @@ extern const char *__ahdecl ath_hal_probe(uint16_t vendorid, uint16_t devid);
* be returned if the status parameter is non-zero.
*/
extern struct ath_hal * __ahdecl ath_hal_attach(uint16_t devid, HAL_SOFTC,
- HAL_BUS_TAG, HAL_BUS_HANDLE, uint16_t *eepromdata, HAL_STATUS* status);
+ HAL_BUS_TAG, HAL_BUS_HANDLE, uint16_t *eepromdata,
+ HAL_OPS_CONFIG *ah_config, HAL_STATUS* status);
extern const char *ath_hal_mac_name(struct ath_hal *);
extern const char *ath_hal_rf_name(struct ath_hal *);
diff --git a/sys/dev/ath/ath_hal/ah_decode.h b/sys/dev/ath/ath_hal/ah_decode.h
index 07c4ac7..3aca975 100644
--- a/sys/dev/ath/ath_hal/ah_decode.h
+++ b/sys/dev/ath/ath_hal/ah_decode.h
@@ -53,6 +53,8 @@ enum {
AH_MARK_ANI_POLL, /* ar*AniReset, listen time */
AH_MARK_ANI_CONTROL, /* ar*AniReset, cmd */
AH_MARK_RX_CTL, /* RX DMA control */
+ AH_MARK_CHIP_POWER, /* chip power control, mode */
+ AH_MARK_CHIP_POWER_DONE, /* chip power control done, status */
};
enum {
@@ -61,6 +63,7 @@ enum {
AH_MARK_RX_CTL_DMA_START,
AH_MARK_RX_CTL_DMA_STOP,
AH_MARK_RX_CTL_DMA_STOP_ERR,
+ AH_MARK_RX_CTL_DMA_STOP_OK,
};
#endif /* _ATH_AH_DECODE_H_ */
diff --git a/sys/dev/ath/ath_hal/ah_devid.h b/sys/dev/ath/ath_hal/ah_devid.h
index 43d994d..1e4d473 100644
--- a/sys/dev/ath/ath_hal/ah_devid.h
+++ b/sys/dev/ath/ath_hal/ah_devid.h
@@ -92,6 +92,7 @@
#define AR9300_DEVID_AR946X_PCIE 0x0034
#define AR9300_DEVID_AR9330 0x0035
#define AR9300_DEVID_QCA9565 0x0036
+#define AR9300_DEVID_AR1111_PCIE 0x0037
#define AR9300_DEVID_QCA955X 0x0039
#define AR_SUBVENDOR_ID_NOG 0x0e11 /* No 11G subvendor ID */
diff --git a/sys/dev/ath/ath_hal/ah_internal.h b/sys/dev/ath/ath_hal/ah_internal.h
index 908f33e..0c855d4 100644
--- a/sys/dev/ath/ath_hal/ah_internal.h
+++ b/sys/dev/ath/ath_hal/ah_internal.h
@@ -50,8 +50,8 @@
#endif
typedef struct {
- uint16_t start; /* first register */
- uint16_t end; /* ending register or zero */
+ uint32_t start; /* first register */
+ uint32_t end; /* ending register or zero */
} HAL_REGRANGE;
typedef struct {
@@ -91,6 +91,7 @@ struct ath_hal_chip {
const char *(*probe)(uint16_t vendorid, uint16_t devid);
struct ath_hal *(*attach)(uint16_t devid, HAL_SOFTC,
HAL_BUS_TAG, HAL_BUS_HANDLE, uint16_t *eepromdata,
+ HAL_OPS_CONFIG *ah,
HAL_STATUS *error);
};
#ifndef AH_CHIP
@@ -280,7 +281,9 @@ typedef struct {
halAntDivCombSupportOrg : 1,
halRadioRetentionSupport : 1,
halSpectralScanSupport : 1,
- halRxUsingLnaMixing : 1;
+ halRxUsingLnaMixing : 1,
+ halRxDoMyBeacon : 1,
+ halHwUapsdTrig : 1;
uint32_t halWirelessModes;
uint16_t halTotalQueues;
@@ -419,9 +422,13 @@ struct ath_hal_private {
uint32_t ah_fatalState[6]; /* AR_ISR+shadow regs */
int ah_rxornIsFatal; /* how to treat HAL_INT_RXORN */
-#ifndef ATH_NF_PER_CHAN
+ /* Only used if ATH_NF_PER_CHAN is defined */
HAL_NFCAL_HIST_FULL nf_cal_hist;
-#endif /* ! ATH_NF_PER_CHAN */
+
+ /*
+ * Channel survey history - current channel only.
+ */
+ HAL_CHANNEL_SURVEY ah_chansurvey; /* channel survey */
};
#define AH_PRIVATE(_ah) ((struct ath_hal_private *)(_ah))
@@ -1026,4 +1033,15 @@ ath_hal_getantennaallowed(struct ath_hal *ah,
*/
extern int ath_hal_mhz2ieee_2ghz(struct ath_hal *, HAL_CHANNEL_INTERNAL *);
+/*
+ * Clear the channel survey data.
+ */
+extern void ath_hal_survey_clear(struct ath_hal *ah);
+
+/*
+ * Add a sample to the channel survey data.
+ */
+extern void ath_hal_survey_add_sample(struct ath_hal *ah,
+ HAL_SURVEY_SAMPLE *hs);
+
#endif /* _ATH_AH_INTERAL_H_ */
diff --git a/sys/dev/ath/ath_hal/ah_regdomain.c b/sys/dev/ath/ath_hal/ah_regdomain.c
index 807db44..fb0c841 100644
--- a/sys/dev/ath/ath_hal/ah_regdomain.c
+++ b/sys/dev/ath/ath_hal/ah_regdomain.c
@@ -169,6 +169,11 @@ isEepromValid(struct ath_hal *ah)
if (regDomainPairs[i].regDmnEnum == rd)
return AH_TRUE;
}
+
+ if (rd == FCC_UBNT) {
+ return AH_TRUE;
+ }
+
HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
"%s: invalid regulatory domain/country code 0x%x\n", __func__, rd);
return AH_FALSE;
diff --git a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regenum.h b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regenum.h
index bc569cb..d8d211e 100644
--- a/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regenum.h
+++ b/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regenum.h
@@ -51,6 +51,7 @@ enum {
FCC2_FCCA = 0x20, /* Canada */
FCC2_WORLD = 0x21, /* Australia & HK */
FCC2_ETSIC = 0x22,
+ FCC_UBNT = 0x2A, /* Ubiquity PicoStation M2HP */
FRANCE_RES = 0x31, /* Legacy France for OEM */
FCC3_FCCA = 0x3A, /* USA & Canada w/5470 band, 11h, DFS enabled */
FCC3_WORLD = 0x3B, /* USA & Canada w/5470 band, 11h, DFS enabled */
diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210.h b/sys/dev/ath/ath_hal/ar5210/ar5210.h
index 48ccc20..3e372f7 100644
--- a/sys/dev/ath/ath_hal/ar5210/ar5210.h
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210.h
@@ -108,7 +108,6 @@ struct ath_hal_5210 {
uint32_t ah_txDescInterruptMask;
uint32_t ah_txEolInterruptMask;
uint32_t ah_txUrnInterruptMask;
- HAL_POWER_MODE ah_powerMode;
uint8_t ah_bssid[IEEE80211_ADDR_LEN];
HAL_TX_QUEUE_INFO ah_txq[HAL_NUM_TX_QUEUES]; /* beacon+cab+data */
/*
@@ -121,6 +120,8 @@ struct ath_hal_5210 {
u_int ah_slottime; /* user-specified slot time */
u_int ah_acktimeout; /* user-specified ack timeout */
u_int ah_ctstimeout; /* user-specified cts timeout */
+
+ uint16_t ah_associd; /* association id */
};
#define AH5210(ah) ((struct ath_hal_5210 *)(ah))
diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c b/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c
index 3c0ed71..ceafa99 100644
--- a/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c
@@ -183,7 +183,7 @@ static HAL_BOOL ar5210FillCapabilityInfo(struct ath_hal *ah);
*/
static struct ath_hal *
ar5210Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh,
- uint16_t *eepromdata, HAL_STATUS *status)
+ uint16_t *eepromdata, HAL_OPS_CONFIG *ah_config, HAL_STATUS *status)
{
#define N(a) (sizeof(a)/sizeof(a[0]))
struct ath_hal_5210 *ahp;
@@ -219,7 +219,7 @@ ar5210Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh,
AH_PRIVATE(ah)->ah_powerLimit = AR5210_MAX_RATE_POWER;
AH_PRIVATE(ah)->ah_tpScale = HAL_TP_SCALE_MAX; /* no scaling */
- ahp->ah_powerMode = HAL_PM_UNDEFINED;
+ ah->ah_powerMode = HAL_PM_UNDEFINED;
ahp->ah_staId1Defaults = 0;
ahp->ah_rssiThr = INIT_RSSI_THR;
ahp->ah_sifstime = (u_int) -1;
diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c b/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c
index 8170880..5eaa18e 100644
--- a/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210_misc.c
@@ -315,6 +315,7 @@ ar5210WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId)
/* XXX save bssid for possible re-use on reset */
OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN);
+ ahp->ah_associd = assocId;
OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));
OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) |
((assocId & 0x3fff)<<AR_BSS_ID1_AID_S));
diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_power.c b/sys/dev/ath/ath_hal/ar5210/ar5210_power.c
index 1c6909b..ec5e75d 100644
--- a/sys/dev/ath/ath_hal/ar5210/ar5210_power.c
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210_power.c
@@ -93,7 +93,6 @@ ar5210SetPowerModeSleep(struct ath_hal *ah, int setChip)
HAL_BOOL
ar5210SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip)
{
- struct ath_hal_5210 *ahp = AH5210(ah);
#ifdef AH_DEBUG
static const char* modes[] = {
"AWAKE",
@@ -105,25 +104,30 @@ ar5210SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip)
int status = AH_TRUE;
HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__,
- modes[ahp->ah_powerMode], modes[mode],
+ modes[ah->ah_powerMode], modes[mode],
setChip ? "set chip " : "");
switch (mode) {
case HAL_PM_AWAKE:
+ if (setChip)
+ ah->ah_powerMode = mode;
status = ar5210SetPowerModeAwake(ah, setChip);
break;
case HAL_PM_FULL_SLEEP:
ar5210SetPowerModeSleep(ah, setChip);
+ if (setChip)
+ ah->ah_powerMode = mode;
break;
case HAL_PM_NETWORK_SLEEP:
ar5210SetPowerModeAuto(ah, setChip);
+ if (setChip)
+ ah->ah_powerMode = mode;
break;
default:
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode %u\n",
__func__, mode);
return AH_FALSE;
}
- ahp->ah_powerMode = mode;
- return status;
+ return status;
}
HAL_POWER_MODE
diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_reset.c b/sys/dev/ath/ath_hal/ar5210/ar5210_reset.c
index 1d50f99..1dba729 100644
--- a/sys/dev/ath/ath_hal/ar5210/ar5210_reset.c
+++ b/sys/dev/ath/ath_hal/ar5210/ar5210_reset.c
@@ -152,8 +152,12 @@ ar5210Reset(struct ath_hal *ah, HAL_OPMODE opmode,
/* Restore previous led state */
OS_REG_WRITE(ah, AR_PCICFG, OS_REG_READ(ah, AR_PCICFG) | ledstate);
+#if 0
OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid));
OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4));
+#endif
+ /* BSSID, association id, ps-poll */
+ ar5210WriteAssocid(ah, ahp->ah_bssid, ahp->ah_associd);
OS_REG_WRITE(ah, AR_TXDP0, 0);
OS_REG_WRITE(ah, AR_TXDP1, 0);
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211.h b/sys/dev/ath/ath_hal/ar5211/ar5211.h
index c50531e..6f04624 100644
--- a/sys/dev/ath/ath_hal/ar5211/ar5211.h
+++ b/sys/dev/ath/ath_hal/ar5211/ar5211.h
@@ -119,7 +119,6 @@ struct ath_hal_5211 {
uint32_t ah_txEolInterruptMask;
uint32_t ah_txUrnInterruptMask;
HAL_TX_QUEUE_INFO ah_txq[HAL_NUM_TX_QUEUES];
- HAL_POWER_MODE ah_powerMode;
HAL_ANT_SETTING ah_diversityControl; /* antenna setting */
uint32_t ah_calibrationTime;
HAL_BOOL ah_bIQCalibration;
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c b/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c
index 4549295..3416dc0 100644
--- a/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c
+++ b/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c
@@ -203,7 +203,7 @@ ar5211GetRadioRev(struct ath_hal *ah)
static struct ath_hal *
ar5211Attach(uint16_t devid, HAL_SOFTC sc,
HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata,
- HAL_STATUS *status)
+ HAL_OPS_CONFIG *ah_config, HAL_STATUS *status)
{
#define N(a) (sizeof(a)/sizeof(a[0]))
struct ath_hal_5211 *ahp;
diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_power.c b/sys/dev/ath/ath_hal/ar5211/ar5211_power.c
index 776cfb3..e646d90 100644
--- a/sys/dev/ath/ath_hal/ar5211/ar5211_power.c
+++ b/sys/dev/ath/ath_hal/ar5211/ar5211_power.c
@@ -95,7 +95,6 @@ ar5211SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip)
HAL_BOOL
ar5211SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip)
{
- struct ath_hal_5211 *ahp = AH5211(ah);
#ifdef AH_DEBUG
static const char* modes[] = {
"AWAKE",
@@ -107,25 +106,30 @@ ar5211SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip)
int status = AH_TRUE;
HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__,
- modes[ahp->ah_powerMode], modes[mode],
+ modes[ah->ah_powerMode], modes[mode],
setChip ? "set chip " : "");
switch (mode) {
case HAL_PM_AWAKE:
+ if (setChip)
+ ah->ah_powerMode = mode;
status = ar5211SetPowerModeAwake(ah, setChip);
break;
case HAL_PM_FULL_SLEEP:
ar5211SetPowerModeSleep(ah, setChip);
+ if (setChip)
+ ah->ah_powerMode = mode;
break;
case HAL_PM_NETWORK_SLEEP:
ar5211SetPowerModeNetworkSleep(ah, setChip);
+ if (setChip)
+ ah->ah_powerMode = mode;
break;
default:
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode %u\n",
__func__, mode);
return AH_FALSE;
}
- ahp->ah_powerMode = mode;
- return status;
+ return status;
}
HAL_POWER_MODE
diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212.h b/sys/dev/ath/ath_hal/ar5212/ar5212.h
index 6d38d65..938a68c 100644
--- a/sys/dev/ath/ath_hal/ar5212/ar5212.h
+++ b/sys/dev/ath/ath_hal/ar5212/ar5212.h
@@ -200,6 +200,7 @@ struct ar5212AniState {
#define HAL_ANI_ENA 0x00000001 /* ANI operation enabled */
#define HAL_RSSI_ANI_ENA 0x00000002 /* rssi-based processing ena'd*/
+#if 0
struct ar5212Stats {
uint32_t ast_ani_niup; /* ANI increased noise immunity */
uint32_t ast_ani_nidown; /* ANI decreased noise immunity */
@@ -219,6 +220,7 @@ struct ar5212Stats {
HAL_MIB_STATS ast_mibstats; /* MIB counter stats */
HAL_NODE_STATS ast_nodestats; /* Latest rssi stats from driver */
};
+#endif
/*
* NF Cal history buffer
@@ -258,7 +260,7 @@ struct ath_hal_5212 {
* Runtime state.
*/
uint32_t ah_maskReg; /* copy of AR_IMR */
- struct ar5212Stats ah_stats; /* various statistics */
+ HAL_ANI_STATS ah_stats; /* various statistics */
RF_HAL_FUNCS *ah_rfHal;
uint32_t ah_txDescMask; /* mask for TXDESC */
uint32_t ah_txOkInterruptMask;
@@ -270,7 +272,6 @@ struct ath_hal_5212 {
uint32_t ah_intrTxqs; /* tx q interrupt state */
/* decomp mask array */
uint8_t ah_decompMask[HAL_DECOMP_MASK_SIZE];
- HAL_POWER_MODE ah_powerMode;
HAL_ANT_SETTING ah_antControl; /* antenna setting */
HAL_BOOL ah_diversity; /* fast diversity setting */
enum {
@@ -320,7 +321,6 @@ struct ath_hal_5212 {
struct ar5212AniParams ah_aniParams5; /* 5GHz parameters */
struct ar5212AniState *ah_curani; /* cached last reference */
struct ar5212AniState ah_ani[AH_MAXCHAN]; /* per-channel state */
- HAL_CHANNEL_SURVEY ah_chansurvey; /* channel survey */
/* AR5416 uses some of the AR5212 ANI code; these are the ANI methods */
HAL_BOOL (*ah_aniControl) (struct ath_hal *, HAL_ANI_CMD cmd, int param);
@@ -345,6 +345,9 @@ struct ath_hal_5212 {
uint32_t ah_txBusy;
uint32_t ah_rx_chainmask;
uint32_t ah_tx_chainmask;
+
+ /* Used to return ANI statistics to the diagnostic API */
+ HAL_ANI_STATS ext_ani_stats;
};
#define AH5212(_ah) ((struct ath_hal_5212 *)(_ah))
@@ -627,7 +630,7 @@ extern void ar5212AniAttach(struct ath_hal *, const struct ar5212AniParams *,
const struct ar5212AniParams *, HAL_BOOL ena);
extern void ar5212AniDetach(struct ath_hal *);
extern struct ar5212AniState *ar5212AniGetCurrentState(struct ath_hal *);
-extern struct ar5212Stats *ar5212AniGetCurrentStats(struct ath_hal *);
+extern HAL_ANI_STATS *ar5212AniGetCurrentStats(struct ath_hal *);
extern HAL_BOOL ar5212AniControl(struct ath_hal *, HAL_ANI_CMD cmd, int param);
extern HAL_BOOL ar5212AniSetParams(struct ath_hal *,
const struct ar5212AniParams *, const struct ar5212AniParams *);
diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c b/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c
index 8e87a2f..c7b5932 100644
--- a/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c
+++ b/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c
@@ -110,7 +110,7 @@ ar5212AniGetCurrentState(struct ath_hal *ah)
/*
* Return the current statistics.
*/
-struct ar5212Stats *
+HAL_ANI_STATS *
ar5212AniGetCurrentStats(struct ath_hal *ah)
{
struct ath_hal_5212 *ahp = AH5212(ah);
@@ -869,7 +869,6 @@ ar5212AniGetListenTime(struct ath_hal *ah)
int32_t listenTime = 0;
int good;
HAL_SURVEY_SAMPLE hs;
- HAL_CHANNEL_SURVEY *cs = AH_NULL;
/*
* We shouldn't see ah_curchan be NULL, but just in case..
@@ -879,21 +878,13 @@ ar5212AniGetListenTime(struct ath_hal *ah)
return (0);
}
- cs = &ahp->ah_chansurvey;
-
/*
* Fetch the current statistics, squirrel away the current
* sample, bump the sequence/sample counter.
*/
OS_MEMZERO(&hs, sizeof(hs));
good = ar5212GetMibCycleCounts(ah, &hs);
- if (cs != AH_NULL) {
- OS_MEMCPY(&cs->samples[cs->cur_sample], &hs, sizeof(hs));
- cs->samples[cs->cur_sample].seq_num = cs->cur_seq;
- cs->cur_sample =
- (cs->cur_sample + 1) % CHANNEL_SURVEY_SAMPLE_COUNT;
- cs->cur_seq++;
- }
+ ath_hal_survey_add_sample(ah, &hs);
if (ANI_ENA(ah))
aniState = ahp->ah_curani;
diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c b/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c
index e0af27c..a95f244 100644
--- a/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c
+++ b/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c
@@ -317,7 +317,7 @@ ar5212IsMacSupported(uint8_t macVersion, uint8_t macRev)
static struct ath_hal *
ar5212Attach(uint16_t devid, HAL_SOFTC sc,
HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata,
- HAL_STATUS *status)
+ HAL_OPS_CONFIG *ah_config, HAL_STATUS *status)
{
#define AH_EEPROM_PROTECT(ah) \
(AH_PRIVATE(ah)->ah_ispcie)? AR_EEPROM_PROTECT_PCIE : AR_EEPROM_PROTECT)
diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c b/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c
index 71ee845..e2f1eb7 100644
--- a/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c
+++ b/sys/dev/ath/ath_hal/ar5212/ar5212_misc.c
@@ -1052,6 +1052,7 @@ ar5212GetDiagState(struct ath_hal *ah, int request,
void **result, uint32_t *resultsize)
{
struct ath_hal_5212 *ahp = AH5212(ah);
+ HAL_ANI_STATS *astats;
(void) ahp;
if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize))
@@ -1083,9 +1084,16 @@ ar5212GetDiagState(struct ath_hal *ah, int request,
0 : sizeof(struct ar5212AniState);
return AH_TRUE;
case HAL_DIAG_ANI_STATS:
- *result = ar5212AniGetCurrentStats(ah);
- *resultsize = (*result == AH_NULL) ?
- 0 : sizeof(struct ar5212Stats);
+ OS_MEMZERO(&ahp->ext_ani_stats, sizeof(ahp->ext_ani_stats));
+ astats = ar5212AniGetCurrentStats(ah);
+ if (astats == NULL) {
+ *result = NULL;
+ *resultsize = 0;
+ } else {
+ OS_MEMCPY(&ahp->ext_ani_stats, astats, sizeof(HAL_ANI_STATS));
+ *result = &ahp->ext_ani_stats;
+ *resultsize = sizeof(ahp->ext_ani_stats);
+ }
return AH_TRUE;
case HAL_DIAG_ANI_CMD:
if (argsize != 2*sizeof(uint32_t))
@@ -1113,10 +1121,6 @@ ar5212GetDiagState(struct ath_hal *ah, int request,
return ar5212AniSetParams(ah, args, args);
}
break;
- case HAL_DIAG_CHANSURVEY:
- *result = &ahp->ah_chansurvey;
- *resultsize = sizeof(HAL_CHANNEL_SURVEY);
- return AH_TRUE;
}
return AH_FALSE;
}
diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_power.c b/sys/dev/ath/ath_hal/ar5212/ar5212_power.c
index 3f755bd..3068510 100644
--- a/sys/dev/ath/ath_hal/ar5212/ar5212_power.c
+++ b/sys/dev/ath/ath_hal/ar5212/ar5212_power.c
@@ -119,7 +119,6 @@ ar5212SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip)
HAL_BOOL
ar5212SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip)
{
- struct ath_hal_5212 *ahp = AH5212(ah);
#ifdef AH_DEBUG
static const char* modes[] = {
"AWAKE",
@@ -131,24 +130,29 @@ ar5212SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip)
int status = AH_TRUE;
HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__,
- modes[ahp->ah_powerMode], modes[mode],
+ modes[ah->ah_powerMode], modes[mode],
setChip ? "set chip " : "");
switch (mode) {
case HAL_PM_AWAKE:
+ if (setChip)
+ ah->ah_powerMode = mode;
status = ar5212SetPowerModeAwake(ah, setChip);
break;
case HAL_PM_FULL_SLEEP:
ar5212SetPowerModeSleep(ah, setChip);
+ if (setChip)
+ ah->ah_powerMode = mode;
break;
case HAL_PM_NETWORK_SLEEP:
ar5212SetPowerModeNetworkSleep(ah, setChip);
+ if (setChip)
+ ah->ah_powerMode = mode;
break;
default:
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode %u\n",
__func__, mode);
return AH_FALSE;
}
- ahp->ah_powerMode = mode;
return status;
}
diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c b/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c
index ccdccb6..fd3b473 100644
--- a/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c
+++ b/sys/dev/ath/ath_hal/ar5212/ar5212_reset.c
@@ -197,7 +197,8 @@ ar5212Reset(struct ath_hal *ah, HAL_OPMODE opmode,
saveFrameSeqCount = 0; /* NB: silence compiler */
/* Blank the channel survey statistics */
- OS_MEMZERO(&ahp->ah_chansurvey, sizeof(ahp->ah_chansurvey));
+ ath_hal_survey_clear(ah);
+
#if 0
/*
* XXX disable for now; this appears to sometimes cause OFDM
diff --git a/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c b/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c
index 4ca1a4d..5c84eb8 100644
--- a/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c
+++ b/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c
@@ -62,7 +62,7 @@ ar5312AniSetup(struct ath_hal *ah)
static struct ath_hal *
ar5312Attach(uint16_t devid, HAL_SOFTC sc,
HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata,
- HAL_STATUS *status)
+ HAL_OPS_CONFIG *ah_config, HAL_STATUS *status)
{
struct ath_hal_5212 *ahp = AH_NULL;
struct ath_hal *ah;
diff --git a/sys/dev/ath/ath_hal/ar5312/ar5312_power.c b/sys/dev/ath/ath_hal/ar5312/ar5312_power.c
index 94a0f1c..7db6d80 100644
--- a/sys/dev/ath/ath_hal/ar5312/ar5312_power.c
+++ b/sys/dev/ath/ath_hal/ar5312/ar5312_power.c
@@ -71,7 +71,6 @@ ar5312SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip)
HAL_BOOL
ar5312SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip)
{
- struct ath_hal_5212 *ahp = AH5212(ah);
#ifdef AH_DEBUG
static const char* modes[] = {
"AWAKE",
@@ -83,7 +82,7 @@ ar5312SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip)
int status = AH_TRUE;
HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__,
- modes[ahp->ah_powerMode], modes[mode],
+ modes[ah->ah_powerMode], modes[mode],
setChip ? "set chip " : "");
switch (mode) {
case HAL_PM_AWAKE:
@@ -100,7 +99,7 @@ ar5312SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip)
__func__, mode);
return AH_FALSE;
}
- ahp->ah_powerMode = mode;
+ ah->ah_powerMode = mode;
return status;
}
diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c b/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c
index 3f9bc69..fadd5ad 100644
--- a/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c
+++ b/sys/dev/ath/ath_hal/ar5416/ar5416_ani.c
@@ -818,7 +818,6 @@ ar5416AniGetListenTime(struct ath_hal *ah)
int32_t listenTime = 0;
int good;
HAL_SURVEY_SAMPLE hs;
- HAL_CHANNEL_SURVEY *cs = AH_NULL;
/*
* We shouldn't see ah_curchan be NULL, but just in case..
@@ -828,21 +827,13 @@ ar5416AniGetListenTime(struct ath_hal *ah)
return (0);
}
- cs = &ahp->ah_chansurvey;
-
/*
* Fetch the current statistics, squirrel away the current
- * sample, bump the sequence/sample counter.
+ * sample.
*/
OS_MEMZERO(&hs, sizeof(hs));
good = ar5416GetMibCycleCounts(ah, &hs);
- if (cs != AH_NULL) {
- OS_MEMCPY(&cs->samples[cs->cur_sample], &hs, sizeof(hs));
- cs->samples[cs->cur_sample].seq_num = cs->cur_seq;
- cs->cur_sample =
- (cs->cur_sample + 1) % CHANNEL_SURVEY_SAMPLE_COUNT;
- cs->cur_seq++;
- }
+ ath_hal_survey_add_sample(ah, &hs);
if (ANI_ENA(ah))
aniState = ahp->ah_curani;
diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c b/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c
index 99bab06..a20499a 100644
--- a/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c
+++ b/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c
@@ -297,7 +297,7 @@ ar5416GetRadioRev(struct ath_hal *ah)
static struct ath_hal *
ar5416Attach(uint16_t devid, HAL_SOFTC sc,
HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata,
- HAL_STATUS *status)
+ HAL_OPS_CONFIG *ah_config, HAL_STATUS *status)
{
struct ath_hal_5416 *ahp5416;
struct ath_hal_5212 *ahp;
@@ -1059,6 +1059,11 @@ ar5416FillCapabilityInfo(struct ath_hal *ah)
if (! AH_PRIVATE(ah)->ah_ispcie)
pCap->halSerialiseRegWar = 1;
+ /*
+ * AR5416 and later NICs support MYBEACON filtering.
+ */
+ pCap->halRxDoMyBeacon = AH_TRUE;
+
return AH_TRUE;
}
diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c b/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c
index e2bf6c7..6691c11 100644
--- a/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c
+++ b/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c
@@ -197,6 +197,25 @@ ar5416SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs)
* beacon jitter; cab timeout is max time to wait for cab
* after seeing the last DTIM or MORE CAB bit
*/
+
+/*
+ * I've bumped these to 30TU for now.
+ *
+ * Some APs (AR933x/AR934x?) in 2GHz especially seem to not always
+ * transmit beacon frames at exactly the right times and with it set
+ * to 10TU, the NIC starts not waking up at the right times to hear
+ * these slightly-larger-jitering beacons. It also never recovers
+ * from that (it doesn't resync? I'm not sure.)
+ *
+ * So for now bump this to 30TU. Ideally we'd cap this based on
+ * the beacon interval so the sum of CAB+BEACON timeouts never
+ * exceeded the beacon interval.
+ *
+ * Now, since we're doing all the math in the ath(4) driver in TU
+ * rather than TSF, we may be seeing the result of dumb rounding
+ * errors causing the jitter to actually be a much bigger problem.
+ * I'll have to investigate that with a fine tooth comb.
+ */
#define CAB_TIMEOUT_VAL 10 /* in TU */
#define BEACON_TIMEOUT_VAL 10 /* in TU */
#define SLEEP_SLOP 3 /* in TU */
@@ -248,6 +267,13 @@ ar5416SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *bs)
OS_REG_SET_BIT(ah, AR_TIMER_MODE,
AR_TIMER_MODE_TBTT | AR_TIMER_MODE_TIM | AR_TIMER_MODE_DTIM);
+
+#define HAL_TSFOOR_THRESHOLD 0x00004240 /* TSF OOR threshold (16k us) */
+
+ /* TSF out of range threshold */
+// OS_REG_WRITE(ah, AR_TSFOOR_THRESHOLD, bs->bs_tsfoor_threshold);
+ OS_REG_WRITE(ah, AR_TSFOOR_THRESHOLD, HAL_TSFOOR_THRESHOLD);
+
HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: next DTIM %d\n",
__func__, bs->bs_nextdtim);
HALDEBUG(ah, HAL_DEBUG_BEACON, "%s: next beacon %d\n",
diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c b/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c
index d51417f4..35bb8d4 100644
--- a/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c
+++ b/sys/dev/ath/ath_hal/ar5416/ar5416_cal.c
@@ -663,7 +663,7 @@ ar5416LoadNF(struct ath_hal *ah, const struct ieee80211_channel *chan)
* by the median we just loaded. This will be initial (and max) value
* of next noise floor calibration the baseband does.
*/
- for (i = 0; i < AR5416_NUM_NF_READINGS; i ++)
+ for (i = 0; i < AR5416_NUM_NF_READINGS; i ++) {
/* Don't write to EXT radio CCA registers unless in HT/40 mode */
/* XXX this check should really be cleaner! */
@@ -676,6 +676,7 @@ ar5416LoadNF(struct ath_hal *ah, const struct ieee80211_channel *chan)
val |= (((uint32_t)(-50) << 1) & 0x1ff);
OS_REG_WRITE(ah, ar5416_cca_regs[i], val);
}
+ }
}
/*
diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c b/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c
index 631ca2f..32ce2ed 100644
--- a/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c
+++ b/sys/dev/ath/ath_hal/ar5416/ar5416_interrupts.c
@@ -337,6 +337,9 @@ ar5416SetInterrupts(struct ath_hal *ah, HAL_INT ints)
/* Write the new IMR and store off our SW copy. */
HALDEBUG(ah, HAL_DEBUG_INTERRUPT, "%s: new IMR 0x%x\n", __func__, mask);
OS_REG_WRITE(ah, AR_IMR, mask);
+ /* Flush write */
+ (void) OS_REG_READ(ah, AR_IMR);
+
mask = OS_REG_READ(ah, AR_IMR_S2) & ~(AR_IMR_S2_TIM |
AR_IMR_S2_DTIM |
AR_IMR_S2_DTIMSYNC |
diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_power.c b/sys/dev/ath/ath_hal/ar5416/ar5416_power.c
index 43a9241..dff9a85 100644
--- a/sys/dev/ath/ath_hal/ar5416/ar5416_power.c
+++ b/sys/dev/ath/ath_hal/ar5416/ar5416_power.c
@@ -124,7 +124,6 @@ ar5416SetPowerModeNetworkSleep(struct ath_hal *ah, int setChip)
HAL_BOOL
ar5416SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip)
{
- struct ath_hal_5212 *ahp = AH5212(ah);
#ifdef AH_DEBUG
static const char* modes[] = {
"AWAKE",
@@ -134,27 +133,35 @@ ar5416SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip)
};
#endif
int status = AH_TRUE;
+
+#if 0
if (!setChip)
return AH_TRUE;
+#endif
HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__,
- modes[ahp->ah_powerMode], modes[mode], setChip ? "set chip " : "");
+ modes[ah->ah_powerMode], modes[mode], setChip ? "set chip " : "");
switch (mode) {
case HAL_PM_AWAKE:
+ if (setChip)
+ ah->ah_powerMode = mode;
status = ar5416SetPowerModeAwake(ah, setChip);
break;
case HAL_PM_FULL_SLEEP:
ar5416SetPowerModeSleep(ah, setChip);
+ if (setChip)
+ ah->ah_powerMode = mode;
break;
case HAL_PM_NETWORK_SLEEP:
ar5416SetPowerModeNetworkSleep(ah, setChip);
+ if (setChip)
+ ah->ah_powerMode = mode;
break;
default:
HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode 0x%x\n",
__func__, mode);
return AH_FALSE;
}
- ahp->ah_powerMode = mode;
return status;
}
diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c b/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c
index eb31f08..baf0ccc 100644
--- a/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c
+++ b/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c
@@ -120,9 +120,10 @@ ar5416Reset(struct ath_hal *ah, HAL_OPMODE opmode,
HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1);
/* Blank the channel survey statistics */
- OS_MEMZERO(&ahp->ah_chansurvey, sizeof(ahp->ah_chansurvey));
+ ath_hal_survey_clear(ah);
/* XXX Turn on fast channel change for 5416 */
+
/*
* Preserve the bmiss rssi threshold and count threshold
* across resets
diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416reg.h b/sys/dev/ath/ath_hal/ar5416/ar5416reg.h
index 435599c..0ee1e70 100644
--- a/sys/dev/ath/ath_hal/ar5416/ar5416reg.h
+++ b/sys/dev/ath/ath_hal/ar5416/ar5416reg.h
@@ -476,10 +476,10 @@
/* Sleep control */
#define AR5416_SLEEP1_ASSUME_DTIM 0x00080000
#define AR5416_SLEEP1_CAB_TIMEOUT 0xFFE00000 /* Cab timeout (TU) */
-#define AR5416_SLEEP1_CAB_TIMEOUT_S 22
+#define AR5416_SLEEP1_CAB_TIMEOUT_S 21
#define AR5416_SLEEP2_BEACON_TIMEOUT 0xFFE00000 /* Beacon timeout (TU)*/
-#define AR5416_SLEEP2_BEACON_TIMEOUT_S 22
+#define AR5416_SLEEP2_BEACON_TIMEOUT_S 21
/* Sleep Registers */
#define AR_SLP32_HALFCLK_LATENCY 0x000FFFFF /* rising <-> falling edge */
diff --git a/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c b/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c
index 4f478c0..c270bab 100644
--- a/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c
+++ b/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c
@@ -69,7 +69,9 @@ static HAL_BOOL ar9130FillCapabilityInfo(struct ath_hal *ah);
*/
static struct ath_hal *
ar9130Attach(uint16_t devid, HAL_SOFTC sc,
- HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_STATUS *status)
+ HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata,
+ HAL_OPS_CONFIG *ah_config,
+ HAL_STATUS *status)
{
struct ath_hal_5416 *ahp5416;
struct ath_hal_5212 *ahp;
diff --git a/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c b/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c
index 979ba1a..5bda519 100644
--- a/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c
+++ b/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c
@@ -114,6 +114,7 @@ ar9160InitPLL(struct ath_hal *ah, const struct ieee80211_channel *chan)
static struct ath_hal *
ar9160Attach(uint16_t devid, HAL_SOFTC sc,
HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata,
+ HAL_OPS_CONFIG *ah_config,
HAL_STATUS *status)
{
struct ath_hal_5416 *ahp5416;
diff --git a/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c b/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c
index 2a67fe5..3be3e35 100644
--- a/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c
+++ b/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c
@@ -148,6 +148,7 @@ ar9280InitPLL(struct ath_hal *ah, const struct ieee80211_channel *chan)
static struct ath_hal *
ar9280Attach(uint16_t devid, HAL_SOFTC sc,
HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata,
+ HAL_OPS_CONFIG *ah_config,
HAL_STATUS *status)
{
struct ath_hal_9280 *ahp9280;
diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c b/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c
index edb6f26..eb3490a 100644
--- a/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c
+++ b/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c
@@ -133,6 +133,7 @@ ar9285_eeprom_print_diversity_settings(struct ath_hal *ah)
static struct ath_hal *
ar9285Attach(uint16_t devid, HAL_SOFTC sc,
HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata,
+ HAL_OPS_CONFIG *ah_config,
HAL_STATUS *status)
{
struct ath_hal_9285 *ahp9285;
diff --git a/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c b/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c
index 010e2c3..0ea565c 100644
--- a/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c
+++ b/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c
@@ -111,6 +111,7 @@ ar9287AniSetup(struct ath_hal *ah)
static struct ath_hal *
ar9287Attach(uint16_t devid, HAL_SOFTC sc,
HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata,
+ HAL_OPS_CONFIG *ah_config,
HAL_STATUS *status)
{
struct ath_hal_9287 *ahp9287;
diff --git a/sys/dev/ath/ath_rate/sample/sample.c b/sys/dev/ath/ath_rate/sample/sample.c
index b3f82fa..36cd679 100644
--- a/sys/dev/ath/ath_rate/sample/sample.c
+++ b/sys/dev/ath/ath_rate/sample/sample.c
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <sys/kernel.h>
#include <sys/lock.h>
+#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/errno.h>
@@ -61,6 +62,7 @@ __FBSDID("$FreeBSD$");
#include <sys/socket.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_media.h>
#include <net/if_arp.h>
#include <net/ethernet.h> /* XXX for ether_sprintf */
@@ -889,8 +891,8 @@ ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
if (!mrr || ts->ts_finaltsi == 0) {
if (!IS_RATE_DEFINED(sn, final_rix)) {
- device_printf(sc->sc_dev, "%s: ts_rate=%d ts_finaltsi=%d\n",
- __func__, ts->ts_rate, ts->ts_finaltsi);
+ device_printf(sc->sc_dev, "%s: ts_rate=%d ts_finaltsi=%d, final_rix=%d\n",
+ __func__, ts->ts_rate, ts->ts_finaltsi, final_rix);
badrate(ifp, 0, ts->ts_rate, long_tries, status);
return;
}
diff --git a/sys/dev/ath/ath_rate/sample/sample.h b/sys/dev/ath/ath_rate/sample/sample.h
index 7438a3d..1c57dee 100644
--- a/sys/dev/ath/ath_rate/sample/sample.h
+++ b/sys/dev/ath/ath_rate/sample/sample.h
@@ -113,7 +113,7 @@ struct sample_node {
#ifdef _KERNEL
#define ATH_NODE_SAMPLE(an) ((struct sample_node *)&(an)[1])
-#define IS_RATE_DEFINED(sn, rix) (((sn)->ratemask & (1<<(rix))) != 0)
+#define IS_RATE_DEFINED(sn, rix) (((uint64_t) (sn)->ratemask & (1ULL<<((uint64_t) rix))) != 0)
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c
index 6e58896..3787500 100644
--- a/sys/dev/ath/if_ath.c
+++ b/sys/dev/ath/if_ath.c
@@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
@@ -164,6 +165,7 @@ static void ath_bmiss_vap(struct ieee80211vap *);
static void ath_bmiss_proc(void *, int);
static void ath_key_update_begin(struct ieee80211vap *);
static void ath_key_update_end(struct ieee80211vap *);
+static void ath_update_mcast_hw(struct ath_softc *);
static void ath_update_mcast(struct ifnet *);
static void ath_update_promisc(struct ifnet *);
static void ath_updateslot(struct ifnet *);
@@ -238,17 +240,14 @@ SYSCTL_INT(_hw_ath, OID_AUTO, anical, CTLFLAG_RW, &ath_anicalinterval,
0, "ANI calibration (msecs)");
int ath_rxbuf = ATH_RXBUF; /* # rx buffers to allocate */
-SYSCTL_INT(_hw_ath, OID_AUTO, rxbuf, CTLFLAG_RW, &ath_rxbuf,
+SYSCTL_INT(_hw_ath, OID_AUTO, rxbuf, CTLFLAG_RWTUN, &ath_rxbuf,
0, "rx buffers allocated");
-TUNABLE_INT("hw.ath.rxbuf", &ath_rxbuf);
int ath_txbuf = ATH_TXBUF; /* # tx buffers to allocate */
-SYSCTL_INT(_hw_ath, OID_AUTO, txbuf, CTLFLAG_RW, &ath_txbuf,
+SYSCTL_INT(_hw_ath, OID_AUTO, txbuf, CTLFLAG_RWTUN, &ath_txbuf,
0, "tx buffers allocated");
-TUNABLE_INT("hw.ath.txbuf", &ath_txbuf);
int ath_txbuf_mgmt = ATH_MGMT_TXBUF; /* # mgmt tx buffers to allocate */
-SYSCTL_INT(_hw_ath, OID_AUTO, txbuf_mgmt, CTLFLAG_RW, &ath_txbuf_mgmt,
+SYSCTL_INT(_hw_ath, OID_AUTO, txbuf_mgmt, CTLFLAG_RWTUN, &ath_txbuf_mgmt,
0, "tx (mgmt) buffers allocated");
-TUNABLE_INT("hw.ath.txbuf_mgmt", &ath_txbuf_mgmt);
int ath_bstuck_threshold = 4; /* max missed beacons */
SYSCTL_INT(_hw_ath, OID_AUTO, bstuck, CTLFLAG_RW, &ath_bstuck_threshold,
@@ -278,6 +277,293 @@ ath_legacy_attach_comp_func(struct ath_softc *sc)
}
}
+/*
+ * Set the target power mode.
+ *
+ * If this is called during a point in time where
+ * the hardware is being programmed elsewhere, it will
+ * simply store it away and update it when all current
+ * uses of the hardware are completed.
+ */
+void
+_ath_power_setpower(struct ath_softc *sc, int power_state, const char *file, int line)
+{
+ ATH_LOCK_ASSERT(sc);
+
+ sc->sc_target_powerstate = power_state;
+
+ DPRINTF(sc, ATH_DEBUG_PWRSAVE, "%s: (%s:%d) state=%d, refcnt=%d\n",
+ __func__,
+ file,
+ line,
+ power_state,
+ sc->sc_powersave_refcnt);
+
+ if (sc->sc_powersave_refcnt == 0 &&
+ power_state != sc->sc_cur_powerstate) {
+ sc->sc_cur_powerstate = power_state;
+ ath_hal_setpower(sc->sc_ah, power_state);
+
+ /*
+ * If the NIC is force-awake, then set the
+ * self-gen frame state appropriately.
+ *
+ * If the nic is in network sleep or full-sleep,
+ * we let the above call leave the self-gen
+ * state as "sleep".
+ */
+ if (sc->sc_cur_powerstate == HAL_PM_AWAKE &&
+ sc->sc_target_selfgen_state != HAL_PM_AWAKE) {
+ ath_hal_setselfgenpower(sc->sc_ah,
+ sc->sc_target_selfgen_state);
+ }
+ }
+}
+
+/*
+ * Set the current self-generated frames state.
+ *
+ * This is separate from the target power mode. The chip may be
+ * awake but the desired state is "sleep", so frames sent to the
+ * destination has PWRMGT=1 in the 802.11 header. The NIC also
+ * needs to know to set PWRMGT=1 in self-generated frames.
+ */
+void
+_ath_power_set_selfgen(struct ath_softc *sc, int power_state, const char *file, int line)
+{
+
+ ATH_LOCK_ASSERT(sc);
+
+ DPRINTF(sc, ATH_DEBUG_PWRSAVE, "%s: (%s:%d) state=%d, refcnt=%d\n",
+ __func__,
+ file,
+ line,
+ power_state,
+ sc->sc_target_selfgen_state);
+
+ sc->sc_target_selfgen_state = power_state;
+
+ /*
+ * If the NIC is force-awake, then set the power state.
+ * Network-state and full-sleep will already transition it to
+ * mark self-gen frames as sleeping - and we can't
+ * guarantee the NIC is awake to program the self-gen frame
+ * setting anyway.
+ */
+ if (sc->sc_cur_powerstate == HAL_PM_AWAKE) {
+ ath_hal_setselfgenpower(sc->sc_ah, power_state);
+ }
+}
+
+/*
+ * Set the hardware power mode and take a reference.
+ *
+ * This doesn't update the target power mode in the driver;
+ * it just updates the hardware power state.
+ *
+ * XXX it should only ever force the hardware awake; it should
+ * never be called to set it asleep.
+ */
+void
+_ath_power_set_power_state(struct ath_softc *sc, int power_state, const char *file, int line)
+{
+ ATH_LOCK_ASSERT(sc);
+
+ DPRINTF(sc, ATH_DEBUG_PWRSAVE, "%s: (%s:%d) state=%d, refcnt=%d\n",
+ __func__,
+ file,
+ line,
+ power_state,
+ sc->sc_powersave_refcnt);
+
+ sc->sc_powersave_refcnt++;
+
+ if (power_state != sc->sc_cur_powerstate) {
+ ath_hal_setpower(sc->sc_ah, power_state);
+ sc->sc_cur_powerstate = power_state;
+
+ /*
+ * Adjust the self-gen powerstate if appropriate.
+ */
+ if (sc->sc_cur_powerstate == HAL_PM_AWAKE &&
+ sc->sc_target_selfgen_state != HAL_PM_AWAKE) {
+ ath_hal_setselfgenpower(sc->sc_ah,
+ sc->sc_target_selfgen_state);
+ }
+
+ }
+}
+
+/*
+ * Restore the power save mode to what it once was.
+ *
+ * This will decrement the reference counter and once it hits
+ * zero, it'll restore the powersave state.
+ */
+void
+_ath_power_restore_power_state(struct ath_softc *sc, const char *file, int line)
+{
+
+ ATH_LOCK_ASSERT(sc);
+
+ DPRINTF(sc, ATH_DEBUG_PWRSAVE, "%s: (%s:%d) refcnt=%d, target state=%d\n",
+ __func__,
+ file,
+ line,
+ sc->sc_powersave_refcnt,
+ sc->sc_target_powerstate);
+
+ if (sc->sc_powersave_refcnt == 0)
+ device_printf(sc->sc_dev, "%s: refcnt=0?\n", __func__);
+ else
+ sc->sc_powersave_refcnt--;
+
+ if (sc->sc_powersave_refcnt == 0 &&
+ sc->sc_target_powerstate != sc->sc_cur_powerstate) {
+ sc->sc_cur_powerstate = sc->sc_target_powerstate;
+ ath_hal_setpower(sc->sc_ah, sc->sc_target_powerstate);
+ }
+
+ /*
+ * Adjust the self-gen powerstate if appropriate.
+ */
+ if (sc->sc_cur_powerstate == HAL_PM_AWAKE &&
+ sc->sc_target_selfgen_state != HAL_PM_AWAKE) {
+ ath_hal_setselfgenpower(sc->sc_ah,
+ sc->sc_target_selfgen_state);
+ }
+
+}
+
+/*
+ * Configure the initial HAL configuration values based on bus
+ * specific parameters.
+ *
+ * Some PCI IDs and other information may need tweaking.
+ *
+ * XXX TODO: ath9k and the Atheros HAL only program comm2g_switch_enable
+ * if BT antenna diversity isn't enabled.
+ *
+ * So, let's also figure out how to enable BT diversity for AR9485.
+ */
+static void
+ath_setup_hal_config(struct ath_softc *sc, HAL_OPS_CONFIG *ah_config)
+{
+ /* XXX TODO: only for PCI devices? */
+
+ if (sc->sc_pci_devinfo & (ATH_PCI_CUS198 | ATH_PCI_CUS230)) {
+ ah_config->ath_hal_ext_lna_ctl_gpio = 0x200; /* bit 9 */
+ ah_config->ath_hal_ext_atten_margin_cfg = AH_TRUE;
+ ah_config->ath_hal_min_gainidx = AH_TRUE;
+ ah_config->ath_hal_ant_ctrl_comm2g_switch_enable = 0x000bbb88;
+ /* XXX low_rssi_thresh */
+ /* XXX fast_div_bias */
+ device_printf(sc->sc_dev, "configuring for %s\n",
+ (sc->sc_pci_devinfo & ATH_PCI_CUS198) ?
+ "CUS198" : "CUS230");
+ }
+
+ if (sc->sc_pci_devinfo & ATH_PCI_CUS217)
+ device_printf(sc->sc_dev, "CUS217 card detected\n");
+
+ if (sc->sc_pci_devinfo & ATH_PCI_CUS252)
+ device_printf(sc->sc_dev, "CUS252 card detected\n");
+
+ if (sc->sc_pci_devinfo & ATH_PCI_AR9565_1ANT)
+ device_printf(sc->sc_dev, "WB335 1-ANT card detected\n");
+
+ if (sc->sc_pci_devinfo & ATH_PCI_AR9565_2ANT)
+ device_printf(sc->sc_dev, "WB335 2-ANT card detected\n");
+
+ if (sc->sc_pci_devinfo & ATH_PCI_KILLER)
+ device_printf(sc->sc_dev, "Killer Wireless card detected\n");
+
+#if 0
+ /*
+ * Some WB335 cards do not support antenna diversity. Since
+ * we use a hardcoded value for AR9565 instead of using the
+ * EEPROM/OTP data, remove the combining feature from
+ * the HW capabilities bitmap.
+ */
+ if (sc->sc_pci_devinfo & (ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_AR9565_2ANT)) {
+ if (!(sc->sc_pci_devinfo & ATH9K_PCI_BT_ANT_DIV))
+ pCap->hw_caps &= ~ATH9K_HW_CAP_ANT_DIV_COMB;
+ }
+
+ if (sc->sc_pci_devinfo & ATH9K_PCI_BT_ANT_DIV) {
+ pCap->hw_caps |= ATH9K_HW_CAP_BT_ANT_DIV;
+ device_printf(sc->sc_dev, "Set BT/WLAN RX diversity capability\n");
+ }
+#endif
+
+ if (sc->sc_pci_devinfo & ATH_PCI_D3_L1_WAR) {
+ ah_config->ath_hal_pcie_waen = 0x0040473b;
+ device_printf(sc->sc_dev, "Enable WAR for ASPM D3/L1\n");
+ }
+
+#if 0
+ if (sc->sc_pci_devinfo & ATH9K_PCI_NO_PLL_PWRSAVE) {
+ ah->config.no_pll_pwrsave = true;
+ device_printf(sc->sc_dev, "Disable PLL PowerSave\n");
+ }
+#endif
+
+}
+
+/*
+ * Attempt to fetch the MAC address from the kernel environment.
+ *
+ * Returns 0, macaddr in macaddr if successful; -1 otherwise.
+ */
+static int
+ath_fetch_mac_kenv(struct ath_softc *sc, uint8_t *macaddr)
+{
+ char devid_str[32];
+ int local_mac = 0;
+ char *local_macstr;
+
+ /*
+ * Fetch from the kenv rather than using hints.
+ *
+ * Hints would be nice but the transition to dynamic
+ * hints/kenv doesn't happen early enough for this
+ * to work reliably (eg on anything embedded.)
+ */
+ snprintf(devid_str, 32, "hint.%s.%d.macaddr",
+ device_get_name(sc->sc_dev),
+ device_get_unit(sc->sc_dev));
+
+ if ((local_macstr = getenv(devid_str)) != NULL) {
+ uint32_t tmpmac[ETHER_ADDR_LEN];
+ int count;
+ int i;
+
+ /* Have a MAC address; should use it */
+ device_printf(sc->sc_dev,
+ "Overriding MAC address from environment: '%s'\n",
+ local_macstr);
+
+ /* Extract out the MAC address */
+ count = sscanf(local_macstr, "%x%*c%x%*c%x%*c%x%*c%x%*c%x",
+ &tmpmac[0], &tmpmac[1],
+ &tmpmac[2], &tmpmac[3],
+ &tmpmac[4], &tmpmac[5]);
+ if (count == 6) {
+ /* Valid! */
+ local_mac = 1;
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+ macaddr[i] = tmpmac[i];
+ }
+ /* Done! */
+ freeenv(local_macstr);
+ local_macstr = NULL;
+ }
+
+ if (local_mac)
+ return (0);
+ return (-1);
+}
+
#define HAL_MODE_HT20 (HAL_MODE_11NG_HT20 | HAL_MODE_11NA_HT20)
#define HAL_MODE_HT40 \
(HAL_MODE_11NG_HT40PLUS | HAL_MODE_11NG_HT40MINUS | \
@@ -293,6 +579,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
u_int wmodes;
uint8_t macaddr[IEEE80211_ADDR_LEN];
int rx_chainmask, tx_chainmask;
+ HAL_OPS_CONFIG ah_config;
DPRINTF(sc, ATH_DEBUG_ANY, "%s: devid 0x%x\n", __func__, devid);
@@ -311,8 +598,17 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
device_get_unit(sc->sc_dev));
CURVNET_RESTORE();
+ /*
+ * Configure the initial configuration data.
+ *
+ * This is stuff that may be needed early during attach
+ * rather than done via configuration calls later.
+ */
+ bzero(&ah_config, sizeof(ah_config));
+ ath_setup_hal_config(sc, &ah_config);
+
ah = ath_hal_attach(devid, sc, sc->sc_st, sc->sc_sh,
- sc->sc_eepromdata, &status);
+ sc->sc_eepromdata, &ah_config, &status);
if (ah == NULL) {
if_printf(ifp, "unable to attach hardware; HAL status %u\n",
status);
@@ -340,6 +636,10 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
ath_xmit_setup_legacy(sc);
}
+ if (ath_hal_hasmybeacon(sc->sc_ah)) {
+ sc->sc_do_mybeacon = 1;
+ }
+
/*
* Check if the MAC has multi-rate retry support.
* We do this by trying to setup a fake extended
@@ -604,6 +904,8 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
#ifdef ATH_ENABLE_DFS
| IEEE80211_C_DFS /* Enable radar detection */
#endif
+ | IEEE80211_C_PMGT /* Station side power mgmt */
+ | IEEE80211_C_SWSLEEP
;
/*
* Query the hal to figure out h/w crypto support.
@@ -901,8 +1203,14 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
*/
sc->sc_hasveol = ath_hal_hasveol(ah);
- /* get mac address from hardware */
- ath_hal_getmac(ah, macaddr);
+ /* get mac address from kenv first, then hardware */
+ if (ath_fetch_mac_kenv(sc, macaddr) == 0) {
+ /* Tell the HAL now about the new MAC */
+ ath_hal_setmac(ah, macaddr);
+ } else {
+ ath_hal_getmac(ah, macaddr);
+ }
+
if (sc->sc_hasbmask)
ath_hal_getbssidmask(ah, sc->sc_hwbssidmask);
@@ -993,6 +1301,14 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
if (bootverbose)
ieee80211_announce(ic);
ath_announce(sc);
+
+ /*
+ * Put it to sleep for now.
+ */
+ ATH_LOCK(sc);
+ ath_power_setpower(sc, HAL_PM_FULL_SLEEP);
+ ATH_UNLOCK(sc);
+
return 0;
bad2:
ath_tx_cleanup(sc);
@@ -1038,7 +1354,22 @@ ath_detach(struct ath_softc *sc)
* it last
* Other than that, it's straightforward...
*/
+
+ /*
+ * XXX Wake the hardware up first. ath_stop() will still
+ * wake it up first, but I'd rather do it here just to
+ * ensure it's awake.
+ */
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ath_power_setpower(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
+ /*
+ * Stop things cleanly.
+ */
ath_stop(ifp);
+
ieee80211_ifdetach(ifp->if_l2com);
taskqueue_free(sc->sc_tq);
#ifdef ATH_TX99_DIAG
@@ -1401,6 +1732,10 @@ ath_vap_delete(struct ieee80211vap *vap)
struct ath_hal *ah = sc->sc_ah;
struct ath_vap *avp = ATH_VAP(vap);
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
DPRINTF(sc, ATH_DEBUG_RESET, "%s: called\n", __func__);
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
/*
@@ -1409,11 +1744,13 @@ ath_vap_delete(struct ieee80211vap *vap)
* the vap state by any frames pending on the tx queues.
*/
ath_hal_intrset(ah, 0); /* disable interrupts */
- ath_draintxq(sc, ATH_RESET_DEFAULT); /* stop hw xmit side */
/* XXX Do all frames from all vaps/nodes need draining here? */
ath_stoprecv(sc, 1); /* stop recv side */
+ ath_draintxq(sc, ATH_RESET_DEFAULT); /* stop hw xmit side */
}
+ /* .. leave the hardware awake for now. */
+
ieee80211_vap_detach(vap);
/*
@@ -1501,6 +1838,9 @@ ath_vap_delete(struct ieee80211vap *vap)
}
ath_hal_intrset(ah, sc->sc_imask);
}
+
+ /* Ok, let the hardware asleep. */
+ ath_power_restore_power_state(sc);
ATH_UNLOCK(sc);
}
@@ -1520,12 +1860,25 @@ ath_suspend(struct ath_softc *sc)
* NB: don't worry about putting the chip in low power
* mode; pci will power off our socket on suspend and
* CardBus detaches the device.
+ *
+ * XXX TODO: well, that's great, except for non-cardbus
+ * devices!
*/
/*
- * XXX ensure none of the taskqueues are running
+ * XXX This doesn't wait until all pending taskqueue
+ * items and parallel transmit/receive/other threads
+ * are running!
+ */
+ ath_hal_intrset(sc->sc_ah, 0);
+ taskqueue_block(sc->sc_tq);
+
+ ATH_LOCK(sc);
+ callout_stop(&sc->sc_cal_ch);
+ ATH_UNLOCK(sc);
+
+ /*
* XXX ensure sc_invalid is 1
- * XXX ensure the calibration callout is disabled
*/
/* Disable the PCIe PHY, complete with workarounds */
@@ -1546,8 +1899,12 @@ ath_reset_keycache(struct ath_softc *sc)
struct ath_hal *ah = sc->sc_ah;
int i;
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
for (i = 0; i < sc->sc_keymax; i++)
ath_hal_keyreset(ah, i);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
ieee80211_crypto_reload_keys(ic);
}
@@ -1599,11 +1956,24 @@ ath_resume(struct ath_softc *sc)
sc->sc_curchan != NULL ? sc->sc_curchan : ic->ic_curchan);
ath_hal_setchainmasks(sc->sc_ah, sc->sc_cur_txchainmask,
sc->sc_cur_rxchainmask);
+
+ /* Ensure we set the current power state to on */
+ ATH_LOCK(sc);
+ ath_power_setselfgen(sc, HAL_PM_AWAKE);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ath_power_setpower(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
ath_hal_reset(ah, sc->sc_opmode,
sc->sc_curchan != NULL ? sc->sc_curchan : ic->ic_curchan,
AH_FALSE, &status);
ath_reset_keycache(sc);
+ ATH_RX_LOCK(sc);
+ sc->sc_rx_stopped = 1;
+ sc->sc_rx_resetted = 1;
+ ATH_RX_UNLOCK(sc);
+
/* Let DFS at it in case it's a DFS channel */
ath_dfs_radar_enable(sc, ic->ic_curchan);
@@ -1631,6 +2001,10 @@ ath_resume(struct ath_softc *sc)
if (sc->sc_resume_up)
ieee80211_resume_all(ic);
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+
/* XXX beacons ? */
}
@@ -1688,6 +2062,10 @@ ath_intr(void *arg)
return;
}
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
if ((ifp->if_flags & IFF_UP) == 0 ||
(ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
HAL_INT status;
@@ -1697,6 +2075,10 @@ ath_intr(void *arg)
ath_hal_getisr(ah, &status); /* clear ISR */
ath_hal_intrset(ah, 0); /* disable further intr's */
ATH_PCU_UNLOCK(sc);
+
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
return;
}
@@ -1736,6 +2118,11 @@ ath_intr(void *arg)
/* Short-circuit un-handled interrupts */
if (status == 0x0) {
ATH_PCU_UNLOCK(sc);
+
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+
return;
}
@@ -1791,44 +2178,46 @@ ath_intr(void *arg)
if (status & HAL_INT_RXEOL) {
int imask;
ATH_KTR(sc, ATH_KTR_ERROR, 0, "ath_intr: RXEOL");
- ATH_PCU_LOCK(sc);
- /*
- * NB: the hardware should re-read the link when
- * RXE bit is written, but it doesn't work at
- * least on older hardware revs.
- */
- sc->sc_stats.ast_rxeol++;
- /*
- * Disable RXEOL/RXORN - prevent an interrupt
- * storm until the PCU logic can be reset.
- * In case the interface is reset some other
- * way before "sc_kickpcu" is called, don't
- * modify sc_imask - that way if it is reset
- * by a call to ath_reset() somehow, the
- * interrupt mask will be correctly reprogrammed.
- */
- imask = sc->sc_imask;
- imask &= ~(HAL_INT_RXEOL | HAL_INT_RXORN);
- ath_hal_intrset(ah, imask);
- /*
- * Only blank sc_rxlink if we've not yet kicked
- * the PCU.
- *
- * This isn't entirely correct - the correct solution
- * would be to have a PCU lock and engage that for
- * the duration of the PCU fiddling; which would include
- * running the RX process. Otherwise we could end up
- * messing up the RX descriptor chain and making the
- * RX desc list much shorter.
- */
- if (! sc->sc_kickpcu)
- sc->sc_rxlink = NULL;
- sc->sc_kickpcu = 1;
- ATH_PCU_UNLOCK(sc);
+ if (! sc->sc_isedma) {
+ ATH_PCU_LOCK(sc);
+ /*
+ * NB: the hardware should re-read the link when
+ * RXE bit is written, but it doesn't work at
+ * least on older hardware revs.
+ */
+ sc->sc_stats.ast_rxeol++;
+ /*
+ * Disable RXEOL/RXORN - prevent an interrupt
+ * storm until the PCU logic can be reset.
+ * In case the interface is reset some other
+ * way before "sc_kickpcu" is called, don't
+ * modify sc_imask - that way if it is reset
+ * by a call to ath_reset() somehow, the
+ * interrupt mask will be correctly reprogrammed.
+ */
+ imask = sc->sc_imask;
+ imask &= ~(HAL_INT_RXEOL | HAL_INT_RXORN);
+ ath_hal_intrset(ah, imask);
+ /*
+ * Only blank sc_rxlink if we've not yet kicked
+ * the PCU.
+ *
+ * This isn't entirely correct - the correct solution
+ * would be to have a PCU lock and engage that for
+ * the duration of the PCU fiddling; which would include
+ * running the RX process. Otherwise we could end up
+ * messing up the RX descriptor chain and making the
+ * RX desc list much shorter.
+ */
+ if (! sc->sc_kickpcu)
+ sc->sc_rxlink = NULL;
+ sc->sc_kickpcu = 1;
+ ATH_PCU_UNLOCK(sc);
+ }
/*
- * Enqueue an RX proc, to handled whatever
+ * Enqueue an RX proc to handle whatever
* is in the RX queue.
- * This will then kick the PCU.
+ * This will then kick the PCU if required.
*/
sc->sc_rx.recv_sched(sc, 1);
}
@@ -1902,10 +2291,18 @@ ath_intr(void *arg)
ATH_KTR(sc, ATH_KTR_ERROR, 0, "ath_intr: RXORN");
sc->sc_stats.ast_rxorn++;
}
+ if (status & HAL_INT_TSFOOR) {
+ device_printf(sc->sc_dev, "%s: TSFOOR\n", __func__);
+ sc->sc_syncbeacon = 1;
+ }
}
ATH_PCU_LOCK(sc);
sc->sc_intr_cnt--;
ATH_PCU_UNLOCK(sc);
+
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
}
static void
@@ -1936,6 +2333,8 @@ ath_fatal_proc(void *arg, int pending)
static void
ath_bmiss_vap(struct ieee80211vap *vap)
{
+ struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
+
/*
* Workaround phantom bmiss interrupts by sanity-checking
* the time of our last rx'd frame. If it is within the
@@ -1944,6 +2343,16 @@ ath_bmiss_vap(struct ieee80211vap *vap)
* be dispatched up for processing. Note this applies only
* for h/w beacon miss events.
*/
+
+ /*
+ * XXX TODO: Just read the TSF during the interrupt path;
+ * that way we don't have to wake up again just to read it
+ * again.
+ */
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
if ((vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS) == 0) {
struct ifnet *ifp = vap->iv_ic->ic_ifp;
struct ath_softc *sc = ifp->if_softc;
@@ -1961,12 +2370,32 @@ ath_bmiss_vap(struct ieee80211vap *vap)
if (tsf - lastrx <= bmisstimeout) {
sc->sc_stats.ast_bmiss_phantom++;
+
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+
return;
}
}
+
+ /*
+ * There's no need to keep the hardware awake during the call
+ * to av_bmiss().
+ */
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+
+ /*
+ * Attempt to force a beacon resync.
+ */
+ sc->sc_syncbeacon = 1;
+
ATH_VAP(vap)->av_bmiss(vap);
}
+/* XXX this needs a force wakeup! */
int
ath_hal_gethangstate(struct ath_hal *ah, uint32_t mask, uint32_t *hangs)
{
@@ -1989,6 +2418,12 @@ ath_bmiss_proc(void *arg, int pending)
DPRINTF(sc, ATH_DEBUG_ANY, "%s: pending %u\n", __func__, pending);
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
+ ath_beacon_miss(sc);
+
/*
* Do a reset upon any becaon miss event.
*
@@ -2002,6 +2437,13 @@ ath_bmiss_proc(void *arg, int pending)
ath_reset(ifp, ATH_RESET_NOLOSS);
ieee80211_beacon_miss(ifp->if_l2com);
}
+
+ /* Force a beacon resync, in case they've drifted */
+ sc->sc_syncbeacon = 1;
+
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
}
/*
@@ -2041,6 +2483,13 @@ ath_init(void *arg)
ATH_LOCK(sc);
/*
+ * Force the sleep state awake.
+ */
+ ath_power_setselfgen(sc, HAL_PM_AWAKE);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ath_power_setpower(sc, HAL_PM_AWAKE);
+
+ /*
* Stop anything previously setup. This is safe
* whether this is the first time through or not.
*/
@@ -2057,12 +2506,19 @@ ath_init(void *arg)
ath_update_chainmasks(sc, ic->ic_curchan);
ath_hal_setchainmasks(sc->sc_ah, sc->sc_cur_txchainmask,
sc->sc_cur_rxchainmask);
+
if (!ath_hal_reset(ah, sc->sc_opmode, ic->ic_curchan, AH_FALSE, &status)) {
if_printf(ifp, "unable to reset hardware; hal status %u\n",
status);
ATH_UNLOCK(sc);
return;
}
+
+ ATH_RX_LOCK(sc);
+ sc->sc_rx_stopped = 1;
+ sc->sc_rx_resetted = 1;
+ ATH_RX_UNLOCK(sc);
+
ath_chan_change(sc, ic->ic_curchan);
/* Let DFS at it in case it's a DFS channel */
@@ -2090,11 +2546,11 @@ ath_init(void *arg)
* state cached in the driver.
*/
sc->sc_diversity = ath_hal_getdiversity(ah);
- sc->sc_lastlongcal = 0;
+ sc->sc_lastlongcal = ticks;
sc->sc_resetcal = 1;
sc->sc_lastcalreset = 0;
- sc->sc_lastani = 0;
- sc->sc_lastshortcal = 0;
+ sc->sc_lastani = ticks;
+ sc->sc_lastshortcal = ticks;
sc->sc_doresetcal = AH_FALSE;
/*
* Beacon timers were cleared here; give ath_newstate()
@@ -2112,6 +2568,7 @@ ath_init(void *arg)
*/
if (ath_startrecv(sc) != 0) {
if_printf(ifp, "unable to start recv logic\n");
+ ath_power_restore_power_state(sc);
ATH_UNLOCK(sc);
return;
}
@@ -2120,8 +2577,7 @@ ath_init(void *arg)
* Enable interrupts.
*/
sc->sc_imask = HAL_INT_RX | HAL_INT_TX
- | HAL_INT_RXEOL | HAL_INT_RXORN
- | HAL_INT_TXURN
+ | HAL_INT_RXORN | HAL_INT_TXURN
| HAL_INT_FATAL | HAL_INT_GLOBAL;
/*
@@ -2132,12 +2588,29 @@ ath_init(void *arg)
sc->sc_imask |= (HAL_INT_RXHP | HAL_INT_RXLP);
/*
+ * If we're an EDMA NIC, we don't care about RXEOL.
+ * Writing a new descriptor in will simply restart
+ * RX DMA.
+ */
+ if (! sc->sc_isedma)
+ sc->sc_imask |= HAL_INT_RXEOL;
+
+ /*
* Enable MIB interrupts when there are hardware phy counters.
* Note we only do this (at the moment) for station mode.
*/
if (sc->sc_needmib && ic->ic_opmode == IEEE80211_M_STA)
sc->sc_imask |= HAL_INT_MIB;
+ /*
+ * XXX add capability for this.
+ *
+ * If we're in STA mode (and maybe IBSS?) then register for
+ * TSFOOR interrupts.
+ */
+ if (ic->ic_opmode == IEEE80211_M_STA)
+ sc->sc_imask |= HAL_INT_TSFOOR;
+
/* Enable global TX timeout and carrier sense timeout if available */
if (ath_hal_gtxto_supported(ah))
sc->sc_imask |= HAL_INT_GTT;
@@ -2149,6 +2622,7 @@ ath_init(void *arg)
callout_reset(&sc->sc_wd_ch, hz, ath_watchdog, sc);
ath_hal_intrset(ah, sc->sc_imask);
+ ath_power_restore_power_state(sc);
ATH_UNLOCK(sc);
#ifdef ATH_TX99_DIAG
@@ -2169,6 +2643,12 @@ ath_stop_locked(struct ifnet *ifp)
__func__, sc->sc_invalid, ifp->if_flags);
ATH_LOCK_ASSERT(sc);
+
+ /*
+ * Wake the hardware up before fiddling with it.
+ */
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
/*
* Shutdown the hardware and driver:
@@ -2201,17 +2681,29 @@ ath_stop_locked(struct ifnet *ifp)
}
ath_hal_intrset(ah, 0);
}
- ath_draintxq(sc, ATH_RESET_DEFAULT);
+ /* XXX we should stop RX regardless of whether it's valid */
if (!sc->sc_invalid) {
ath_stoprecv(sc, 1);
ath_hal_phydisable(ah);
} else
sc->sc_rxlink = NULL;
+ ath_draintxq(sc, ATH_RESET_DEFAULT);
ath_beacon_free(sc); /* XXX not needed */
}
+
+ /* And now, restore the current power state */
+ ath_power_restore_power_state(sc);
}
-#define MAX_TXRX_ITERATIONS 1000
+/*
+ * Wait until all pending TX/RX has completed.
+ *
+ * This waits until all existing transmit, receive and interrupts
+ * have completed. It's assumed that the caller has first
+ * grabbed the reset lock so it doesn't try to do overlapping
+ * chip resets.
+ */
+#define MAX_TXRX_ITERATIONS 100
static void
ath_txrx_stop_locked(struct ath_softc *sc)
{
@@ -2230,7 +2722,8 @@ ath_txrx_stop_locked(struct ath_softc *sc)
sc->sc_txstart_cnt || sc->sc_intr_cnt) {
if (i <= 0)
break;
- msleep(sc, &sc->sc_pcu_mtx, 0, "ath_txrx_stop", 1);
+ msleep(sc, &sc->sc_pcu_mtx, 0, "ath_txrx_stop",
+ msecs_to_ticks(10));
i--;
}
@@ -2277,7 +2770,7 @@ ath_txrx_start(struct ath_softc *sc)
* Another, cleaner way should be found to serialise all of
* these operations.
*/
-#define MAX_RESET_ITERATIONS 10
+#define MAX_RESET_ITERATIONS 25
static int
ath_reset_grablock(struct ath_softc *sc, int dowait)
{
@@ -2295,7 +2788,11 @@ ath_reset_grablock(struct ath_softc *sc, int dowait)
break;
}
ATH_PCU_UNLOCK(sc);
- pause("ath_reset_grablock", 1);
+ /*
+ * 1 tick is likely not enough time for long calibrations
+ * to complete. So we should wait quite a while.
+ */
+ pause("ath_reset_grablock", msecs_to_ticks(100));
i--;
ATH_PCU_LOCK(sc);
} while (i > 0);
@@ -2360,6 +2857,13 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type)
/* Try to (stop any further TX/RX from occuring */
taskqueue_block(sc->sc_tq);
+ /*
+ * Wake the hardware up.
+ */
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
ATH_PCU_LOCK(sc);
/*
@@ -2385,13 +2889,6 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type)
ATH_PCU_UNLOCK(sc);
/*
- * Should now wait for pending TX/RX to complete
- * and block future ones from occuring. This needs to be
- * done before the TX queue is drained.
- */
- ath_draintxq(sc, reset_type); /* stop xmit side */
-
- /*
* Regardless of whether we're doing a no-loss flush or
* not, stop the PCU and handle what's in the RX queue.
* That way frames aren't dropped which shouldn't be.
@@ -2399,6 +2896,13 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type)
ath_stoprecv(sc, (reset_type != ATH_RESET_NOLOSS));
ath_rx_flush(sc);
+ /*
+ * Should now wait for pending TX/RX to complete
+ * and block future ones from occuring. This needs to be
+ * done before the TX queue is drained.
+ */
+ ath_draintxq(sc, reset_type); /* stop xmit side */
+
ath_settkipmic(sc); /* configure TKIP MIC handling */
/* NB: indicate channel change so we do a full reset */
ath_update_chainmasks(sc, ic->ic_curchan);
@@ -2409,6 +2913,11 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type)
__func__, status);
sc->sc_diversity = ath_hal_getdiversity(ah);
+ ATH_RX_LOCK(sc);
+ sc->sc_rx_stopped = 1;
+ sc->sc_rx_resetted = 1;
+ ATH_RX_UNLOCK(sc);
+
/* Let DFS at it in case it's a DFS channel */
ath_dfs_radar_enable(sc, ic->ic_curchan);
@@ -2454,9 +2963,13 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type)
* reset counter - this way ath_intr() doesn't end up
* disabling interrupts without a corresponding enable
* in the rest or channel change path.
+ *
+ * Grab the TX reference in case we need to transmit.
+ * That way a parallel transmit doesn't.
*/
ATH_PCU_LOCK(sc);
sc->sc_inreset_cnt--;
+ sc->sc_txstart_cnt++;
/* XXX only do this if sc_inreset_cnt == 0? */
ath_hal_intrset(ah, sc->sc_imask);
ATH_PCU_UNLOCK(sc);
@@ -2473,6 +2986,8 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type)
/* Restart TX/RX as needed */
ath_txrx_start(sc);
+ /* XXX TODO: we need to hold the tx refcount here! */
+
/* Restart TX completion and pending TX */
if (reset_type == ATH_RESET_NOLOSS) {
for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
@@ -2497,6 +3012,14 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type)
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
IF_UNLOCK(&ifp->if_snd);
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+
+ ATH_PCU_LOCK(sc);
+ sc->sc_txstart_cnt--;
+ ATH_PCU_UNLOCK(sc);
+
/* Handle any frames in the TX queue */
/*
* XXX should this be done by the caller, rather than
@@ -2637,6 +3160,7 @@ ath_buf_clone(struct ath_softc *sc, struct ath_buf *bf)
tbf->bf_status = bf->bf_status;
tbf->bf_m = bf->bf_m;
tbf->bf_node = bf->bf_node;
+ KASSERT((bf->bf_node != NULL), ("%s: bf_node=NULL!", __func__));
/* will be setup by the chain/setup function */
tbf->bf_lastds = NULL;
/* for now, last == self */
@@ -2738,6 +3262,11 @@ ath_transmit(struct ifnet *ifp, struct mbuf *m)
sc->sc_txstart_cnt++;
ATH_PCU_UNLOCK(sc);
+ /* Wake the hardware up already */
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
ATH_KTR(sc, ATH_KTR_TX, 0, "ath_transmit: start");
/*
* Grab the TX lock - it's ok to do this here; we haven't
@@ -2846,7 +3375,7 @@ ath_transmit(struct ifnet *ifp, struct mbuf *m)
DPRINTF(sc, ATH_DEBUG_XMIT,
"%s: out of txfrag buffers\n", __func__);
sc->sc_stats.ast_tx_nofrag++;
- ifp->if_oerrors++;
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
ath_freetx(m);
goto bad;
}
@@ -2894,7 +3423,7 @@ ath_transmit(struct ifnet *ifp, struct mbuf *m)
*
* XXX should use atomics?
*/
- ifp->if_opackets++;
+ if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
nextfrag:
/*
* Pass the frame to the h/w for transmission.
@@ -2914,7 +3443,7 @@ nextfrag:
next = m->m_nextpkt;
if (ath_tx_start(sc, ni, bf, m)) {
bad:
- ifp->if_oerrors++;
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
reclaim:
bf->bf_m = NULL;
bf->bf_node = NULL;
@@ -2971,6 +3500,11 @@ finish:
sc->sc_txstart_cnt--;
ATH_PCU_UNLOCK(sc);
+ /* Sleep the hardware if required */
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+
ATH_KTR(sc, ATH_KTR_TX, 0, "ath_transmit: finished");
return (retval);
@@ -2998,7 +3532,6 @@ ath_key_update_begin(struct ieee80211vap *vap)
DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__);
taskqueue_block(sc->sc_tq);
- IF_LOCK(&ifp->if_snd); /* NB: doesn't block mgmt frames */
}
static void
@@ -3008,7 +3541,6 @@ ath_key_update_end(struct ieee80211vap *vap)
struct ath_softc *sc = ifp->if_softc;
DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__);
- IF_UNLOCK(&ifp->if_snd);
taskqueue_unblock(sc->sc_tq);
}
@@ -3019,16 +3551,25 @@ ath_update_promisc(struct ifnet *ifp)
u_int32_t rfilt;
/* configure rx filter */
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
rfilt = ath_calcrxfilter(sc);
ath_hal_setrxfilter(sc->sc_ah, rfilt);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
DPRINTF(sc, ATH_DEBUG_MODE, "%s: RX filter 0x%x\n", __func__, rfilt);
}
+/*
+ * Driver-internal mcast update call.
+ *
+ * Assumes the hardware is already awake.
+ */
static void
-ath_update_mcast(struct ifnet *ifp)
+ath_update_mcast_hw(struct ath_softc *sc)
{
- struct ath_softc *sc = ifp->if_softc;
+ struct ifnet *ifp = sc->sc_ifp;
u_int32_t mfilt[2];
/* calculate and install multicast filter */
@@ -3056,11 +3597,33 @@ ath_update_mcast(struct ifnet *ifp)
if_maddr_runlock(ifp);
} else
mfilt[0] = mfilt[1] = ~0;
+
ath_hal_setmcastfilter(sc->sc_ah, mfilt[0], mfilt[1]);
+
DPRINTF(sc, ATH_DEBUG_MODE, "%s: MC filter %08x:%08x\n",
__func__, mfilt[0], mfilt[1]);
}
+/*
+ * Called from the net80211 layer - force the hardware
+ * awake before operating.
+ */
+static void
+ath_update_mcast(struct ifnet *ifp)
+{
+ struct ath_softc *sc = ifp->if_softc;
+
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
+ ath_update_mcast_hw(sc);
+
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+}
+
void
ath_mode_init(struct ath_softc *sc)
{
@@ -3086,7 +3649,7 @@ ath_mode_init(struct ath_softc *sc)
ath_hal_setmac(ah, IF_LLADDR(ifp));
/* calculate and install multicast filter */
- ath_update_mcast(ifp);
+ ath_update_mcast_hw(sc);
}
/*
@@ -3118,8 +3681,13 @@ ath_setslottime(struct ath_softc *sc)
__func__, ic->ic_curchan->ic_freq, ic->ic_curchan->ic_flags,
ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long", usec);
+ /* Wake up the hardware first before updating the slot time */
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
ath_hal_setslottime(ah, usec);
+ ath_power_restore_power_state(sc);
sc->sc_updateslot = OK;
+ ATH_UNLOCK(sc);
}
/*
@@ -3136,6 +3704,8 @@ ath_updateslot(struct ifnet *ifp)
* When not coordinating the BSS, change the hardware
* immediately. For other operation we defer the change
* until beacon updates have propagated to the stations.
+ *
+ * XXX sc_updateslot isn't changed behind a lock?
*/
if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
ic->ic_opmode == IEEE80211_M_MBSS)
@@ -4041,14 +4611,12 @@ ath_tx_process_buf_completion(struct ath_softc *sc, struct ath_txq *txq,
struct ath_tx_status *ts, struct ath_buf *bf)
{
struct ieee80211_node *ni = bf->bf_node;
- struct ath_node *an = NULL;
ATH_TX_UNLOCK_ASSERT(sc);
ATH_TXQ_UNLOCK_ASSERT(txq);
/* If unicast frame, update general statistics */
if (ni != NULL) {
- an = ATH_NODE(ni);
/* update statistics */
ath_tx_update_stats(sc, ts, bf);
}
@@ -4257,6 +4825,10 @@ ath_tx_proc_q0(void *arg, int npending)
sc->sc_txq_active &= ~txqs;
ATH_PCU_UNLOCK(sc);
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
ATH_KTR(sc, ATH_KTR_TXCOMP, 1,
"ath_tx_proc_q0: txqs=0x%08x", txqs);
@@ -4277,6 +4849,10 @@ ath_tx_proc_q0(void *arg, int npending)
sc->sc_txproc_cnt--;
ATH_PCU_UNLOCK(sc);
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+
ath_tx_kick(sc);
}
@@ -4298,6 +4874,10 @@ ath_tx_proc_q0123(void *arg, int npending)
sc->sc_txq_active &= ~txqs;
ATH_PCU_UNLOCK(sc);
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
ATH_KTR(sc, ATH_KTR_TXCOMP, 1,
"ath_tx_proc_q0123: txqs=0x%08x", txqs);
@@ -4330,6 +4910,10 @@ ath_tx_proc_q0123(void *arg, int npending)
sc->sc_txproc_cnt--;
ATH_PCU_UNLOCK(sc);
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+
ath_tx_kick(sc);
}
@@ -4350,6 +4934,10 @@ ath_tx_proc(void *arg, int npending)
sc->sc_txq_active &= ~txqs;
ATH_PCU_UNLOCK(sc);
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
ATH_KTR(sc, ATH_KTR_TXCOMP, 1, "ath_tx_proc: txqs=0x%08x", txqs);
/*
@@ -4375,6 +4963,10 @@ ath_tx_proc(void *arg, int npending)
sc->sc_txproc_cnt--;
ATH_PCU_UNLOCK(sc);
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+
ath_tx_kick(sc);
}
#undef TXQACTIVE
@@ -4401,6 +4993,10 @@ ath_txq_sched_tasklet(void *arg, int npending)
sc->sc_txproc_cnt++;
ATH_PCU_UNLOCK(sc);
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
ATH_TX_LOCK(sc);
for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
if (ATH_TXQ_SETUP(sc, i)) {
@@ -4409,6 +5005,10 @@ ath_txq_sched_tasklet(void *arg, int npending)
}
ATH_TX_UNLOCK(sc);
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+
ATH_PCU_LOCK(sc);
sc->sc_txproc_cnt--;
ATH_PCU_UNLOCK(sc);
@@ -4916,14 +5516,15 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan)
ATH_PCU_LOCK(sc);
+ /* Disable interrupts */
+ ath_hal_intrset(ah, 0);
+
/* Stop new RX/TX/interrupt completion */
if (ath_reset_grablock(sc, 1) == 0) {
device_printf(sc->sc_dev, "%s: concurrent reset! Danger!\n",
__func__);
}
- ath_hal_intrset(ah, 0);
-
/* Stop pending RX/TX completion */
ath_txrx_stop_locked(sc);
@@ -4967,6 +5568,11 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan)
}
sc->sc_diversity = ath_hal_getdiversity(ah);
+ ATH_RX_LOCK(sc);
+ sc->sc_rx_stopped = 1;
+ sc->sc_rx_resetted = 1;
+ ATH_RX_UNLOCK(sc);
+
/* Let DFS at it in case it's a DFS channel */
ath_dfs_radar_enable(sc, chan);
@@ -5056,6 +5662,17 @@ ath_calibrate(void *arg)
HAL_BOOL aniCal, shortCal = AH_FALSE;
int nextcal;
+ ATH_LOCK_ASSERT(sc);
+
+ /*
+ * Force the hardware awake for ANI work.
+ */
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+
+ /* Skip trying to do this if we're in reset */
+ if (sc->sc_inreset_cnt)
+ goto restart;
+
if (ic->ic_flags & IEEE80211_F_SCAN) /* defer, off channel */
goto restart;
longCal = (ticks - sc->sc_lastlongcal >= ath_longcalinterval*hz);
@@ -5085,6 +5702,7 @@ ath_calibrate(void *arg)
sc->sc_doresetcal = AH_TRUE;
taskqueue_enqueue(sc->sc_tq, &sc->sc_resettask);
callout_reset(&sc->sc_cal_ch, 1, ath_calibrate, sc);
+ ath_power_restore_power_state(sc);
return;
}
/*
@@ -5156,6 +5774,10 @@ restart:
__func__);
/* NB: don't rearm timer */
}
+ /*
+ * Restore power state now that we're done.
+ */
+ ath_power_restore_power_state(sc);
}
static void
@@ -5241,6 +5863,10 @@ ath_set_channel(struct ieee80211com *ic)
struct ifnet *ifp = ic->ic_ifp;
struct ath_softc *sc = ifp->if_softc;
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
(void) ath_chan_set(sc, ic->ic_curchan);
/*
* If we are returning to our bss channel then mark state
@@ -5251,6 +5877,7 @@ ath_set_channel(struct ieee80211com *ic)
ATH_LOCK(sc);
if (!sc->sc_scanning && ic->ic_curchan == ic->ic_bsschan)
sc->sc_syncbeacon = 1;
+ ath_power_restore_power_state(sc);
ATH_UNLOCK(sc);
}
@@ -5283,6 +5910,7 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
int i, error, stamode;
u_int32_t rfilt;
int csa_run_transition = 0;
+ enum ieee80211_state ostate = vap->iv_state;
static const HAL_LED_STATE leds[] = {
HAL_LED_INIT, /* IEEE80211_S_INIT */
@@ -5296,7 +5924,7 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
};
DPRINTF(sc, ATH_DEBUG_STATE, "%s: %s -> %s\n", __func__,
- ieee80211_state_name[vap->iv_state],
+ ieee80211_state_name[ostate],
ieee80211_state_name[nstate]);
/*
@@ -5308,10 +5936,34 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
*/
IEEE80211_LOCK_ASSERT(ic);
- if (vap->iv_state == IEEE80211_S_CSA && nstate == IEEE80211_S_RUN)
+ /* Before we touch the hardware - wake it up */
+ ATH_LOCK(sc);
+ /*
+ * If the NIC is in anything other than SLEEP state,
+ * we need to ensure that self-generated frames are
+ * set for PWRMGT=0. Otherwise we may end up with
+ * strange situations.
+ *
+ * XXX TODO: is this actually the case? :-)
+ */
+ if (nstate != IEEE80211_S_SLEEP)
+ ath_power_setselfgen(sc, HAL_PM_AWAKE);
+
+ /*
+ * Now, wake the thing up.
+ */
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+
+ /*
+ * And stop the calibration callout whilst we have
+ * ATH_LOCK held.
+ */
+ callout_stop(&sc->sc_cal_ch);
+ ATH_UNLOCK(sc);
+
+ if (ostate == IEEE80211_S_CSA && nstate == IEEE80211_S_RUN)
csa_run_transition = 1;
- callout_drain(&sc->sc_cal_ch);
ath_hal_setledstate(ah, leds[nstate]); /* set LED */
if (nstate == IEEE80211_S_SCAN) {
@@ -5321,6 +5973,13 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
* [re]setup beacons. Unblock the task q thread so
* deferred interrupt processing is done.
*/
+
+ /* Ensure we stay awake during scan */
+ ATH_LOCK(sc);
+ ath_power_setselfgen(sc, HAL_PM_AWAKE);
+ ath_power_setpower(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
ath_hal_intrset(ah,
sc->sc_imask &~ (HAL_INT_SWBA | HAL_INT_BMISS));
sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS);
@@ -5333,6 +5992,11 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
stamode = (vap->iv_opmode == IEEE80211_M_STA ||
vap->iv_opmode == IEEE80211_M_AHDEMO ||
vap->iv_opmode == IEEE80211_M_IBSS);
+
+ /*
+ * XXX Dont need to do this (and others) if we've transitioned
+ * from SLEEP->RUN.
+ */
if (stamode && nstate == IEEE80211_S_RUN) {
sc->sc_curaid = ni->ni_associd;
IEEE80211_ADDR_COPY(sc->sc_curbssid, ni->ni_bssid);
@@ -5435,11 +6099,14 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
* beacon to update the beacon timer and thus we
* won't get notified of the missing beacons.
*/
- sc->sc_syncbeacon = 1;
-#if 0
- if (csa_run_transition)
-#endif
- ath_beacon_config(sc, vap);
+ if (ostate != IEEE80211_S_RUN &&
+ ostate != IEEE80211_S_SLEEP) {
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ "%s: STA; syncbeacon=1\n", __func__);
+ sc->sc_syncbeacon = 1;
+
+ if (csa_run_transition)
+ ath_beacon_config(sc, vap);
/*
* PR: kern/175227
@@ -5453,7 +6120,8 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
* timer fires (too often), leading to a STA
* disassociation.
*/
- sc->sc_beacons = 1;
+ sc->sc_beacons = 1;
+ }
break;
case IEEE80211_M_MONITOR:
/*
@@ -5479,6 +6147,14 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER;
sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
+
+ /*
+ * Force awake for RUN mode.
+ */
+ ATH_LOCK(sc);
+ ath_power_setselfgen(sc, HAL_PM_AWAKE);
+ ath_power_setpower(sc, HAL_PM_AWAKE);
+
/*
* Finally, start any timers and the task q thread
* (in case we didn't go through SCAN state).
@@ -5490,6 +6166,8 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
DPRINTF(sc, ATH_DEBUG_CALIBRATE,
"%s: calibration disabled\n", __func__);
}
+ ATH_UNLOCK(sc);
+
taskqueue_unblock(sc->sc_tq);
} else if (nstate == IEEE80211_S_INIT) {
/*
@@ -5509,9 +6187,43 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
#ifdef IEEE80211_SUPPORT_TDMA
ath_hal_setcca(ah, AH_TRUE);
#endif
+ } else if (nstate == IEEE80211_S_SLEEP) {
+ /* We're going to sleep, so transition appropriately */
+ /* For now, only do this if we're a single STA vap */
+ if (sc->sc_nvaps == 1 &&
+ vap->iv_opmode == IEEE80211_M_STA) {
+ DPRINTF(sc, ATH_DEBUG_BEACON, "%s: syncbeacon=%d\n", __func__, sc->sc_syncbeacon);
+ ATH_LOCK(sc);
+ /*
+ * Always at least set the self-generated
+ * frame config to set PWRMGT=1.
+ */
+ ath_power_setselfgen(sc, HAL_PM_NETWORK_SLEEP);
+
+ /*
+ * If we're not syncing beacons, transition
+ * to NETWORK_SLEEP.
+ *
+ * We stay awake if syncbeacon > 0 in case
+ * we need to listen for some beacons otherwise
+ * our beacon timer config may be wrong.
+ */
+ if (sc->sc_syncbeacon == 0) {
+ ath_power_setpower(sc, HAL_PM_NETWORK_SLEEP);
+ }
+ ATH_UNLOCK(sc);
+ }
}
bad:
ieee80211_free_node(ni);
+
+ /*
+ * Restore the power state - either to what it was, or
+ * to network_sleep if it's alright.
+ */
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
return error;
}
@@ -5566,7 +6278,16 @@ ath_newassoc(struct ieee80211_node *ni, int isnew)
an->an_mcastrix = ath_tx_findrix(sc, tp->mcastrate);
an->an_mgmtrix = ath_tx_findrix(sc, tp->mgmtrate);
+ DPRINTF(sc, ATH_DEBUG_NODE, "%s: %6D: reassoc; isnew=%d, is_powersave=%d\n",
+ __func__,
+ ni->ni_macaddr,
+ ":",
+ isnew,
+ an->an_is_powersave);
+
+ ATH_NODE_LOCK(an);
ath_rate_newassoc(sc, an, isnew);
+ ATH_NODE_UNLOCK(an);
if (isnew &&
(vap->iv_flags & IEEE80211_F_PRIVACY) == 0 && sc->sc_hasclrkey &&
@@ -5806,10 +6527,14 @@ ath_watchdog(void *arg)
struct ath_softc *sc = arg;
int do_reset = 0;
+ ATH_LOCK_ASSERT(sc);
+
if (sc->sc_wd_timer != 0 && --sc->sc_wd_timer == 0) {
struct ifnet *ifp = sc->sc_ifp;
uint32_t hangs;
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+
if (ath_hal_gethangstate(sc->sc_ah, 0xffff, &hangs) &&
hangs != 0) {
if_printf(ifp, "%s hang detected (0x%x)\n",
@@ -5817,8 +6542,10 @@ ath_watchdog(void *arg)
} else
if_printf(ifp, "device timeout\n");
do_reset = 1;
- ifp->if_oerrors++;
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
sc->sc_stats.ast_watchdog++;
+
+ ath_power_restore_power_state(sc);
}
/*
@@ -5916,6 +6643,13 @@ ath_ioctl_diag(struct ath_softc *sc, struct ath_diag *ad)
goto bad;
}
}
+
+
+ ATH_LOCK(sc);
+ if (id != HAL_DIAG_REGS)
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
if (ath_hal_getdiagstate(ah, id, indata, insize, &outdata, &outsize)) {
if (outsize < ad->ad_out_size)
ad->ad_out_size = outsize;
@@ -5925,6 +6659,12 @@ ath_ioctl_diag(struct ath_softc *sc, struct ath_diag *ad)
} else {
error = EINVAL;
}
+
+ ATH_LOCK(sc);
+ if (id != HAL_DIAG_REGS)
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+
bad:
if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL)
free(indata, M_TEMP);
@@ -5947,14 +6687,17 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
switch (cmd) {
case SIOCSIFFLAGS:
- ATH_LOCK(sc);
if (IS_RUNNING(ifp)) {
/*
* To avoid rescanning another access point,
* do not call ath_init() here. Instead,
* only reflect promisc mode settings.
*/
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
ath_mode_init(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
} else if (ifp->if_flags & IFF_UP) {
/*
* Beware of being called during attach/detach
@@ -5968,14 +6711,12 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if (!sc->sc_invalid)
ath_init(sc); /* XXX lose error */
} else {
+ ATH_LOCK(sc);
ath_stop_locked(ifp);
-#ifdef notyet
- /* XXX must wakeup in places like ath_vap_delete */
if (!sc->sc_invalid)
- ath_hal_setpower(sc->sc_ah, HAL_PM_FULL_SLEEP);
-#endif
+ ath_power_setpower(sc, HAL_PM_FULL_SLEEP);
+ ATH_UNLOCK(sc);
}
- ATH_UNLOCK(sc);
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
@@ -5983,8 +6724,10 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
break;
case SIOCGATHSTATS:
/* NB: embed these numbers to get a consistent view */
- sc->sc_stats.ast_tx_packets = ifp->if_opackets;
- sc->sc_stats.ast_rx_packets = ifp->if_ipackets;
+ sc->sc_stats.ast_tx_packets = if_get_counter_default(ifp,
+ IFCOUNTER_OPACKETS);
+ sc->sc_stats.ast_rx_packets = if_get_counter_default(ifp,
+ IFCOUNTER_IPACKETS);
sc->sc_stats.ast_tx_rssi = ATH_RSSI(sc->sc_halstats.ns_avgtxrssi);
sc->sc_stats.ast_rx_rssi = ATH_RSSI(sc->sc_halstats.ns_avgrssi);
#ifdef IEEE80211_SUPPORT_TDMA
@@ -6341,7 +7084,7 @@ ath_tx_update_tim(struct ath_softc *sc, struct ieee80211_node *ni,
/*
* Don't bother grabbing the lock unless the queue is empty.
*/
- if (&an->an_swq_depth != 0)
+ if (an->an_swq_depth != 0)
return;
if (an->an_is_powersave &&
@@ -6511,6 +7254,6 @@ ath_node_recv_pspoll(struct ieee80211_node *ni, struct mbuf *m)
MODULE_VERSION(if_ath, 1);
MODULE_DEPEND(if_ath, wlan, 1, 1, 1); /* 802.11 media layer */
-#if defined(IEEE80211_ALQ) || defined(AH_DEBUG_ALQ)
+#if defined(IEEE80211_ALQ) || defined(AH_DEBUG_ALQ) || defined(ATH_DEBUG_ALQ)
MODULE_DEPEND(if_ath, alq, 1, 1, 1);
#endif
diff --git a/sys/dev/ath/if_ath_ahb.c b/sys/dev/ath/if_ath_ahb.c
index 59593b6..ffe825d 100644
--- a/sys/dev/ath/if_ath_ahb.c
+++ b/sys/dev/ath/if_ath_ahb.c
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/lock.h>
@@ -55,6 +56,7 @@ __FBSDID("$FreeBSD$");
#include <net/if.h>
#include <net/if_media.h>
#include <net/if_arp.h>
+#include <net/ethernet.h>
#include <net80211/ieee80211_var.h>
@@ -151,19 +153,30 @@ ath_ahb_attach(device_t dev)
eepromsize = ATH_EEPROM_DATA_SIZE * 2;
}
-
rid = 0;
device_printf(sc->sc_dev, "eeprom @ %p (%d bytes)\n",
(void *) eepromaddr, eepromsize);
- psc->sc_eeprom = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, (uintptr_t) eepromaddr,
- (uintptr_t) eepromaddr + (uintptr_t) (eepromsize - 1), 0, RF_ACTIVE);
+ /*
+ * XXX this assumes that the parent device is the nexus
+ * and will just pass through requests for all of memory.
+ *
+ * Later on, when this has to attach off of the actual
+ * AHB, this won't work.
+ *
+ * Ideally this would be done in machdep code in mips/atheros/
+ * and it'd expose the EEPROM via the firmware interface,
+ * so the ath/ath_ahb drivers can be loaded as modules
+ * after boot-time.
+ */
+ psc->sc_eeprom = bus_alloc_resource(dev, SYS_RES_MEMORY,
+ &rid, (uintptr_t) eepromaddr,
+ (uintptr_t) eepromaddr + (uintptr_t) (eepromsize - 1), 0, RF_ACTIVE);
if (psc->sc_eeprom == NULL) {
device_printf(dev, "cannot map eeprom space\n");
goto bad0;
}
- /* XXX uintptr_t is a bandaid for ia64; to be fixed */
- sc->sc_st = (HAL_BUS_TAG)(uintptr_t) rman_get_bustag(psc->sc_sr);
+ sc->sc_st = (HAL_BUS_TAG) rman_get_bustag(psc->sc_sr);
sc->sc_sh = (HAL_BUS_HANDLE) rman_get_bushandle(psc->sc_sr);
/*
* Mark device invalid so any interrupts (shared or otherwise)
@@ -348,6 +361,7 @@ static driver_t ath_ahb_driver = {
};
static devclass_t ath_devclass;
DRIVER_MODULE(ath, nexus, ath_ahb_driver, ath_devclass, 0, 0);
+DRIVER_MODULE(ath, apb, ath_ahb_driver, ath_devclass, 0, 0);
MODULE_VERSION(ath, 1);
MODULE_DEPEND(ath, wlan, 1, 1, 1); /* 802.11 media layer */
MODULE_DEPEND(ath, if_ath, 1, 1, 1); /* if_ath driver */
diff --git a/sys/dev/ath/if_ath_beacon.c b/sys/dev/ath/if_ath_beacon.c
index 11b0426..a672c71 100644
--- a/sys/dev/ath/if_ath_beacon.c
+++ b/sys/dev/ath/if_ath_beacon.c
@@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
@@ -381,7 +382,7 @@ ath_beacon_update(struct ieee80211vap *vap, int item)
/*
* Handle a beacon miss.
*/
-static void
+void
ath_beacon_miss(struct ath_softc *sc)
{
HAL_SURVEY_SAMPLE hs;
@@ -748,6 +749,11 @@ ath_beacon_generate(struct ath_softc *sc, struct ieee80211vap *vap)
*
* More thought is required here.
*/
+ /*
+ * XXX can we even stop TX DMA here? Check what the
+ * reference driver does for cabq for beacons, given
+ * that stopping TX requires RX is paused.
+ */
ath_tx_draintxq(sc, cabq);
}
}
@@ -915,7 +921,7 @@ ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap)
struct ieee80211_node *ni;
u_int32_t nexttbtt, intval, tsftu;
u_int32_t nexttbtt_u8, intval_u8;
- u_int64_t tsf;
+ u_int64_t tsf, tsf_beacon;
if (vap == NULL)
vap = TAILQ_FIRST(&ic->ic_vaps); /* XXX */
@@ -931,9 +937,17 @@ ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap)
ni = ieee80211_ref_node(vap->iv_bss);
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
/* extract tstamp from last beacon and convert to TU */
nexttbtt = TSF_TO_TU(LE_READ_4(ni->ni_tstamp.data + 4),
LE_READ_4(ni->ni_tstamp.data));
+
+ tsf_beacon = ((uint64_t) LE_READ_4(ni->ni_tstamp.data + 4)) << 32;
+ tsf_beacon |= LE_READ_4(ni->ni_tstamp.data);
+
if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
ic->ic_opmode == IEEE80211_M_MBSS) {
/*
@@ -979,14 +993,63 @@ ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap)
*/
tsf = ath_hal_gettsf64(ah);
tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
- do {
- nexttbtt += intval;
- if (--dtimcount < 0) {
- dtimcount = dtimperiod - 1;
- if (--cfpcount < 0)
- cfpcount = cfpperiod - 1;
+
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ "%s: beacon tsf=%llu, hw tsf=%llu, nexttbtt=%u, tsftu=%u\n",
+ __func__,
+ (unsigned long long) tsf_beacon,
+ (unsigned long long) tsf,
+ nexttbtt,
+ tsftu);
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ "%s: beacon tsf=%llu, hw tsf=%llu, tsf delta=%lld\n",
+ __func__,
+ (unsigned long long) tsf_beacon,
+ (unsigned long long) tsf,
+ (long long) tsf -
+ (long long) tsf_beacon);
+
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ "%s: nexttbtt=%llu, beacon tsf delta=%lld\n",
+ __func__,
+ (unsigned long long) nexttbtt,
+ (long long) ((long long) nexttbtt * 1024LL) - (long long) tsf_beacon);
+
+ /* XXX cfpcount? */
+
+ if (nexttbtt > tsftu) {
+ uint32_t countdiff, oldtbtt, remainder;
+
+ oldtbtt = nexttbtt;
+ remainder = (nexttbtt - tsftu) % intval;
+ nexttbtt = tsftu + remainder;
+
+ countdiff = (oldtbtt - nexttbtt) / intval % dtimperiod;
+ if (dtimcount > countdiff) {
+ dtimcount -= countdiff;
+ } else {
+ dtimcount += dtimperiod - countdiff;
+ }
+ } else { //nexttbtt <= tsftu
+ uint32_t countdiff, oldtbtt, remainder;
+
+ oldtbtt = nexttbtt;
+ remainder = (tsftu - nexttbtt) % intval;
+ nexttbtt = tsftu - remainder + intval;
+ countdiff = (nexttbtt - oldtbtt) / intval % dtimperiod;
+ if (dtimcount > countdiff) {
+ dtimcount -= countdiff;
+ } else {
+ dtimcount += dtimperiod - countdiff;
}
- } while (nexttbtt < tsftu);
+ }
+
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ "%s: adj nexttbtt=%llu, rx tsf delta=%lld\n",
+ __func__,
+ (unsigned long long) nexttbtt,
+ (long long) ((long long)nexttbtt * 1024LL) - (long long)tsf);
+
memset(&bs, 0, sizeof(bs));
bs.bs_intval = intval;
bs.bs_nexttbtt = nexttbtt;
@@ -1033,9 +1096,12 @@ ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap)
bs.bs_sleepduration = roundup(bs.bs_sleepduration, bs.bs_dtimperiod);
DPRINTF(sc, ATH_DEBUG_BEACON,
- "%s: tsf %ju tsf:tu %u intval %u nexttbtt %u dtim %u nextdtim %u bmiss %u sleep %u cfp:period %u maxdur %u next %u timoffset %u\n"
+ "%s: tsf %ju tsf:tu %u intval %u nexttbtt %u dtim %u "
+ "nextdtim %u bmiss %u sleep %u cfp:period %u "
+ "maxdur %u next %u timoffset %u\n"
, __func__
- , tsf, tsftu
+ , tsf
+ , tsftu
, bs.bs_intval
, bs.bs_nexttbtt
, bs.bs_dtimperiod
@@ -1112,8 +1178,11 @@ ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap)
if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol)
ath_beacon_start_adhoc(sc, vap);
}
- sc->sc_syncbeacon = 0;
ieee80211_free_node(ni);
+
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
#undef FUDGE
#undef TSF_TO_TU
}
diff --git a/sys/dev/ath/if_ath_beacon.h b/sys/dev/ath/if_ath_beacon.h
index f3f73d7..a940268 100644
--- a/sys/dev/ath/if_ath_beacon.h
+++ b/sys/dev/ath/if_ath_beacon.h
@@ -48,5 +48,7 @@ extern int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_node *ni);
extern void ath_beacon_return(struct ath_softc *sc, struct ath_buf *bf);
extern void ath_beacon_free(struct ath_softc *sc);
extern void ath_beacon_proc(void *arg, int pending);
+extern void ath_beacon_miss(struct ath_softc *sc);
#endif
+
diff --git a/sys/dev/ath/if_ath_btcoex.c b/sys/dev/ath/if_ath_btcoex.c
index fff6f3b..b78f866 100644
--- a/sys/dev/ath/if_ath_btcoex.c
+++ b/sys/dev/ath/if_ath_btcoex.c
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <sys/kernel.h>
#include <sys/lock.h>
+#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/errno.h>
@@ -54,6 +55,7 @@ __FBSDID("$FreeBSD$");
#include <sys/socket.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_media.h>
#include <net/if_arp.h>
#include <net/ethernet.h> /* XXX for ether_sprintf */
@@ -186,6 +188,72 @@ ath_btcoex_cfg_wb225(struct ath_softc *sc)
return (0);
}
+/*
+ * Initial AR9462 / (WB222) bluetooth coexistence settings,
+ * just for experimentation.
+ *
+ * Return 0 for OK; errno for error.
+ */
+static int
+ath_btcoex_cfg_wb222(struct ath_softc *sc)
+{
+ HAL_BT_COEX_INFO btinfo;
+ HAL_BT_COEX_CONFIG btconfig;
+ struct ath_hal *ah = sc->sc_ah;
+
+ if (! ath_hal_btcoex_supported(ah))
+ return (EINVAL);
+
+ bzero(&btinfo, sizeof(btinfo));
+ bzero(&btconfig, sizeof(btconfig));
+
+ device_printf(sc->sc_dev, "Enabling WB222 BTCOEX\n");
+
+ btinfo.bt_module = HAL_BT_MODULE_JANUS; /* XXX not used? */
+ btinfo.bt_coex_config = HAL_BT_COEX_CFG_MCI;
+
+ /*
+ * MCI uses a completely different interface to speak
+ * to the bluetooth module - it's a command based
+ * thing over a serial line, rather than
+ * state pins to/from the bluetooth module.
+ *
+ * So, the GPIO configuration, polarity, etc
+ * doesn't matter on MCI devices; it's just
+ * completely ignored by the HAL.
+ */
+ btinfo.bt_gpio_bt_active = 4;
+ btinfo.bt_gpio_bt_priority = 8;
+ btinfo.bt_gpio_wlan_active = 5;
+
+ btinfo.bt_active_polarity = 1; /* XXX not used */
+ btinfo.bt_single_ant = 0; /* 2 antenna on WB222 */
+ btinfo.bt_isolation = 0; /* in dB, not used */
+
+ ath_hal_btcoex_set_info(ah, &btinfo);
+
+ btconfig.bt_time_extend = 0;
+ btconfig.bt_txstate_extend = 1; /* true */
+ btconfig.bt_txframe_extend = 1; /* true */
+ btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED;
+ btconfig.bt_quiet_collision = 1; /* true */
+ btconfig.bt_rxclear_polarity = 1; /* true */
+ btconfig.bt_priority_time = 2;
+ btconfig.bt_first_slot_time = 5;
+ btconfig.bt_hold_rxclear = 1; /* true */
+
+ ath_hal_btcoex_set_config(ah, &btconfig);
+
+ /*
+ * Enable antenna diversity.
+ */
+ ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1);
+
+ return (0);
+}
+
+
+
#if 0
/*
@@ -241,6 +309,8 @@ ath_btcoex_attach(struct ath_softc *sc)
if (strncmp(profname, "wb195", 5) == 0) {
ret = ath_btcoex_cfg_wb195(sc);
+ } else if (strncmp(profname, "wb222", 5) == 0) {
+ ret = ath_btcoex_cfg_wb222(sc);
} else if (strncmp(profname, "wb225", 5) == 0) {
ret = ath_btcoex_cfg_wb225(sc);
} else {
diff --git a/sys/dev/ath/if_ath_debug.c b/sys/dev/ath/if_ath_debug.c
index e3c73f5..d21ad6f 100644
--- a/sys/dev/ath/if_ath_debug.c
+++ b/sys/dev/ath/if_ath_debug.c
@@ -92,9 +92,8 @@ __FBSDID("$FreeBSD$");
uint64_t ath_debug = 0;
SYSCTL_DECL(_hw_ath);
-SYSCTL_QUAD(_hw_ath, OID_AUTO, debug, CTLFLAG_RW, &ath_debug,
+SYSCTL_QUAD(_hw_ath, OID_AUTO, debug, CTLFLAG_RWTUN, &ath_debug,
0, "control debugging printfs");
-TUNABLE_QUAD("hw.ath.debug", &ath_debug);
void
ath_printrxbuf(struct ath_softc *sc, const struct ath_buf *bf,
diff --git a/sys/dev/ath/if_ath_debug.h b/sys/dev/ath/if_ath_debug.h
index 83597af..40c0b9a 100644
--- a/sys/dev/ath/if_ath_debug.h
+++ b/sys/dev/ath/if_ath_debug.h
@@ -68,6 +68,7 @@ enum {
ATH_DEBUG_SW_TX_FILT = 0x400000000ULL, /* SW TX FF */
ATH_DEBUG_NODE_PWRSAVE = 0x800000000ULL, /* node powersave */
ATH_DEBUG_DIVERSITY = 0x1000000000ULL, /* Diversity logic */
+ ATH_DEBUG_PWRSAVE = 0x2000000000ULL,
ATH_DEBUG_ANY = 0xffffffffffffffffULL
};
diff --git a/sys/dev/ath/if_ath_keycache.c b/sys/dev/ath/if_ath_keycache.c
index 6c2749f..fe99f10 100644
--- a/sys/dev/ath/if_ath_keycache.c
+++ b/sys/dev/ath/if_ath_keycache.c
@@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
@@ -77,6 +78,7 @@ __FBSDID("$FreeBSD$");
#include <dev/ath/if_ath_debug.h>
#include <dev/ath/if_ath_keycache.h>
+#include <dev/ath/if_ath_misc.h>
#ifdef ATH_DEBUG
static void
@@ -197,6 +199,7 @@ ath_keyset(struct ath_softc *sc, struct ieee80211vap *vap,
u_int8_t gmac[IEEE80211_ADDR_LEN];
const u_int8_t *mac;
HAL_KEYVAL hk;
+ int ret;
memset(&hk, 0, sizeof(hk));
/*
@@ -250,13 +253,19 @@ ath_keyset(struct ath_softc *sc, struct ieee80211vap *vap,
} else
mac = k->wk_macaddr;
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
if (hk.kv_type == HAL_CIPHER_TKIP &&
(k->wk_flags & IEEE80211_KEY_SWMIC) == 0) {
- return ath_keyset_tkip(sc, k, &hk, mac);
+ ret = ath_keyset_tkip(sc, k, &hk, mac);
} else {
KEYPRINTF(sc, k->wk_keyix, &hk, mac);
- return ath_hal_keyset(ah, k->wk_keyix, &hk, mac);
+ ret = ath_hal_keyset(ah, k->wk_keyix, &hk, mac);
}
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+
+ return (ret);
#undef N
}
@@ -491,6 +500,8 @@ ath_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: delete key %u\n", __func__, keyix);
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
ath_hal_keyreset(ah, keyix);
/*
* Handle split tx/rx keying required for TKIP with h/w MIC.
@@ -514,6 +525,8 @@ ath_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
}
}
}
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
return 1;
}
diff --git a/sys/dev/ath/if_ath_led.c b/sys/dev/ath/if_ath_led.c
index 33cc512..a55e036 100644
--- a/sys/dev/ath/if_ath_led.c
+++ b/sys/dev/ath/if_ath_led.c
@@ -122,6 +122,11 @@ __FBSDID("$FreeBSD$");
void
ath_led_config(struct ath_softc *sc)
{
+
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
/* Software LED blinking - GPIO controlled LED */
if (sc->sc_softled) {
ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin,
@@ -144,6 +149,10 @@ ath_led_config(struct ath_softc *sc)
ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_led_net_pin,
HAL_GPIO_OUTPUT_MUX_MAC_NETWORK_LED);
}
+
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
}
static void
diff --git a/sys/dev/ath/if_ath_lna_div.c b/sys/dev/ath/if_ath_lna_div.c
index 4ae81a3..f0a33a5 100644
--- a/sys/dev/ath/if_ath_lna_div.c
+++ b/sys/dev/ath/if_ath_lna_div.c
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <sys/kernel.h>
#include <sys/lock.h>
+#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/errno.h>
@@ -54,6 +55,7 @@ __FBSDID("$FreeBSD$");
#include <sys/socket.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_media.h>
#include <net/if_arp.h>
#include <net/ethernet.h> /* XXX for ether_sprintf */
@@ -207,6 +209,10 @@ bad:
return (error);
}
+/*
+ * XXX need to low_rssi_thresh config from ath9k, to support CUS198
+ * antenna diversity correctly.
+ */
static HAL_BOOL
ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, int mindelta,
int main_rssi_avg, int alt_rssi_avg, int pkt_count)
diff --git a/sys/dev/ath/if_ath_misc.h b/sys/dev/ath/if_ath_misc.h
index 0c99bc7..711e69e8 100644
--- a/sys/dev/ath/if_ath_misc.h
+++ b/sys/dev/ath/if_ath_misc.h
@@ -128,6 +128,19 @@ extern void ath_start_task(void *arg, int npending);
extern void ath_tx_dump(struct ath_softc *sc, struct ath_txq *txq);
/*
+ * Power state tracking.
+ */
+extern void _ath_power_setpower(struct ath_softc *sc, int power_state, const char *file, int line);
+extern void _ath_power_set_selfgen(struct ath_softc *sc, int power_state, const char *file, int line);
+extern void _ath_power_set_power_state(struct ath_softc *sc, int power_state, const char *file, int line);
+extern void _ath_power_restore_power_state(struct ath_softc *sc, const char *file, int line);
+
+#define ath_power_setpower(sc, ps) _ath_power_setpower(sc, ps, __FILE__, __LINE__)
+#define ath_power_setselfgen(sc, ps) _ath_power_set_selfgen(sc, ps, __FILE__, __LINE__)
+#define ath_power_set_power_state(sc, ps) _ath_power_set_power_state(sc, ps, __FILE__, __LINE__)
+#define ath_power_restore_power_state(sc) _ath_power_restore_power_state(sc, __FILE__, __LINE__)
+
+/*
* Kick the frame TX task.
*/
static inline void
diff --git a/sys/dev/ath/if_ath_pci.c b/sys/dev/ath/if_ath_pci.c
index 91cb425..5610882 100644
--- a/sys/dev/ath/if_ath_pci.c
+++ b/sys/dev/ath/if_ath_pci.c
@@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/lock.h>
@@ -53,6 +54,7 @@ __FBSDID("$FreeBSD$");
#include <net/if.h>
#include <net/if_media.h>
#include <net/if_arp.h>
+#include <net/ethernet.h>
#include <net80211/ieee80211_var.h>
@@ -78,6 +80,98 @@ struct ath_pci_softc {
void *sc_ih; /* interrupt handler */
};
+/*
+ * XXX eventually this should be some system level definition
+ * so modules will hvae probe/attach information like USB.
+ * But for now..
+ */
+struct pci_device_id {
+ int vendor_id;
+ int device_id;
+
+ int sub_vendor_id;
+ int sub_device_id;
+
+ int driver_data;
+
+ int match_populated:1;
+ int match_vendor_id:1;
+ int match_device_id:1;
+ int match_sub_vendor_id:1;
+ int match_sub_device_id:1;
+};
+
+#define PCI_VDEVICE(v, s) \
+ .vendor_id = (v), \
+ .device_id = (s), \
+ .match_populated = 1, \
+ .match_vendor_id = 1, \
+ .match_device_id = 1
+
+#define PCI_DEVICE_SUB(v, d, dv, ds) \
+ .match_populated = 1, \
+ .vendor_id = (v), .match_vendor_id = 1, \
+ .device_id = (d), .match_device_id = 1, \
+ .sub_vendor_id = (dv), .match_sub_vendor_id = 1, \
+ .sub_device_id = (ds), .match_sub_device_id = 1
+
+#define PCI_VENDOR_ID_ATHEROS 0x168c
+#define PCI_VENDOR_ID_SAMSUNG 0x144d
+#define PCI_VENDOR_ID_AZWAVE 0x1a3b
+#define PCI_VENDOR_ID_FOXCONN 0x105b
+#define PCI_VENDOR_ID_ATTANSIC 0x1969
+#define PCI_VENDOR_ID_ASUSTEK 0x1043
+#define PCI_VENDOR_ID_DELL 0x1028
+#define PCI_VENDOR_ID_QMI 0x1a32
+#define PCI_VENDOR_ID_LENOVO 0x17aa
+#define PCI_VENDOR_ID_HP 0x103c
+
+#include "if_ath_pci_devlist.h"
+
+/*
+ * Attempt to find a match for the given device in
+ * the given device table.
+ *
+ * Returns the device structure or NULL if no matching
+ * PCI device is found.
+ */
+static const struct pci_device_id *
+ath_pci_probe_device(device_t dev, const struct pci_device_id *dev_table, int nentries)
+{
+ int i;
+ int vendor_id, device_id;
+ int sub_vendor_id, sub_device_id;
+
+ vendor_id = pci_get_vendor(dev);
+ device_id = pci_get_device(dev);
+ sub_vendor_id = pci_get_subvendor(dev);
+ sub_device_id = pci_get_subdevice(dev);
+
+ for (i = 0; i < nentries; i++) {
+ /* Don't match on non-populated (eg empty) entries */
+ if (! dev_table[i].match_populated)
+ continue;
+
+ if (dev_table[i].match_vendor_id &&
+ (dev_table[i].vendor_id != vendor_id))
+ continue;
+ if (dev_table[i].match_device_id &&
+ (dev_table[i].device_id != device_id))
+ continue;
+ if (dev_table[i].match_sub_vendor_id &&
+ (dev_table[i].sub_vendor_id != sub_vendor_id))
+ continue;
+ if (dev_table[i].match_sub_device_id &&
+ (dev_table[i].sub_device_id != sub_device_id))
+ continue;
+
+ /* Match */
+ return (&dev_table[i]);
+ }
+
+ return (NULL);
+}
+
#define BS_BAR 0x10
#define PCIR_RETRY_TIMEOUT 0x41
#define PCIR_CFG_PMCSR 0x48
@@ -148,9 +242,15 @@ ath_pci_attach(device_t dev)
const struct firmware *fw = NULL;
const char *buf;
#endif
+ const struct pci_device_id *pd;
sc->sc_dev = dev;
+ /* Do this lookup anyway; figure out what to do with it later */
+ pd = ath_pci_probe_device(dev, ath_pci_id_table, nitems(ath_pci_id_table));
+ if (pd)
+ sc->sc_pci_devinfo = pd->driver_data;
+
/*
* Enable bus mastering.
*/
@@ -171,8 +271,7 @@ ath_pci_attach(device_t dev)
device_printf(dev, "cannot map register space\n");
goto bad;
}
- /* XXX uintptr_t is a bandaid for ia64; to be fixed */
- sc->sc_st = (HAL_BUS_TAG)(uintptr_t) rman_get_bustag(psc->sc_sr);
+ sc->sc_st = (HAL_BUS_TAG) rman_get_bustag(psc->sc_sr);
sc->sc_sh = (HAL_BUS_HANDLE) rman_get_bushandle(psc->sc_sr);
/*
* Mark device invalid so any interrupts (shared or otherwise)
@@ -180,6 +279,13 @@ ath_pci_attach(device_t dev)
*/
sc->sc_invalid = 1;
+ ATH_LOCK_INIT(sc);
+ ATH_PCU_LOCK_INIT(sc);
+ ATH_RX_LOCK_INIT(sc);
+ ATH_TX_LOCK_INIT(sc);
+ ATH_TX_IC_LOCK_INIT(sc);
+ ATH_TXSTATUS_LOCK_INIT(sc);
+
/*
* Arrange interrupt line.
*/
@@ -230,7 +336,7 @@ ath_pci_attach(device_t dev)
if (fw == NULL) {
device_printf(dev, "%s: couldn't find firmware\n",
__func__);
- goto bad3;
+ goto bad4;
}
device_printf(dev, "%s: EEPROM firmware @ %p\n",
@@ -240,30 +346,20 @@ ath_pci_attach(device_t dev)
if (! sc->sc_eepromdata) {
device_printf(dev, "%s: can't malloc eepromdata\n",
__func__);
- goto bad3;
+ goto bad4;
}
memcpy(sc->sc_eepromdata, fw->data, fw->datasize);
firmware_put(fw, 0);
}
#endif /* ATH_EEPROM_FIRMWARE */
- ATH_LOCK_INIT(sc);
- ATH_PCU_LOCK_INIT(sc);
- ATH_RX_LOCK_INIT(sc);
- ATH_TX_LOCK_INIT(sc);
- ATH_TX_IC_LOCK_INIT(sc);
- ATH_TXSTATUS_LOCK_INIT(sc);
-
error = ath_attach(pci_get_device(dev), sc);
if (error == 0) /* success */
return 0;
- ATH_TXSTATUS_LOCK_DESTROY(sc);
- ATH_PCU_LOCK_DESTROY(sc);
- ATH_RX_LOCK_DESTROY(sc);
- ATH_TX_IC_LOCK_DESTROY(sc);
- ATH_TX_LOCK_DESTROY(sc);
- ATH_LOCK_DESTROY(sc);
+#ifdef ATH_EEPROM_FIRMWARE
+bad4:
+#endif
bus_dma_tag_destroy(sc->sc_dmat);
bad3:
bus_teardown_intr(dev, psc->sc_irq, psc->sc_ih);
@@ -271,6 +367,14 @@ bad2:
bus_release_resource(dev, SYS_RES_IRQ, 0, psc->sc_irq);
bad1:
bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, psc->sc_sr);
+
+ ATH_TXSTATUS_LOCK_DESTROY(sc);
+ ATH_PCU_LOCK_DESTROY(sc);
+ ATH_RX_LOCK_DESTROY(sc);
+ ATH_TX_IC_LOCK_DESTROY(sc);
+ ATH_TX_LOCK_DESTROY(sc);
+ ATH_LOCK_DESTROY(sc);
+
bad:
return (error);
}
diff --git a/sys/dev/ath/if_ath_pci_devlist.h b/sys/dev/ath/if_ath_pci_devlist.h
new file mode 100644
index 0000000..ae65909
--- /dev/null
+++ b/sys/dev/ath/if_ath_pci_devlist.h
@@ -0,0 +1,669 @@
+/*-
+ * Copyright (c) 2014 Qualcomm Atheros.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD$
+ */
+
+static const struct pci_device_id ath_pci_id_table[] = {
+ { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x0023) }, /* PCI */
+ { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x0024) }, /* PCI-E */
+ { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x0027) }, /* PCI */
+ { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x0029) }, /* PCI */
+ { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x002A) }, /* PCI-E */
+
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x002A,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x1C71),
+ .driver_data = ATH_PCI_D3_L1_WAR },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x002A,
+ PCI_VENDOR_ID_FOXCONN,
+ 0xE01F),
+ .driver_data = ATH_PCI_D3_L1_WAR },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x002A,
+ 0x11AD, /* LITEON */
+ 0x6632),
+ .driver_data = ATH_PCI_D3_L1_WAR },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x002A,
+ 0x11AD, /* LITEON */
+ 0x6642),
+ .driver_data = ATH_PCI_D3_L1_WAR },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x002A,
+ PCI_VENDOR_ID_QMI,
+ 0x0306),
+ .driver_data = ATH_PCI_D3_L1_WAR },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x002A,
+ 0x185F, /* WNC */
+ 0x309D),
+ .driver_data = ATH_PCI_D3_L1_WAR },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x002A,
+ 0x10CF, /* Fujitsu */
+ 0x147C),
+ .driver_data = ATH_PCI_D3_L1_WAR },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x002A,
+ 0x10CF, /* Fujitsu */
+ 0x147D),
+ .driver_data = ATH_PCI_D3_L1_WAR },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x002A,
+ 0x10CF, /* Fujitsu */
+ 0x1536),
+ .driver_data = ATH_PCI_D3_L1_WAR },
+
+ /* AR9285 card for Asus */
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x002B,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x2C37),
+ .driver_data = ATH_PCI_BT_ANT_DIV },
+
+ { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x002B) }, /* PCI-E */
+ { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */
+ { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x002D) }, /* PCI */
+ { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x002E) }, /* PCI-E */
+
+ /* Killer Wireless (3x3) */
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0030,
+ 0x1A56,
+ 0x2000),
+ .driver_data = ATH_PCI_KILLER },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0030,
+ 0x1A56,
+ 0x2001),
+ .driver_data = ATH_PCI_KILLER },
+
+ { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x0030) }, /* PCI-E AR9300 */
+
+ /* PCI-E CUS198 */
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x2086),
+ .driver_data = ATH_PCI_CUS198 | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x1237),
+ .driver_data = ATH_PCI_CUS198 | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x2126),
+ .driver_data = ATH_PCI_CUS198 | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x126A),
+ .driver_data = ATH_PCI_CUS198 | ATH_PCI_BT_ANT_DIV },
+
+ /* PCI-E CUS230 */
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x2152),
+ .driver_data = ATH_PCI_CUS230 | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_FOXCONN,
+ 0xE075),
+ .driver_data = ATH_PCI_CUS230 | ATH_PCI_BT_ANT_DIV },
+
+ /* WB225 */
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_ATHEROS,
+ 0x3119),
+ .driver_data = ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_ATHEROS,
+ 0x3122),
+ .driver_data = ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ 0x185F, /* WNC */
+ 0x3119),
+ .driver_data = ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ 0x185F, /* WNC */
+ 0x3027),
+ .driver_data = ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_SAMSUNG,
+ 0x4105),
+ .driver_data = ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_SAMSUNG,
+ 0x4106),
+ .driver_data = ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_SAMSUNG,
+ 0x410D),
+ .driver_data = ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_SAMSUNG,
+ 0x410E),
+ .driver_data = ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_SAMSUNG,
+ 0x410F),
+ .driver_data = ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_SAMSUNG,
+ 0xC706),
+ .driver_data = ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_SAMSUNG,
+ 0xC680),
+ .driver_data = ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_SAMSUNG,
+ 0xC708),
+ .driver_data = ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_LENOVO,
+ 0x3218),
+ .driver_data = ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_LENOVO,
+ 0x3219),
+ .driver_data = ATH_PCI_BT_ANT_DIV },
+
+ /* AR9485 cards with PLL power-save disabled by default. */
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x2C97),
+ .driver_data = ATH_PCI_NO_PLL_PWRSAVE },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x2100),
+ .driver_data = ATH_PCI_NO_PLL_PWRSAVE },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ 0x1C56, /* ASKEY */
+ 0x4001),
+ .driver_data = ATH_PCI_NO_PLL_PWRSAVE },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ 0x11AD, /* LITEON */
+ 0x6627),
+ .driver_data = ATH_PCI_NO_PLL_PWRSAVE },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ 0x11AD, /* LITEON */
+ 0x6628),
+ .driver_data = ATH_PCI_NO_PLL_PWRSAVE },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_FOXCONN,
+ 0xE04E),
+ .driver_data = ATH_PCI_NO_PLL_PWRSAVE },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_FOXCONN,
+ 0xE04F),
+ .driver_data = ATH_PCI_NO_PLL_PWRSAVE },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ 0x144F, /* ASKEY */
+ 0x7197),
+ .driver_data = ATH_PCI_NO_PLL_PWRSAVE },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ 0x1B9A, /* XAVI */
+ 0x2000),
+ .driver_data = ATH_PCI_NO_PLL_PWRSAVE },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ 0x1B9A, /* XAVI */
+ 0x2001),
+ .driver_data = ATH_PCI_NO_PLL_PWRSAVE },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x1186),
+ .driver_data = ATH_PCI_NO_PLL_PWRSAVE },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x1F86),
+ .driver_data = ATH_PCI_NO_PLL_PWRSAVE },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x1195),
+ .driver_data = ATH_PCI_NO_PLL_PWRSAVE },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x1F95),
+ .driver_data = ATH_PCI_NO_PLL_PWRSAVE },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ 0x1B9A, /* XAVI */
+ 0x1C00),
+ .driver_data = ATH_PCI_NO_PLL_PWRSAVE },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ 0x1B9A, /* XAVI */
+ 0x1C01),
+ .driver_data = ATH_PCI_NO_PLL_PWRSAVE },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0032,
+ PCI_VENDOR_ID_ASUSTEK,
+ 0x850D),
+ .driver_data = ATH_PCI_NO_PLL_PWRSAVE },
+
+ { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x0032) }, /* PCI-E AR9485 */
+ { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x0033) }, /* PCI-E AR9580 */
+
+ /* PCI-E CUS217 */
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0034,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x2116),
+ .driver_data = ATH_PCI_CUS217 },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0034,
+ 0x11AD, /* LITEON */
+ 0x6661),
+ .driver_data = ATH_PCI_CUS217 },
+
+ /* AR9462 with WoW support */
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0034,
+ PCI_VENDOR_ID_ATHEROS,
+ 0x3117),
+ .driver_data = ATH_PCI_WOW },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0034,
+ PCI_VENDOR_ID_LENOVO,
+ 0x3214),
+ .driver_data = ATH_PCI_WOW },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0034,
+ PCI_VENDOR_ID_ATTANSIC,
+ 0x0091),
+ .driver_data = ATH_PCI_WOW },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0034,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x2110),
+ .driver_data = ATH_PCI_WOW },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0034,
+ PCI_VENDOR_ID_ASUSTEK,
+ 0x850E),
+ .driver_data = ATH_PCI_WOW },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0034,
+ 0x11AD, /* LITEON */
+ 0x6631),
+ .driver_data = ATH_PCI_WOW },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0034,
+ 0x11AD, /* LITEON */
+ 0x6641),
+ .driver_data = ATH_PCI_WOW },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0034,
+ PCI_VENDOR_ID_HP,
+ 0x1864),
+ .driver_data = ATH_PCI_WOW },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0034,
+ 0x14CD, /* USI */
+ 0x0063),
+ .driver_data = ATH_PCI_WOW },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0034,
+ 0x14CD, /* USI */
+ 0x0064),
+ .driver_data = ATH_PCI_WOW },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0034,
+ 0x10CF, /* Fujitsu */
+ 0x1783),
+ .driver_data = ATH_PCI_WOW },
+
+ /* Killer Wireless (2x2) */
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0030,
+ 0x1A56,
+ 0x2003),
+ .driver_data = ATH_PCI_KILLER },
+
+ { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x0034) }, /* PCI-E AR9462 */
+ { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x0037) }, /* PCI-E AR1111/AR9485 */
+
+ /* CUS252 */
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_ATHEROS,
+ 0x3028),
+ .driver_data = ATH_PCI_CUS252 |
+ ATH_PCI_AR9565_2ANT |
+ ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x2176),
+ .driver_data = ATH_PCI_CUS252 |
+ ATH_PCI_AR9565_2ANT |
+ ATH_PCI_BT_ANT_DIV },
+
+ /* WB335 1-ANT */
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_FOXCONN,
+ 0xE068),
+ .driver_data = ATH_PCI_AR9565_1ANT },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x185F, /* WNC */
+ 0xA119),
+ .driver_data = ATH_PCI_AR9565_1ANT },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x11AD, /* LITEON */
+ 0x0632),
+ .driver_data = ATH_PCI_AR9565_1ANT },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x11AD, /* LITEON */
+ 0x06B2),
+ .driver_data = ATH_PCI_AR9565_1ANT },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x11AD, /* LITEON */
+ 0x0842),
+ .driver_data = ATH_PCI_AR9565_1ANT },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x11AD, /* LITEON */
+ 0x6671),
+ .driver_data = ATH_PCI_AR9565_1ANT },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x1B9A, /* XAVI */
+ 0x2811),
+ .driver_data = ATH_PCI_AR9565_1ANT },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x1B9A, /* XAVI */
+ 0x2812),
+ .driver_data = ATH_PCI_AR9565_1ANT },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x1B9A, /* XAVI */
+ 0x28A1),
+ .driver_data = ATH_PCI_AR9565_1ANT },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x218A),
+ .driver_data = ATH_PCI_AR9565_1ANT },
+
+ /* WB335 1-ANT / Antenna Diversity */
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_ATHEROS,
+ 0x3025),
+ .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_ATHEROS,
+ 0x3026),
+ .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_ATHEROS,
+ 0x302B),
+ .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_FOXCONN,
+ 0xE069),
+ .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x185F, /* WNC */
+ 0x3028),
+ .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x11AD, /* LITEON */
+ 0x0622),
+ .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x11AD, /* LITEON */
+ 0x0672),
+ .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x11AD, /* LITEON */
+ 0x0662),
+ .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x11AD, /* LITEON */
+ 0x06A2),
+ .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x11AD, /* LITEON */
+ 0x0682),
+ .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x213A),
+ .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_HP,
+ 0x18E3),
+ .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_HP,
+ 0x217F),
+ .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_HP,
+ 0x2005),
+ .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_DELL,
+ 0x020C),
+ .driver_data = ATH_PCI_AR9565_1ANT | ATH_PCI_BT_ANT_DIV },
+
+ /* WB335 2-ANT / Antenna-Diversity */
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_SAMSUNG,
+ 0x411A),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_SAMSUNG,
+ 0x411B),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_SAMSUNG,
+ 0x411C),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_SAMSUNG,
+ 0x411D),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_SAMSUNG,
+ 0x411E),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_ATHEROS,
+ 0x3027),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_ATHEROS,
+ 0x302C),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x11AD, /* LITEON */
+ 0x0642),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x11AD, /* LITEON */
+ 0x0652),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x11AD, /* LITEON */
+ 0x0612),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x11AD, /* LITEON */
+ 0x0832),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x11AD, /* LITEON */
+ 0x0692),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x2130),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x213B),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x2182),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x144F, /* ASKEY */
+ 0x7202),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x1B9A, /* XAVI */
+ 0x2810),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x1B9A, /* XAVI */
+ 0x28A2),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x185F, /* WNC */
+ 0x3027),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x185F, /* WNC */
+ 0xA120),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_FOXCONN,
+ 0xE07F),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_FOXCONN,
+ 0xE081),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_LENOVO,
+ 0x3026),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_LENOVO,
+ 0x4026),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_ASUSTEK,
+ 0x85F2),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_DELL,
+ 0x020E),
+ .driver_data = ATH_PCI_AR9565_2ANT | ATH_PCI_BT_ANT_DIV },
+
+ /* PCI-E AR9565 (WB335) */
+ { PCI_VDEVICE(PCI_VENDOR_ID_ATHEROS, 0x0036),
+ .driver_data = ATH_PCI_BT_ANT_DIV },
+
+ { 0 }
+};
+
diff --git a/sys/dev/ath/if_ath_rx.c b/sys/dev/ath/if_ath_rx.c
index d9e212b..bed9488 100644
--- a/sys/dev/ath/if_ath_rx.c
+++ b/sys/dev/ath/if_ath_rx.c
@@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
@@ -165,10 +166,22 @@ ath_calcrxfilter(struct ath_softc *sc)
/* XXX ic->ic_monvaps != 0? */
if (ic->ic_opmode == IEEE80211_M_MONITOR || (ifp->if_flags & IFF_PROMISC))
rfilt |= HAL_RX_FILTER_PROM;
+
+ /*
+ * Only listen to all beacons if we're scanning.
+ *
+ * Otherwise we only really need to hear beacons from
+ * our own BSSID.
+ */
if (ic->ic_opmode == IEEE80211_M_STA ||
- ic->ic_opmode == IEEE80211_M_IBSS ||
- sc->sc_swbmiss || sc->sc_scanning)
- rfilt |= HAL_RX_FILTER_BEACON;
+ ic->ic_opmode == IEEE80211_M_IBSS || sc->sc_swbmiss) {
+ if (sc->sc_do_mybeacon && ! sc->sc_scanning) {
+ rfilt |= HAL_RX_FILTER_MYBEACON;
+ } else { /* scanning, non-mybeacon chips */
+ rfilt |= HAL_RX_FILTER_BEACON;
+ }
+ }
+
/*
* NB: We don't recalculate the rx filter when
* ic_protmode changes; otherwise we could do
@@ -232,6 +245,8 @@ ath_legacy_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf)
struct mbuf *m;
struct ath_desc *ds;
+ /* XXX TODO: ATH_RX_LOCK_ASSERT(sc); */
+
m = bf->bf_m;
if (m == NULL) {
/*
@@ -316,6 +331,23 @@ ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
{
struct ieee80211vap *vap = ni->ni_vap;
struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
+ uint64_t tsf_beacon_old, tsf_beacon;
+ uint64_t nexttbtt;
+ int64_t tsf_delta;
+ int32_t tsf_delta_bmiss;
+ int32_t tsf_remainder;
+ uint64_t tsf_beacon_target;
+ int tsf_intval;
+
+ tsf_beacon_old = ((uint64_t) LE_READ_4(ni->ni_tstamp.data + 4)) << 32;
+ tsf_beacon_old |= LE_READ_4(ni->ni_tstamp.data);
+
+#define TU_TO_TSF(_tu) (((u_int64_t)(_tu)) << 10)
+ tsf_intval = 1;
+ if (ni->ni_intval > 0) {
+ tsf_intval = TU_TO_TSF(ni->ni_intval);
+ }
+#undef TU_TO_TSF
/*
* Call up first so subsequent work can use information
@@ -327,14 +359,79 @@ ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
/* update rssi statistics for use by the hal */
/* XXX unlocked check against vap->iv_bss? */
ATH_RSSI_LPF(sc->sc_halstats.ns_avgbrssi, rssi);
+
+ tsf_beacon = ((uint64_t) LE_READ_4(ni->ni_tstamp.data + 4)) << 32;
+ tsf_beacon |= LE_READ_4(ni->ni_tstamp.data);
+
+ nexttbtt = ath_hal_getnexttbtt(sc->sc_ah);
+
+ /*
+ * Let's calculate the delta and remainder, so we can see
+ * if the beacon timer from the AP is varying by more than
+ * a few TU. (Which would be a huge, huge problem.)
+ */
+ tsf_delta = (long long) tsf_beacon - (long long) tsf_beacon_old;
+
+ tsf_delta_bmiss = tsf_delta / tsf_intval;
+
+ /*
+ * If our delta is greater than half the beacon interval,
+ * let's round the bmiss value up to the next beacon
+ * interval. Ie, we're running really, really early
+ * on the next beacon.
+ */
+ if (tsf_delta % tsf_intval > (tsf_intval / 2))
+ tsf_delta_bmiss ++;
+
+ tsf_beacon_target = tsf_beacon_old +
+ (((unsigned long long) tsf_delta_bmiss) * (long long) tsf_intval);
+
+ /*
+ * The remainder using '%' is between 0 .. intval-1.
+ * If we're actually running too fast, then the remainder
+ * will be some large number just under intval-1.
+ * So we need to look at whether we're running
+ * before or after the target beacon interval
+ * and if we are, modify how we do the remainder
+ * calculation.
+ */
+ if (tsf_beacon < tsf_beacon_target) {
+ tsf_remainder =
+ -(tsf_intval - ((tsf_beacon - tsf_beacon_old) % tsf_intval));
+ } else {
+ tsf_remainder = (tsf_beacon - tsf_beacon_old) % tsf_intval;
+ }
+
+ DPRINTF(sc, ATH_DEBUG_BEACON, "%s: old_tsf=%llu, new_tsf=%llu, target_tsf=%llu, delta=%lld, bmiss=%d, remainder=%d\n",
+ __func__,
+ (unsigned long long) tsf_beacon_old,
+ (unsigned long long) tsf_beacon,
+ (unsigned long long) tsf_beacon_target,
+ (long long) tsf_delta,
+ tsf_delta_bmiss,
+ tsf_remainder);
+
+ DPRINTF(sc, ATH_DEBUG_BEACON, "%s: tsf=%llu, nexttbtt=%llu, delta=%d\n",
+ __func__,
+ (unsigned long long) tsf_beacon,
+ (unsigned long long) nexttbtt,
+ (int32_t) tsf_beacon - (int32_t) nexttbtt + tsf_intval);
+
if (sc->sc_syncbeacon &&
- ni == vap->iv_bss && vap->iv_state == IEEE80211_S_RUN) {
+ ni == vap->iv_bss &&
+ (vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP)) {
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ "%s: syncbeacon=1; syncing\n",
+ __func__);
/*
* Resync beacon timers using the tsf of the beacon
* frame we just received.
*/
ath_beacon_config(sc, vap);
+ sc->sc_syncbeacon = 0;
}
+
+
/* fall thru... */
case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
if (vap->iv_opmode == IEEE80211_M_IBSS &&
@@ -607,7 +704,7 @@ ath_rx_pkt(struct ath_softc *sc, struct ath_rx_status *rs, HAL_STATUS status,
rs->rs_keyix-32 : rs->rs_keyix);
}
}
- ifp->if_ierrors++;
+ if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
rx_error:
/*
* Cleanup any pending partial frame.
@@ -733,7 +830,7 @@ rx_accept:
rs->rs_antenna |= 0x4;
}
- ifp->if_ipackets++;
+ if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
sc->sc_stats.ast_ant_rx[rs->rs_antenna]++;
/*
@@ -879,6 +976,14 @@ rx_next:
#define ATH_RX_MAX 128
+/*
+ * XXX TODO: break out the "get buffers" from "call ath_rx_pkt()" like
+ * the EDMA code does.
+ *
+ * XXX TODO: then, do all of the RX list management stuff inside
+ * ATH_RX_LOCK() so we don't end up potentially racing. The EDMA
+ * code is doing it right.
+ */
static void
ath_rx_proc(struct ath_softc *sc, int resched)
{
@@ -900,6 +1005,7 @@ ath_rx_proc(struct ath_softc *sc, int resched)
u_int64_t tsf;
int npkts = 0;
int kickpcu = 0;
+ int ret;
/* XXX we must not hold the ATH_LOCK here */
ATH_UNLOCK_ASSERT(sc);
@@ -910,6 +1016,10 @@ ath_rx_proc(struct ath_softc *sc, int resched)
kickpcu = sc->sc_kickpcu;
ATH_PCU_UNLOCK(sc);
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s: called\n", __func__);
ngood = 0;
nf = ath_hal_getchannoise(ah, sc->sc_curchan);
@@ -995,8 +1105,26 @@ ath_rx_proc(struct ath_softc *sc, int resched)
if (ath_rx_pkt(sc, rs, status, tsf, nf, HAL_RX_QUEUE_HP, bf, m))
ngood++;
rx_proc_next:
- TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
- } while (ath_rxbuf_init(sc, bf) == 0);
+ /*
+ * If there's a holding buffer, insert that onto
+ * the RX list; the hardware is now definitely not pointing
+ * to it now.
+ */
+ ret = 0;
+ if (sc->sc_rxedma[HAL_RX_QUEUE_HP].m_holdbf != NULL) {
+ TAILQ_INSERT_TAIL(&sc->sc_rxbuf,
+ sc->sc_rxedma[HAL_RX_QUEUE_HP].m_holdbf,
+ bf_list);
+ ret = ath_rxbuf_init(sc,
+ sc->sc_rxedma[HAL_RX_QUEUE_HP].m_holdbf);
+ }
+ /*
+ * Next, throw our buffer into the holding entry. The hardware
+ * may use the descriptor to read the link pointer before
+ * DMAing the next descriptor in to write out a packet.
+ */
+ sc->sc_rxedma[HAL_RX_QUEUE_HP].m_holdbf = bf;
+ } while (ret == 0);
/* rx signal state monitoring */
ath_hal_rxmonitor(ah, &sc->sc_halstats, sc->sc_curchan);
@@ -1028,6 +1156,13 @@ rx_proc_next:
* constantly write over the same frame, leading
* the RX driver code here to get heavily confused.
*/
+ /*
+ * XXX Has RX DMA stopped enough here to just call
+ * ath_startrecv()?
+ * XXX Do we need to use the holding buffer to restart
+ * RX DMA by appending entries to the final
+ * descriptor? Quite likely.
+ */
#if 1
ath_startrecv(sc);
#else
@@ -1065,6 +1200,13 @@ rx_proc_next:
#undef PA2DESC
/*
+ * Put the hardware to sleep again if we're done with it.
+ */
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+
+ /*
* If we hit the maximum number of frames in this round,
* reschedule for another immediate pass. This gives
* the TX and TX completion routines time to run, which
@@ -1111,6 +1253,58 @@ ath_legacy_flushrecv(struct ath_softc *sc)
ath_rx_proc(sc, 0);
}
+static void
+ath_legacy_flush_rxpending(struct ath_softc *sc)
+{
+
+ /* XXX ATH_RX_LOCK_ASSERT(sc); */
+
+ if (sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending != NULL) {
+ m_freem(sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending);
+ sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending = NULL;
+ }
+ if (sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending != NULL) {
+ m_freem(sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending);
+ sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending = NULL;
+ }
+}
+
+static int
+ath_legacy_flush_rxholdbf(struct ath_softc *sc)
+{
+ struct ath_buf *bf;
+
+ /* XXX ATH_RX_LOCK_ASSERT(sc); */
+ /*
+ * If there are RX holding buffers, free them here and return
+ * them to the list.
+ *
+ * XXX should just verify that bf->bf_m is NULL, as it must
+ * be at this point!
+ */
+ bf = sc->sc_rxedma[HAL_RX_QUEUE_HP].m_holdbf;
+ if (bf != NULL) {
+ if (bf->bf_m != NULL)
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
+ (void) ath_rxbuf_init(sc, bf);
+ }
+ sc->sc_rxedma[HAL_RX_QUEUE_HP].m_holdbf = NULL;
+
+ bf = sc->sc_rxedma[HAL_RX_QUEUE_LP].m_holdbf;
+ if (bf != NULL) {
+ if (bf->bf_m != NULL)
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
+ (void) ath_rxbuf_init(sc, bf);
+ }
+ sc->sc_rxedma[HAL_RX_QUEUE_LP].m_holdbf = NULL;
+
+ return (0);
+}
+
/*
* Disable the receive h/w in preparation for a reset.
*/
@@ -1122,6 +1316,8 @@ ath_legacy_stoprecv(struct ath_softc *sc, int dodelay)
((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
struct ath_hal *ah = sc->sc_ah;
+ ATH_RX_LOCK(sc);
+
ath_hal_stoppcurecv(ah); /* disable PCU */
ath_hal_setrxfilter(ah, 0); /* clear recv filter */
ath_hal_stopdmarecv(ah); /* disable DMA engine */
@@ -1155,22 +1351,23 @@ ath_legacy_stoprecv(struct ath_softc *sc, int dodelay)
}
}
#endif
- /*
- * Free both high/low RX pending, just in case.
- */
- if (sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending != NULL) {
- m_freem(sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending);
- sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending = NULL;
- }
- if (sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending != NULL) {
- m_freem(sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending);
- sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending = NULL;
- }
+
+ (void) ath_legacy_flush_rxpending(sc);
+ (void) ath_legacy_flush_rxholdbf(sc);
+
sc->sc_rxlink = NULL; /* just in case */
+
+ ATH_RX_UNLOCK(sc);
#undef PA2DESC
}
/*
+ * XXX TODO: something was calling startrecv without calling
+ * stoprecv. Let's figure out what/why. It was showing up
+ * as a mbuf leak (rxpending) and ath_buf leak (holdbf.)
+ */
+
+/*
* Enable the receive h/w following a reset.
*/
static int
@@ -1179,9 +1376,18 @@ ath_legacy_startrecv(struct ath_softc *sc)
struct ath_hal *ah = sc->sc_ah;
struct ath_buf *bf;
+ ATH_RX_LOCK(sc);
+
+ /*
+ * XXX should verify these are already all NULL!
+ */
sc->sc_rxlink = NULL;
- sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending = NULL;
- sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending = NULL;
+ (void) ath_legacy_flush_rxpending(sc);
+ (void) ath_legacy_flush_rxholdbf(sc);
+
+ /*
+ * Re-chain all of the buffers in the RX buffer list.
+ */
TAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
int error = ath_rxbuf_init(sc, bf);
if (error != 0) {
@@ -1197,6 +1403,8 @@ ath_legacy_startrecv(struct ath_softc *sc)
ath_hal_rxena(ah); /* enable recv descriptors */
ath_mode_init(sc); /* set filters, etc. */
ath_hal_startpcurecv(ah); /* re-enable PCU/DMA engine */
+
+ ATH_RX_UNLOCK(sc);
return 0;
}
diff --git a/sys/dev/ath/if_ath_rx_edma.c b/sys/dev/ath/if_ath_rx_edma.c
index 2be8627..7aa818f 100644
--- a/sys/dev/ath/if_ath_rx_edma.c
+++ b/sys/dev/ath/if_ath_rx_edma.c
@@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
@@ -159,10 +160,20 @@ ath_edma_stoprecv(struct ath_softc *sc, int dodelay)
struct ath_hal *ah = sc->sc_ah;
ATH_RX_LOCK(sc);
+
ath_hal_stoppcurecv(ah);
ath_hal_setrxfilter(ah, 0);
- ath_hal_stopdmarecv(ah);
+ /*
+ *
+ */
+ if (ath_hal_stopdmarecv(ah) == AH_TRUE)
+ sc->sc_rx_stopped = 1;
+
+ /*
+ * Give the various bus FIFOs (not EDMA descriptor FIFO)
+ * time to finish flushing out data.
+ */
DELAY(3000);
/* Flush RX pending for each queue */
@@ -217,10 +228,6 @@ ath_edma_reinit_fifo(struct ath_softc *sc, HAL_RX_QUEUE qtype)
/*
* Start receive.
- *
- * XXX TODO: this needs to reallocate the FIFO entries when a reset
- * occurs, in case the FIFO is filled up and no new descriptors get
- * thrown into the FIFO.
*/
static int
ath_edma_startrecv(struct ath_softc *sc)
@@ -229,35 +236,31 @@ ath_edma_startrecv(struct ath_softc *sc)
ATH_RX_LOCK(sc);
+ /*
+ * Sanity check - are we being called whilst RX
+ * isn't stopped? If so, we may end up pushing
+ * too many entries into the RX FIFO and
+ * badness occurs.
+ */
+
/* Enable RX FIFO */
ath_hal_rxena(ah);
/*
- * Entries should only be written out if the
- * FIFO is empty.
- *
- * XXX This isn't correct. I should be looking
- * at the value of AR_RXDP_SIZE (0x0070) to determine
- * how many entries are in here.
- *
- * A warm reset will clear the registers but not the FIFO.
- *
- * And I believe this is actually the address of the last
- * handled buffer rather than the current FIFO pointer.
- * So if no frames have been (yet) seen, we'll reinit the
- * FIFO.
- *
- * I'll chase that up at some point.
+ * In theory the hardware has been initialised, right?
*/
- if (ath_hal_getrxbuf(sc->sc_ah, HAL_RX_QUEUE_HP) == 0) {
+ if (sc->sc_rx_resetted == 1) {
DPRINTF(sc, ATH_DEBUG_EDMA_RX,
"%s: Re-initing HP FIFO\n", __func__);
ath_edma_reinit_fifo(sc, HAL_RX_QUEUE_HP);
- }
- if (ath_hal_getrxbuf(sc->sc_ah, HAL_RX_QUEUE_LP) == 0) {
DPRINTF(sc, ATH_DEBUG_EDMA_RX,
"%s: Re-initing LP FIFO\n", __func__);
ath_edma_reinit_fifo(sc, HAL_RX_QUEUE_LP);
+ sc->sc_rx_resetted = 0;
+ } else {
+ device_printf(sc->sc_dev,
+ "%s: called without resetting chip?\n",
+ __func__);
}
/* Add up to m_fifolen entries in each queue */
@@ -265,6 +268,9 @@ ath_edma_startrecv(struct ath_softc *sc)
* These must occur after the above write so the FIFO buffers
* are pushed/tracked in the same order as the hardware will
* process them.
+ *
+ * XXX TODO: is this really necessary? We should've stopped
+ * the hardware already and reinitialised it, so it's a no-op.
*/
ath_edma_rxfifo_alloc(sc, HAL_RX_QUEUE_HP,
sc->sc_rxedma[HAL_RX_QUEUE_HP].m_fifolen);
@@ -275,6 +281,11 @@ ath_edma_startrecv(struct ath_softc *sc)
ath_mode_init(sc);
ath_hal_startpcurecv(ah);
+ /*
+ * We're now doing RX DMA!
+ */
+ sc->sc_rx_stopped = 0;
+
ATH_RX_UNLOCK(sc);
return (0);
@@ -285,7 +296,16 @@ ath_edma_recv_sched_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype,
int dosched)
{
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
ath_edma_recv_proc_queue(sc, qtype, dosched);
+
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+
taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask);
}
@@ -293,8 +313,17 @@ static void
ath_edma_recv_sched(struct ath_softc *sc, int dosched)
{
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_HP, dosched);
ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_LP, dosched);
+
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+
taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask);
}
@@ -308,6 +337,10 @@ ath_edma_recv_flush(struct ath_softc *sc)
sc->sc_rxproc_cnt++;
ATH_PCU_UNLOCK(sc);
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
/*
* Flush any active frames from FIFO -> deferred list
*/
@@ -317,9 +350,18 @@ ath_edma_recv_flush(struct ath_softc *sc)
/*
* Process what's in the deferred queue
*/
+ /*
+ * XXX: If we read the tsf/channoise here and then pass it in,
+ * we could restore the power state before processing
+ * the deferred queue.
+ */
ath_edma_recv_proc_deferred_queue(sc, HAL_RX_QUEUE_HP, 0);
ath_edma_recv_proc_deferred_queue(sc, HAL_RX_QUEUE_LP, 0);
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+
ATH_PCU_LOCK(sc);
sc->sc_rxproc_cnt--;
ATH_PCU_UNLOCK(sc);
@@ -348,6 +390,21 @@ ath_edma_recv_proc_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype,
ATH_RX_LOCK(sc);
+#if 1
+ if (sc->sc_rx_resetted == 1) {
+ /*
+ * XXX We shouldn't ever be scheduled if
+ * receive has been stopped - so complain
+ * loudly!
+ */
+ device_printf(sc->sc_dev,
+ "%s: sc_rx_resetted=1! Bad!\n",
+ __func__);
+ ATH_RX_UNLOCK(sc);
+ return;
+ }
+#endif
+
do {
bf = re->m_fifo[re->m_fifo_head];
/* This shouldn't occur! */
@@ -419,24 +476,6 @@ ath_edma_recv_proc_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype,
"ath edma rx proc: npkts=%d\n",
npkts);
- /* Handle resched and kickpcu appropriately */
- ATH_PCU_LOCK(sc);
- if (dosched && sc->sc_kickpcu) {
- ATH_KTR(sc, ATH_KTR_ERROR, 0,
- "ath_edma_recv_proc_queue(): kickpcu");
- if (npkts > 0)
- device_printf(sc->sc_dev,
- "%s: handled npkts %d\n",
- __func__, npkts);
-
- /*
- * XXX TODO: what should occur here? Just re-poke and
- * re-enable the RX FIFO?
- */
- sc->sc_kickpcu = 0;
- }
- ATH_PCU_UNLOCK(sc);
-
return;
}
@@ -449,18 +488,20 @@ ath_edma_recv_proc_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype,
static void
ath_edma_flush_deferred_queue(struct ath_softc *sc)
{
- struct ath_buf *bf, *next;
+ struct ath_buf *bf;
ATH_RX_LOCK_ASSERT(sc);
/* Free in one set, inside the lock */
- TAILQ_FOREACH_SAFE(bf,
- &sc->sc_rx_rxlist[HAL_RX_QUEUE_LP], bf_list, next) {
+ while (! TAILQ_EMPTY(&sc->sc_rx_rxlist[HAL_RX_QUEUE_LP])) {
+ bf = TAILQ_FIRST(&sc->sc_rx_rxlist[HAL_RX_QUEUE_LP]);
+ TAILQ_REMOVE(&sc->sc_rx_rxlist[HAL_RX_QUEUE_LP], bf, bf_list);
/* Free the buffer/mbuf */
ath_edma_rxbuf_free(sc, bf);
}
- TAILQ_FOREACH_SAFE(bf,
- &sc->sc_rx_rxlist[HAL_RX_QUEUE_HP], bf_list, next) {
+ while (! TAILQ_EMPTY(&sc->sc_rx_rxlist[HAL_RX_QUEUE_HP])) {
+ bf = TAILQ_FIRST(&sc->sc_rx_rxlist[HAL_RX_QUEUE_HP]);
+ TAILQ_REMOVE(&sc->sc_rx_rxlist[HAL_RX_QUEUE_HP], bf, bf_list);
/* Free the buffer/mbuf */
ath_edma_rxbuf_free(sc, bf);
}
@@ -494,6 +535,10 @@ ath_edma_recv_proc_deferred_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype,
ATH_RX_UNLOCK(sc);
/* Handle the completed descriptors */
+ /*
+ * XXX is this SAFE call needed? The ath_buf entries
+ * aren't modified by ath_rx_pkt, right?
+ */
TAILQ_FOREACH_SAFE(bf, &rxlist, bf_list, next) {
/*
* Skip the RX descriptor status - start at the data offset
@@ -519,7 +564,9 @@ ath_edma_recv_proc_deferred_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype,
/* Free in one set, inside the lock */
ATH_RX_LOCK(sc);
- TAILQ_FOREACH_SAFE(bf, &rxlist, bf_list, next) {
+ while (! TAILQ_EMPTY(&rxlist)) {
+ bf = TAILQ_FIRST(&rxlist);
+ TAILQ_REMOVE(&rxlist, bf, bf_list);
/* Free the buffer/mbuf */
ath_edma_rxbuf_free(sc, bf);
}
@@ -551,12 +598,25 @@ ath_edma_recv_tasklet(void *arg, int npending)
sc->sc_rxproc_cnt++;
ATH_PCU_UNLOCK(sc);
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_HP, 1);
ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_LP, 1);
ath_edma_recv_proc_deferred_queue(sc, HAL_RX_QUEUE_HP, 1);
ath_edma_recv_proc_deferred_queue(sc, HAL_RX_QUEUE_LP, 1);
+ /*
+ * XXX: If we read the tsf/channoise here and then pass it in,
+ * we could restore the power state before processing
+ * the deferred queue.
+ */
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+
/* XXX inside IF_LOCK ? */
if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
#ifdef IEEE80211_SUPPORT_SUPERG
@@ -835,10 +895,13 @@ ath_edma_setup_rxfifo(struct ath_softc *sc, HAL_RX_QUEUE qtype)
qtype);
return (-EINVAL);
}
- device_printf(sc->sc_dev, "%s: type=%d, FIFO depth = %d entries\n",
- __func__,
- qtype,
- re->m_fifolen);
+
+ if (bootverbose)
+ device_printf(sc->sc_dev,
+ "%s: type=%d, FIFO depth = %d entries\n",
+ __func__,
+ qtype,
+ re->m_fifolen);
/* Allocate ath_buf FIFO array, pre-zero'ed */
re->m_fifo = malloc(sizeof(struct ath_buf *) * re->m_fifolen,
@@ -929,10 +992,12 @@ ath_recv_setup_edma(struct ath_softc *sc)
(void) ath_hal_setrxbufsize(sc->sc_ah, sc->sc_edma_bufsize -
sc->sc_rx_statuslen);
- device_printf(sc->sc_dev, "RX status length: %d\n",
- sc->sc_rx_statuslen);
- device_printf(sc->sc_dev, "RX buffer size: %d\n",
- sc->sc_edma_bufsize);
+ if (bootverbose) {
+ device_printf(sc->sc_dev, "RX status length: %d\n",
+ sc->sc_rx_statuslen);
+ device_printf(sc->sc_dev, "RX buffer size: %d\n",
+ sc->sc_edma_bufsize);
+ }
sc->sc_rx.recv_stop = ath_edma_stoprecv;
sc->sc_rx.recv_start = ath_edma_startrecv;
diff --git a/sys/dev/ath/if_ath_spectral.c b/sys/dev/ath/if_ath_spectral.c
index 5cfb1a9..e4afdae 100644
--- a/sys/dev/ath/if_ath_spectral.c
+++ b/sys/dev/ath/if_ath_spectral.c
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <sys/kernel.h>
#include <sys/lock.h>
+#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/errno.h>
@@ -53,6 +54,7 @@ __FBSDID("$FreeBSD$");
#include <sys/socket.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_media.h>
#include <net/if_arp.h>
#include <net/ethernet.h> /* XXX for ether_sprintf */
diff --git a/sys/dev/ath/if_ath_sysctl.c b/sys/dev/ath/if_ath_sysctl.c
index 0a5719a..45c8ae4 100644
--- a/sys/dev/ath/if_ath_sysctl.c
+++ b/sys/dev/ath/if_ath_sysctl.c
@@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
@@ -107,13 +108,26 @@ static int
ath_sysctl_slottime(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
- u_int slottime = ath_hal_getslottime(sc->sc_ah);
+ u_int slottime;
int error;
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ slottime = ath_hal_getslottime(sc->sc_ah);
+ ATH_UNLOCK(sc);
+
error = sysctl_handle_int(oidp, &slottime, 0, req);
if (error || !req->newptr)
- return error;
- return !ath_hal_setslottime(sc->sc_ah, slottime) ? EINVAL : 0;
+ goto finish;
+
+ error = !ath_hal_setslottime(sc->sc_ah, slottime) ? EINVAL : 0;
+
+finish:
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+
+ return error;
}
static int
@@ -399,12 +413,14 @@ ath_sysctl_txagg(SYSCTL_HANDLER_ARGS)
ATH_RX_LOCK(sc);
for (i = 0; i < 2; i++) {
- printf("%d: fifolen: %d/%d; head=%d; tail=%d\n",
+ printf("%d: fifolen: %d/%d; head=%d; tail=%d; m_pending=%p, m_holdbf=%p\n",
i,
sc->sc_rxedma[i].m_fifo_depth,
sc->sc_rxedma[i].m_fifolen,
sc->sc_rxedma[i].m_fifo_head,
- sc->sc_rxedma[i].m_fifo_tail);
+ sc->sc_rxedma[i].m_fifo_tail,
+ sc->sc_rxedma[i].m_rxpending,
+ sc->sc_rxedma[i].m_holdbf);
}
i = 0;
TAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
@@ -430,7 +446,15 @@ ath_sysctl_rfsilent(SYSCTL_HANDLER_ARGS)
return error;
if (!ath_hal_setrfsilent(sc->sc_ah, rfsilent))
return EINVAL;
- sc->sc_rfsilentpin = rfsilent & 0x1c;
+ /*
+ * Earlier chips (< AR5212) have up to 8 GPIO
+ * pins exposed.
+ *
+ * AR5416 and later chips have many more GPIO
+ * pins (up to 16) so the mask is expanded to
+ * four bits.
+ */
+ sc->sc_rfsilentpin = rfsilent & 0x3c;
sc->sc_rfsilentpol = (rfsilent & 0x2) != 0;
return 0;
}
diff --git a/sys/dev/ath/if_ath_tdma.c b/sys/dev/ath/if_ath_tdma.c
index c075d01..de1a91c 100644
--- a/sys/dev/ath/if_ath_tdma.c
+++ b/sys/dev/ath/if_ath_tdma.c
@@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
@@ -476,16 +477,19 @@ ath_tdma_update(struct ieee80211_node *ni,
DPRINTF(sc, ATH_DEBUG_TDMA_TIMER,
"rs->rstamp %llu rstamp %llu tsf %llu txtime %d, nextslot %llu, "
"nextslottu %d, nextslottume %d\n",
- (unsigned long long) rs->rs_tstamp, rstamp, tsf, txtime,
- nextslot, nextslottu, TSF_TO_TU(nextslot >> 32, nextslot));
+ (unsigned long long) rs->rs_tstamp,
+ (unsigned long long) rstamp,
+ (unsigned long long) tsf, txtime,
+ (unsigned long long) nextslot,
+ nextslottu, TSF_TO_TU(nextslot >> 32, nextslot));
DPRINTF(sc, ATH_DEBUG_TDMA,
" beacon tstamp: %llu (0x%016llx)\n",
- le64toh(ni->ni_tstamp.tsf),
- le64toh(ni->ni_tstamp.tsf));
+ (unsigned long long) le64toh(ni->ni_tstamp.tsf),
+ (unsigned long long) le64toh(ni->ni_tstamp.tsf));
DPRINTF(sc, ATH_DEBUG_TDMA_TIMER,
"nexttbtt %llu (0x%08llx) tsfdelta %d avg +%d/-%d\n",
- nexttbtt,
+ (unsigned long long) nexttbtt,
(long long) nexttbtt,
tsfdelta,
TDMA_AVG(sc->sc_avgtsfdeltap), TDMA_AVG(sc->sc_avgtsfdeltam));
@@ -579,7 +583,7 @@ ath_tdma_update(struct ieee80211_node *ni,
DPRINTF(sc, ATH_DEBUG_TDMA_TIMER,
"%s: calling ath_hal_adjusttsf: TSF=%llu, tsfdelta=%d\n",
__func__,
- tsf,
+ (unsigned long long) tsf,
tsfdelta);
#ifdef ATH_DEBUG_ALQ
diff --git a/sys/dev/ath/if_ath_tx.c b/sys/dev/ath/if_ath_tx.c
index 8bacd92..096278e 100644
--- a/sys/dev/ath/if_ath_tx.c
+++ b/sys/dev/ath/if_ath_tx.c
@@ -59,10 +59,12 @@ __FBSDID("$FreeBSD$");
#include <sys/kthread.h>
#include <sys/taskqueue.h>
#include <sys/priv.h>
+#include <sys/ktr.h>
#include <machine/bus.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
@@ -759,37 +761,21 @@ ath_tx_handoff_hw(struct ath_softc *sc, struct ath_txq *txq,
("ath_tx_handoff_hw called for mcast queue"));
/*
- * XXX racy, should hold the PCU lock when checking this,
- * and also should ensure that the TX counter is >0!
+ * XXX We should instead just verify that sc_txstart_cnt
+ * or ath_txproc_cnt > 0. That would mean that
+ * the reset is going to be waiting for us to complete.
*/
- KASSERT((sc->sc_inreset_cnt == 0),
- ("%s: TX during reset?\n", __func__));
+ if (sc->sc_txproc_cnt == 0 && sc->sc_txstart_cnt == 0) {
+ device_printf(sc->sc_dev,
+ "%s: TX dispatch without holding txcount/txstart refcnt!\n",
+ __func__);
+ }
-#if 0
/*
- * This causes a LOR. Find out where the PCU lock is being
- * held whilst the TXQ lock is grabbed - that shouldn't
- * be occuring.
+ * XXX .. this is going to cause the hardware to get upset;
+ * so we really should find some way to drop or queue
+ * things.
*/
- ATH_PCU_LOCK(sc);
- if (sc->sc_inreset_cnt) {
- ATH_PCU_UNLOCK(sc);
- DPRINTF(sc, ATH_DEBUG_RESET,
- "%s: called with sc_in_reset != 0\n",
- __func__);
- DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: queued: TXDP[%u] = %p (%p) depth %d\n",
- __func__, txq->axq_qnum,
- (caddr_t)bf->bf_daddr, bf->bf_desc,
- txq->axq_depth);
- /* XXX axq_link needs to be set and updated! */
- ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
- if (bf->bf_state.bfs_aggr)
- txq->axq_aggr_depth++;
- return;
- }
- ATH_PCU_UNLOCK(sc);
-#endif
ATH_TXQ_LOCK(txq);
@@ -1613,6 +1599,7 @@ ath_tx_normal_setup(struct ath_softc *sc, struct ieee80211_node *ni,
error = ath_tx_dmasetup(sc, bf, m0);
if (error != 0)
return error;
+ KASSERT((ni != NULL), ("%s: ni=NULL!", __func__));
bf->bf_node = ni; /* NB: held reference */
m0 = bf->bf_m; /* NB: may have changed */
wh = mtod(m0, struct ieee80211_frame *);
@@ -2104,6 +2091,7 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni,
int do_override;
uint8_t type, subtype;
int queue_to_head;
+ struct ath_node *an = ATH_NODE(ni);
ATH_TX_LOCK_ASSERT(sc);
@@ -2163,6 +2151,7 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni,
return error;
m0 = bf->bf_m; /* NB: may have changed */
wh = mtod(m0, struct ieee80211_frame *);
+ KASSERT((ni != NULL), ("%s: ni=NULL!", __func__));
bf->bf_node = ni; /* NB: held reference */
/* Always enable CLRDMASK for raw frames for now.. */
@@ -2181,12 +2170,24 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni,
rt = sc->sc_currates;
KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
+
+ /* Fetch first rate information */
rix = ath_tx_findrix(sc, params->ibp_rate0);
+ try0 = params->ibp_try0;
+
+ /*
+ * Override EAPOL rate as appropriate.
+ */
+ if (m0->m_flags & M_EAPOL) {
+ /* XXX? maybe always use long preamble? */
+ rix = an->an_mgmtrix;
+ try0 = ATH_TXMAXTRY; /* XXX?too many? */
+ }
+
txrate = rt->info[rix].rateCode;
if (params->ibp_flags & IEEE80211_BPF_SHORTPRE)
txrate |= rt->info[rix].shortPreamble;
sc->sc_txrix = rix;
- try0 = params->ibp_try0;
ismrr = (params->ibp_try1 != 0);
txantenna = params->ibp_pri >> 2;
if (txantenna == 0) /* XXX? */
@@ -2259,8 +2260,7 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni,
/* Blank the legacy rate array */
bzero(&bf->bf_state.bfs_rc, sizeof(bf->bf_state.bfs_rc));
- bf->bf_state.bfs_rc[0].rix =
- ath_tx_findrix(sc, params->ibp_rate0);
+ bf->bf_state.bfs_rc[0].rix = rix;
bf->bf_state.bfs_rc[0].tries = try0;
bf->bf_state.bfs_rc[0].ratecode = txrate;
@@ -2352,11 +2352,16 @@ ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
"%s: sc_inreset_cnt > 0; bailing\n", __func__);
error = EIO;
ATH_PCU_UNLOCK(sc);
- goto bad0;
+ goto badbad;
}
sc->sc_txstart_cnt++;
ATH_PCU_UNLOCK(sc);
+ /* Wake the hardware up already */
+ ATH_LOCK(sc);
+ ath_power_set_power_state(sc, HAL_PM_AWAKE);
+ ATH_UNLOCK(sc);
+
ATH_TX_LOCK(sc);
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid) {
@@ -2419,7 +2424,7 @@ ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
}
}
sc->sc_wd_timer = 5;
- ifp->if_opackets++;
+ if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
sc->sc_stats.ast_tx_raw++;
/*
@@ -2435,7 +2440,14 @@ ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
sc->sc_txstart_cnt--;
ATH_PCU_UNLOCK(sc);
+
+ /* Put the hardware back to sleep if required */
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+
return 0;
+
bad2:
ATH_KTR(sc, ATH_KTR_TX, 3, "ath_raw_xmit: bad2: m=%p, params=%p, "
"bf=%p",
@@ -2445,17 +2457,23 @@ bad2:
ATH_TXBUF_LOCK(sc);
ath_returnbuf_head(sc, bf);
ATH_TXBUF_UNLOCK(sc);
-bad:
+bad:
ATH_TX_UNLOCK(sc);
ATH_PCU_LOCK(sc);
sc->sc_txstart_cnt--;
ATH_PCU_UNLOCK(sc);
-bad0:
+
+ /* Put the hardware back to sleep if required */
+ ATH_LOCK(sc);
+ ath_power_restore_power_state(sc);
+ ATH_UNLOCK(sc);
+
+badbad:
ATH_KTR(sc, ATH_KTR_TX, 2, "ath_raw_xmit: bad0: m=%p, params=%p",
m, params);
- ifp->if_oerrors++;
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
sc->sc_stats.ast_tx_raw_fail++;
ieee80211_free_node(ni);
@@ -2748,8 +2766,8 @@ ath_tx_update_baw(struct ath_softc *sc, struct ath_node *an,
INCR(tid->baw_head, ATH_TID_MAX_BUFS);
}
DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
- "%s: baw is now %d:%d, baw head=%d\n",
- __func__, tap->txa_start, tap->txa_wnd, tid->baw_head);
+ "%s: tid=%d: baw is now %d:%d, baw head=%d\n",
+ __func__, tid->tid, tap->txa_start, tap->txa_wnd, tid->baw_head);
}
static void
@@ -3242,8 +3260,11 @@ ath_tx_tid_pause(struct ath_softc *sc, struct ath_tid *tid)
ATH_TX_LOCK_ASSERT(sc);
tid->paused++;
- DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, "%s: paused = %d\n",
- __func__, tid->paused);
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, "%s: [%6D]: tid=%d, paused = %d\n",
+ __func__,
+ tid->an->an_node.ni_macaddr, ":",
+ tid->tid,
+ tid->paused);
}
/*
@@ -3260,15 +3281,21 @@ ath_tx_tid_resume(struct ath_softc *sc, struct ath_tid *tid)
* until it's actually resolved.
*/
if (tid->paused == 0) {
- DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
- "%s: %6D: paused=0?\n", __func__,
- tid->an->an_node.ni_macaddr, ":");
+ device_printf(sc->sc_dev,
+ "%s: [%6D]: tid=%d, paused=0?\n",
+ __func__,
+ tid->an->an_node.ni_macaddr, ":",
+ tid->tid);
} else {
tid->paused--;
}
- DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, "%s: unpaused = %d\n",
- __func__, tid->paused);
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
+ "%s: [%6D]: tid=%d, unpaused = %d\n",
+ __func__,
+ tid->an->an_node.ni_macaddr, ":",
+ tid->tid,
+ tid->paused);
if (tid->paused)
return;
@@ -3334,8 +3361,8 @@ ath_tx_tid_filt_comp_buf(struct ath_softc *sc, struct ath_tid *tid,
ATH_TX_LOCK_ASSERT(sc);
if (! tid->isfiltered) {
- DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, "%s: filter transition\n",
- __func__);
+ DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, "%s: tid=%d; filter transition\n",
+ __func__, tid->tid);
tid->isfiltered = 1;
ath_tx_tid_pause(sc, tid);
}
@@ -3355,15 +3382,20 @@ static void
ath_tx_tid_filt_comp_complete(struct ath_softc *sc, struct ath_tid *tid)
{
struct ath_buf *bf;
+ int do_resume = 0;
ATH_TX_LOCK_ASSERT(sc);
if (tid->hwq_depth != 0)
return;
- DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, "%s: hwq=0, transition back\n",
- __func__);
- tid->isfiltered = 0;
+ DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, "%s: tid=%d, hwq=0, transition back\n",
+ __func__, tid->tid);
+ if (tid->isfiltered == 1) {
+ tid->isfiltered = 0;
+ do_resume = 1;
+ }
+
/* XXX ath_tx_tid_resume() also calls ath_tx_set_clrdmask()! */
ath_tx_set_clrdmask(sc, tid->an);
@@ -3373,16 +3405,21 @@ ath_tx_tid_filt_comp_complete(struct ath_softc *sc, struct ath_tid *tid)
ATH_TID_INSERT_HEAD(tid, bf, bf_list);
}
- ath_tx_tid_resume(sc, tid);
+ /* And only resume if we had paused before */
+ if (do_resume)
+ ath_tx_tid_resume(sc, tid);
}
/*
* Called when a single (aggregate or otherwise) frame is completed.
*
- * Returns 1 if the buffer could be added to the filtered list
- * (cloned or otherwise), 0 if the buffer couldn't be added to the
+ * Returns 0 if the buffer could be added to the filtered list
+ * (cloned or otherwise), 1 if the buffer couldn't be added to the
* filtered list (failed clone; expired retry) and the caller should
* free it and handle it like a failure (eg by sending a BAR.)
+ *
+ * since the buffer may be cloned, bf must be not touched after this
+ * if the return value is 0.
*/
static int
ath_tx_tid_filt_comp_single(struct ath_softc *sc, struct ath_tid *tid,
@@ -3402,8 +3439,9 @@ ath_tx_tid_filt_comp_single(struct ath_softc *sc, struct ath_tid *tid,
"%s: bf=%p, seqno=%d, exceeded retries\n",
__func__,
bf,
- bf->bf_state.bfs_seqno);
- return (0);
+ SEQNO(bf->bf_state.bfs_seqno));
+ retval = 1; /* error */
+ goto finish;
}
/*
@@ -3423,11 +3461,12 @@ ath_tx_tid_filt_comp_single(struct ath_softc *sc, struct ath_tid *tid,
DPRINTF(sc, ATH_DEBUG_SW_TX_FILT,
"%s: busy buffer couldn't be cloned (%p)!\n",
__func__, bf);
- retval = 1;
+ retval = 1; /* error */
} else {
ath_tx_tid_filt_comp_buf(sc, tid, nbf);
- retval = 0;
+ retval = 0; /* ok */
}
+finish:
ath_tx_tid_filt_comp_complete(sc, tid);
return (retval);
@@ -3452,10 +3491,11 @@ ath_tx_tid_filt_comp_aggr(struct ath_softc *sc, struct ath_tid *tid,
if (bf->bf_state.bfs_retries > SWMAX_RETRIES) {
sc->sc_stats.ast_tx_swretrymax++;
DPRINTF(sc, ATH_DEBUG_SW_TX_FILT,
- "%s: bf=%p, seqno=%d, exceeded retries\n",
+ "%s: tid=%d, bf=%p, seqno=%d, exceeded retries\n",
__func__,
+ tid->tid,
bf,
- bf->bf_state.bfs_seqno);
+ SEQNO(bf->bf_state.bfs_seqno));
TAILQ_INSERT_TAIL(bf_q, bf, bf_list);
goto next;
}
@@ -3463,8 +3503,8 @@ ath_tx_tid_filt_comp_aggr(struct ath_softc *sc, struct ath_tid *tid,
if (bf->bf_flags & ATH_BUF_BUSY) {
nbf = ath_tx_retry_clone(sc, tid->an, tid, bf);
DPRINTF(sc, ATH_DEBUG_SW_TX_FILT,
- "%s: busy buffer cloned: %p -> %p",
- __func__, bf, nbf);
+ "%s: tid=%d, busy buffer cloned: %p -> %p, seqno=%d\n",
+ __func__, tid->tid, bf, nbf, SEQNO(bf->bf_state.bfs_seqno));
} else {
nbf = bf;
}
@@ -3475,8 +3515,8 @@ ath_tx_tid_filt_comp_aggr(struct ath_softc *sc, struct ath_tid *tid,
*/
if (nbf == NULL) {
DPRINTF(sc, ATH_DEBUG_SW_TX_FILT,
- "%s: buffer couldn't be cloned! (%p)\n",
- __func__, bf);
+ "%s: tid=%d, buffer couldn't be cloned! (%p) seqno=%d\n",
+ __func__, tid->tid, bf, SEQNO(bf->bf_state.bfs_seqno));
TAILQ_INSERT_TAIL(bf_q, bf, bf_list);
} else {
ath_tx_tid_filt_comp_buf(sc, tid, nbf);
@@ -3717,7 +3757,7 @@ ath_tx_tid_drain_print(struct ath_softc *sc, struct ath_node *an,
txq = sc->sc_ac2q[tid->ac];
tap = ath_tx_get_tx_tid(an, tid->tid);
- DPRINTF(sc, ATH_DEBUG_SW_TX,
+ DPRINTF(sc, ATH_DEBUG_SW_TX | ATH_DEBUG_RESET,
"%s: %s: %6D: bf=%p: addbaw=%d, dobaw=%d, "
"seqno=%d, retry=%d\n",
__func__,
@@ -3729,7 +3769,7 @@ ath_tx_tid_drain_print(struct ath_softc *sc, struct ath_node *an,
bf->bf_state.bfs_dobaw,
SEQNO(bf->bf_state.bfs_seqno),
bf->bf_state.bfs_retries);
- DPRINTF(sc, ATH_DEBUG_SW_TX,
+ DPRINTF(sc, ATH_DEBUG_SW_TX | ATH_DEBUG_RESET,
"%s: %s: %6D: bf=%p: txq[%d] axq_depth=%d, axq_aggr_depth=%d\n",
__func__,
pfx,
@@ -3739,7 +3779,7 @@ ath_tx_tid_drain_print(struct ath_softc *sc, struct ath_node *an,
txq->axq_qnum,
txq->axq_depth,
txq->axq_aggr_depth);
- DPRINTF(sc, ATH_DEBUG_SW_TX,
+ DPRINTF(sc, ATH_DEBUG_SW_TX | ATH_DEBUG_RESET,
"%s: %s: %6D: bf=%p: tid txq_depth=%d hwq_depth=%d, bar_wait=%d, "
"isfiltered=%d\n",
__func__,
@@ -3751,7 +3791,7 @@ ath_tx_tid_drain_print(struct ath_softc *sc, struct ath_node *an,
tid->hwq_depth,
tid->bar_wait,
tid->isfiltered);
- DPRINTF(sc, ATH_DEBUG_SW_TX,
+ DPRINTF(sc, ATH_DEBUG_SW_TX | ATH_DEBUG_RESET,
"%s: %s: %6D: tid %d: "
"sched=%d, paused=%d, "
"incomp=%d, baw_head=%d, "
@@ -3811,7 +3851,7 @@ ath_tx_tid_drain(struct ath_softc *sc, struct ath_node *an,
if (t == 0) {
ath_tx_tid_drain_print(sc, an, "norm", tid, bf);
- t = 1;
+// t = 1;
}
ATH_TID_REMOVE(tid, bf, bf_list);
@@ -3827,7 +3867,7 @@ ath_tx_tid_drain(struct ath_softc *sc, struct ath_node *an,
if (t == 0) {
ath_tx_tid_drain_print(sc, an, "filt", tid, bf);
- t = 1;
+// t = 1;
}
ATH_TID_FILT_REMOVE(tid, bf, bf_list);
@@ -4084,6 +4124,19 @@ ath_tx_normal_comp(struct ath_softc *sc, struct ath_buf *bf, int fail)
DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: hwq_depth < 0: %d\n",
__func__, atid->hwq_depth);
+ /* If the TID is being cleaned up, track things */
+ /* XXX refactor! */
+ if (atid->cleanup_inprogress) {
+ atid->incomp--;
+ if (atid->incomp == 0) {
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
+ "%s: TID %d: cleaned up! resume!\n",
+ __func__, tid);
+ atid->cleanup_inprogress = 0;
+ ath_tx_tid_resume(sc, atid);
+ }
+ }
+
/*
* If the queue is filtered, potentially mark it as complete
* and reschedule it as needed.
@@ -4131,6 +4184,16 @@ ath_tx_comp_cleanup_unaggr(struct ath_softc *sc, struct ath_buf *bf)
ATH_TX_LOCK(sc);
atid->incomp--;
+
+ /* XXX refactor! */
+ if (bf->bf_state.bfs_dobaw) {
+ ath_tx_update_baw(sc, an, atid, bf);
+ if (!bf->bf_state.bfs_addedbaw)
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
+ "%s: wasn't added: seqno %d\n",
+ __func__, SEQNO(bf->bf_state.bfs_seqno));
+ }
+
if (atid->incomp == 0) {
DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
"%s: TID %d: cleaned up! resume!\n",
@@ -4143,14 +4206,72 @@ ath_tx_comp_cleanup_unaggr(struct ath_softc *sc, struct ath_buf *bf)
ath_tx_default_comp(sc, bf, 0);
}
+
+/*
+ * This as it currently stands is a bit dumb. Ideally we'd just
+ * fail the frame the normal way and have it permanently fail
+ * via the normal aggregate completion path.
+ */
+static void
+ath_tx_tid_cleanup_frame(struct ath_softc *sc, struct ath_node *an,
+ int tid, struct ath_buf *bf_head, ath_bufhead *bf_cq)
+{
+ struct ath_tid *atid = &an->an_tid[tid];
+ struct ath_buf *bf, *bf_next;
+
+ ATH_TX_LOCK_ASSERT(sc);
+
+ /*
+ * Remove this frame from the queue.
+ */
+ ATH_TID_REMOVE(atid, bf_head, bf_list);
+
+ /*
+ * Loop over all the frames in the aggregate.
+ */
+ bf = bf_head;
+ while (bf != NULL) {
+ bf_next = bf->bf_next; /* next aggregate frame, or NULL */
+
+ /*
+ * If it's been added to the BAW we need to kick
+ * it out of the BAW before we continue.
+ *
+ * XXX if it's an aggregate, assert that it's in the
+ * BAW - we shouldn't have it be in an aggregate
+ * otherwise!
+ */
+ if (bf->bf_state.bfs_addedbaw) {
+ ath_tx_update_baw(sc, an, atid, bf);
+ bf->bf_state.bfs_dobaw = 0;
+ }
+
+ /*
+ * Give it the default completion handler.
+ */
+ bf->bf_comp = ath_tx_normal_comp;
+ bf->bf_next = NULL;
+
+ /*
+ * Add it to the list to free.
+ */
+ TAILQ_INSERT_TAIL(bf_cq, bf, bf_list);
+
+ /*
+ * Now advance to the next frame in the aggregate.
+ */
+ bf = bf_next;
+ }
+}
+
/*
* Performs transmit side cleanup when TID changes from aggregated to
- * unaggregated.
+ * unaggregated and during reassociation.
*
- * - Discard all retry frames from the s/w queue.
- * - Fix the tx completion function for all buffers in s/w queue.
- * - Count the number of unacked frames, and let transmit completion
- * handle it later.
+ * For now, this just tosses everything from the TID software queue
+ * whether or not it has been retried and marks the TID as
+ * pending completion if there's anything for this TID queued to
+ * the hardware.
*
* The caller is responsible for pausing the TID and unpausing the
* TID if no cleanup was required. Otherwise the cleanup path will
@@ -4161,18 +4282,19 @@ ath_tx_tid_cleanup(struct ath_softc *sc, struct ath_node *an, int tid,
ath_bufhead *bf_cq)
{
struct ath_tid *atid = &an->an_tid[tid];
- struct ieee80211_tx_ampdu *tap;
struct ath_buf *bf, *bf_next;
ATH_TX_LOCK_ASSERT(sc);
DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
- "%s: TID %d: called\n", __func__, tid);
+ "%s: TID %d: called; inprogress=%d\n", __func__, tid,
+ atid->cleanup_inprogress);
/*
* Move the filtered frames to the TX queue, before
* we run off and discard/process things.
*/
+
/* XXX this is really quite inefficient */
while ((bf = ATH_TID_FILT_LAST(atid, ath_bufhead_s)) != NULL) {
ATH_TID_FILT_REMOVE(atid, bf, bf_list);
@@ -4187,47 +4309,35 @@ ath_tx_tid_cleanup(struct ath_softc *sc, struct ath_node *an, int tid,
*/
bf = ATH_TID_FIRST(atid);
while (bf) {
- if (bf->bf_state.bfs_isretried) {
- bf_next = TAILQ_NEXT(bf, bf_list);
- ATH_TID_REMOVE(atid, bf, bf_list);
- if (bf->bf_state.bfs_dobaw) {
- ath_tx_update_baw(sc, an, atid, bf);
- if (!bf->bf_state.bfs_addedbaw)
- DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
- "%s: wasn't added: seqno %d\n",
- __func__,
- SEQNO(bf->bf_state.bfs_seqno));
- }
- bf->bf_state.bfs_dobaw = 0;
- /*
- * Call the default completion handler with "fail" just
- * so upper levels are suitably notified about this.
- */
- TAILQ_INSERT_TAIL(bf_cq, bf, bf_list);
- bf = bf_next;
- continue;
- }
- /* Give these the default completion handler */
- bf->bf_comp = ath_tx_normal_comp;
- bf = TAILQ_NEXT(bf, bf_list);
+ /*
+ * Grab the next frame in the list, we may
+ * be fiddling with the list.
+ */
+ bf_next = TAILQ_NEXT(bf, bf_list);
+
+ /*
+ * Free the frame and all subframes.
+ */
+ ath_tx_tid_cleanup_frame(sc, an, tid, bf, bf_cq);
+
+ /*
+ * Next frame!
+ */
+ bf = bf_next;
}
/*
- * Calculate what hardware-queued frames exist based
- * on the current BAW size. Ie, what frames have been
- * added to the TX hardware queue for this TID but
- * not yet ACKed.
+ * If there's anything in the hardware queue we wait
+ * for the TID HWQ to empty.
*/
- tap = ath_tx_get_tx_tid(an, tid);
- /* Need the lock - fiddling with BAW */
- while (atid->baw_head != atid->baw_tail) {
- if (atid->tx_buf[atid->baw_head]) {
- atid->incomp++;
- atid->cleanup_inprogress = 1;
- atid->tx_buf[atid->baw_head] = NULL;
- }
- INCR(atid->baw_head, ATH_TID_MAX_BUFS);
- INCR(tap->txa_start, IEEE80211_SEQ_RANGE);
+ if (atid->hwq_depth > 0) {
+ /*
+ * XXX how about we kill atid->incomp, and instead
+ * replace it with a macro that checks that atid->hwq_depth
+ * is 0?
+ */
+ atid->incomp = atid->hwq_depth;
+ atid->cleanup_inprogress = 1;
}
if (atid->cleanup_inprogress)
@@ -4560,9 +4670,19 @@ ath_tx_comp_cleanup_aggr(struct ath_softc *sc, struct ath_buf *bf_first)
ATH_TX_LOCK(sc);
/* update incomp */
+ atid->incomp--;
+
+ /* Update the BAW */
bf = bf_first;
while (bf) {
- atid->incomp--;
+ /* XXX refactor! */
+ if (bf->bf_state.bfs_dobaw) {
+ ath_tx_update_baw(sc, an, atid, bf);
+ if (!bf->bf_state.bfs_addedbaw)
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
+ "%s: wasn't added: seqno %d\n",
+ __func__, SEQNO(bf->bf_state.bfs_seqno));
+ }
bf = bf->bf_next;
}
@@ -4585,10 +4705,11 @@ ath_tx_comp_cleanup_aggr(struct ath_softc *sc, struct ath_buf *bf_first)
ATH_TX_UNLOCK(sc);
- /* Handle frame completion */
+ /* Handle frame completion as individual frames */
bf = bf_first;
while (bf) {
bf_next = bf->bf_next;
+ bf->bf_next = NULL;
ath_tx_default_comp(sc, bf, 1);
bf = bf_next;
}
@@ -5030,6 +5151,10 @@ ath_tx_aggr_comp_unaggr(struct ath_softc *sc, struct ath_buf *bf, int fail)
"%s: isfiltered=1, fail=%d\n",
__func__, fail);
freeframe = ath_tx_tid_filt_comp_single(sc, atid, bf);
+ /*
+ * If freeframe=0 then bf is no longer ours; don't
+ * touch it.
+ */
if (freeframe) {
/* Remove from BAW */
if (bf->bf_state.bfs_addedbaw)
@@ -5065,7 +5190,6 @@ ath_tx_aggr_comp_unaggr(struct ath_softc *sc, struct ath_buf *bf, int fail)
if (freeframe)
ath_tx_default_comp(sc, bf, fail);
-
return;
}
/*
@@ -5495,7 +5619,7 @@ ath_txq_sched(struct ath_softc *sc, struct ath_txq *txq)
* a frame; be careful.
*/
if (! ath_tx_tid_can_tx_or_sched(sc, tid)) {
- continue;
+ goto loop_done;
}
if (ath_tx_ampdu_running(sc, tid->an, tid->tid))
ath_tx_tid_hw_queue_aggr(sc, tid->an, tid);
@@ -5518,7 +5642,7 @@ ath_txq_sched(struct ath_softc *sc, struct ath_txq *txq)
if (txq->axq_depth >= sc->sc_hwq_limit_nonaggr) {
break;
}
-
+loop_done:
/*
* If this was the last entry on the original list, stop.
* Otherwise nodes that have been rescheduled onto the end
@@ -5771,12 +5895,26 @@ ath_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
*/
TAILQ_INIT(&bf_cq);
ATH_TX_LOCK(sc);
- ath_tx_tid_cleanup(sc, an, tid, &bf_cq);
+
/*
- * Unpause the TID if no cleanup is required.
+ * In case there's a followup call to this, only call it
+ * if we don't have a cleanup in progress.
+ *
+ * Since we've paused the queue above, we need to make
+ * sure we unpause if there's already a cleanup in
+ * progress - it means something else is also doing
+ * this stuff, so we don't need to also keep it paused.
*/
- if (! atid->cleanup_inprogress)
+ if (atid->cleanup_inprogress) {
ath_tx_tid_resume(sc, atid);
+ } else {
+ ath_tx_tid_cleanup(sc, an, tid, &bf_cq);
+ /*
+ * Unpause the TID if no cleanup is required.
+ */
+ if (! atid->cleanup_inprogress)
+ ath_tx_tid_resume(sc, atid);
+ }
ATH_TX_UNLOCK(sc);
/* Handle completing frames and fail them */
@@ -5810,19 +5948,25 @@ ath_tx_node_reassoc(struct ath_softc *sc, struct ath_node *an)
tid = &an->an_tid[i];
if (tid->hwq_depth == 0)
continue;
- ath_tx_tid_pause(sc, tid);
DPRINTF(sc, ATH_DEBUG_NODE,
"%s: %6D: TID %d: cleaning up TID\n",
__func__,
an->an_node.ni_macaddr,
":",
i);
- ath_tx_tid_cleanup(sc, an, i, &bf_cq);
/*
- * Unpause the TID if no cleanup is required.
+ * In case there's a followup call to this, only call it
+ * if we don't have a cleanup in progress.
*/
- if (! tid->cleanup_inprogress)
- ath_tx_tid_resume(sc, tid);
+ if (! tid->cleanup_inprogress) {
+ ath_tx_tid_pause(sc, tid);
+ ath_tx_tid_cleanup(sc, an, i, &bf_cq);
+ /*
+ * Unpause the TID if no cleanup is required.
+ */
+ if (! tid->cleanup_inprogress)
+ ath_tx_tid_resume(sc, tid);
+ }
}
ATH_TX_UNLOCK(sc);
@@ -5852,19 +5996,43 @@ ath_bar_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,
struct ath_node *an = ATH_NODE(ni);
struct ath_tid *atid = &an->an_tid[tid];
int attempts = tap->txa_attempts;
+ int old_txa_start;
DPRINTF(sc, ATH_DEBUG_SW_TX_BAR,
- "%s: %6D: called; txa_tid=%d, atid->tid=%d, status=%d, attempts=%d\n",
+ "%s: %6D: called; txa_tid=%d, atid->tid=%d, status=%d, attempts=%d, txa_start=%d, txa_seqpending=%d\n",
__func__,
ni->ni_macaddr,
":",
tap->txa_tid,
atid->tid,
status,
- attempts);
+ attempts,
+ tap->txa_start,
+ tap->txa_seqpending);
/* Note: This may update the BAW details */
+ /*
+ * XXX What if this does slide the BAW along? We need to somehow
+ * XXX either fix things when it does happen, or prevent the
+ * XXX seqpending value to be anything other than exactly what
+ * XXX the hell we want!
+ *
+ * XXX So for now, how I do this inside the TX lock for now
+ * XXX and just correct it afterwards? The below condition should
+ * XXX never happen and if it does I need to fix all kinds of things.
+ */
+ ATH_TX_LOCK(sc);
+ old_txa_start = tap->txa_start;
sc->sc_bar_response(ni, tap, status);
+ if (tap->txa_start != old_txa_start) {
+ device_printf(sc->sc_dev, "%s: tid=%d; txa_start=%d, old=%d, adjusting\n",
+ __func__,
+ tid,
+ tap->txa_start,
+ old_txa_start);
+ }
+ tap->txa_start = old_txa_start;
+ ATH_TX_UNLOCK(sc);
/* Unpause the TID */
/*
diff --git a/sys/dev/ath/if_ath_tx_edma.c b/sys/dev/ath/if_ath_tx_edma.c
index 5498dd5..7d14920 100644
--- a/sys/dev/ath/if_ath_tx_edma.c
+++ b/sys/dev/ath/if_ath_tx_edma.c
@@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
@@ -865,12 +866,14 @@ ath_xmit_setup_edma(struct ath_softc *sc)
(void) ath_hal_gettxstatuslen(sc->sc_ah, &sc->sc_tx_statuslen);
(void) ath_hal_getntxmaps(sc->sc_ah, &sc->sc_tx_nmaps);
- device_printf(sc->sc_dev, "TX descriptor length: %d\n",
- sc->sc_tx_desclen);
- device_printf(sc->sc_dev, "TX status length: %d\n",
- sc->sc_tx_statuslen);
- device_printf(sc->sc_dev, "TX buffers per descriptor: %d\n",
- sc->sc_tx_nmaps);
+ if (bootverbose) {
+ device_printf(sc->sc_dev, "TX descriptor length: %d\n",
+ sc->sc_tx_desclen);
+ device_printf(sc->sc_dev, "TX status length: %d\n",
+ sc->sc_tx_statuslen);
+ device_printf(sc->sc_dev, "TX buffers per descriptor: %d\n",
+ sc->sc_tx_nmaps);
+ }
sc->sc_tx.xmit_setup = ath_edma_dma_txsetup;
sc->sc_tx.xmit_teardown = ath_edma_dma_txteardown;
diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h
index 6b074d6..e888ca2 100644
--- a/sys/dev/ath/if_athvar.h
+++ b/sys/dev/ath/if_athvar.h
@@ -82,6 +82,25 @@
#define ATH_BEACON_CWMAX_DEFAULT 0 /* default cwmax for ap beacon q */
/*
+ * The following bits can be set during the PCI (and perhaps non-PCI
+ * later) device probe path.
+ *
+ * It controls some of the driver and HAL behaviour.
+ */
+
+#define ATH_PCI_CUS198 0x0001
+#define ATH_PCI_CUS230 0x0002
+#define ATH_PCI_CUS217 0x0004
+#define ATH_PCI_CUS252 0x0008
+#define ATH_PCI_WOW 0x0010
+#define ATH_PCI_BT_ANT_DIV 0x0020
+#define ATH_PCI_D3_L1_WAR 0x0040
+#define ATH_PCI_AR9565_1ANT 0x0080
+#define ATH_PCI_AR9565_2ANT 0x0100
+#define ATH_PCI_NO_PLL_PWRSAVE 0x0200
+#define ATH_PCI_KILLER 0x0400
+
+/*
* The key cache is used for h/w cipher state and also for
* tracking station state such as the current tx antenna.
* We also setup a mapping table between key cache slot indices
@@ -510,6 +529,7 @@ struct ath_rx_edma {
int m_fifo_tail;
int m_fifo_depth;
struct mbuf *m_rxpending;
+ struct ath_buf *m_holdbf;
};
struct ath_tx_edma_fifo {
@@ -565,6 +585,8 @@ struct ath_softc {
int sc_tx_statuslen;
int sc_tx_nmaps; /* Number of TX maps */
int sc_edma_bufsize;
+ int sc_rx_stopped; /* XXX only for EDMA */
+ int sc_rx_resetted; /* XXX only for EDMA */
void (*sc_node_cleanup)(struct ieee80211_node *);
void (*sc_node_free)(struct ieee80211_node *);
@@ -621,7 +643,8 @@ struct ath_softc {
sc_resetcal : 1,/* reset cal state next trip */
sc_rxslink : 1,/* do self-linked final descriptor */
sc_rxtsf32 : 1,/* RX dec TSF is 32 bits */
- sc_isedma : 1;/* supports EDMA */
+ sc_isedma : 1,/* supports EDMA */
+ sc_do_mybeacon : 1; /* supports mybeacon */
/*
* Second set of flags.
@@ -864,6 +887,25 @@ struct ath_softc {
void (*sc_bar_response)(struct ieee80211_node *ni,
struct ieee80211_tx_ampdu *tap,
int status);
+
+ /*
+ * Powersave state tracking.
+ *
+ * target/cur powerstate is the chip power state.
+ * target selfgen state is the self-generated frames
+ * state. The chip can be awake but transmitted frames
+ * can have the PWRMGT bit set to 1 so the destination
+ * thinks the node is asleep.
+ */
+ HAL_POWER_MODE sc_target_powerstate;
+ HAL_POWER_MODE sc_target_selfgen_state;
+
+ HAL_POWER_MODE sc_cur_powerstate;
+
+ int sc_powersave_refcnt;
+
+ /* ATH_PCI_* flags */
+ uint32_t sc_pci_devinfo;
};
#define ATH_LOCK_INIT(_sc) \
@@ -1038,6 +1080,8 @@ void ath_intr(void *);
((*(_ah)->ah_updateTxTrigLevel)((_ah), (_inc)))
#define ath_hal_setpower(_ah, _mode) \
((*(_ah)->ah_setPowerMode)((_ah), (_mode), AH_TRUE))
+#define ath_hal_setselfgenpower(_ah, _mode) \
+ ((*(_ah)->ah_setPowerMode)((_ah), (_mode), AH_FALSE))
#define ath_hal_keycachesize(_ah) \
((*(_ah)->ah_getKeyCacheSize)((_ah)))
#define ath_hal_keyreset(_ah, _ix) \
@@ -1266,6 +1310,8 @@ void ath_intr(void *);
#define ath_hal_setintmit(_ah, _v) \
ath_hal_setcapability(_ah, HAL_CAP_INTMIT, \
HAL_CAP_INTMIT_ENABLE, _v, NULL)
+#define ath_hal_hasmybeacon(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_DO_MYBEACON, 1, NULL) == HAL_OK)
#define ath_hal_hasenforcetxop(_ah) \
(ath_hal_getcapability(_ah, HAL_CAP_ENFORCE_TXOP, 0, NULL) == HAL_OK)
OpenPOWER on IntegriCloud