Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem

This commit is contained in:
John W. Linville
2014-02-20 15:02:02 -05:00
211 changed files with 9951 additions and 6366 deletions
+2
View File
@@ -161,6 +161,8 @@ struct ath_common {
bool btcoex_enabled;
bool disable_ani;
bool bt_ant_diversity;
int last_rssi;
};
struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
+2 -2
View File
@@ -204,7 +204,7 @@ static void process_rx_rates(struct ath10k *ar, struct htt_rx_info *info,
break;
/* 80MHZ */
case 2:
status->flag |= RX_FLAG_80MHZ;
status->vht_flag |= RX_VHT_FLAG_80MHZ;
}
status->flag |= RX_FLAG_VHT;
@@ -266,7 +266,7 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info)
status->flag & RX_FLAG_HT ? "ht" : "",
status->flag & RX_FLAG_VHT ? "vht" : "",
status->flag & RX_FLAG_40MHZ ? "40" : "",
status->flag & RX_FLAG_80MHZ ? "80" : "",
status->vht_flag & RX_VHT_FLAG_80MHZ ? "80" : "",
status->flag & RX_FLAG_SHORT_GI ? "sgi " : "",
status->rate_idx,
status->vht_nss,
+16 -11
View File
@@ -790,7 +790,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
if (nw_type & ADHOC_NETWORK) {
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
nw_type & ADHOC_CREATOR ? "creator" : "joiner");
cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
cfg80211_ibss_joined(vif->ndev, bssid, chan, GFP_KERNEL);
cfg80211_put_bss(ar->wiphy, bss);
return;
}
@@ -861,13 +861,9 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
}
if (vif->nw_type & ADHOC_NETWORK) {
if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC)
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"%s: ath6k not in ibss mode\n", __func__);
return;
}
memset(bssid, 0, ETH_ALEN);
cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
return;
}
@@ -3256,6 +3252,15 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
struct ath6kl_vif *vif = netdev_priv(dev);
u16 interval;
int ret, rssi_thold;
int n_match_sets = request->n_match_sets;
/*
* If there's a matchset w/o an SSID, then assume it's just for
* the RSSI (nothing else is currently supported) and ignore it.
* The device only supports a global RSSI filter that we set below.
*/
if (n_match_sets == 1 && !request->match_sets[0].ssid.ssid_len)
n_match_sets = 0;
if (ar->state != ATH6KL_STATE_ON)
return -EIO;
@@ -3268,11 +3273,11 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
request->n_ssids,
request->match_sets,
request->n_match_sets);
n_match_sets);
if (ret < 0)
return ret;
if (!request->n_match_sets) {
if (!n_match_sets) {
ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
ALL_BSS_FILTER, 0);
if (ret < 0)
@@ -3286,12 +3291,12 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD,
ar->fw_capabilities)) {
if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)
if (request->min_rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)
rssi_thold = 0;
else if (request->rssi_thold < -127)
else if (request->min_rssi_thold < -127)
rssi_thold = -127;
else
rssi_thold = request->rssi_thold;
rssi_thold = request->min_rssi_thold;
ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx,
rssi_thold);
-12
View File
@@ -120,18 +120,6 @@ config ATH9K_WOW
This option enables Wake on Wireless LAN support for certain cards.
Currently, AR9462 is supported.
config ATH9K_LEGACY_RATE_CONTROL
bool "Atheros ath9k rate control"
depends on ATH9K
default n
---help---
Say Y, if you want to use the ath9k specific rate control
module instead of minstrel_ht. Be warned that there are various
issues with the ath9k RC and minstrel is a more robust algorithm.
Note that even if this option is selected, "ath9k_rate_control"
has to be passed to mac80211 using the module parameter,
ieee80211_default_rc_algo.
config ATH9K_RFKILL
bool "Atheros ath9k rfkill support" if EXPERT
depends on ATH9K
-1
View File
@@ -8,7 +8,6 @@ ath9k-y += beacon.o \
antenna.o
ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o
ath9k-$(CONFIG_ATH9K_LEGACY_RATE_CONTROL) += rc.o
ath9k-$(CONFIG_ATH9K_PCI) += pci.o
ath9k-$(CONFIG_ATH9K_AHB) += ahb.o
ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o
+172 -61
View File
@@ -23,10 +23,11 @@
#define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT
#define MAX_MAG_DELTA 11
#define MAX_PHS_DELTA 10
#define MAXIQCAL 3
struct coeff {
int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];
int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];
int iqc_coeff[2];
};
@@ -655,9 +656,6 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
if (i2_m_q2_a0_d1 > 0x800)
i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1);
if (i2_p_q2_a0_d1 > 0x1000)
i2_p_q2_a0_d1 = -((0x1fff - i2_p_q2_a0_d1) + 1);
if (iq_corr_a0_d1 > 0x800)
iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1);
@@ -800,7 +798,7 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
if (q_q_coff > 63)
q_q_coff = 63;
iqc_coeff[0] = (q_q_coff * 128) + q_i_coff;
iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff);
ath_dbg(common, CALIBRATE, "tx chain %d: iq corr coeff=%x\n",
chain_idx, iqc_coeff[0]);
@@ -831,7 +829,7 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
if (q_q_coff > 63)
q_q_coff = 63;
iqc_coeff[1] = (q_q_coff * 128) + q_i_coff;
iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff);
ath_dbg(common, CALIBRATE, "rx chain %d: iq corr coeff=%x\n",
chain_idx, iqc_coeff[1]);
@@ -839,7 +837,8 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
return true;
}
static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
static void ar9003_hw_detect_outlier(int mp_coeff[][MAXIQCAL],
int nmeasurement,
int max_delta)
{
int mp_max = -64, max_idx = 0;
@@ -848,20 +847,20 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
/* find min/max mismatch across all calibrated gains */
for (i = 0; i < nmeasurement; i++) {
if (mp_coeff[i] > mp_max) {
mp_max = mp_coeff[i];
if (mp_coeff[i][0] > mp_max) {
mp_max = mp_coeff[i][0];
max_idx = i;
} else if (mp_coeff[i] < mp_min) {
mp_min = mp_coeff[i];
} else if (mp_coeff[i][0] < mp_min) {
mp_min = mp_coeff[i][0];
min_idx = i;
}
}
/* find average (exclude max abs value) */
for (i = 0; i < nmeasurement; i++) {
if ((abs(mp_coeff[i]) < abs(mp_max)) ||
(abs(mp_coeff[i]) < abs(mp_min))) {
mp_avg += mp_coeff[i];
if ((abs(mp_coeff[i][0]) < abs(mp_max)) ||
(abs(mp_coeff[i][0]) < abs(mp_min))) {
mp_avg += mp_coeff[i][0];
mp_count++;
}
}
@@ -873,7 +872,7 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
if (mp_count)
mp_avg /= mp_count;
else
mp_avg = mp_coeff[nmeasurement - 1];
mp_avg = mp_coeff[nmeasurement - 1][0];
/* detect outlier */
if (abs(mp_max - mp_min) > max_delta) {
@@ -882,15 +881,16 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
else
outlier_idx = min_idx;
mp_coeff[outlier_idx] = mp_avg;
mp_coeff[outlier_idx][0] = mp_avg;
}
}
static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
struct coeff *coeff,
bool is_reusable)
static void ar9003_hw_tx_iq_cal_outlier_detection(struct ath_hw *ah,
struct coeff *coeff,
bool is_reusable)
{
int i, im, nmeasurement;
int magnitude, phase;
u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];
struct ath9k_hw_cal_data *caldata = ah->caldata;
@@ -920,21 +920,30 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
if (nmeasurement > MAX_MEASUREMENT)
nmeasurement = MAX_MEASUREMENT;
/* detect outlier only if nmeasurement > 1 */
if (nmeasurement > 1) {
/* Detect magnitude outlier */
ar9003_hw_detect_outlier(coeff->mag_coeff[i],
nmeasurement, MAX_MAG_DELTA);
/*
* Skip normal outlier detection for AR9550.
*/
if (!AR_SREV_9550(ah)) {
/* detect outlier only if nmeasurement > 1 */
if (nmeasurement > 1) {
/* Detect magnitude outlier */
ar9003_hw_detect_outlier(coeff->mag_coeff[i],
nmeasurement,
MAX_MAG_DELTA);
/* Detect phase outlier */
ar9003_hw_detect_outlier(coeff->phs_coeff[i],
nmeasurement, MAX_PHS_DELTA);
/* Detect phase outlier */
ar9003_hw_detect_outlier(coeff->phs_coeff[i],
nmeasurement,
MAX_PHS_DELTA);
}
}
for (im = 0; im < nmeasurement; im++) {
magnitude = coeff->mag_coeff[i][im][0];
phase = coeff->phs_coeff[i][im][0];
coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) |
((coeff->phs_coeff[i][im] & 0x7f) << 7);
coeff->iqc_coeff[0] =
(phase & 0x7f) | ((magnitude & 0x7f) << 7);
if ((im % 2) == 0)
REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
@@ -991,7 +1000,63 @@ static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
return true;
}
static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
static void __ar955x_tx_iq_cal_sort(struct ath_hw *ah,
struct coeff *coeff,
int i, int nmeasurement)
{
struct ath_common *common = ath9k_hw_common(ah);
int im, ix, iy, temp;
for (im = 0; im < nmeasurement; im++) {
for (ix = 0; ix < MAXIQCAL - 1; ix++) {
for (iy = ix + 1; iy <= MAXIQCAL - 1; iy++) {
if (coeff->mag_coeff[i][im][iy] <
coeff->mag_coeff[i][im][ix]) {
temp = coeff->mag_coeff[i][im][ix];
coeff->mag_coeff[i][im][ix] =
coeff->mag_coeff[i][im][iy];
coeff->mag_coeff[i][im][iy] = temp;
}
if (coeff->phs_coeff[i][im][iy] <
coeff->phs_coeff[i][im][ix]) {
temp = coeff->phs_coeff[i][im][ix];
coeff->phs_coeff[i][im][ix] =
coeff->phs_coeff[i][im][iy];
coeff->phs_coeff[i][im][iy] = temp;
}
}
}
coeff->mag_coeff[i][im][0] = coeff->mag_coeff[i][im][MAXIQCAL / 2];
coeff->phs_coeff[i][im][0] = coeff->phs_coeff[i][im][MAXIQCAL / 2];
ath_dbg(common, CALIBRATE,
"IQCAL: Median [ch%d][gain%d]: mag = %d phase = %d\n",
i, im,
coeff->mag_coeff[i][im][0],
coeff->phs_coeff[i][im][0]);
}
}
static bool ar955x_tx_iq_cal_median(struct ath_hw *ah,
struct coeff *coeff,
int iqcal_idx,
int nmeasurement)
{
int i;
if ((iqcal_idx + 1) != MAXIQCAL)
return false;
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
__ar955x_tx_iq_cal_sort(ah, coeff, i, nmeasurement);
}
return true;
}
static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah,
int iqcal_idx,
bool is_reusable)
{
struct ath_common *common = ath9k_hw_common(ah);
const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
@@ -1004,10 +1069,11 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
AR_PHY_CHAN_INFO_TAB_1,
AR_PHY_CHAN_INFO_TAB_2,
};
struct coeff coeff;
static struct coeff coeff;
s32 iq_res[6];
int i, im, j;
int nmeasurement;
int nmeasurement = 0;
bool outlier_detect = true;
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
if (!(ah->txchainmask & (1 << i)))
@@ -1065,17 +1131,23 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
goto tx_iqcal_fail;
}
coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f;
coeff.phs_coeff[i][im] =
coeff.phs_coeff[i][im][iqcal_idx] =
coeff.iqc_coeff[0] & 0x7f;
coeff.mag_coeff[i][im][iqcal_idx] =
(coeff.iqc_coeff[0] >> 7) & 0x7f;
if (coeff.mag_coeff[i][im] > 63)
coeff.mag_coeff[i][im] -= 128;
if (coeff.phs_coeff[i][im] > 63)
coeff.phs_coeff[i][im] -= 128;
if (coeff.mag_coeff[i][im][iqcal_idx] > 63)
coeff.mag_coeff[i][im][iqcal_idx] -= 128;
if (coeff.phs_coeff[i][im][iqcal_idx] > 63)
coeff.phs_coeff[i][im][iqcal_idx] -= 128;
}
}
ar9003_hw_tx_iqcal_load_avg_2_passes(ah, &coeff, is_reusable);
if (AR_SREV_9550(ah))
outlier_detect = ar955x_tx_iq_cal_median(ah, &coeff,
iqcal_idx, nmeasurement);
if (outlier_detect)
ar9003_hw_tx_iq_cal_outlier_detection(ah, &coeff, is_reusable);
return;
@@ -1409,7 +1481,7 @@ skip_tx_iqcal:
}
if (txiqcal_done)
ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable);
ar9003_hw_tx_iq_cal_post_proc(ah, 0, is_reusable);
else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags))
ar9003_hw_tx_iq_cal_reload(ah);
@@ -1455,14 +1527,38 @@ skip_tx_iqcal:
return true;
}
static bool do_ar9003_agc_cal(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
bool status;
REG_WRITE(ah, AR_PHY_AGC_CONTROL,
REG_READ(ah, AR_PHY_AGC_CONTROL) |
AR_PHY_AGC_CONTROL_CAL);
status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_CAL,
0, AH_WAIT_TIMEOUT);
if (!status) {
ath_dbg(common, CALIBRATE,
"offset calibration failed to complete in %d ms,"
"noisy environment?\n",
AH_WAIT_TIMEOUT / 1000);
return false;
}
return true;
}
static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
struct ath9k_channel *chan)
{
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_cal_data *caldata = ah->caldata;
bool txiqcal_done = false;
bool is_reusable = true, status = true;
bool status = true;
bool run_agc_cal = false, sep_iq_cal = false;
int i = 0;
/* Use chip chainmask only for calibration */
ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);
@@ -1485,7 +1581,12 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
* AGC calibration. Specifically, AR9550 in SoC chips.
*/
if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) {
txiqcal_done = true;
if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0,
AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)) {
txiqcal_done = true;
} else {
txiqcal_done = false;
}
run_agc_cal = true;
} else {
sep_iq_cal = true;
@@ -1512,27 +1613,37 @@ skip_tx_iqcal:
if (AR_SREV_9330_11(ah))
ar9003_hw_manual_peak_cal(ah, 0, IS_CHAN_2GHZ(chan));
/* Calibrate the AGC */
REG_WRITE(ah, AR_PHY_AGC_CONTROL,
REG_READ(ah, AR_PHY_AGC_CONTROL) |
AR_PHY_AGC_CONTROL_CAL);
/*
* For non-AR9550 chips, we just trigger AGC calibration
* in the HW, poll for completion and then process
* the results.
*
* For AR955x, we run it multiple times and use
* median IQ correction.
*/
if (!AR_SREV_9550(ah)) {
status = do_ar9003_agc_cal(ah);
if (!status)
return false;
/* Poll for offset calibration complete */
status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_CAL,
0, AH_WAIT_TIMEOUT);
if (txiqcal_done)
ar9003_hw_tx_iq_cal_post_proc(ah, 0, false);
} else {
if (!txiqcal_done) {
status = do_ar9003_agc_cal(ah);
if (!status)
return false;
} else {
for (i = 0; i < MAXIQCAL; i++) {
status = do_ar9003_agc_cal(ah);
if (!status)
return false;
ar9003_hw_tx_iq_cal_post_proc(ah, i, false);
}
}
}
}
if (!status) {
ath_dbg(common, CALIBRATE,
"offset calibration failed to complete in %d ms; noisy environment?\n",
AH_WAIT_TIMEOUT / 1000);
return false;
}
if (txiqcal_done)
ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable);
/* Revert chainmask to runtime parameters */
ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
+7 -4
View File
@@ -30,7 +30,6 @@
#include "spectral.h"
struct ath_node;
struct ath_rate_table;
extern struct ieee80211_ops ath9k_ops;
extern int ath9k_modparam_nohwcrypt;
@@ -150,6 +149,11 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
#define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e))
#define IS_OFDM_RATE(rate) ((rate >= 0x8) && (rate <= 0xf))
enum {
WLAN_RC_PHY_OFDM,
WLAN_RC_PHY_CCK,
};
struct ath_txq {
int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */
u32 axq_qnum; /* ath9k hardware queue number */
@@ -442,7 +446,8 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
void ath9k_set_beacon(struct ath_softc *sc);
bool ath9k_csa_is_finished(struct ath_softc *sc);
bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif);
void ath9k_csa_update(struct ath_softc *sc);
/*******************/
/* Link Monitoring */
@@ -757,7 +762,6 @@ struct ath_softc {
#endif
struct ath9k_hw_cal_data caldata;
int last_rssi;
#ifdef CONFIG_ATH9K_DEBUGFS
struct ath9k_debug debug;
@@ -774,7 +778,6 @@ struct ath_softc {
#endif
struct ath_descdma txsdma;
struct ieee80211_vif *csa_vif;
struct ath_ant_comb ant_comb;
u8 ant_tx, ant_rx;
+19 -10
View File
@@ -292,11 +292,8 @@ static void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif)
(unsigned long long)tsfadjust, avp->av_bslot);
}
bool ath9k_csa_is_finished(struct ath_softc *sc)
bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif)
{
struct ieee80211_vif *vif;
vif = sc->csa_vif;
if (!vif || !vif->csa_active)
return false;
@@ -304,11 +301,23 @@ bool ath9k_csa_is_finished(struct ath_softc *sc)
return false;
ieee80211_csa_finish(vif);
sc->csa_vif = NULL;
return true;
}
static void ath9k_csa_update_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
{
struct ath_softc *sc = data;
ath9k_csa_is_finished(sc, vif);
}
void ath9k_csa_update(struct ath_softc *sc)
{
ieee80211_iterate_active_interfaces(sc->hw,
IEEE80211_IFACE_ITER_NORMAL,
ath9k_csa_update_vif,
sc);
}
void ath9k_beacon_tasklet(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *)data;
@@ -362,13 +371,13 @@ void ath9k_beacon_tasklet(unsigned long data)
return;
}
/* EDMA devices check that in the tx completion function. */
if (!edma && ath9k_csa_is_finished(sc))
return;
slot = ath9k_beacon_choose_slot(sc);
vif = sc->beacon.bslot[slot];
/* EDMA devices check that in the tx completion function. */
if (!edma && ath9k_csa_is_finished(sc, vif))
return;
if (!vif || !vif->bss_conf.enable_beacon)
return;
+244
View File
@@ -27,6 +27,250 @@ MODULE_AUTHOR("Atheros Communications");
MODULE_DESCRIPTION("Shared library for Atheros wireless 802.11n LAN cards.");
MODULE_LICENSE("Dual BSD/GPL");
/* Assumes you've already done the endian to CPU conversion */
bool ath9k_cmn_rx_accept(struct ath_common *common,
struct ieee80211_hdr *hdr,
struct ieee80211_rx_status *rxs,
struct ath_rx_status *rx_stats,
bool *decrypt_error,
unsigned int rxfilter)
{
struct ath_hw *ah = common->ah;
bool is_mc, is_valid_tkip, strip_mic, mic_error;
__le16 fc;
fc = hdr->frame_control;
is_mc = !!is_multicast_ether_addr(hdr->addr1);
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));
/*
* Key miss events are only relevant for pairwise keys where the
* descriptor does contain a valid key index. This has been observed
* mostly with CCMP encryption.
*/
if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID ||
!test_bit(rx_stats->rs_keyix, common->ccmp_keymap))
rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS;
mic_error = is_valid_tkip && !ieee80211_is_ctl(fc) &&
!ieee80211_has_morefrags(fc) &&
!(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) &&
(rx_stats->rs_status & ATH9K_RXERR_MIC);
/*
* The rx_stats->rs_status will not be set until the end of the
* chained descriptors so it can be ignored if rs_more is set. The
* rs_more will be false at the last element of the chained
* descriptors.
*/
if (rx_stats->rs_status != 0) {
u8 status_mask;
if (rx_stats->rs_status & ATH9K_RXERR_CRC) {
rxs->flag |= RX_FLAG_FAILED_FCS_CRC;
mic_error = false;
}
if ((rx_stats->rs_status & ATH9K_RXERR_DECRYPT) ||
(!is_mc && (rx_stats->rs_status & ATH9K_RXERR_KEYMISS))) {
*decrypt_error = true;
mic_error = false;
}
/*
* Reject error frames with the exception of
* decryption and MIC failures. For monitor mode,
* we also ignore the CRC error.
*/
status_mask = ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
ATH9K_RXERR_KEYMISS;
if (ah->is_monitoring && (rxfilter & FIF_FCSFAIL))
status_mask |= ATH9K_RXERR_CRC;
if (rx_stats->rs_status & ~status_mask)
return false;
}
/*
* For unicast frames the MIC error bit can have false positives,
* so all MIC error reports need to be validated in software.
* False negatives are not common, so skip software verification
* if the hardware considers the MIC valid.
*/
if (strip_mic)
rxs->flag |= RX_FLAG_MMIC_STRIPPED;
else if (is_mc && mic_error)
rxs->flag |= RX_FLAG_MMIC_ERROR;
return true;
}
EXPORT_SYMBOL(ath9k_cmn_rx_accept);
void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
struct sk_buff *skb,
struct ath_rx_status *rx_stats,
struct ieee80211_rx_status *rxs,
bool decrypt_error)
{
struct ath_hw *ah = common->ah;
struct ieee80211_hdr *hdr;
int hdrlen, padpos, padsize;
u8 keyix;
__le16 fc;
/* see if any padding is done by the hw and remove it */
hdr = (struct ieee80211_hdr *) skb->data;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
fc = hdr->frame_control;
padpos = ieee80211_hdrlen(fc);
/* The MAC header is padded to have 32-bit boundary if the
* packet payload is non-zero. The general calculation for
* padsize would take into account odd header lengths:
* padsize = (4 - padpos % 4) % 4; However, since only
* even-length headers are used, padding can only be 0 or 2
* bytes and we can optimize this a bit. In addition, we must
* not try to remove padding from short control frames that do
* not have payload. */
padsize = padpos & 3;
if (padsize && skb->len>=padpos+padsize+FCS_LEN) {
memmove(skb->data + padsize, skb->data, padpos);
skb_pull(skb, padsize);
}
keyix = rx_stats->rs_keyix;
if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error &&
ieee80211_has_protected(fc)) {
rxs->flag |= RX_FLAG_DECRYPTED;
} else if (ieee80211_has_protected(fc)
&& !decrypt_error && skb->len >= hdrlen + 4) {
keyix = skb->data[hdrlen + 3] >> 6;
if (test_bit(keyix, common->keymap))
rxs->flag |= RX_FLAG_DECRYPTED;
}
if (ah->sw_mgmt_crypto &&
(rxs->flag & RX_FLAG_DECRYPTED) &&
ieee80211_is_mgmt(fc))
/* Use software decrypt for management frames. */
rxs->flag &= ~RX_FLAG_DECRYPTED;
}
EXPORT_SYMBOL(ath9k_cmn_rx_skb_postprocess);
int ath9k_cmn_process_rate(struct ath_common *common,
struct ieee80211_hw *hw,
struct ath_rx_status *rx_stats,
struct ieee80211_rx_status *rxs)
{
struct ieee80211_supported_band *sband;
enum ieee80211_band band;
unsigned int i = 0;
struct ath_hw *ah = common->ah;
band = ah->curchan->chan->band;
sband = hw->wiphy->bands[band];
if (IS_CHAN_QUARTER_RATE(ah->curchan))
rxs->flag |= RX_FLAG_5MHZ;
else if (IS_CHAN_HALF_RATE(ah->curchan))
rxs->flag |= RX_FLAG_10MHZ;
if (rx_stats->rs_rate & 0x80) {
/* HT rate */
rxs->flag |= RX_FLAG_HT;
rxs->flag |= rx_stats->flag;
rxs->rate_idx = rx_stats->rs_rate & 0x7f;
return 0;
}
for (i = 0; i < sband->n_bitrates; i++) {
if (sband->bitrates[i].hw_value == rx_stats->rs_rate) {
rxs->rate_idx = i;
return 0;
}
if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) {
rxs->flag |= RX_FLAG_SHORTPRE;
rxs->rate_idx = i;
return 0;
}
}
return -EINVAL;
}
EXPORT_SYMBOL(ath9k_cmn_process_rate);
void ath9k_cmn_process_rssi(struct ath_common *common,
struct ieee80211_hw *hw,
struct ath_rx_status *rx_stats,
struct ieee80211_rx_status *rxs)
{
struct ath_hw *ah = common->ah;
int last_rssi;
int rssi = rx_stats->rs_rssi;
int i, j;
/*
* RSSI is not available for subframes in an A-MPDU.
*/
if (rx_stats->rs_moreaggr) {
rxs->flag |= RX_FLAG_NO_SIGNAL_VAL;
return;
}
/*
* Check if the RSSI for the last subframe in an A-MPDU
* or an unaggregated frame is valid.
*/
if (rx_stats->rs_rssi == ATH9K_RSSI_BAD) {
rxs->flag |= RX_FLAG_NO_SIGNAL_VAL;
return;
}
for (i = 0, j = 0; i < ARRAY_SIZE(rx_stats->rs_rssi_ctl); i++) {
s8 rssi;
if (!(ah->rxchainmask & BIT(i)))
continue;
rssi = rx_stats->rs_rssi_ctl[i];
if (rssi != ATH9K_RSSI_BAD) {
rxs->chains |= BIT(j);
rxs->chain_signal[j] = ah->noise + rssi;
}
j++;
}
/*
* Update Beacon RSSI, this is used by ANI.
*/
if (rx_stats->is_mybeacon &&
((ah->opmode == NL80211_IFTYPE_STATION) ||
(ah->opmode == NL80211_IFTYPE_ADHOC))) {
ATH_RSSI_LPF(common->last_rssi, rx_stats->rs_rssi);
last_rssi = common->last_rssi;
if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER);
if (rssi < 0)
rssi = 0;
ah->stats.avgbrssi = rssi;
}
rxs->signal = ah->noise + rx_stats->rs_rssi;
}
EXPORT_SYMBOL(ath9k_cmn_process_rssi);
int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+19
View File
@@ -42,6 +42,25 @@
#define ATH_EP_RND(x, mul) \
(((x) + ((mul)/2)) / (mul))
bool ath9k_cmn_rx_accept(struct ath_common *common,
struct ieee80211_hdr *hdr,
struct ieee80211_rx_status *rxs,
struct ath_rx_status *rx_stats,
bool *decrypt_error,
unsigned int rxfilter);
void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
struct sk_buff *skb,
struct ath_rx_status *rx_stats,
struct ieee80211_rx_status *rxs,
bool decrypt_error);
int ath9k_cmn_process_rate(struct ath_common *common,
struct ieee80211_hw *hw,
struct ath_rx_status *rx_stats,
struct ieee80211_rx_status *rxs);
void ath9k_cmn_process_rssi(struct ath_common *common,
struct ieee80211_hw *hw,
struct ath_rx_status *rx_stats,
struct ieee80211_rx_status *rxs);
int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb);
struct ath9k_channel *ath9k_cmn_get_channel(struct ieee80211_hw *hw,
struct ath_hw *ah,
-1
View File
@@ -18,7 +18,6 @@
#define DEBUG_H
#include "hw.h"
#include "rc.h"
#include "dfs_debug.h"
struct ath_txq;
@@ -21,6 +21,8 @@
#include "hw.h"
struct ath_softc;
/**
* struct ath_dfs_stats - DFS Statistics per wiphy
* @pulses_total: pulses reported by HW
+2
View File
@@ -54,6 +54,8 @@ static struct usb_device_id ath9k_hif_usb_ids[] = {
.driver_info = AR9280_USB }, /* SMC Networks */
{ USB_DEVICE(0x0411, 0x017f),
.driver_info = AR9280_USB }, /* Sony UWA-BR100 */
{ USB_DEVICE(0x0411, 0x0197),
.driver_info = AR9280_USB }, /* Buffalo WLI-UV-AG300P */
{ USB_DEVICE(0x04da, 0x3904),
.driver_info = AR9280_USB },
-1
View File
@@ -277,7 +277,6 @@ struct ath9k_htc_rxbuf {
};
struct ath9k_htc_rx {
int last_rssi; /* FIXME: per-STA */
struct list_head rxbuf;
spinlock_t rxbuflock;
};
@@ -611,6 +611,7 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv)
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
common->last_rssi = ATH_RSSI_DUMMY_MARKER;
priv->ah->opmode = NL80211_IFTYPE_STATION;
}
@@ -1474,6 +1474,7 @@ static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
if ((vif->type == NL80211_IFTYPE_STATION) && bss_conf->assoc) {
common->curaid = bss_conf->aid;
common->last_rssi = ATH_RSSI_DUMMY_MARKER;
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
}
}
+52 -120
View File
@@ -927,43 +927,39 @@ void ath9k_host_rx_init(struct ath9k_htc_priv *priv)
ath9k_hw_rxena(priv->ah);
ath9k_htc_opmode_init(priv);
ath9k_hw_startpcureceive(priv->ah, test_bit(OP_SCANNING, &priv->op_flags));
priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER;
}
static void ath9k_process_rate(struct ieee80211_hw *hw,
struct ieee80211_rx_status *rxs,
u8 rx_rate, u8 rs_flags)
static inline void convert_htc_flag(struct ath_rx_status *rx_stats,
struct ath_htc_rx_status *rxstatus)
{
struct ieee80211_supported_band *sband;
enum ieee80211_band band;
unsigned int i = 0;
rx_stats->flag = 0;
if (rxstatus->rs_flags & ATH9K_RX_2040)
rx_stats->flag |= RX_FLAG_40MHZ;
if (rxstatus->rs_flags & ATH9K_RX_GI)
rx_stats->flag |= RX_FLAG_SHORT_GI;
}
if (rx_rate & 0x80) {
/* HT rate */
rxs->flag |= RX_FLAG_HT;
if (rs_flags & ATH9K_RX_2040)
rxs->flag |= RX_FLAG_40MHZ;
if (rs_flags & ATH9K_RX_GI)
rxs->flag |= RX_FLAG_SHORT_GI;
rxs->rate_idx = rx_rate & 0x7f;
return;
}
static void rx_status_htc_to_ath(struct ath_rx_status *rx_stats,
struct ath_htc_rx_status *rxstatus)
{
rx_stats->rs_datalen = rxstatus->rs_datalen;
rx_stats->rs_status = rxstatus->rs_status;
rx_stats->rs_phyerr = rxstatus->rs_phyerr;
rx_stats->rs_rssi = rxstatus->rs_rssi;
rx_stats->rs_keyix = rxstatus->rs_keyix;
rx_stats->rs_rate = rxstatus->rs_rate;
rx_stats->rs_antenna = rxstatus->rs_antenna;
rx_stats->rs_more = rxstatus->rs_more;
band = hw->conf.chandef.chan->band;
sband = hw->wiphy->bands[band];
for (i = 0; i < sband->n_bitrates; i++) {
if (sband->bitrates[i].hw_value == rx_rate) {
rxs->rate_idx = i;
return;
}
if (sband->bitrates[i].hw_value_short == rx_rate) {
rxs->rate_idx = i;
rxs->flag |= RX_FLAG_SHORTPRE;
return;
}
}
memcpy(rx_stats->rs_rssi_ctl, rxstatus->rs_rssi_ctl,
sizeof(rx_stats->rs_rssi_ctl));
memcpy(rx_stats->rs_rssi_ext, rxstatus->rs_rssi_ext,
sizeof(rx_stats->rs_rssi_ext));
rx_stats->rs_isaggr = rxstatus->rs_isaggr;
rx_stats->rs_moreaggr = rxstatus->rs_moreaggr;
rx_stats->rs_num_delims = rxstatus->rs_num_delims;
convert_htc_flag(rx_stats, rxstatus);
}
static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
@@ -975,10 +971,10 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
struct ieee80211_hw *hw = priv->hw;
struct sk_buff *skb = rxbuf->skb;
struct ath_common *common = ath9k_hw_common(priv->ah);
struct ath_hw *ah = common->ah;
struct ath_htc_rx_status *rxstatus;
int hdrlen, padsize;
int last_rssi = ATH_RSSI_DUMMY_MARKER;
__le16 fc;
struct ath_rx_status rx_stats;
bool decrypt_error;
if (skb->len < HTC_RX_FRAME_HEADER_SIZE) {
ath_err(common, "Corrupted RX frame, dropping (len: %d)\n",
@@ -999,103 +995,39 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
ath9k_htc_err_stat_rx(priv, rxstatus);
/* Get the RX status information */
memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE);
skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE);
hdr = (struct ieee80211_hdr *)skb->data;
fc = hdr->frame_control;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
padsize = hdrlen & 3;
if (padsize && skb->len >= hdrlen+padsize+FCS_LEN) {
memmove(skb->data + padsize, skb->data, hdrlen);
skb_pull(skb, padsize);
}
memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
if (rxbuf->rxstatus.rs_status != 0) {
if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_CRC)
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_PHY)
goto rx_next;
/* Copy everything from ath_htc_rx_status (HTC_RX_FRAME_HEADER).
* After this, we can drop this part of skb. */
rx_status_htc_to_ath(&rx_stats, rxstatus);
rx_status->mactime = be64_to_cpu(rxstatus->rs_tstamp);
skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE);
if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT) {
/* FIXME */
} else if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_MIC) {
if (ieee80211_is_ctl(fc))
/*
* Sometimes, we get invalid
* MIC failures on valid control frames.
* Remove these mic errors.
*/
rxbuf->rxstatus.rs_status &= ~ATH9K_RXERR_MIC;
else
rx_status->flag |= RX_FLAG_MMIC_ERROR;
}
/*
* everything but the rate is checked here, the rate check is done
* separately to avoid doing two lookups for a rate for each frame.
*/
hdr = (struct ieee80211_hdr *)skb->data;
if (!ath9k_cmn_rx_accept(common, hdr, rx_status, &rx_stats,
&decrypt_error, priv->rxfilter))
goto rx_next;
/*
* Reject error frames with the exception of
* decryption and MIC failures. For monitor mode,
* we also ignore the CRC error.
*/
if (priv->ah->opmode == NL80211_IFTYPE_MONITOR) {
if (rxbuf->rxstatus.rs_status &
~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
ATH9K_RXERR_CRC))
goto rx_next;
} else {
if (rxbuf->rxstatus.rs_status &
~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
goto rx_next;
}
}
}
ath9k_cmn_rx_skb_postprocess(common, skb, &rx_stats,
rx_status, decrypt_error);
if (!(rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT)) {
u8 keyix;
keyix = rxbuf->rxstatus.rs_keyix;
if (keyix != ATH9K_RXKEYIX_INVALID) {
rx_status->flag |= RX_FLAG_DECRYPTED;
} else if (ieee80211_has_protected(fc) &&
skb->len >= hdrlen + 4) {
keyix = skb->data[hdrlen + 3] >> 6;
if (test_bit(keyix, common->keymap))
rx_status->flag |= RX_FLAG_DECRYPTED;
}
}
if (ath9k_cmn_process_rate(common, hw, &rx_stats, rx_status))
goto rx_next;
ath9k_process_rate(hw, rx_status, rxbuf->rxstatus.rs_rate,
rxbuf->rxstatus.rs_flags);
rx_stats.is_mybeacon = ath_is_mybeacon(common, hdr);
ath9k_cmn_process_rssi(common, hw, &rx_stats, rx_status);
if (rxbuf->rxstatus.rs_rssi != ATH9K_RSSI_BAD &&
!rxbuf->rxstatus.rs_moreaggr)
ATH_RSSI_LPF(priv->rx.last_rssi,
rxbuf->rxstatus.rs_rssi);
last_rssi = priv->rx.last_rssi;
if (ath_is_mybeacon(common, hdr)) {
s8 rssi = rxbuf->rxstatus.rs_rssi;
if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER);
if (rssi < 0)
rssi = 0;
priv->ah->stats.avgbrssi = rssi;
}
rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp);
rx_status->band = hw->conf.chandef.chan->band;
rx_status->freq = hw->conf.chandef.chan->center_freq;
rx_status->signal = rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR;
rx_status->antenna = rxbuf->rxstatus.rs_antenna;
rx_status->band = ah->curchan->chan->band;
rx_status->freq = ah->curchan->chan->center_freq;
rx_status->antenna = rx_stats.rs_antenna;
rx_status->flag |= RX_FLAG_MACTIME_END;
return true;
rx_next:
return false;
}
+36
View File
@@ -358,6 +358,36 @@ ret:
kfree_skb(skb);
}
static void ath9k_htc_fw_panic_report(struct htc_target *htc_handle,
struct sk_buff *skb)
{
uint32_t *pattern = (uint32_t *)skb->data;
switch (*pattern) {
case 0x33221199:
{
struct htc_panic_bad_vaddr *htc_panic;
htc_panic = (struct htc_panic_bad_vaddr *) skb->data;
dev_err(htc_handle->dev, "ath: firmware panic! "
"exccause: 0x%08x; pc: 0x%08x; badvaddr: 0x%08x.\n",
htc_panic->exccause, htc_panic->pc,
htc_panic->badvaddr);
break;
}
case 0x33221299:
{
struct htc_panic_bad_epid *htc_panic;
htc_panic = (struct htc_panic_bad_epid *) skb->data;
dev_err(htc_handle->dev, "ath: firmware panic! "
"bad epid: 0x%08x\n", htc_panic->epid);
break;
}
default:
dev_err(htc_handle->dev, "ath: uknown panic pattern!\n");
break;
}
}
/*
* HTC Messages are handled directly here and the obtained SKB
* is freed.
@@ -379,6 +409,12 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle,
htc_hdr = (struct htc_frame_hdr *) skb->data;
epid = htc_hdr->endpoint_id;
if (epid == 0x99) {
ath9k_htc_fw_panic_report(htc_handle, skb);
kfree_skb(skb);
return;
}
if (epid >= ENDPOINT_MAX) {
if (pipe_id != USB_REG_IN_PIPE)
dev_kfree_skb_any(skb);
+12
View File
@@ -77,6 +77,18 @@ struct htc_config_pipe_msg {
u8 credits;
} __packed;
struct htc_panic_bad_vaddr {
__be32 pattern;
__be32 exccause;
__be32 pc;
__be32 badvaddr;
} __packed;
struct htc_panic_bad_epid {
__be32 pattern;
__be32 epid;
} __packed;
struct htc_ep_callbacks {
void *priv;
void (*tx) (void *, struct sk_buff *, enum htc_endpoint_id, bool txok);
-1
View File
@@ -23,7 +23,6 @@
#include "hw.h"
#include "hw-ops.h"
#include "rc.h"
#include "ar9003_mac.h"
#include "ar9003_mci.h"
#include "ar9003_phy.h"

Some files were not shown because too many files have changed in this diff Show More