2009-06-10 16:25:37

by Senthil Balasubramanian

[permalink] [raw]
Subject: [PATCH 0/7] ATH9K bug fixes - TX hang & Signal Quality issue

This seris fixes couple of important issues

1) Signal Quality issue (patch 1/7)
2) INI update - fixes performance issue (Patch 2/7)
3) TX hang issue (happens after an hour time, Patch 6/7 & 7/7)

Thanks
Senthil



2009-06-10 16:26:20

by Senthil Balasubramanian

[permalink] [raw]
Subject: [PATCH 7/7] ath9k: schedule aggregation regardless of queue depth

schedule aggregation regardless of queue depth. Also we shouldn't
remove holding descriptor from AC queue if it happens to be the
only descriptor.

Signed-off-by: Senthil Balasubramanian <[email protected]>
---
drivers/net/wireless/ath/ath9k/xmit.c | 15 +--------------
1 files changed, 1 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 328391e..eda2458 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1113,8 +1113,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
if (tid->paused)
continue;

- if ((txq->axq_depth % 2) == 0)
- ath_tx_sched_aggr(sc, txq, tid);
+ ath_tx_sched_aggr(sc, txq, tid);

/*
* add tid to round-robin queue if more frames
@@ -1957,19 +1956,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
if (bf->bf_stale) {
bf_held = bf;
if (list_is_last(&bf_held->list, &txq->axq_q)) {
- txq->axq_link = NULL;
- txq->axq_linkbuf = NULL;
spin_unlock_bh(&txq->axq_lock);
-
- /*
- * The holding descriptor is the last
- * descriptor in queue. It's safe to remove
- * the last holding descriptor in BH context.
- */
- spin_lock_bh(&sc->tx.txbuflock);
- list_move_tail(&bf_held->list, &sc->tx.txbuf);
- spin_unlock_bh(&sc->tx.txbuflock);
-
break;
} else {
bf = list_entry(bf_held->list.next,
--
1.6.0.4


2009-06-10 16:25:43

by Senthil Balasubramanian

[permalink] [raw]
Subject: [PATCH 1/7] ath9k: Manipulate and report the correct RSSI

RSSI reported by the RX descriptor requires little manipulation.
Manipulate and report the correct RSSI to the stack. This will
fix the improper signal levels reported by iwconfig iw dev wlanX
station dump.

Also use the default noise floor for now as the one reported
during the caliberation seems to be wrong.

Signed-off-by: Senthil Balasubramanian <[email protected]>
Signed-off-by: Vasanthakumar Thiagarajan <[email protected]>
---
drivers/net/wireless/ath/ath9k/ath9k.h | 15 +++++++++++++++
drivers/net/wireless/ath/ath9k/calib.c | 13 ++++++++++---
drivers/net/wireless/ath/ath9k/calib.h | 4 +++-
drivers/net/wireless/ath/ath9k/main.c | 1 +
drivers/net/wireless/ath/ath9k/recv.c | 20 +++++++++++++++++++-
5 files changed, 48 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 9cd523f..2a3c66f 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -297,12 +297,27 @@ struct ath_tx_control {
#define ATH_TX_XRETRY 0x02
#define ATH_TX_BAR 0x04

+#define ATH_RSSI_LPF_LEN 10
+#define RSSI_LPF_THRESHOLD -20
+#define ATH_RSSI_EP_MULTIPLIER (1<<7)
+#define ATH_EP_MUL(x, mul) ((x) * (mul))
+#define ATH_RSSI_IN(x) (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER))
+#define ATH_LPF_RSSI(x, y, len) \
+ ((x != ATH_RSSI_DUMMY_MARKER) ? (((x) * ((len) - 1) + (y)) / (len)) : (y))
+#define ATH_RSSI_LPF(x, y) do { \
+ if ((y) >= RSSI_LPF_THRESHOLD) \
+ x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \
+} while (0)
+#define ATH_EP_RND(x, mul) \
+ ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
+
struct ath_node {
struct ath_softc *an_sc;
struct ath_atx_tid tid[WME_NUM_TID];
struct ath_atx_ac ac[WME_NUM_AC];
u16 maxampdu;
u8 mpdudensity;
+ int last_rssi;
};

struct ath_tx {
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index a32d7e7..1f0c5fe 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -691,15 +691,22 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
{
int i, j;
+ s16 noise_floor;
+
+ if (AR_SREV_9280(ah))
+ noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE;
+ else if (AR_SREV_9285(ah))
+ noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE;
+ else
+ noise_floor = AR_PHY_CCA_MAX_AR5416_GOOD_VALUE;

for (i = 0; i < NUM_NF_READINGS; i++) {
ah->nfCalHist[i].currIndex = 0;
- ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE;
+ ah->nfCalHist[i].privNF = noise_floor;
ah->nfCalHist[i].invalidNFcount =
AR_PHY_CCA_FILTERWINDOW_LENGTH;
for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
- ah->nfCalHist[i].nfCalBuffer[j] =
- AR_PHY_CCA_MAX_GOOD_VALUE;
+ ah->nfCalHist[i].nfCalBuffer[j] = noise_floor;
}
}
}
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index fe5367f..547e697 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -25,7 +25,9 @@ extern const struct ath9k_percal_data adc_dc_cal_multi_sample;
extern const struct ath9k_percal_data adc_dc_cal_single_sample;
extern const struct ath9k_percal_data adc_init_dc_cal;

-#define AR_PHY_CCA_MAX_GOOD_VALUE -85
+#define AR_PHY_CCA_MAX_AR5416_GOOD_VALUE -85
+#define AR_PHY_CCA_MAX_AR9280_GOOD_VALUE -112
+#define AR_PHY_CCA_MAX_AR9285_GOOD_VALUE -118
#define AR_PHY_CCA_MAX_HIGH_VALUE -62
#define AR_PHY_CCA_MIN_BAD_VALUE -140
#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index f7baa40..0fd3f25 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -447,6 +447,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
sta->ht_cap.ampdu_factor);
an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
+ an->last_rssi = ATH_RSSI_DUMMY_MARKER;
}
}

diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 5014a19..0f62795 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -145,6 +145,9 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
u8 ratecode;
__le16 fc;
struct ieee80211_hw *hw;
+ struct ieee80211_sta *sta;
+ struct ath_node *an;
+

hdr = (struct ieee80211_hdr *)skb->data;
fc = hdr->frame_control;
@@ -229,11 +232,26 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
}
}

+ rcu_read_lock();
+ sta = ieee80211_find_sta(sc->hw, hdr->addr2);
+ if (sta) {
+ an = (struct ath_node *) sta->drv_priv;
+ ATH_RSSI_LPF(an->last_rssi, ds->ds_rxstat.rs_rssi);
+ if (likely(an->last_rssi != ATH_RSSI_DUMMY_MARKER))
+ ds->ds_rxstat.rs_rssi = ATH_EP_RND(an->last_rssi,
+ ATH_RSSI_EP_MULTIPLIER);
+ if (ds->ds_rxstat.rs_rssi < 0)
+ ds->ds_rxstat.rs_rssi = 0;
+ else if (ds->ds_rxstat.rs_rssi > 127)
+ ds->ds_rxstat.rs_rssi = 127;
+ }
+ rcu_read_unlock();
+
rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
rx_status->band = hw->conf.channel->band;
rx_status->freq = hw->conf.channel->center_freq;
rx_status->noise = sc->ani.noise_floor;
- rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi;
+ rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + ds->ds_rxstat.rs_rssi;
rx_status->antenna = ds->ds_rxstat.rs_antenna;

/* at 45 you will be able to use MCS 15 reliably. A more elaborate
--
1.6.0.4


2009-06-10 16:25:49

by Senthil Balasubramanian

[permalink] [raw]
Subject: [PATCH 2/7] ath9k: AR9285 & AR9280 INI update and minor bug fixes.

INI Update for AR9285 & AR9280 chipsets.

Also set the margin and db values of chain1(block1) to chain0(block0)

Signed-off-by: Senthil Balasubramanian <[email protected]>
---
drivers/net/wireless/ath/ath9k/eeprom.c | 20 +++++++++++-
drivers/net/wireless/ath/ath9k/initvals.h | 47 +++++++++++++++-------------
2 files changed, 44 insertions(+), 23 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index a2fda70..5035420 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -1208,6 +1208,19 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
pModal->xatten2Margin[0]);
REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]);
+
+ /* Set the block 1 value to block 0 value */
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+ AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
+ pModal->bswMargin[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+ AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+ AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
+ pModal->xatten2Margin[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+ AR_PHY_GAIN_2GHZ_XATTEN2_DB,
+ pModal->xatten2Db[0]);
}

REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
@@ -1215,6 +1228,11 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);

+ REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000,
+ AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
+ REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000,
+ AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
+
if (AR_SREV_9285_11(ah))
REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
}
@@ -1239,7 +1257,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0);

/* Initialize Ant Diversity settings from EEPROM */
- if (pModal->version == 3) {
+ if (pModal->version >= 3) {
ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf);
ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf);
regVal = REG_READ(ah, 0x99ac);
diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h
index e2f0a34..f67a2a9 100644
--- a/drivers/net/wireless/ath/ath9k/initvals.h
+++ b/drivers/net/wireless/ath/ath9k/initvals.h
@@ -2782,7 +2782,7 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00008338, 0x00ff0000 },
{ 0x0000833c, 0x00000000 },
{ 0x00008340, 0x000107ff },
- { 0x00008344, 0x00581043 },
+ { 0x00008344, 0x00481043 },
{ 0x00009808, 0x00000000 },
{ 0x0000980c, 0xafa68e30 },
{ 0x00009810, 0xfd14e000 },
@@ -3439,7 +3439,7 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
{0x00004044, 0x00000000 },
};

-/* AR9285 */
+/* AR9285 Revsion 10*/
static const u_int32_t ar9285Modes_9285[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -3955,7 +3955,7 @@ static const u_int32_t ar9285Common_9285[][2] = {
{ 0x00008338, 0x00000000 },
{ 0x0000833c, 0x00000000 },
{ 0x00008340, 0x00010380 },
- { 0x00008344, 0x00581043 },
+ { 0x00008344, 0x00481043 },
{ 0x00009808, 0x00000000 },
{ 0x0000980c, 0xafe68e30 },
{ 0x00009810, 0xfd14e000 },
@@ -4121,8 +4121,9 @@ static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = {
{0x00004044, 0x00000000 },
};

-/* AR9285 v1_2 PCI Register Writes. Created: 03/04/09 */
+/* AR9285 v1_2 PCI Register Writes. Created: 04/13/09 */
static const u_int32_t ar9285Modes_9285_1_2[][6] = {
+ /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
{ 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
@@ -4139,6 +4140,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
{ 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e },
{ 0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0 },
{ 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
+ { 0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
{ 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
{ 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
{ 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e },
@@ -4419,6 +4421,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
{ 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
{ 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 },
{ 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
+ { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
{ 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
{ 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
{ 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 },
@@ -4618,7 +4621,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
{ 0x00008338, 0x00ff0000 },
{ 0x0000833c, 0x00000000 },
{ 0x00008340, 0x00010380 },
- { 0x00008344, 0x00581043 },
+ { 0x00008344, 0x00481043 },
{ 0x00009808, 0x00000000 },
{ 0x0000980c, 0xafe68e30 },
{ 0x00009810, 0xfd14e000 },
@@ -4752,18 +4755,18 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
/* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
{ 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a304, 0x00000000, 0x00000000, 0x00005200, 0x00005200, 0x00000000 },
- { 0x0000a308, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 },
+ { 0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000 },
+ { 0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000 },
{ 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 },
{ 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 },
- { 0x0000a314, 0x00000000, 0x00000000, 0x0000f440, 0x0000f440, 0x00000000 },
- { 0x0000a318, 0x00000000, 0x00000000, 0x00014640, 0x00014640, 0x00000000 },
- { 0x0000a31c, 0x00000000, 0x00000000, 0x00018680, 0x00018680, 0x00000000 },
- { 0x0000a320, 0x00000000, 0x00000000, 0x00019841, 0x00019841, 0x00000000 },
- { 0x0000a324, 0x00000000, 0x00000000, 0x0001ca40, 0x0001ca40, 0x00000000 },
- { 0x0000a328, 0x00000000, 0x00000000, 0x0001fa80, 0x0001fa80, 0x00000000 },
- { 0x0000a32c, 0x00000000, 0x00000000, 0x00023ac0, 0x00023ac0, 0x00000000 },
- { 0x0000a330, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 },
+ { 0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000 },
+ { 0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000 },
+ { 0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000 },
+ { 0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000 },
+ { 0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000 },
+ { 0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000 },
+ { 0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 },
+ { 0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000 },
{ 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 },
{ 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
{ 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
@@ -4776,13 +4779,13 @@ static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
{ 0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803 },
{ 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe },
{ 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 },
- { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a21a652, 0x0a21a652, 0x0a22a652 },
- { 0x0000a278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
- { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce },
- { 0x0000a394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
- { 0x0000a398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce },
- { 0x0000a3dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
- { 0x0000a3e0, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce },
+ { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652 },
+ { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+ { 0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7 },
+ { 0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+ { 0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
+ { 0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+ { 0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
};

static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = {
--
1.6.0.4


2009-06-10 16:25:55

by Senthil Balasubramanian

[permalink] [raw]
Subject: [PATCH 3/7] ath9k: remove unnecessary STATION mode check.

Remove unncessary STATION mode check in ath9k_bss_assoc_info() as
it is called only for STATION mode.

Signed-off-by: Senthil Balasubramanian <[email protected]>
---
drivers/net/wireless/ath/ath9k/main.c | 21 +++++++++------------
1 files changed, 9 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 0fd3f25..84fa69d 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -905,24 +905,21 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf)
{
- struct ath_vif *avp = (void *)vif->drv_priv;

if (bss_conf->assoc) {
DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n",
bss_conf->aid, sc->curbssid);

/* New association, store aid */
- if (avp->av_opmode == NL80211_IFTYPE_STATION) {
- sc->curaid = bss_conf->aid;
- ath9k_hw_write_associd(sc);
+ sc->curaid = bss_conf->aid;
+ ath9k_hw_write_associd(sc);

- /*
- * Request a re-configuration of Beacon related timers
- * on the receipt of the first Beacon frame (i.e.,
- * after time sync with the AP).
- */
- sc->sc_flags |= SC_OP_BEACON_SYNC;
- }
+ /*
+ * Request a re-configuration of Beacon related timers
+ * on the receipt of the first Beacon frame (i.e.,
+ * after time sync with the AP).
+ */
+ sc->sc_flags |= SC_OP_BEACON_SYNC;

/* Configure the beacon */
ath_beacon_config(sc, vif);
--
1.6.0.4


2009-06-10 16:26:14

by Senthil Balasubramanian

[permalink] [raw]
Subject: [PATCH 6/7] ath9k: Fix TX hang issue with Atheros chipsets

The hardware doesn't generate interrupts in some cases and so work
around that by monitoring the TX status periodically and reset the
chip of required. The STA seems to be pretty stable with this fix.

Signed-off-by: Senthil Balasubramanian <[email protected]>
Signed-off-by: Vasanthakumar Thiagarajan <[email protected]>
---
drivers/net/wireless/ath/ath9k/ath9k.h | 4 +++
drivers/net/wireless/ath/ath9k/main.c | 2 +
drivers/net/wireless/ath/ath9k/xmit.c | 41 ++++++++++++++++++++++++++++++++
3 files changed, 47 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 71d71c0..3939396 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -231,6 +231,8 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA)
#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)])

+#define ATH_TX_COMPLETE_POLL_INT 1000
+
enum ATH_AGGR_STATUS {
ATH_AGGR_DONE,
ATH_AGGR_BAW_CLOSED,
@@ -246,6 +248,7 @@ struct ath_txq {
u8 axq_aggr_depth;
u32 axq_totalqueued;
bool stopped;
+ bool axq_tx_inprogress;
struct ath_buf *axq_linkbuf;

/* first desc of the last descriptor that contains CTS */
@@ -619,6 +622,7 @@ struct ath_softc {
#endif
struct ath_bus_ops *bus_ops;
struct ath_beacon_config cur_beacon_conf;
+ struct delayed_work tx_complete_work;
};

struct ath_wiphy {
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 5ee9800..2ebd0ed 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1291,6 +1291,7 @@ void ath_detach(struct ath_softc *sc)
ath_deinit_leds(sc);
cancel_work_sync(&sc->chan_work);
cancel_delayed_work_sync(&sc->wiphy_work);
+ cancel_delayed_work_sync(&sc->tx_complete_work);

for (i = 0; i < sc->num_sec_wiphy; i++) {
struct ath_wiphy *aphy = sc->sec_wiphy[i];
@@ -2025,6 +2026,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
r = ath_start_rfkill_poll(sc);
#endif
+ queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work, 0);

mutex_unlock:
mutex_unlock(&sc->mutex);
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index a8def4f..328391e 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -864,6 +864,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
txq->axq_aggr_depth = 0;
txq->axq_totalqueued = 0;
txq->axq_linkbuf = NULL;
+ txq->axq_tx_inprogress = false;
sc->tx.txqsetup |= 1<<qnum;
}
return &sc->tx.txq[qnum];
@@ -1028,6 +1029,8 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
ath_tx_complete_aggr(sc, txq, bf, &bf_head, 0);
else
ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
+
+ txq->axq_tx_inprogress = false;
}

/* flush any pending frames if aggregation is enabled */
@@ -2027,6 +2030,8 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
else
ath_tx_complete_buf(sc, bf, &bf_head, txok, 0);

+ txq->axq_tx_inprogress = false;
+
ath_wake_mac80211_queue(sc, txq);

spin_lock_bh(&txq->axq_lock);
@@ -2036,6 +2041,40 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
}
}

+void ath_tx_complete_poll_work(struct work_struct *work)
+{
+ struct ath_softc *sc = container_of(work, struct ath_softc,
+ tx_complete_work.work);
+ struct ath_txq *txq;
+ int i;
+ bool needreset = false;
+
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+ if (ATH_TXQ_SETUP(sc, i)) {
+ txq = &sc->tx.txq[i];
+ spin_lock_bh(&txq->axq_lock);
+ if (txq->axq_depth) {
+ if (txq->axq_tx_inprogress) {
+ needreset = true;
+ spin_unlock_bh(&txq->axq_lock);
+ break;
+ } else {
+ txq->axq_tx_inprogress = true;
+ }
+ }
+ spin_unlock_bh(&txq->axq_lock);
+ }
+
+ if (needreset) {
+ DPRINTF(sc, ATH_DBG_RESET, "tx hung, resetting the chip\n");
+ ath_reset(sc, false);
+ }
+
+ queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work,
+ msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
+}
+
+

void ath_tx_tasklet(struct ath_softc *sc)
{
@@ -2076,6 +2115,8 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
goto err;
}

+ INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
+
err:
if (error != 0)
ath_tx_cleanup(sc);
--
1.6.0.4


2009-06-10 16:31:32

by Senthil Balasubramanian

[permalink] [raw]
Subject: Re: [PATCH] ath9k: Fix panic when ath9k is unloaded.

John

Please drop this patch alone. It was sent accidentally. I was using this patch
to get around RFKILL rmmod panic until RFKILL is properly tested with ath9k.

Sorry! for the confusion.

Senthil

On Wed, Jun 10, 2009 at 09:55:33PM +0530, Senthilkumar Balasubramanian wrote:
> RFKILL deinit should happen after the device is unregistered with
> mac80211.
>
> EIP: 0060:[<f8a52231>] EFLAGS: 00010286 CPU: 1
> EIP is at rfkill_pause_polling+0x11/0x30 [rfkill]
> EAX: 00000000 EBX: e1eaeab4 ECX: f8947048 EDX: da8f5c00
> ESI: e1eae1c0 EDI: e1eaeb78 EBP: d808ddac ESP: d808ddac
> DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
> Process rmmod (pid: 5618, ti=d808c000 task=f61a8410 task.ti=d808c000)
> Stack:
> d808ddcc f8902191 c02e4e10 ffffffff e1eaeb78 00000000 e1eae1c0 e1c0b360
> d808de04 f856d62e e1c0b360 e1c0b4d8 e1c0b000 e1eae2b0 c02f500e 00000000
> 00000002 e1c0b6e0 e1c0b140 e1c0b000 f8586180 e1eae760 d808de20 c02e4df3
> Call Trace:
> [<f8902191>] ? ath9k_stop+0x81/0x120 [ath9k]
> [<c02e4e10>] ? dev_close+0x90/0xd0
> [<f856d62e>] ? ieee80211_stop+0x27e/0x5c0 [mac80211]
> [<c02f500e>] ? dev_deactivate+0x17e/0x1a0
> [<c02e4df3>] ? dev_close+0x73/0xd0
> [<c02e4e97>] ? rollback_registered+0x47/0x210
> [<c02e507e>] ? unregister_netdevice+0x1e/0x70
> [<f856ceb9>] ? ieee80211_remove_interfaces+0x69/0xa0 [mac80211]
> [<f8560190>] ? ieee80211_unregister_hw+0x40/0xe0 [mac80211]
> [<f890438e>] ? ath_detach+0xbe/0x1e0 [ath9k]
> [<f89044c0>] ? ath_cleanup+0x10/0x40 [ath9k]
> [<f890bfa8>] ? ath_pci_remove+0x18/0x20 [ath9k]
> [<c024867e>] ? pci_device_remove+0x1e/0x40
> [<c02b4ec6>] ? __device_release_driver+0x56/0x90
> [<c02b4f8f>] ? driver_detach+0x8f/0xa0
> [<c02b40db>] ? bus_remove_driver+0x7b/0xb0
> [<c02b54d9>] ? driver_unregister+0x39/0x40
> [<c02488d5>] ? pci_unregister_driver+0x35/0x90
> [<f890bec2>] ? ath_pci_exit+0x12/0x20 [ath9k]
> [<f890d7e4>] ? ath9k_exit+0x10/0x3d [ath9k]
> [<c036edcd>] ? mutex_unlock+0xd/0x10
> [<c015d257>] ? sys_delete_module+0x167/0x210
> [<c019c40b>] ? do_munmap+0x22b/0x280
> [<c0103af0>] ? sysenter_do_call+0x12/0x2c
> EIP: [<f8a52231>] rfkill_pause_polling+0x11/0x30 [rfkill] SS:ESP 0068:d808ddac
>
> Signed-off-by: Senthil Balasubramanian <[email protected]>
> ---
> drivers/net/wireless/ath/ath9k/main.c | 7 ++++---
> 1 files changed, 4 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
> index e2c8649..5ee9800 100644
> --- a/drivers/net/wireless/ath/ath9k/main.c
> +++ b/drivers/net/wireless/ath/ath9k/main.c
> @@ -1288,9 +1288,6 @@ void ath_detach(struct ath_softc *sc)
>
> DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n");
>
> -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
> - ath_deinit_rfkill(sc);
> -#endif
> ath_deinit_leds(sc);
> cancel_work_sync(&sc->chan_work);
> cancel_delayed_work_sync(&sc->wiphy_work);
> @@ -1304,6 +1301,10 @@ void ath_detach(struct ath_softc *sc)
> ieee80211_free_hw(aphy->hw);
> }
> ieee80211_unregister_hw(hw);
> +
> +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
> + ath_deinit_rfkill(sc);
> +#endif
> ath_rx_cleanup(sc);
> ath_tx_cleanup(sc);
>
> --
> 1.6.0.4
>

2009-06-10 16:26:27

by Senthil Balasubramanian

[permalink] [raw]
Subject: [PATCH] ath9k: Fix panic when ath9k is unloaded.

RFKILL deinit should happen after the device is unregistered with
mac80211.

EIP: 0060:[<f8a52231>] EFLAGS: 00010286 CPU: 1
EIP is at rfkill_pause_polling+0x11/0x30 [rfkill]
EAX: 00000000 EBX: e1eaeab4 ECX: f8947048 EDX: da8f5c00
ESI: e1eae1c0 EDI: e1eaeb78 EBP: d808ddac ESP: d808ddac
DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
Process rmmod (pid: 5618, ti=d808c000 task=f61a8410 task.ti=d808c000)
Stack:
d808ddcc f8902191 c02e4e10 ffffffff e1eaeb78 00000000 e1eae1c0 e1c0b360
d808de04 f856d62e e1c0b360 e1c0b4d8 e1c0b000 e1eae2b0 c02f500e 00000000
00000002 e1c0b6e0 e1c0b140 e1c0b000 f8586180 e1eae760 d808de20 c02e4df3
Call Trace:
[<f8902191>] ? ath9k_stop+0x81/0x120 [ath9k]
[<c02e4e10>] ? dev_close+0x90/0xd0
[<f856d62e>] ? ieee80211_stop+0x27e/0x5c0 [mac80211]
[<c02f500e>] ? dev_deactivate+0x17e/0x1a0
[<c02e4df3>] ? dev_close+0x73/0xd0
[<c02e4e97>] ? rollback_registered+0x47/0x210
[<c02e507e>] ? unregister_netdevice+0x1e/0x70
[<f856ceb9>] ? ieee80211_remove_interfaces+0x69/0xa0 [mac80211]
[<f8560190>] ? ieee80211_unregister_hw+0x40/0xe0 [mac80211]
[<f890438e>] ? ath_detach+0xbe/0x1e0 [ath9k]
[<f89044c0>] ? ath_cleanup+0x10/0x40 [ath9k]
[<f890bfa8>] ? ath_pci_remove+0x18/0x20 [ath9k]
[<c024867e>] ? pci_device_remove+0x1e/0x40
[<c02b4ec6>] ? __device_release_driver+0x56/0x90
[<c02b4f8f>] ? driver_detach+0x8f/0xa0
[<c02b40db>] ? bus_remove_driver+0x7b/0xb0
[<c02b54d9>] ? driver_unregister+0x39/0x40
[<c02488d5>] ? pci_unregister_driver+0x35/0x90
[<f890bec2>] ? ath_pci_exit+0x12/0x20 [ath9k]
[<f890d7e4>] ? ath9k_exit+0x10/0x3d [ath9k]
[<c036edcd>] ? mutex_unlock+0xd/0x10
[<c015d257>] ? sys_delete_module+0x167/0x210
[<c019c40b>] ? do_munmap+0x22b/0x280
[<c0103af0>] ? sysenter_do_call+0x12/0x2c
EIP: [<f8a52231>] rfkill_pause_polling+0x11/0x30 [rfkill] SS:ESP 0068:d808ddac

Signed-off-by: Senthil Balasubramanian <[email protected]>
---
drivers/net/wireless/ath/ath9k/main.c | 7 ++++---
1 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index e2c8649..5ee9800 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1288,9 +1288,6 @@ void ath_detach(struct ath_softc *sc)

DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n");

-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
- ath_deinit_rfkill(sc);
-#endif
ath_deinit_leds(sc);
cancel_work_sync(&sc->chan_work);
cancel_delayed_work_sync(&sc->wiphy_work);
@@ -1304,6 +1301,10 @@ void ath_detach(struct ath_softc *sc)
ieee80211_free_hw(aphy->hw);
}
ieee80211_unregister_hw(hw);
+
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+ ath_deinit_rfkill(sc);
+#endif
ath_rx_cleanup(sc);
ath_tx_cleanup(sc);

--
1.6.0.4


2009-06-17 19:00:33

by John W. Linville

[permalink] [raw]
Subject: Re: [PATCH 0/7] ATH9K bug fixes - TX hang & Signal Quality issue

On Wed, Jun 10, 2009 at 09:55:25PM +0530, Senthil Balasubramanian wrote:
> This seris fixes couple of important issues
>
> 1) Signal Quality issue (patch 1/7)
> 2) INI update - fixes performance issue (Patch 2/7)
> 3) TX hang issue (happens after an hour time, Patch 6/7 & 7/7)

I'm sorry, but the changelog entries for those patches is
insufficiently detailed -- especially if you want them merged as
fixes for 2.6.31. I need a report with enough details for the fix
to be properly evaluated and preferably a link to an actual bug report.

John
--
John W. Linville Someday the world will need a hero, and you
[email protected] might be all we have. Be ready.

2009-06-10 16:26:02

by Senthil Balasubramanian

[permalink] [raw]
Subject: [PATCH 4/7] ath9k: stop ani when the STA gets disconnected.

ANI is not required when the STA is disconnected. So stop it and enable
ANI for adhoc and monitor mode.

Signed-off-by: Senthil Balasubramanian <[email protected]>
---
drivers/net/wireless/ath/ath9k/main.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 84fa69d..10dc7d1 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -934,6 +934,8 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
} else {
DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
sc->curaid = 0;
+ /* Stop ANI */
+ del_timer_sync(&sc->ani.timer);
}
}

@@ -2243,7 +2245,9 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,

ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);

- if (conf->type == NL80211_IFTYPE_AP)
+ if (conf->type == NL80211_IFTYPE_AP ||
+ conf->type == NL80211_IFTYPE_ADHOC ||
+ conf->type == NL80211_IFTYPE_MONITOR)
ath_start_ani(sc);

out:
--
1.6.0.4


2009-06-10 16:26:08

by Senthil Balasubramanian

[permalink] [raw]
Subject: [PATCH 5/7] ath9k: race condition in SCANNING state check during ANI calibration

ANI calibration shouldn't be done when we are not on our home channel.
This is already verified. However, it is racy. Fix this by proper
spin locks.

Signed-off-by: Senthil Balasubramanian <[email protected]>
---
drivers/net/wireless/ath/ath9k/ath9k.h | 1 +
drivers/net/wireless/ath/ath9k/main.c | 11 +++++++----
2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 2a3c66f..71d71c0 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -568,6 +568,7 @@ struct ath_softc {
int irq;
spinlock_t sc_resetlock;
spinlock_t sc_serial_rw;
+ spinlock_t ani_lock;
struct mutex mutex;

u8 curbssid[ETH_ALEN];
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 10dc7d1..e2c8649 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -326,6 +326,7 @@ static void ath_ani_calibrate(unsigned long data)
* don't calibrate when we're scanning.
* we are most likely not on our home channel.
*/
+ spin_lock(&sc->ani_lock);
if (sc->sc_flags & SC_OP_SCANNING)
goto set_timer;

@@ -389,6 +390,7 @@ static void ath_ani_calibrate(unsigned long data)
ath9k_ps_restore(sc);

set_timer:
+ spin_unlock(&sc->ani_lock);
/*
* Set timer interval based on previous results.
* The interval must be the shortest necessary to satisfy ANI,
@@ -1348,6 +1350,7 @@ static int ath_init(u16 devid, struct ath_softc *sc)
spin_lock_init(&sc->wiphy_lock);
spin_lock_init(&sc->sc_resetlock);
spin_lock_init(&sc->sc_serial_rw);
+ spin_lock_init(&sc->ani_lock);
mutex_init(&sc->mutex);
tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
@@ -2732,9 +2735,9 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
aphy->state = ATH_WIPHY_SCAN;
ath9k_wiphy_pause_all_forced(sc, aphy);

- mutex_lock(&sc->mutex);
+ spin_lock_bh(&sc->ani_lock);
sc->sc_flags |= SC_OP_SCANNING;
- mutex_unlock(&sc->mutex);
+ spin_unlock_bh(&sc->ani_lock);
}

static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
@@ -2742,11 +2745,11 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;

- mutex_lock(&sc->mutex);
+ spin_lock_bh(&sc->ani_lock);
aphy->state = ATH_WIPHY_ACTIVE;
sc->sc_flags &= ~SC_OP_SCANNING;
sc->sc_flags |= SC_OP_FULL_RESET;
- mutex_unlock(&sc->mutex);
+ spin_unlock_bh(&sc->ani_lock);
}

struct ieee80211_ops ath9k_ops = {
--
1.6.0.4