summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2012-04-26 19:03:48 (GMT)
committerJohn W. Linville <linville@tuxdriver.com>2012-04-26 19:03:48 (GMT)
commitd9b8ae6bd8c3304569a25079fcdbebaa28a48ee4 (patch)
tree9ce3e4eb355685f970dd7333a0a935109aff0583 /drivers/net/wireless/ath
parent872f24dbc604ef585ea7eec73020dcdfaffd1956 (diff)
parent94c514fe240fc0dd02187b78facefde8b6744634 (diff)
downloadlinux-d9b8ae6bd8c3304569a25079fcdbebaa28a48ee4.tar.xz
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Conflicts: drivers/net/wireless/iwlwifi/iwl-testmode.c
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_phy.c17
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_calib.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.c64
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.c28
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.c14
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_debug.c46
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_debug.h45
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_pri_detector.c130
-rw-r--r--drivers/net/wireless/ath/ath9k/gpio.c21
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c42
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h5
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c21
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c105
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c3
19 files changed, 387 insertions, 186 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index de30cb3..f554bff 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -618,19 +618,10 @@ static void ar5008_hw_init_bb(struct ath_hw *ah,
u32 synthDelay;
synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
- if (IS_CHAN_B(chan))
- synthDelay = (4 * synthDelay) / 22;
- else
- synthDelay /= 10;
-
- if (IS_CHAN_HALF_RATE(chan))
- synthDelay *= 2;
- else if (IS_CHAN_QUARTER_RATE(chan))
- synthDelay *= 4;
REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
- udelay(synthDelay + BASE_ACTIVATE_DELAY);
+ ath9k_hw_synth_delay(ah, chan, synthDelay);
}
static void ar5008_hw_init_chain_masks(struct ath_hw *ah)
@@ -948,12 +939,8 @@ static bool ar5008_hw_rfbus_req(struct ath_hw *ah)
static void ar5008_hw_rfbus_done(struct ath_hw *ah)
{
u32 synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
- if (IS_CHAN_B(ah->curchan))
- synthDelay = (4 * synthDelay) / 22;
- else
- synthDelay /= 10;
- udelay(synthDelay + BASE_ACTIVATE_DELAY);
+ ath9k_hw_synth_delay(ah, ah->curchan, synthDelay);
REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 63089cc..a0387a0 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -1000,10 +1000,12 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal)
ar9003_mci_init_cal_req(ah, &is_reusable);
- txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
- REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
- udelay(5);
- REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+ if (!(IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))) {
+ txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
+ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
+ udelay(5);
+ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+ }
skip_tx_iqcal:
if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index 1188db2..ac53d90 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -4281,18 +4281,10 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
#undef POW_SM
}
-static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq,
- u8 *targetPowerValT2)
+static void ar9003_hw_get_legacy_target_powers(struct ath_hw *ah, u16 freq,
+ u8 *targetPowerValT2,
+ bool is2GHz)
{
- /* XXX: hard code for now, need to get from eeprom struct */
- u8 ht40PowerIncForPdadc = 0;
- bool is2GHz = false;
- unsigned int i = 0;
- struct ath_common *common = ath9k_hw_common(ah);
-
- if (freq < 4000)
- is2GHz = true;
-
targetPowerValT2[ALL_TARGET_LEGACY_6_24] =
ar9003_hw_eeprom_get_tgt_pwr(ah, LEGACY_TARGET_RATE_6_24, freq,
is2GHz);
@@ -4305,6 +4297,11 @@ static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq,
targetPowerValT2[ALL_TARGET_LEGACY_54] =
ar9003_hw_eeprom_get_tgt_pwr(ah, LEGACY_TARGET_RATE_54, freq,
is2GHz);
+}
+
+static void ar9003_hw_get_cck_target_powers(struct ath_hw *ah, u16 freq,
+ u8 *targetPowerValT2)
+{
targetPowerValT2[ALL_TARGET_LEGACY_1L_5L] =
ar9003_hw_eeprom_get_cck_tgt_pwr(ah, LEGACY_TARGET_RATE_1L_5L,
freq);
@@ -4314,6 +4311,11 @@ static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq,
ar9003_hw_eeprom_get_cck_tgt_pwr(ah, LEGACY_TARGET_RATE_11L, freq);
targetPowerValT2[ALL_TARGET_LEGACY_11S] =
ar9003_hw_eeprom_get_cck_tgt_pwr(ah, LEGACY_TARGET_RATE_11S, freq);
+}
+
+static void ar9003_hw_get_ht20_target_powers(struct ath_hw *ah, u16 freq,
+ u8 *targetPowerValT2, bool is2GHz)
+{
targetPowerValT2[ALL_TARGET_HT20_0_8_16] =
ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_0_8_16, freq,
is2GHz);
@@ -4356,6 +4358,16 @@ static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq,
targetPowerValT2[ALL_TARGET_HT20_23] =
ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_23, freq,
is2GHz);
+}
+
+static void ar9003_hw_get_ht40_target_powers(struct ath_hw *ah,
+ u16 freq,
+ u8 *targetPowerValT2,
+ bool is2GHz)
+{
+ /* XXX: hard code for now, need to get from eeprom struct */
+ u8 ht40PowerIncForPdadc = 0;
+
targetPowerValT2[ALL_TARGET_HT40_0_8_16] =
ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_0_8_16, freq,
is2GHz) + ht40PowerIncForPdadc;
@@ -4399,6 +4411,26 @@ static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq,
targetPowerValT2[ALL_TARGET_HT40_23] =
ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_23, freq,
is2GHz) + ht40PowerIncForPdadc;
+}
+
+static void ar9003_hw_get_target_power_eeprom(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ u8 *targetPowerValT2)
+{
+ bool is2GHz = IS_CHAN_2GHZ(chan);
+ unsigned int i = 0;
+ struct ath_common *common = ath9k_hw_common(ah);
+ u16 freq = chan->channel;
+
+ if (is2GHz)
+ ar9003_hw_get_cck_target_powers(ah, freq, targetPowerValT2);
+
+ ar9003_hw_get_legacy_target_powers(ah, freq, targetPowerValT2, is2GHz);
+ ar9003_hw_get_ht20_target_powers(ah, freq, targetPowerValT2, is2GHz);
+
+ if (IS_CHAN_HT40(chan))
+ ar9003_hw_get_ht40_target_powers(ah, freq, targetPowerValT2,
+ is2GHz);
for (i = 0; i < ar9300RateSize; i++) {
ath_dbg(common, EEPROM, "TPC[%02d] 0x%08x\n",
@@ -4778,9 +4810,6 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
scaledPower = ath9k_hw_get_scaled_power(ah, powerLimit,
antenna_reduction);
- /*
- * Get target powers from EEPROM - our baseline for TX Power
- */
if (is2ghz) {
/* Setup for CTL modes */
/* CTL_11B, CTL_11G, CTL_2GHT20 */
@@ -4952,7 +4981,12 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
unsigned int i = 0, paprd_scale_factor = 0;
u8 pwr_idx, min_pwridx = 0;
- ar9003_hw_set_target_power_eeprom(ah, chan->channel, targetPowerValT2);
+ memset(targetPowerValT2, 0 , sizeof(targetPowerValT2));
+
+ /*
+ * Get target powers from EEPROM - our baseline for TX Power
+ */
+ ar9003_hw_get_target_power_eeprom(ah, chan, targetPowerValT2);
if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) {
if (IS_CHAN_2GHZ(chan))
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index bbda25f..a1c0879 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -526,22 +526,10 @@ static void ar9003_hw_init_bb(struct ath_hw *ah,
* Value is in 100ns increments.
*/
synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
- if (IS_CHAN_B(chan))
- synthDelay = (4 * synthDelay) / 22;
- else
- synthDelay /= 10;
/* Activate the PHY (includes baseband activate + synthesizer on) */
REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
-
- /*
- * There is an issue if the AP starts the calibration before
- * the base band timeout completes. This could result in the
- * rx_clear false triggering. As a workaround we add delay an
- * extra BASE_ACTIVATE_DELAY usecs to ensure this condition
- * does not happen.
- */
- udelay(synthDelay + BASE_ACTIVATE_DELAY);
+ ath9k_hw_synth_delay(ah, chan, synthDelay);
}
static void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
@@ -723,6 +711,14 @@ static void ar9003_hw_set_rfmode(struct ath_hw *ah,
if (IS_CHAN_A_FAST_CLOCK(ah, chan))
rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
+ if (IS_CHAN_QUARTER_RATE(chan))
+ rfMode |= AR_PHY_MODE_QUARTER;
+ if (IS_CHAN_HALF_RATE(chan))
+ rfMode |= AR_PHY_MODE_HALF;
+
+ if (rfMode & (AR_PHY_MODE_QUARTER | AR_PHY_MODE_HALF))
+ REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL,
+ AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW, 3);
REG_WRITE(ah, AR_PHY_MODE, rfMode);
}
@@ -793,12 +789,8 @@ static bool ar9003_hw_rfbus_req(struct ath_hw *ah)
static void ar9003_hw_rfbus_done(struct ath_hw *ah)
{
u32 synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
- if (IS_CHAN_B(ah->curchan))
- synthDelay = (4 * synthDelay) / 22;
- else
- synthDelay /= 10;
- udelay(synthDelay + BASE_ACTIVATE_DELAY);
+ ath9k_hw_synth_delay(ah, ah->curchan, synthDelay);
REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index d834d97..7268a48 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -468,6 +468,9 @@
#define AR_PHY_ADDAC_PARA_CTL (AR_SM_BASE + 0x150)
#define AR_PHY_XPA_CFG (AR_SM_BASE + 0x158)
+#define AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW 3
+#define AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW_S 0
+
#define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A 0x0001FC00
#define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A_S 10
#define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A 0x3FF
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 702e5ab..11bc55e 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -817,8 +817,10 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
{
struct ath_hw *ah = sc->sc_ah;
- if (!ath_has_valid_bslot(sc))
+ if (!ath_has_valid_bslot(sc)) {
+ sc->sc_flags &= ~SC_OP_BEACONS;
return;
+ }
ath9k_ps_wakeup(sc);
if (status) {
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c
index ec32719..1ca6da80 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.c
+++ b/drivers/net/wireless/ath/ath9k/btcoex.c
@@ -108,9 +108,7 @@ void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah)
return;
}
- if (AR_SREV_9462(ah)) {
- btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI;
- } else if (AR_SREV_9300_20_OR_LATER(ah)) {
+ if (AR_SREV_9300_20_OR_LATER(ah)) {
btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300;
btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300;
@@ -284,11 +282,12 @@ void ath9k_hw_btcoex_enable(struct ath_hw *ah)
ath9k_hw_btcoex_enable_2wire(ah);
break;
case ATH_BTCOEX_CFG_3WIRE:
+ if (AR_SREV_9462(ah)) {
+ ath9k_hw_btcoex_enable_mci(ah);
+ return;
+ }
ath9k_hw_btcoex_enable_3wire(ah);
break;
- case ATH_BTCOEX_CFG_MCI:
- ath9k_hw_btcoex_enable_mci(ah);
- return;
}
REG_RMW(ah, AR_GPIO_PDPU,
@@ -305,11 +304,12 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah)
int i;
btcoex_hw->enabled = false;
- if (btcoex_hw->scheme == ATH_BTCOEX_CFG_MCI) {
+ if (AR_SREV_9462(ah)) {
ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
REG_WRITE(ah, AR_MCI_COEX_WL_WEIGHTS(i),
btcoex_hw->wlan_weight[i]);
+ return;
}
ath9k_hw_set_gpio(ah, btcoex_hw->wlanactive_gpio, 0);
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h
index 8f93aef..3a1e1cf 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.h
+++ b/drivers/net/wireless/ath/ath9k/btcoex.h
@@ -51,7 +51,6 @@ enum ath_btcoex_scheme {
ATH_BTCOEX_CFG_NONE,
ATH_BTCOEX_CFG_2WIRE,
ATH_BTCOEX_CFG_3WIRE,
- ATH_BTCOEX_CFG_MCI,
};
struct ath9k_hw_mci {
diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c
index 92891f5..ecc8179 100644
--- a/drivers/net/wireless/ath/ath9k/dfs.c
+++ b/drivers/net/wireless/ath/ath9k/dfs.c
@@ -148,11 +148,13 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data,
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
+ DFS_STAT_INC(sc, pulses_total);
if ((rs->rs_phyerr != ATH9K_PHYERR_RADAR) &&
(rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT)) {
ath_dbg(common, DFS,
"Error: rs_phyer=0x%x not a radar error\n",
rs->rs_phyerr);
+ DFS_STAT_INC(sc, pulses_no_dfs);
return;
}
@@ -188,7 +190,9 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data,
"width=%d, rssi=%d, delta_ts=%llu\n",
pe.freq, pe.ts, pe.width, pe.rssi, pe.ts-last_ts);
last_ts = pe.ts;
+ DFS_STAT_INC(sc, pulses_processed);
if (pd != NULL && pd->add_pulse(pd, &pe)) {
+ DFS_STAT_INC(sc, radar_detected);
/*
* TODO: forward radar event to DFS management layer
*/
diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.c b/drivers/net/wireless/ath/ath9k/dfs_debug.c
index 4364c10..55d2807 100644
--- a/drivers/net/wireless/ath/ath9k/dfs_debug.c
+++ b/drivers/net/wireless/ath/ath9k/dfs_debug.c
@@ -21,9 +21,15 @@
#include "ath9k.h"
#include "dfs_debug.h"
+
+struct ath_dfs_pool_stats global_dfs_pool_stats = { 0 };
+
#define ATH9K_DFS_STAT(s, p) \
len += snprintf(buf + len, size - len, "%28s : %10u\n", s, \
sc->debug.stats.dfs_stats.p);
+#define ATH9K_DFS_POOL_STAT(s, p) \
+ len += snprintf(buf + len, size - len, "%28s : %10u\n", s, \
+ global_dfs_pool_stats.p);
static ssize_t read_file_dfs(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
@@ -43,6 +49,9 @@ static ssize_t read_file_dfs(struct file *file, char __user *user_buf,
hw_ver->macVersion, hw_ver->macRev,
(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_DFS) ?
"enabled" : "disabled");
+ len += snprintf(buf + len, size - len, "Pulse detector statistics:\n");
+ ATH9K_DFS_STAT("pulse events reported ", pulses_total);
+ ATH9K_DFS_STAT("invalid pulse events ", pulses_no_dfs);
ATH9K_DFS_STAT("DFS pulses detected ", pulses_detected);
ATH9K_DFS_STAT("Datalen discards ", datalen_discards);
ATH9K_DFS_STAT("RSSI discards ", rssi_discards);
@@ -50,6 +59,18 @@ static ssize_t read_file_dfs(struct file *file, char __user *user_buf,
ATH9K_DFS_STAT("Primary channel pulses ", pri_phy_errors);
ATH9K_DFS_STAT("Secondary channel pulses", ext_phy_errors);
ATH9K_DFS_STAT("Dual channel pulses ", dc_phy_errors);
+ len += snprintf(buf + len, size - len, "Radar detector statistics "
+ "(current DFS region: %d)\n", sc->dfs_detector->region);
+ ATH9K_DFS_STAT("Pulse events processed ", pulses_processed);
+ ATH9K_DFS_STAT("Radars detected ", radar_detected);
+ len += snprintf(buf + len, size - len, "Global Pool statistics:\n");
+ ATH9K_DFS_POOL_STAT("Pool references ", pool_reference);
+ ATH9K_DFS_POOL_STAT("Pulses allocated ", pulse_allocated);
+ ATH9K_DFS_POOL_STAT("Pulses alloc error ", pulse_alloc_error);
+ ATH9K_DFS_POOL_STAT("Pulses in use ", pulse_used);
+ ATH9K_DFS_POOL_STAT("Seqs. allocated ", pseq_allocated);
+ ATH9K_DFS_POOL_STAT("Seqs. alloc error ", pseq_alloc_error);
+ ATH9K_DFS_POOL_STAT("Seqs. in use ", pseq_used);
if (len > size)
len = size;
@@ -60,8 +81,33 @@ static ssize_t read_file_dfs(struct file *file, char __user *user_buf,
return retval;
}
+/* magic number to prevent accidental reset of DFS statistics */
+#define DFS_STATS_RESET_MAGIC 0x80000000
+static ssize_t write_file_dfs(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ unsigned long val;
+ char buf[32];
+ ssize_t len;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ if (strict_strtoul(buf, 0, &val))
+ return -EINVAL;
+
+ if (val == DFS_STATS_RESET_MAGIC)
+ memset(&sc->debug.stats.dfs_stats, 0,
+ sizeof(sc->debug.stats.dfs_stats));
+ return count;
+}
+
static const struct file_operations fops_dfs_stats = {
.read = read_file_dfs,
+ .write = write_file_dfs,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.h b/drivers/net/wireless/ath/ath9k/dfs_debug.h
index 4911724..e36810a 100644
--- a/drivers/net/wireless/ath/ath9k/dfs_debug.h
+++ b/drivers/net/wireless/ath/ath9k/dfs_debug.h
@@ -22,17 +22,23 @@
#include "hw.h"
/**
- * struct ath_dfs_stats - DFS Statistics
- *
- * @pulses_detected: No. of pulses detected so far
- * @datalen_discards: No. of pulses discarded due to invalid datalen
- * @rssi_discards: No. of pulses discarded due to invalid RSSI
- * @bwinfo_discards: No. of pulses discarded due to invalid BW info
- * @pri_phy_errors: No. of pulses reported for primary channel
- * @ext_phy_errors: No. of pulses reported for extension channel
- * @dc_phy_errors: No. of pulses reported for primary + extension channel
+ * struct ath_dfs_stats - DFS Statistics per wiphy
+ * @pulses_total: pulses reported by HW
+ * @pulses_no_dfs: pulses wrongly reported as DFS
+ * @pulses_detected: pulses detected so far
+ * @datalen_discards: pulses discarded due to invalid datalen
+ * @rssi_discards: pulses discarded due to invalid RSSI
+ * @bwinfo_discards: pulses discarded due to invalid BW info
+ * @pri_phy_errors: pulses reported for primary channel
+ * @ext_phy_errors: pulses reported for extension channel
+ * @dc_phy_errors: pulses reported for primary + extension channel
+ * @pulses_processed: pulses forwarded to detector
+ * @radar_detected: radars detected
*/
struct ath_dfs_stats {
+ /* pulse stats */
+ u32 pulses_total;
+ u32 pulses_no_dfs;
u32 pulses_detected;
u32 datalen_discards;
u32 rssi_discards;
@@ -40,18 +46,39 @@ struct ath_dfs_stats {
u32 pri_phy_errors;
u32 ext_phy_errors;
u32 dc_phy_errors;
+ /* pattern detection stats */
+ u32 pulses_processed;
+ u32 radar_detected;
};
+/**
+ * struct ath_dfs_pool_stats - DFS Statistics for global pools
+ */
+struct ath_dfs_pool_stats {
+ u32 pool_reference;
+ u32 pulse_allocated;
+ u32 pulse_alloc_error;
+ u32 pulse_used;
+ u32 pseq_allocated;
+ u32 pseq_alloc_error;
+ u32 pseq_used;
+};
#if defined(CONFIG_ATH9K_DFS_DEBUGFS)
#define DFS_STAT_INC(sc, c) (sc->debug.stats.dfs_stats.c++)
void ath9k_dfs_init_debug(struct ath_softc *sc);
+#define DFS_POOL_STAT_INC(c) (global_dfs_pool_stats.c++)
+#define DFS_POOL_STAT_DEC(c) (global_dfs_pool_stats.c--)
+extern struct ath_dfs_pool_stats global_dfs_pool_stats;
+
#else
#define DFS_STAT_INC(sc, c) do { } while (0)
static inline void ath9k_dfs_init_debug(struct ath_softc *sc) { }
+#define DFS_POOL_STAT_INC(c) do { } while (0)
+#define DFS_POOL_STAT_DEC(c) do { } while (0)
#endif /* CONFIG_ATH9K_DFS_DEBUGFS */
#endif /* ATH9K_DFS_DEBUG_H */
diff --git a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c b/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c
index 025e88a..91b8dce 100644
--- a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c
+++ b/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c
@@ -15,9 +15,12 @@
*/
#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include "ath9k.h"
#include "dfs_pattern_detector.h"
#include "dfs_pri_detector.h"
+#include "dfs_debug.h"
/**
* struct pri_sequence - sequence of pulses matching one PRI
@@ -94,6 +97,81 @@ static u32 pde_get_multiple(u32 val, u32 fraction, u32 tolerance)
static u32 singleton_pool_references;
static LIST_HEAD(pulse_pool);
static LIST_HEAD(pseq_pool);
+static DEFINE_SPINLOCK(pool_lock);
+
+static void pool_register_ref(void)
+{
+ spin_lock_bh(&pool_lock);
+ singleton_pool_references++;
+ DFS_POOL_STAT_INC(pool_reference);
+ spin_unlock_bh(&pool_lock);
+}
+
+static void pool_deregister_ref(void)
+{
+ spin_lock_bh(&pool_lock);
+ singleton_pool_references--;
+ DFS_POOL_STAT_DEC(pool_reference);
+ if (singleton_pool_references == 0) {
+ /* free singleton pools with no references left */
+ struct pri_sequence *ps, *ps0;
+ struct pulse_elem *p, *p0;
+
+ list_for_each_entry_safe(p, p0, &pulse_pool, head) {
+ list_del(&p->head);
+ DFS_POOL_STAT_DEC(pulse_allocated);
+ kfree(p);
+ }
+ list_for_each_entry_safe(ps, ps0, &pseq_pool, head) {
+ list_del(&ps->head);
+ DFS_POOL_STAT_DEC(pseq_allocated);
+ kfree(ps);
+ }
+ }
+ spin_unlock_bh(&pool_lock);
+}
+
+static void pool_put_pulse_elem(struct pulse_elem *pe)
+{
+ spin_lock_bh(&pool_lock);
+ list_add(&pe->head, &pulse_pool);
+ DFS_POOL_STAT_DEC(pulse_used);
+ spin_unlock_bh(&pool_lock);
+}
+
+static void pool_put_pseq_elem(struct pri_sequence *pse)
+{
+ spin_lock_bh(&pool_lock);
+ list_add(&pse->head, &pseq_pool);
+ DFS_POOL_STAT_DEC(pseq_used);
+ spin_unlock_bh(&pool_lock);
+}
+
+static struct pri_sequence *pool_get_pseq_elem(void)
+{
+ struct pri_sequence *pse = NULL;
+ spin_lock_bh(&pool_lock);
+ if (!list_empty(&pseq_pool)) {
+ pse = list_first_entry(&pseq_pool, struct pri_sequence, head);
+ list_del(&pse->head);
+ DFS_POOL_STAT_INC(pseq_used);
+ }
+ spin_unlock_bh(&pool_lock);
+ return pse;
+}
+
+static struct pulse_elem *pool_get_pulse_elem(void)
+{
+ struct pulse_elem *pe = NULL;
+ spin_lock_bh(&pool_lock);
+ if (!list_empty(&pulse_pool)) {
+ pe = list_first_entry(&pulse_pool, struct pulse_elem, head);
+ list_del(&pe->head);
+ DFS_POOL_STAT_INC(pulse_used);
+ }
+ spin_unlock_bh(&pool_lock);
+ return pe;
+}
static struct pulse_elem *pulse_queue_get_tail(struct pri_detector *pde)
{
@@ -110,7 +188,7 @@ static bool pulse_queue_dequeue(struct pri_detector *pde)
list_del_init(&p->head);
pde->count--;
/* give it back to pool */
- list_add(&p->head, &pulse_pool);
+ pool_put_pulse_elem(p);
}
return (pde->count > 0);
}
@@ -138,16 +216,15 @@ static void pulse_queue_check_window(struct pri_detector *pde)
static bool pulse_queue_enqueue(struct pri_detector *pde, u64 ts)
{
- struct pulse_elem *p;
- if (!list_empty(&pulse_pool)) {
- p = list_first_entry(&pulse_pool, struct pulse_elem, head);
- list_del(&p->head);
- } else {
+ struct pulse_elem *p = pool_get_pulse_elem();
+ if (p == NULL) {
p = kmalloc(sizeof(*p), GFP_KERNEL);
if (p == NULL) {
- pr_err("failed to allocate pulse_elem\n");
+ DFS_POOL_STAT_INC(pulse_alloc_error);
return false;
}
+ DFS_POOL_STAT_INC(pulse_allocated);
+ DFS_POOL_STAT_INC(pulse_used);
}
INIT_LIST_HEAD(&p->head);
p->ts = ts;
@@ -220,15 +297,15 @@ static bool pseq_handler_create_sequences(struct pri_detector *pde,
/* this is a valid one, add it */
ps.deadline_ts = ps.first_ts + ps.dur;
-
- if (!list_empty(&pseq_pool)) {
- new_ps = list_first_entry(&pseq_pool,
- struct pri_sequence, head);
- list_del(&new_ps->head);
- } else {
+ new_ps = pool_get_pseq_elem();
+ if (new_ps == NULL) {
new_ps = kmalloc(sizeof(*new_ps), GFP_KERNEL);
- if (new_ps == NULL)
+ if (new_ps == NULL) {
+ DFS_POOL_STAT_INC(pseq_alloc_error);
return false;
+ }
+ DFS_POOL_STAT_INC(pseq_allocated);
+ DFS_POOL_STAT_INC(pseq_used);
}
memcpy(new_ps, &ps, sizeof(ps));
INIT_LIST_HEAD(&new_ps->head);
@@ -250,7 +327,7 @@ pseq_handler_add_to_existing_seqs(struct pri_detector *pde, u64 ts)
/* first ensure that sequence is within window */
if (ts > ps->deadline_ts) {
list_del_init(&ps->head);
- list_add(&ps->head, &pseq_pool);
+ pool_put_pseq_elem(ps);
continue;
}
@@ -299,11 +376,11 @@ static void pri_detector_reset(struct pri_detector *pde, u64 ts)
struct pulse_elem *p, *p0;
list_for_each_entry_safe(ps, ps0, &pde->sequences, head) {
list_del_init(&ps->head);
- list_add(&ps->head, &pseq_pool);
+ pool_put_pseq_elem(ps);
}
list_for_each_entry_safe(p, p0, &pde->pulses, head) {
list_del_init(&p->head);
- list_add(&p->head, &pulse_pool);
+ pool_put_pulse_elem(p);
}
pde->count = 0;
pde->last_ts = ts;
@@ -312,22 +389,7 @@ static void pri_detector_reset(struct pri_detector *pde, u64 ts)
static void pri_detector_exit(struct pri_detector *de)
{
pri_detector_reset(de, 0);
-
- singleton_pool_references--;
- if (singleton_pool_references == 0) {
- /* free singleton pools with no references left */
- struct pri_sequence *ps, *ps0;
- struct pulse_elem *p, *p0;
-
- list_for_each_entry_safe(p, p0, &pulse_pool, head) {
- list_del(&p->head);
- kfree(p);
- }
- list_for_each_entry_safe(ps, ps0, &pseq_pool, head) {
- list_del(&ps->head);
- kfree(ps);
- }
- }
+ pool_deregister_ref();
kfree(de);
}
@@ -385,6 +447,6 @@ pri_detector_init(const struct radar_detector_specs *rs)
de->max_count = rs->ppb * 2;
de->rs = rs;
- singleton_pool_references++;
+ pool_register_ref();
return de;
}
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
index dd10f4a..281a9af 100644
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -365,7 +365,7 @@ void ath9k_stop_btcoex(struct ath_softc *sc)
ath9k_hw_btcoex_disable(ah);
if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE)
ath9k_btcoex_timer_pause(sc);
- if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_MCI)
+ if (AR_SREV_9462(ah))
ath_mci_flush_profile(&sc->btcoex.mci);
}
}
@@ -376,7 +376,7 @@ void ath9k_deinit_btcoex(struct ath_softc *sc)
ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_3WIRE)
ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer);
- if (ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_MCI)
+ if (AR_SREV_9462(sc->sc_ah))
ath_mci_cleanup(sc);
}
@@ -402,17 +402,16 @@ int ath9k_init_btcoex(struct ath_softc *sc)
txq = sc->tx.txq_map[WME_AC_BE];
ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum);
sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
- break;
- case ATH_BTCOEX_CFG_MCI:
- sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
- sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
- INIT_LIST_HEAD(&sc->btcoex.mci.info);
+ if (AR_SREV_9462(ah)) {
+ sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
+ INIT_LIST_HEAD(&sc->btcoex.mci.info);
- r = ath_mci_setup(sc);
- if (r)
- return r;
+ r = ath_mci_setup(sc);
+ if (r)
+ return r;
- ath9k_hw_btcoex_init_mci(ah);
+ ath9k_hw_btcoex_init_mci(ah);
+ }
break;
default:
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 72c5bcd..75fd87f 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -191,6 +191,22 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout)
}
EXPORT_SYMBOL(ath9k_hw_wait);
+void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan,
+ int hw_delay)
+{
+ if (IS_CHAN_B(chan))
+ hw_delay = (4 * hw_delay) / 22;
+ else
+ hw_delay /= 10;
+
+ if (IS_CHAN_HALF_RATE(chan))
+ hw_delay *= 2;
+ else if (IS_CHAN_QUARTER_RATE(chan))
+ hw_delay *= 4;
+
+ udelay(hw_delay + BASE_ACTIVATE_DELAY);
+}
+
void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
int column, unsigned int *writecnt)
{
@@ -1020,7 +1036,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_conf *conf = &common->hw->conf;
const struct ath9k_channel *chan = ah->curchan;
- int acktimeout, ctstimeout;
+ int acktimeout, ctstimeout, ack_offset = 0;
int slottime;
int sifstime;
int rx_lat = 0, tx_lat = 0, eifs = 0;
@@ -1041,6 +1057,11 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
rx_lat = 37;
tx_lat = 54;
+ if (IS_CHAN_5GHZ(chan))
+ sifstime = 16;
+ else
+ sifstime = 10;
+
if (IS_CHAN_HALF_RATE(chan)) {
eifs = 175;
rx_lat *= 2;
@@ -1048,8 +1069,9 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
if (IS_CHAN_A_FAST_CLOCK(ah, chan))
tx_lat += 11;
+ sifstime *= 2;
+ ack_offset = 16;
slottime = 13;
- sifstime = 32;
} else if (IS_CHAN_QUARTER_RATE(chan)) {
eifs = 340;
rx_lat = (rx_lat * 4) - 1;
@@ -1057,8 +1079,9 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
if (IS_CHAN_A_FAST_CLOCK(ah, chan))
tx_lat += 22;
+ sifstime *= 4;
+ ack_offset = 32;
slottime = 21;
- sifstime = 64;
} else {
if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah)) {
eifs = AR_D_GBL_IFS_EIFS_ASYNC_FIFO;
@@ -1072,14 +1095,10 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
tx_lat = MS(reg, AR_USEC_TX_LAT);
slottime = ah->slottime;
- if (IS_CHAN_5GHZ(chan))
- sifstime = 16;
- else
- sifstime = 10;
}
/* As defined by IEEE 802.11-2007 17.3.8.6 */
- acktimeout = slottime + sifstime + 3 * ah->coverage_class;
+ acktimeout = slottime + sifstime + 3 * ah->coverage_class + ack_offset;
ctstimeout = acktimeout;
/*
@@ -1089,7 +1108,8 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
* BA frames in some implementations, but it has been found to fix ACK
* timeout issues in other cases as well.
*/
- if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ) {
+ if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ &&
+ !IS_CHAN_HALF_RATE(chan) && !IS_CHAN_QUARTER_RATE(chan)) {
acktimeout += 64 - sifstime - ah->slottime;
ctstimeout += 48 - sifstime - ah->slottime;
}
@@ -1667,6 +1687,10 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
if (chan->channel == ah->curchan->channel)
goto fail;
+ if ((ah->curchan->channelFlags | chan->channelFlags) &
+ (CHANNEL_HALF | CHANNEL_QUARTER))
+ goto fail;
+
if ((chan->channelFlags & CHANNEL_ALL) !=
(ah->curchan->channelFlags & CHANNEL_ALL))
goto fail;
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index dd4b8f4..8535f76 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -923,6 +923,8 @@ void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val);
void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna);
/* General Operation */
+void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan,
+ int hw_delay);
bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
int column, unsigned int *writecnt);
@@ -959,7 +961,8 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode);
#ifdef CONFIG_ATH9K_DEBUGFS
void ath9k_debug_sync_cause(struct ath_common *common, u32 sync_cause);
#else
-static void ath9k_debug_sync_cause(struct ath_common *common, u32 sync_cause) {}
+static inline void ath9k_debug_sync_cause(struct ath_common *common,
+ u32 sync_cause) {}
#endif
/* Generic hw timer primitives */
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 7a6b9f6..dee9e09 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -646,6 +646,24 @@ void ath9k_reload_chainmask_settings(struct ath_softc *sc)
setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
}
+static const struct ieee80211_iface_limit if_limits[] = {
+ { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_WDS) },
+ { .max = 8, .types =
+#ifdef CONFIG_MAC80211_MESH
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+#endif
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_GO) },
+};
+
+static const struct ieee80211_iface_combination if_comb = {
+ .limits = if_limits,
+ .n_limits = ARRAY_SIZE(if_limits),
+ .max_interfaces = 2048,
+ .num_different_channels = 1,
+};
void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
{
@@ -675,6 +693,9 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_MESH_POINT);
+ hw->wiphy->iface_combinations = &if_comb;
+ hw->wiphy->n_iface_combinations = 1;
+
if (AR_SREV_5416(sc->sc_ah))
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index f7bd253..04ef775 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -133,8 +133,16 @@ EXPORT_SYMBOL(ath9k_hw_updatetxtriglevel);
void ath9k_hw_abort_tx_dma(struct ath_hw *ah)
{
+ int maxdelay = 1000;
int i, q;
+ if (ah->curchan) {
+ if (IS_CHAN_HALF_RATE(ah->curchan))
+ maxdelay *= 2;
+ else if (IS_CHAN_QUARTER_RATE(ah->curchan))
+ maxdelay *= 4;
+ }
+
REG_WRITE(ah, AR_Q_TXD, AR_Q_TXD_M);
REG_SET_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);
@@ -142,7 +150,7 @@ void ath9k_hw_abort_tx_dma(struct ath_hw *ah)
REG_SET_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);
for (q = 0; q < AR_NUM_QCU; q++) {
- for (i = 0; i < 1000; i++) {
+ for (i = 0; i < maxdelay; i++) {
if (i)
udelay(5);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index d0a4b9b..dfa78e8 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -113,21 +113,25 @@ void ath9k_ps_restore(struct ath_softc *sc)
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
enum ath9k_power_mode mode;
unsigned long flags;
+ bool reset;
spin_lock_irqsave(&sc->sc_pm_lock, flags);
if (--sc->ps_usecount != 0)
goto unlock;
- if (sc->ps_idle && (sc->ps_flags & PS_WAIT_FOR_TX_ACK))
+ if (sc->ps_idle) {
+ ath9k_hw_setrxabort(sc->sc_ah, 1);
+ ath9k_hw_stopdmarecv(sc->sc_ah, &reset);
mode = ATH9K_PM_FULL_SLEEP;
- else if (sc->ps_enabled &&
- !(sc->ps_flags & (PS_WAIT_FOR_BEACON |
- PS_WAIT_FOR_CAB |
- PS_WAIT_FOR_PSPOLL_DATA |
- PS_WAIT_FOR_TX_ACK)))
+ } else if (sc->ps_enabled &&
+ !(sc->ps_flags & (PS_WAIT_FOR_BEACON |
+ PS_WAIT_FOR_CAB |
+ PS_WAIT_FOR_PSPOLL_DATA |
+ PS_WAIT_FOR_TX_ACK))) {
mode = ATH9K_PM_NETWORK_SLEEP;
- else
+ } else {
goto unlock;
+ }
spin_lock(&common->cc_lock);
ath_hw_cycle_counters_update(common);
@@ -1100,14 +1104,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
}
}
- /*
- * Cannot tx while the hardware is in full sleep, it first needs a full
- * chip reset to recover from that
- */
- if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_FULL_SLEEP))
- goto exit;
-
- if (unlikely(sc->sc_ah->power_mode != ATH9K_PM_AWAKE)) {
+ if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_NETWORK_SLEEP)) {
/*
* We are using PS-Poll and mac80211 can request TX while in
* power save mode. Need to wake up hardware for the TX to be
@@ -1126,12 +1123,21 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
}
/*
* The actual restore operation will happen only after
- * the sc_flags bit is cleared. We are just dropping
+ * the ps_flags bit is cleared. We are just dropping
* the ps_usecount here.
*/
ath9k_ps_restore(sc);
}
+ /*
+ * Cannot tx while the hardware is in full sleep, it first needs a full
+ * chip reset to recover from that
+ */
+ if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_FULL_SLEEP)) {
+ ath_err(common, "TX while HW is in FULL_SLEEP mode\n");
+ goto exit;
+ }
+
memset(&txctl, 0, sizeof(struct ath_tx_control));
txctl.txq = sc->tx.txq_map[skb_get_queue_mapping(skb)];
@@ -1245,7 +1251,6 @@ static void ath9k_reclaim_beacon(struct ath_softc *sc,
ath9k_set_beaconing_status(sc, false);
ath_beacon_return(sc, avp);
ath9k_set_beaconing_status(sc, true);
- sc->sc_flags &= ~SC_OP_BEACONS;
}
static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
@@ -1376,17 +1381,9 @@ static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw,
ath9k_calculate_summary_state(hw, vif);
if (ath9k_uses_beacons(vif->type)) {
- int error;
- /* This may fail because upper levels do not have beacons
- * properly configured yet. That's OK, we assume it
- * will be properly configured and then we will be notified
- * in the info_changed method and set up beacons properly
- * there.
- */
+ /* Reserve a beacon slot for the vif */
ath9k_set_beaconing_status(sc, false);
- error = ath_beacon_alloc(sc, vif);
- if (!error)
- ath_beacon_config(sc, vif);
+ ath_beacon_alloc(sc, vif);
ath9k_set_beaconing_status(sc, true);
}
}
@@ -1537,6 +1534,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
static void ath9k_enable_ps(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
sc->ps_enabled = true;
if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
@@ -1546,11 +1544,13 @@ static void ath9k_enable_ps(struct ath_softc *sc)
}
ath9k_hw_setrxabort(ah, 1);
}
+ ath_dbg(common, PS, "PowerSave enabled\n");
}
static void ath9k_disable_ps(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
sc->ps_enabled = false;
ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);
@@ -1565,7 +1565,7 @@ static void ath9k_disable_ps(struct ath_softc *sc)
ath9k_hw_set_interrupts(ah);
}
}
-
+ ath_dbg(common, PS, "PowerSave disabled\n");
}
static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
@@ -1993,7 +1993,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
struct ath_common *common = ath9k_hw_common(ah);
struct ath_vif *avp = (void *)vif->drv_priv;
int slottime;
- int error;
ath9k_ps_wakeup(sc);
mutex_lock(&sc->mutex);
@@ -2026,13 +2025,25 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
}
}
- /* Enable transmission of beacons (AP, IBSS, MESH) */
- if ((changed & BSS_CHANGED_BEACON) ||
- ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon)) {
+ /*
+ * In case of AP mode, the HW TSF has to be reset
+ * when the beacon interval changes.
+ */
+ if ((changed & BSS_CHANGED_BEACON_INT) &&
+ (vif->type == NL80211_IFTYPE_AP))
+ sc->sc_flags |= SC_OP_TSF_RESET;
+
+ /* Configure beaconing (AP, IBSS, MESH) */
+ if (ath9k_uses_beacons(vif->type) &&
+ ((changed & BSS_CHANGED_BEACON) ||
+ (changed & BSS_CHANGED_BEACON_ENABLED) ||
+ (changed & BSS_CHANGED_BEACON_INT))) {
ath9k_set_beaconing_status(sc, false);
- error = ath_beacon_alloc(sc, vif);
- if (!error)
- ath_beacon_config(sc, vif);
+ if (bss_conf->enable_beacon)
+ ath_beacon_alloc(sc, vif);
+ else
+ avp->is_bslot_active = false;
+ ath_beacon_config(sc, vif);
ath9k_set_beaconing_status(sc, true);
}
@@ -2055,30 +2066,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
}
}
- /* Disable transmission of beacons */
- if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
- !bss_conf->enable_beacon) {
- ath9k_set_beaconing_status(sc, false);
- avp->is_bslot_active = false;
- ath9k_set_beaconing_status(sc, true);
- }
-
- if (changed & BSS_CHANGED_BEACON_INT) {
- /*
- * In case of AP mode, the HW TSF has to be reset
- * when the beacon interval changes.
- */
- if (vif->type == NL80211_IFTYPE_AP) {
- sc->sc_flags |= SC_OP_TSF_RESET;
- ath9k_set_beaconing_status(sc, false);
- error = ath_beacon_alloc(sc, vif);
- if (!error)
- ath_beacon_config(sc, vif);
- ath9k_set_beaconing_status(sc, true);
- } else
- ath_beacon_config(sc, vif);
- }
-
mutex_unlock(&sc->mutex);
ath9k_ps_restore(sc);
}
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 301ef3e..544e549 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -812,6 +812,7 @@ static bool ath9k_rx_accept(struct ath_common *common,
is_valid_tkip = rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID &&
test_bit(rx_stats->rs_keyix, common->tkip_keymap);
strip_mic = is_valid_tkip && ieee80211_is_data(fc) &&
+ ieee80211_has_protected(fc) &&
!(rx_stats->rs_status &
(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC |
ATH9K_RXERR_KEYMISS));
@@ -907,7 +908,7 @@ static int ath9k_process_rate(struct ath_common *common,
struct ieee80211_supported_band *sband;
enum ieee80211_band band;
unsigned int i = 0;
- struct ath_softc *sc = (struct ath_softc *) common->priv;
+ struct ath_softc __maybe_unused *sc = common->priv;
band = hw->conf.channel->band;
sband = hw->wiphy->bands[band];