Signed-off-by: Felix Fietkau <nbd@openwrt.org> SVN-Revision: 46436master
parent
3b17e2ab68
commit
9384cc5951
@ -1,11 +0,0 @@ |
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -2008,7 +2008,7 @@ static int ieee80211_scan(struct wiphy *
|
||||
* the frames sent while scanning on other channel will be
|
||||
* lost)
|
||||
*/
|
||||
- if (sdata->u.ap.beacon &&
|
||||
+ if (0 && sdata->u.ap.beacon &&
|
||||
(!(wiphy->features & NL80211_FEATURE_AP_SCAN) ||
|
||||
!(req->flags & NL80211_SCAN_FLAG_AP)))
|
||||
return -EOPNOTSUPP;
|
@ -1,28 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sun, 21 Jun 2015 19:45:59 +0200
|
||||
Subject: [PATCH] ath9k_hw: fix device ID check for AR956x
|
||||
|
||||
Because of the missing return, the macVersion value was being
|
||||
overwritten with an invalid register read
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
||||
@@ -279,6 +279,7 @@ static void ath9k_hw_read_revisions(stru
|
||||
return;
|
||||
case AR9300_DEVID_QCA956X:
|
||||
ah->hw_version.macVersion = AR_SREV_VERSION_9561;
|
||||
+ return;
|
||||
}
|
||||
|
||||
val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
|
||||
@@ -3169,6 +3170,7 @@ static struct {
|
||||
{ AR_SREV_VERSION_9550, "9550" },
|
||||
{ AR_SREV_VERSION_9565, "9565" },
|
||||
{ AR_SREV_VERSION_9531, "9531" },
|
||||
+ { AR_SREV_VERSION_9561, "956X" },
|
||||
};
|
||||
|
||||
/* For devices with external radios */
|
@ -1,35 +0,0 @@ |
||||
From: Zefir Kurtisi <zefir.kurtisi@neratec.com>
|
||||
Date: Tue, 16 Jun 2015 10:34:03 +0200
|
||||
Subject: [PATCH] ath: DFS - limit number of potential PRI sequences
|
||||
|
||||
In the PRI detector, after the current radar pulse
|
||||
has been checked agains existing PRI sequences, it
|
||||
is considered as part of a new potential sequence.
|
||||
|
||||
Previously, the condition to accept a new sequence
|
||||
was to have at least the same number of pulses as
|
||||
the longest matching sequence. This was wrong,
|
||||
since it led to duplicates of PRI sequences.
|
||||
|
||||
This patch changes the acceptance criteria for new
|
||||
potential sequences from 'at least' to 'more than'
|
||||
the longest existing.
|
||||
|
||||
Detection performance remains unaffected, while
|
||||
the number of PRI sequences accounted at runtime
|
||||
(and with it CPU load) is reduced by up to 50%.
|
||||
|
||||
Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/dfs_pri_detector.c
|
||||
+++ b/drivers/net/wireless/ath/dfs_pri_detector.c
|
||||
@@ -273,7 +273,7 @@ static bool pseq_handler_create_sequence
|
||||
tmp_false_count++;
|
||||
}
|
||||
}
|
||||
- if (ps.count < min_count)
|
||||
+ if (ps.count <= min_count)
|
||||
/* did not reach minimum count, drop sequence */
|
||||
continue;
|
||||
|
@ -1,25 +0,0 @@ |
||||
From: Zefir Kurtisi <zefir.kurtisi@neratec.com>
|
||||
Date: Tue, 16 Jun 2015 11:46:42 +0200
|
||||
Subject: [PATCH] ath9k: DFS - consider ext_channel pulses only in HT40
|
||||
mode
|
||||
|
||||
The chip reports radar pulses on extension channel
|
||||
even if operating in HT20 mode. This patch adds a
|
||||
sanity check for HT40 mode before it feeds pulses
|
||||
on extension channel to the pattern detector.
|
||||
|
||||
Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/dfs.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/dfs.c
|
||||
@@ -198,7 +198,8 @@ void ath9k_dfs_process_phyerr(struct ath
|
||||
sc->dfs_prev_pulse_ts = pe.ts;
|
||||
if (ard.pulse_bw_info & PRI_CH_RADAR_FOUND)
|
||||
ath9k_dfs_process_radar_pulse(sc, &pe);
|
||||
- if (ard.pulse_bw_info & EXT_CH_RADAR_FOUND) {
|
||||
+ if (IS_CHAN_HT40(ah->curchan) &&
|
||||
+ ard.pulse_bw_info & EXT_CH_RADAR_FOUND) {
|
||||
pe.freq += IS_CHAN_HT40PLUS(ah->curchan) ? 20 : -20;
|
||||
ath9k_dfs_process_radar_pulse(sc, &pe);
|
||||
}
|
@ -0,0 +1,17 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Mon, 11 May 2015 18:35:20 +0200
|
||||
Subject: [PATCH] ath9k: add fast-xmit support
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/init.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
||||
@@ -826,6 +826,7 @@ static void ath9k_set_hw_capab(struct at
|
||||
ieee80211_hw_set(hw, SIGNAL_DBM);
|
||||
ieee80211_hw_set(hw, RX_INCLUDES_FCS);
|
||||
ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
|
||||
+ ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
|
||||
|
||||
if (ath9k_ps_enable)
|
||||
ieee80211_hw_set(hw, SUPPORTS_PS);
|
@ -1,211 +0,0 @@ |
||||
From: Zefir Kurtisi <zefir.kurtisi@neratec.com>
|
||||
Date: Tue, 16 Jun 2015 12:52:16 +0200
|
||||
Subject: [PATCH] ath9k: DFS - add pulse chirp detection for FCC
|
||||
|
||||
FCC long pulse radar (type 5) requires pulses to be
|
||||
checked for chirping. This patch implements chirp
|
||||
detection based on the FFT data provided for long
|
||||
pulses.
|
||||
|
||||
A chirp is detected when a set of criteria defined
|
||||
by FCC pulse characteristics is met, including
|
||||
* have at least 4 FFT samples
|
||||
* max_bin index moves equidistantly between samples
|
||||
* the gradient is within defined range
|
||||
|
||||
The chirp detection has been tested with reference
|
||||
radar generating devices and proved to work reliably.
|
||||
|
||||
Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/dfs.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/dfs.c
|
||||
@@ -30,6 +30,157 @@ struct ath_radar_data {
|
||||
u8 pulse_length_pri;
|
||||
};
|
||||
|
||||
+/**** begin: CHIRP ************************************************************/
|
||||
+
|
||||
+/* min and max gradients for defined FCC chirping pulses, given by
|
||||
+ * - 20MHz chirp width over a pulse width of 50us
|
||||
+ * - 5MHz chirp width over a pulse width of 100us
|
||||
+ */
|
||||
+static const int BIN_DELTA_MIN = 1;
|
||||
+static const int BIN_DELTA_MAX = 10;
|
||||
+
|
||||
+/* we need at least 3 deltas / 4 samples for a reliable chirp detection */
|
||||
+#define NUM_DIFFS 3
|
||||
+static const int FFT_NUM_SAMPLES = (NUM_DIFFS + 1);
|
||||
+
|
||||
+/* Threshold for difference of delta peaks */
|
||||
+static const int MAX_DIFF = 2;
|
||||
+
|
||||
+/* width range to be checked for chirping */
|
||||
+static const int MIN_CHIRP_PULSE_WIDTH = 20;
|
||||
+static const int MAX_CHIRP_PULSE_WIDTH = 110;
|
||||
+
|
||||
+struct ath9k_dfs_fft_20 {
|
||||
+ u8 bin[28];
|
||||
+ u8 lower_bins[3];
|
||||
+} __packed;
|
||||
+struct ath9k_dfs_fft_40 {
|
||||
+ u8 bin[64];
|
||||
+ u8 lower_bins[3];
|
||||
+ u8 upper_bins[3];
|
||||
+} __packed;
|
||||
+
|
||||
+static inline int fft_max_index(u8 *bins)
|
||||
+{
|
||||
+ return (bins[2] & 0xfc) >> 2;
|
||||
+}
|
||||
+static inline int fft_max_magnitude(u8 *bins)
|
||||
+{
|
||||
+ return (bins[0] & 0xc0) >> 6 | bins[1] << 2 | (bins[2] & 0x03) << 10;
|
||||
+}
|
||||
+static inline u8 fft_bitmap_weight(u8 *bins)
|
||||
+{
|
||||
+ return bins[0] & 0x3f;
|
||||
+}
|
||||
+
|
||||
+static int ath9k_get_max_index_ht40(struct ath9k_dfs_fft_40 *fft,
|
||||
+ bool is_ctl, bool is_ext)
|
||||
+{
|
||||
+ const int DFS_UPPER_BIN_OFFSET = 64;
|
||||
+ /* if detected radar on both channels, select the significant one */
|
||||
+ if (is_ctl && is_ext) {
|
||||
+ /* first check wether channels have 'strong' bins */
|
||||
+ is_ctl = fft_bitmap_weight(fft->lower_bins) != 0;
|
||||
+ is_ext = fft_bitmap_weight(fft->upper_bins) != 0;
|
||||
+
|
||||
+ /* if still unclear, take higher magnitude */
|
||||
+ if (is_ctl && is_ext) {
|
||||
+ int mag_lower = fft_max_magnitude(fft->lower_bins);
|
||||
+ int mag_upper = fft_max_magnitude(fft->upper_bins);
|
||||
+ if (mag_upper > mag_lower)
|
||||
+ is_ctl = false;
|
||||
+ else
|
||||
+ is_ext = false;
|
||||
+ }
|
||||
+ }
|
||||
+ if (is_ctl)
|
||||
+ return fft_max_index(fft->lower_bins);
|
||||
+ return fft_max_index(fft->upper_bins) + DFS_UPPER_BIN_OFFSET;
|
||||
+}
|
||||
+static bool ath9k_check_chirping(struct ath_softc *sc, u8 *data,
|
||||
+ int datalen, bool is_ctl, bool is_ext)
|
||||
+{
|
||||
+ int i;
|
||||
+ int max_bin[FFT_NUM_SAMPLES];
|
||||
+ struct ath_hw *ah = sc->sc_ah;
|
||||
+ struct ath_common *common = ath9k_hw_common(ah);
|
||||
+ int prev_delta;
|
||||
+
|
||||
+ if (IS_CHAN_HT40(ah->curchan)) {
|
||||
+ struct ath9k_dfs_fft_40 *fft = (struct ath9k_dfs_fft_40 *) data;
|
||||
+ int num_fft_packets = datalen / sizeof(*fft);
|
||||
+ if (num_fft_packets == 0)
|
||||
+ return false;
|
||||
+
|
||||
+ ath_dbg(common, DFS, "HT40: datalen=%d, num_fft_packets=%d\n",
|
||||
+ datalen, num_fft_packets);
|
||||
+ if (num_fft_packets < (FFT_NUM_SAMPLES)) {
|
||||
+ ath_dbg(common, DFS, "not enough packets for chirp\n");
|
||||
+ return false;
|
||||
+ }
|
||||
+ /* HW sometimes adds 2 garbage bytes in front of FFT samples */
|
||||
+ if ((datalen % sizeof(*fft)) == 2) {
|
||||
+ fft = (struct ath9k_dfs_fft_40 *) (data + 2);
|
||||
+ ath_dbg(common, DFS, "fixing datalen by 2\n");
|
||||
+ }
|
||||
+ if (IS_CHAN_HT40MINUS(ah->curchan)) {
|
||||
+ int temp = is_ctl;
|
||||
+ is_ctl = is_ext;
|
||||
+ is_ext = temp;
|
||||
+ }
|
||||
+ for (i = 0; i < FFT_NUM_SAMPLES; i++)
|
||||
+ max_bin[i] = ath9k_get_max_index_ht40(fft + i, is_ctl,
|
||||
+ is_ext);
|
||||
+ } else {
|
||||
+ struct ath9k_dfs_fft_20 *fft = (struct ath9k_dfs_fft_20 *) data;
|
||||
+ int num_fft_packets = datalen / sizeof(*fft);
|
||||
+ if (num_fft_packets == 0)
|
||||
+ return false;
|
||||
+ ath_dbg(common, DFS, "HT20: datalen=%d, num_fft_packets=%d\n",
|
||||
+ datalen, num_fft_packets);
|
||||
+ if (num_fft_packets < (FFT_NUM_SAMPLES)) {
|
||||
+ ath_dbg(common, DFS, "not enough packets for chirp\n");
|
||||
+ return false;
|
||||
+ }
|
||||
+ /* in ht20, this is a 6-bit signed number => shift it to 0 */
|
||||
+ for (i = 0; i < FFT_NUM_SAMPLES; i++)
|
||||
+ max_bin[i] = fft_max_index(fft[i].lower_bins) ^ 0x20;
|
||||
+ }
|
||||
+ ath_dbg(common, DFS, "bin_max = [%d, %d, %d, %d]\n",
|
||||
+ max_bin[0], max_bin[1], max_bin[2], max_bin[3]);
|
||||
+
|
||||
+ /* Check for chirp attributes within specs
|
||||
+ * a) delta of adjacent max_bins is within range
|
||||
+ * b) delta of adjacent deltas are within tolerance
|
||||
+ */
|
||||
+ prev_delta = 0;
|
||||
+ for (i = 0; i < NUM_DIFFS; i++) {
|
||||
+ int ddelta = -1;
|
||||
+ int delta = max_bin[i + 1] - max_bin[i];
|
||||
+
|
||||
+ /* ensure gradient is within valid range */
|
||||
+ if (abs(delta) < BIN_DELTA_MIN || abs(delta) > BIN_DELTA_MAX) {
|
||||
+ ath_dbg(common, DFS, "CHIRP: invalid delta %d "
|
||||
+ "in sample %d\n", delta, i);
|
||||
+ return false;
|
||||
+ }
|
||||
+ if (i == 0)
|
||||
+ goto done;
|
||||
+ ddelta = delta - prev_delta;
|
||||
+ if (abs(ddelta) > MAX_DIFF) {
|
||||
+ ath_dbg(common, DFS, "CHIRP: ddelta %d too high\n",
|
||||
+ ddelta);
|
||||
+ return false;
|
||||
+ }
|
||||
+done:
|
||||
+ ath_dbg(common, DFS, "CHIRP - %d: delta=%d, ddelta=%d\n",
|
||||
+ i, delta, ddelta);
|
||||
+ prev_delta = delta;
|
||||
+ }
|
||||
+ return true;
|
||||
+}
|
||||
+/**** end: CHIRP **************************************************************/
|
||||
+
|
||||
/* convert pulse duration to usecs, considering clock mode */
|
||||
static u32 dur_to_usecs(struct ath_hw *ah, u32 dur)
|
||||
{
|
||||
@@ -113,12 +264,6 @@ ath9k_postprocess_radar_event(struct ath
|
||||
return false;
|
||||
}
|
||||
|
||||
- /*
|
||||
- * TODO: check chirping pulses
|
||||
- * checks for chirping are dependent on the DFS regulatory domain
|
||||
- * used, which is yet TBD
|
||||
- */
|
||||
-
|
||||
/* convert duration to usecs */
|
||||
pe->width = dur_to_usecs(sc->sc_ah, dur);
|
||||
pe->rssi = rssi;
|
||||
@@ -190,6 +335,16 @@ void ath9k_dfs_process_phyerr(struct ath
|
||||
if (!ath9k_postprocess_radar_event(sc, &ard, &pe))
|
||||
return;
|
||||
|
||||
+ if (pe.width > MIN_CHIRP_PULSE_WIDTH &&
|
||||
+ pe.width < MAX_CHIRP_PULSE_WIDTH) {
|
||||
+ bool is_ctl = !!(ard.pulse_bw_info & PRI_CH_RADAR_FOUND);
|
||||
+ bool is_ext = !!(ard.pulse_bw_info & EXT_CH_RADAR_FOUND);
|
||||
+ int clen = datalen - 3;
|
||||
+ pe.chirp = ath9k_check_chirping(sc, data, clen, is_ctl, is_ext);
|
||||
+ } else {
|
||||
+ pe.chirp = false;
|
||||
+ }
|
||||
+
|
||||
ath_dbg(common, DFS,
|
||||
"ath9k_dfs_process_phyerr: type=%d, freq=%d, ts=%llu, "
|
||||
"width=%d, rssi=%d, delta_ts=%llu\n",
|
@ -0,0 +1,385 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sat, 4 Apr 2015 18:39:06 +0200
|
||||
Subject: [PATCH] ath9k: remove struct ath_atx_ac
|
||||
|
||||
struct ath_atx_ac contains a list of active TIDs belonging to one WMM AC.
|
||||
This patch changes the code to track active station TIDs in the txq directly.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
|
||||
@@ -173,14 +173,6 @@ struct ath_txq {
|
||||
struct sk_buff_head complete_q;
|
||||
};
|
||||
|
||||
-struct ath_atx_ac {
|
||||
- struct ath_txq *txq;
|
||||
- struct list_head list;
|
||||
- struct list_head tid_q;
|
||||
- bool clear_ps_filter;
|
||||
- bool sched;
|
||||
-};
|
||||
-
|
||||
struct ath_frame_info {
|
||||
struct ath_buf *bf;
|
||||
u16 framelen;
|
||||
@@ -243,7 +235,7 @@ struct ath_atx_tid {
|
||||
struct sk_buff_head buf_q;
|
||||
struct sk_buff_head retry_q;
|
||||
struct ath_node *an;
|
||||
- struct ath_atx_ac *ac;
|
||||
+ struct ath_txq *txq;
|
||||
unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)];
|
||||
u16 seq_start;
|
||||
u16 seq_next;
|
||||
@@ -255,6 +247,7 @@ struct ath_atx_tid {
|
||||
s8 bar_index;
|
||||
bool sched;
|
||||
bool active;
|
||||
+ bool clear_ps_filter;
|
||||
};
|
||||
|
||||
struct ath_node {
|
||||
@@ -262,7 +255,6 @@ struct ath_node {
|
||||
struct ieee80211_sta *sta; /* station struct we're part of */
|
||||
struct ieee80211_vif *vif; /* interface with which we're associated */
|
||||
struct ath_atx_tid tid[IEEE80211_NUM_TIDS];
|
||||
- struct ath_atx_ac ac[IEEE80211_NUM_ACS];
|
||||
|
||||
u16 maxampdu;
|
||||
u8 mpdudensity;
|
||||
--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
||||
@@ -106,7 +106,6 @@ void ath_txq_unlock_complete(struct ath_
|
||||
static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq,
|
||||
struct ath_atx_tid *tid)
|
||||
{
|
||||
- struct ath_atx_ac *ac = tid->ac;
|
||||
struct list_head *list;
|
||||
struct ath_vif *avp = (struct ath_vif *) tid->an->vif->drv_priv;
|
||||
struct ath_chanctx *ctx = avp->chanctx;
|
||||
@@ -118,15 +117,8 @@ static void ath_tx_queue_tid(struct ath_
|
||||
return;
|
||||
|
||||
tid->sched = true;
|
||||
- list_add_tail(&tid->list, &ac->tid_q);
|
||||
-
|
||||
- if (ac->sched)
|
||||
- return;
|
||||
-
|
||||
- ac->sched = true;
|
||||
-
|
||||
list = &ctx->acq[TID_TO_WME_AC(tid->tidno)];
|
||||
- list_add_tail(&ac->list, list);
|
||||
+ list_add_tail(&tid->list, list);
|
||||
}
|
||||
|
||||
static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
|
||||
@@ -223,7 +215,7 @@ static struct sk_buff *ath_tid_dequeue(s
|
||||
static void
|
||||
ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid)
|
||||
{
|
||||
- struct ath_txq *txq = tid->ac->txq;
|
||||
+ struct ath_txq *txq = tid->txq;
|
||||
struct ieee80211_tx_info *tx_info;
|
||||
struct sk_buff *skb, *tskb;
|
||||
struct ath_buf *bf;
|
||||
@@ -252,7 +244,7 @@ ath_tx_tid_change_state(struct ath_softc
|
||||
|
||||
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
|
||||
{
|
||||
- struct ath_txq *txq = tid->ac->txq;
|
||||
+ struct ath_txq *txq = tid->txq;
|
||||
struct sk_buff *skb;
|
||||
struct ath_buf *bf;
|
||||
struct list_head bf_head;
|
||||
@@ -659,7 +651,7 @@ static void ath_tx_complete_aggr(struct
|
||||
ath_tx_queue_tid(sc, txq, tid);
|
||||
|
||||
if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY))
|
||||
- tid->ac->clear_ps_filter = true;
|
||||
+ tid->clear_ps_filter = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -749,7 +741,7 @@ static u32 ath_lookup_rate(struct ath_so
|
||||
struct ieee80211_tx_rate *rates;
|
||||
u32 max_4ms_framelen, frmlen;
|
||||
u16 aggr_limit, bt_aggr_limit, legacy = 0;
|
||||
- int q = tid->ac->txq->mac80211_qnum;
|
||||
+ int q = tid->txq->mac80211_qnum;
|
||||
int i;
|
||||
|
||||
skb = bf->bf_mpdu;
|
||||
@@ -1486,8 +1478,8 @@ static bool ath_tx_sched_aggr(struct ath
|
||||
if (list_empty(&bf_q))
|
||||
return false;
|
||||
|
||||
- if (tid->ac->clear_ps_filter || tid->an->no_ps_filter) {
|
||||
- tid->ac->clear_ps_filter = false;
|
||||
+ if (tid->clear_ps_filter || tid->an->no_ps_filter) {
|
||||
+ tid->clear_ps_filter = false;
|
||||
tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
|
||||
}
|
||||
|
||||
@@ -1506,7 +1498,7 @@ int ath_tx_aggr_start(struct ath_softc *
|
||||
|
||||
an = (struct ath_node *)sta->drv_priv;
|
||||
txtid = ATH_AN_2_TID(an, tid);
|
||||
- txq = txtid->ac->txq;
|
||||
+ txq = txtid->txq;
|
||||
|
||||
ath_txq_lock(sc, txq);
|
||||
|
||||
@@ -1540,7 +1532,7 @@ void ath_tx_aggr_stop(struct ath_softc *
|
||||
{
|
||||
struct ath_node *an = (struct ath_node *)sta->drv_priv;
|
||||
struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
|
||||
- struct ath_txq *txq = txtid->ac->txq;
|
||||
+ struct ath_txq *txq = txtid->txq;
|
||||
|
||||
ath_txq_lock(sc, txq);
|
||||
txtid->active = false;
|
||||
@@ -1553,7 +1545,6 @@ void ath_tx_aggr_sleep(struct ieee80211_
|
||||
struct ath_node *an)
|
||||
{
|
||||
struct ath_atx_tid *tid;
|
||||
- struct ath_atx_ac *ac;
|
||||
struct ath_txq *txq;
|
||||
bool buffered;
|
||||
int tidno;
|
||||
@@ -1561,8 +1552,7 @@ void ath_tx_aggr_sleep(struct ieee80211_
|
||||
for (tidno = 0, tid = &an->tid[tidno];
|
||||
tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
|
||||
|
||||
- ac = tid->ac;
|
||||
- txq = ac->txq;
|
||||
+ txq = tid->txq;
|
||||
|
||||
ath_txq_lock(sc, txq);
|
||||
|
||||
@@ -1576,11 +1566,6 @@ void ath_tx_aggr_sleep(struct ieee80211_
|
||||
tid->sched = false;
|
||||
list_del(&tid->list);
|
||||
|
||||
- if (ac->sched) {
|
||||
- ac->sched = false;
|
||||
- list_del(&ac->list);
|
||||
- }
|
||||
-
|
||||
ath_txq_unlock(sc, txq);
|
||||
|
||||
ieee80211_sta_set_buffered(sta, tidno, buffered);
|
||||
@@ -1590,18 +1575,16 @@ void ath_tx_aggr_sleep(struct ieee80211_
|
||||
void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
|
||||
{
|
||||
struct ath_atx_tid *tid;
|
||||
- struct ath_atx_ac *ac;
|
||||
struct ath_txq *txq;
|
||||
int tidno;
|
||||
|
||||
for (tidno = 0, tid = &an->tid[tidno];
|
||||
tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
|
||||
|
||||
- ac = tid->ac;
|
||||
- txq = ac->txq;
|
||||
+ txq = tid->txq;
|
||||
|
||||
ath_txq_lock(sc, txq);
|
||||
- ac->clear_ps_filter = true;
|
||||
+ tid->clear_ps_filter = true;
|
||||
|
||||
if (ath_tid_has_buffered(tid)) {
|
||||
ath_tx_queue_tid(sc, txq, tid);
|
||||
@@ -1621,7 +1604,7 @@ void ath_tx_aggr_resume(struct ath_softc
|
||||
|
||||
an = (struct ath_node *)sta->drv_priv;
|
||||
tid = ATH_AN_2_TID(an, tidno);
|
||||
- txq = tid->ac->txq;
|
||||
+ txq = tid->txq;
|
||||
|
||||
ath_txq_lock(sc, txq);
|
||||
|
||||
@@ -1660,7 +1643,7 @@ void ath9k_release_buffered_frames(struc
|
||||
|
||||
tid = ATH_AN_2_TID(an, i);
|
||||
|
||||
- ath_txq_lock(sc, tid->ac->txq);
|
||||
+ ath_txq_lock(sc, tid->txq);
|
||||
while (nframes > 0) {
|
||||
bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q);
|
||||
if (!bf)
|
||||
@@ -1684,7 +1667,7 @@ void ath9k_release_buffered_frames(struc
|
||||
if (an->sta && !ath_tid_has_buffered(tid))
|
||||
ieee80211_sta_set_buffered(an->sta, i, false);
|
||||
}
|
||||
- ath_txq_unlock_complete(sc, tid->ac->txq);
|
||||
+ ath_txq_unlock_complete(sc, tid->txq);
|
||||
}
|
||||
|
||||
if (list_empty(&bf_q))
|
||||
@@ -1933,9 +1916,8 @@ void ath_tx_cleanupq(struct ath_softc *s
|
||||
void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
- struct ath_atx_ac *ac, *last_ac;
|
||||
struct ath_atx_tid *tid, *last_tid;
|
||||
- struct list_head *ac_list;
|
||||
+ struct list_head *tid_list;
|
||||
bool sent = false;
|
||||
|
||||
if (txq->mac80211_qnum < 0)
|
||||
@@ -1945,63 +1927,46 @@ void ath_txq_schedule(struct ath_softc *
|
||||
return;
|
||||
|
||||
spin_lock_bh(&sc->chan_lock);
|
||||
- ac_list = &sc->cur_chan->acq[txq->mac80211_qnum];
|
||||
+ tid_list = &sc->cur_chan->acq[txq->mac80211_qnum];
|
||||
|
||||
- if (list_empty(ac_list)) {
|
||||
+ if (list_empty(tid_list)) {
|
||||
spin_unlock_bh(&sc->chan_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
- last_ac = list_entry(ac_list->prev, struct ath_atx_ac, list);
|
||||
- while (!list_empty(ac_list)) {
|
||||
+ last_tid = list_entry(tid_list->prev, struct ath_atx_tid, list);
|
||||
+ while (!list_empty(tid_list)) {
|
||||
bool stop = false;
|
||||
|
||||
if (sc->cur_chan->stopped)
|
||||
break;
|
||||
|
||||
- ac = list_first_entry(ac_list, struct ath_atx_ac, list);
|
||||
- last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list);
|
||||
- list_del(&ac->list);
|
||||
- ac->sched = false;
|
||||
-
|
||||
- while (!list_empty(&ac->tid_q)) {
|
||||
-
|
||||
- tid = list_first_entry(&ac->tid_q, struct ath_atx_tid,
|
||||
- list);
|
||||
- list_del(&tid->list);
|
||||
- tid->sched = false;
|
||||
-
|
||||
- if (ath_tx_sched_aggr(sc, txq, tid, &stop))
|
||||
- sent = true;
|
||||
-
|
||||
- /*
|
||||
- * add tid to round-robin queue if more frames
|
||||
- * are pending for the tid
|
||||
- */
|
||||
- if (ath_tid_has_buffered(tid))
|
||||
- ath_tx_queue_tid(sc, txq, tid);
|
||||
+ tid = list_first_entry(tid_list, struct ath_atx_tid, list);
|
||||
+ list_del(&tid->list);
|
||||
+ tid->sched = false;
|
||||
|
||||
- if (stop || tid == last_tid)
|
||||
- break;
|
||||
- }
|
||||
+ if (ath_tx_sched_aggr(sc, txq, tid, &stop))
|
||||
+ sent = true;
|
||||
|
||||
- if (!list_empty(&ac->tid_q) && !ac->sched) {
|
||||
- ac->sched = true;
|
||||
- list_add_tail(&ac->list, ac_list);
|
||||
- }
|
||||
+ /*
|
||||
+ * add tid to round-robin queue if more frames
|
||||
+ * are pending for the tid
|
||||
+ */
|
||||
+ if (ath_tid_has_buffered(tid))
|
||||
+ ath_tx_queue_tid(sc, txq, tid);
|
||||
|
||||
if (stop)
|
||||
break;
|
||||
|
||||
- if (ac == last_ac) {
|
||||
+ if (tid == last_tid) {
|
||||
if (!sent)
|
||||
break;
|
||||
|
||||
sent = false;
|
||||
- last_ac = list_entry(ac_list->prev,
|
||||
- struct ath_atx_ac, list);
|
||||
+ last_tid = list_entry(tid_list->prev,
|
||||
+ struct ath_atx_tid, list);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2391,10 +2356,10 @@ int ath_tx_start(struct ieee80211_hw *hw
|
||||
txq = sc->tx.uapsdq;
|
||||
ath_txq_lock(sc, txq);
|
||||
} else if (txctl->an && queue) {
|
||||
- WARN_ON(tid->ac->txq != txctl->txq);
|
||||
+ WARN_ON(tid->txq != txctl->txq);
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
|
||||
- tid->ac->clear_ps_filter = true;
|
||||
+ tid->clear_ps_filter = true;
|
||||
|
||||
/*
|
||||
* Add this frame to software queue for scheduling later
|
||||
@@ -2888,7 +2853,6 @@ int ath_tx_init(struct ath_softc *sc, in
|
||||
void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
|
||||
{
|
||||
struct ath_atx_tid *tid;
|
||||
- struct ath_atx_ac *ac;
|
||||
int tidno, acno;
|
||||
|
||||
for (tidno = 0, tid = &an->tid[tidno];
|
||||
@@ -2901,24 +2865,16 @@ void ath_tx_node_init(struct ath_softc *
|
||||
tid->baw_head = tid->baw_tail = 0;
|
||||
tid->sched = false;
|
||||
tid->active = false;
|
||||
+ tid->clear_ps_filter = true;
|
||||
__skb_queue_head_init(&tid->buf_q);
|
||||
__skb_queue_head_init(&tid->retry_q);
|
||||
acno = TID_TO_WME_AC(tidno);
|
||||
- tid->ac = &an->ac[acno];
|
||||
- }
|
||||
-
|
||||
- for (acno = 0, ac = &an->ac[acno];
|
||||
- acno < IEEE80211_NUM_ACS; acno++, ac++) {
|
||||
- ac->sched = false;
|
||||
- ac->clear_ps_filter = true;
|
||||
- ac->txq = sc->tx.txq_map[acno];
|
||||
- INIT_LIST_HEAD(&ac->tid_q);
|
||||
+ tid->txq = sc->tx.txq_map[acno];
|
||||
}
|
||||
}
|
||||
|
||||
void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
|
||||
{
|
||||
- struct ath_atx_ac *ac;
|
||||
struct ath_atx_tid *tid;
|
||||
struct ath_txq *txq;
|
||||
int tidno;
|
||||
@@ -2926,8 +2882,7 @@ void ath_tx_node_cleanup(struct ath_soft
|
||||
for (tidno = 0, tid = &an->tid[tidno];
|
||||
tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
|
||||
|
||||
- ac = tid->ac;
|
||||
- txq = ac->txq;
|
||||
+ txq = tid->txq;
|
||||
|
||||
ath_txq_lock(sc, txq);
|
||||
|
||||
@@ -2936,11 +2891,6 @@ void ath_tx_node_cleanup(struct ath_soft
|
||||
tid->sched = false;
|
||||
}
|
||||
|
||||
- if (ac->sched) {
|
||||
- list_del(&ac->list);
|
||||
- tid->ac->sched = false;
|
||||
- }
|
||||
-
|
||||
ath_tid_drain(sc, txq, tid);
|
||||
tid->active = false;
|
||||
|
@ -1,74 +0,0 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Thu, 2 Jul 2015 13:35:05 +0200
|
||||
Subject: [PATCH] ath9k: make DMA stop related messages debug-only
|
||||
|
||||
A long time ago, ath9k had issues during reset where the DMA engine
|
||||
would stay active and could potentially corrupt memory.
|
||||
To debug those issues, the driver would print warnings whenever they
|
||||
occur.
|
||||
|
||||
Nowadays, these issues are gone and the primary cause of these messages
|
||||
is if the MAC is stuck during reset or busy processing a long
|
||||
transmission. This is fairly harmless, yet these messages continue to
|
||||
worry users.
|
||||
|
||||
To reduce the number of bogus bug reports, turn these messages into
|
||||
debug messages and count their occurence in the "reset" debugfs file.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/debug.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/debug.c
|
||||
@@ -765,6 +765,8 @@ static int read_file_reset(struct seq_fi
|
||||
[RESET_TYPE_BEACON_STUCK] = "Stuck Beacon",
|
||||
[RESET_TYPE_MCI] = "MCI Reset",
|
||||
[RESET_TYPE_CALIBRATION] = "Calibration error",
|
||||
+ [RESET_TX_DMA_ERROR] = "Tx DMA stop error",
|
||||
+ [RESET_RX_DMA_ERROR] = "Rx DMA stop error",
|
||||
};
|
||||
int i;
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/debug.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/debug.h
|
||||
@@ -50,6 +50,8 @@ enum ath_reset_type {
|
||||
RESET_TYPE_BEACON_STUCK,
|
||||
RESET_TYPE_MCI,
|
||||
RESET_TYPE_CALIBRATION,
|
||||
+ RESET_TX_DMA_ERROR,
|
||||
+ RESET_RX_DMA_ERROR,
|
||||
__RESET_TYPE_MAX
|
||||
};
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/recv.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/recv.c
|
||||
@@ -491,10 +491,9 @@ bool ath_stoprecv(struct ath_softc *sc)
|
||||
|
||||
if (!(ah->ah_flags & AH_UNPLUGGED) &&
|
||||
unlikely(!stopped)) {
|
||||
- ath_err(ath9k_hw_common(sc->sc_ah),
|
||||
- "Could not stop RX, we could be "
|
||||
- "confusing the DMA engine when we start RX up\n");
|
||||
- ATH_DBG_WARN_ON_ONCE(!stopped);
|
||||
+ ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
|
||||
+ "Failed to stop Rx DMA\n");
|
||||
+ RESET_STAT_INC(sc, RESET_RX_DMA_ERROR);
|
||||
}
|
||||
return stopped && !reset;
|
||||
}
|
||||
--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
||||
@@ -1883,8 +1883,11 @@ bool ath_drain_all_txq(struct ath_softc
|
||||
npend |= BIT(i);
|
||||
}
|
||||
|
||||
- if (npend)
|
||||
- ath_err(common, "Failed to stop TX DMA, queues=0x%03x!\n", npend);
|
||||
+ if (npend) {
|
||||
+ RESET_STAT_INC(sc, RESET_TX_DMA_ERROR);
|
||||
+ ath_dbg(common, RESET,
|
||||
+ "Failed to stop TX DMA, queues=0x%03x!\n", npend);
|
||||
+ }
|
||||
|
||||
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
|
||||
if (!ATH_TXQ_SETUP(sc, i))
|
@ -0,0 +1,90 @@ |
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sat, 4 Apr 2015 18:42:33 +0200
|
||||
Subject: [PATCH] ath9k: remove the sched field in struct ath_atx_tid
|
||||
|
||||
Use list_empty(&tid->list) instead
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
|
||||
@@ -245,7 +245,6 @@ struct ath_atx_tid {
|
||||
int baw_tail; /* next unused tx buffer slot */
|
||||
|
||||
s8 bar_index;
|
||||
- bool sched;
|
||||
bool active;
|
||||
bool clear_ps_filter;
|
||||
};
|
||||
--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
||||
@@ -113,12 +113,9 @@ static void ath_tx_queue_tid(struct ath_
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
- if (tid->sched)
|
||||
- return;
|
||||
-
|
||||
- tid->sched = true;
|
||||
list = &ctx->acq[TID_TO_WME_AC(tid->tidno)];
|
||||
- list_add_tail(&tid->list, list);
|
||||
+ if (list_empty(&tid->list))
|
||||
+ list_add_tail(&tid->list, list);
|
||||
}
|
||||
|
||||
static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
|
||||
@@ -1556,15 +1553,14 @@ void ath_tx_aggr_sleep(struct ieee80211_
|
||||
|
||||
ath_txq_lock(sc, txq);
|
||||
|
||||
- if (!tid->sched) {
|
||||
+ if (list_empty(&tid->list)) {
|
||||
ath_txq_unlock(sc, txq);
|
||||
continue;
|
||||
}
|
||||
|
||||
buffered = ath_tid_has_buffered(tid);
|
||||
|
||||
- tid->sched = false;
|
||||
- list_del(&tid->list);
|
||||
+ list_del_init(&tid->list);
|
||||
|
||||
ath_txq_unlock(sc, txq);
|
||||
|
||||
@@ -1944,8 +1940,7 @@ void ath_txq_schedule(struct ath_softc *
|
||||
break;
|
||||
|
||||
tid = list_first_entry(tid_list, struct ath_atx_tid, list);
|
||||
- list_del(&tid->list);
|
||||
- tid->sched = false;
|
||||
+ list_del_init(&tid->list);
|
||||
|
||||
if (ath_tx_sched_aggr(sc, txq, tid, &stop))
|
||||
sent = true;
|
||||
@@ -2863,11 +2858,11 @@ void ath_tx_node_init(struct ath_softc *
|
||||
tid->seq_start = tid->seq_next = 0;
|
||||
tid->baw_size = WME_MAX_BA;
|
||||
tid->baw_head = tid->baw_tail = 0;
|
||||
- tid->sched = false;
|
||||
tid->active = false;
|
||||
tid->clear_ps_filter = true;
|
||||
__skb_queue_head_init(&tid->buf_q);
|
||||
__skb_queue_head_init(&tid->retry_q);
|
||||
+ INIT_LIST_HEAD(&tid->list);
|
||||
acno = TID_TO_WME_AC(tidno);
|
||||
tid->txq = sc->tx.txq_map[acno];
|
||||
}
|
||||
@@ -2886,10 +2881,8 @@ void ath_tx_node_cleanup(struct ath_soft
|
||||
|
||||
ath_txq_lock(sc, txq);
|
||||
|
||||
- if (tid->sched) {
|
||||
- list_del(&tid->list);
|
||||
- tid->sched = false;
|
||||
- }
|
||||
+ if (!list_empty(&tid->list))
|
||||
+ list_del_init(&tid->list);
|
||||
|
||||
ath_tid_drain(sc, txq, tid);
|
||||
tid->active = false;
|
@ -0,0 +1,161 @@ |
||||
From: Denys Vlasenko <dvlasenk@redhat.com>
|
||||
Date: Wed, 15 Jul 2015 14:56:06 +0200
|
||||
Subject: [PATCH] mac80211: Deinline rate_control_rate_init,
|
||||
rate_control_rate_update
|
||||
|
||||
With this .config: http://busybox.net/~vda/kernel_config,
|
||||
after deinlining these functions have sizes and callsite counts
|
||||
as follows:
|
||||
|
||||
rate_control_rate_init: 554 bytes, 8 calls
|
||||
rate_control_rate_update: 1596 bytes, 5 calls
|
||||
|
||||
Total size reduction: about 11 kbytes.
|
||||
|
||||
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
|
||||
CC: John Linville <linville@tuxdriver.com>
|
||||
CC: Michal Kazior <michal.kazior@tieto.com>
|
||||
CC: Johannes Berg <johannes.berg@intel.com>
|
||||
Cc: linux-wireless@vger.kernel.org
|
||||
Cc: netdev@vger.kernel.org
|
||||
CC: linux-kernel@vger.kernel.org
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rate.c
|
||||
+++ b/net/mac80211/rate.c
|
||||
@@ -29,6 +29,65 @@ module_param(ieee80211_default_rc_algo,
|
||||
MODULE_PARM_DESC(ieee80211_default_rc_algo,
|
||||
"Default rate control algorithm for mac80211 to use");
|
||||
|
||||
+void rate_control_rate_init(struct sta_info *sta)
|
||||
+{
|
||||
+ struct ieee80211_local *local = sta->sdata->local;
|
||||
+ struct rate_control_ref *ref = sta->rate_ctrl;
|
||||
+ struct ieee80211_sta *ista = &sta->sta;
|
||||
+ void *priv_sta = sta->rate_ctrl_priv;
|
||||
+ struct ieee80211_supported_band *sband;
|
||||
+ struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
+
|
||||
+ ieee80211_sta_set_rx_nss(sta);
|
||||
+
|
||||
+ if (!ref)
|
||||
+ return;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+
|
||||
+ chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf);
|
||||
+ if (WARN_ON(!chanctx_conf)) {
|
||||
+ rcu_read_unlock();
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band];
|
||||
+
|
||||
+ spin_lock_bh(&sta->rate_ctrl_lock);
|
||||
+ ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista,
|
||||
+ priv_sta);
|
||||
+ spin_unlock_bh(&sta->rate_ctrl_lock);
|
||||
+ rcu_read_unlock();
|
||||
+ set_sta_flag(sta, WLAN_STA_RATE_CONTROL);
|
||||
+}
|
||||
+
|
||||
+void rate_control_rate_update(struct ieee80211_local *local,
|
||||
+ struct ieee80211_supported_band *sband,
|
||||
+ struct sta_info *sta, u32 changed)
|
||||
+{
|
||||
+ struct rate_control_ref *ref = local->rate_ctrl;
|
||||
+ struct ieee80211_sta *ista = &sta->sta;
|
||||
+ void *priv_sta = sta->rate_ctrl_priv;
|
||||
+ struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
+
|
||||
+ if (ref && ref->ops->rate_update) {
|
||||
+ rcu_read_lock();
|
||||
+
|
||||
+ chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf);
|
||||
+ if (WARN_ON(!chanctx_conf)) {
|
||||
+ rcu_read_unlock();
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ spin_lock_bh(&sta->rate_ctrl_lock);
|
||||
+ ref->ops->rate_update(ref->priv, sband, &chanctx_conf->def,
|
||||
+ ista, priv_sta, changed);
|
||||
+ spin_unlock_bh(&sta->rate_ctrl_lock);
|
||||
+ rcu_read_unlock();
|
||||
+ }
|
||||
+ drv_sta_rc_update(local, sta->sdata, &sta->sta, changed);
|
||||
+}
|
||||
+
|
||||
int ieee80211_rate_control_register(const struct rate_control_ops *ops)
|
||||
{
|
||||
struct rate_control_alg *alg;
|
||||
--- a/net/mac80211/rate.h
|
||||
+++ b/net/mac80211/rate.h
|
||||
@@ -71,64 +71,10 @@ rate_control_tx_status_noskb(struct ieee
|
||||
spin_unlock_bh(&sta->rate_ctrl_lock);
|
||||
}
|
||||
|
||||
-static inline void rate_control_rate_init(struct sta_info *sta)
|
||||
-{
|
||||
- struct ieee80211_local *local = sta->sdata->local;
|
||||
- struct rate_control_ref *ref = sta->rate_ctrl;
|
||||
- struct ieee80211_sta *ista = &sta->sta;
|
||||
- void *priv_sta = sta->rate_ctrl_priv;
|
||||
- struct ieee80211_supported_band *sband;
|
||||
- struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
-
|
||||
- ieee80211_sta_set_rx_nss(sta);
|
||||
-
|
||||
- if (!ref)
|
||||
- return;
|
||||
-
|
||||
- rcu_read_lock();
|
||||
-
|
||||
- chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf);
|
||||
- if (WARN_ON(!chanctx_conf)) {
|
||||
- rcu_read_unlock();
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band];
|
||||
-
|
||||
- spin_lock_bh(&sta->rate_ctrl_lock);
|
||||
- ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista,
|
||||
- priv_sta);
|
||||
- spin_unlock_bh(&sta->rate_ctrl_lock);
|
||||
- rcu_read_unlock();
|
||||
- set_sta_flag(sta, WLAN_STA_RATE_CONTROL);
|
||||
-}
|
||||
-
|
||||
-static inline void rate_control_rate_update(struct ieee80211_local *local,
|
||||
+void rate_control_rate_init(struct sta_info *sta);
|
||||
+void rate_control_rate_update(struct ieee80211_local *local,
|
||||
struct ieee80211_supported_band *sband,
|
||||
- struct sta_info *sta, u32 changed)
|
||||
-{
|
||||
- struct rate_control_ref *ref = local->rate_ctrl;
|
||||
- struct ieee80211_sta *ista = &sta->sta;
|
||||
- void *priv_sta = sta->rate_ctrl_priv;
|
||||
- struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
-
|
||||
- if (ref && ref->ops->rate_update) {
|
||||
- rcu_read_lock();
|
||||
-
|
||||
- chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf);
|
||||
- if (WARN_ON(!chanctx_conf)) {
|
||||
- rcu_read_unlock();
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- spin_lock_bh(&sta->rate_ctrl_lock);
|
||||
- ref->ops->rate_update(ref->priv, sband, &chanctx_conf->def,
|
||||
- ista, priv_sta, changed);
|
||||
- spin_unlock_bh(&sta->rate_ctrl_lock);
|
||||
- rcu_read_unlock();
|
||||
- }
|
||||
- drv_sta_rc_update(local, sta->sdata, &sta->sta, changed);
|
||||
-}
|
||||
+ struct sta_info *sta, u32 changed);
|
||||
|
||||
static inline void *rate_control_alloc_sta(struct rate_control_ref *ref,
|
||||
struct sta_info *sta, gfp_t gfp)
|
@ -0,0 +1,116 @@ |
||||
From: Denys Vlasenko <dvlasenk@redhat.com>
|
||||
Date: Wed, 15 Jul 2015 14:56:05 +0200
|
||||
Subject: [PATCH] mac80211: Deinline drv_sta_state
|
||||
|
||||
With this .config: http://busybox.net/~vda/kernel_config,
|
||||
after deinlining the function size is 3132 bytes and there are
|
||||
7 callsites.
|
||||
|
||||
Total size reduction: about 20 kbytes.
|
||||
|
||||
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
|
||||
CC: John Linville <linville@tuxdriver.com>
|
||||
CC: Michal Kazior <michal.kazior@tieto.com>
|
||||
Cc: Johannes Berg <johannes.berg@intel.com>
|
||||
Cc: linux-wireless@vger.kernel.org
|
||||
Cc: netdev@vger.kernel.org
|
||||
CC: linux-kernel@vger.kernel.org
|
||||
---
|
||||
create mode 100644 net/mac80211/driver-ops.c
|
||||
|
||||
--- a/net/mac80211/Makefile
|
||||
+++ b/net/mac80211/Makefile
|
||||
@@ -3,6 +3,7 @@ obj-$(CPTCFG_MAC80211) += mac80211.o
|
||||
# mac80211 objects
|
||||
mac80211-y := \
|
||||
main.o status.o \
|
||||
+ driver-ops.o \
|
||||
sta_info.o \
|
||||
wep.o \
|
||||
wpa.o \
|
||||
--- /dev/null
|
||||
+++ b/net/mac80211/driver-ops.c
|
||||
@@ -0,0 +1,41 @@
|
||||
+/*
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 as
|
||||
+ * published by the Free Software Foundation.
|
||||
+ */
|
||||
+#include <net/mac80211.h>
|
||||
+#include "ieee80211_i.h"
|
||||
+#include "trace.h"
|
||||
+#include "driver-ops.h"
|
||||
+
|
||||
+__must_check
|
||||
+int drv_sta_state(struct ieee80211_local *local,
|
||||
+ struct ieee80211_sub_if_data *sdata,
|
||||
+ struct sta_info *sta,
|
||||
+ enum ieee80211_sta_state old_state,
|
||||
+ enum ieee80211_sta_state new_state)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ might_sleep();
|
||||
+
|
||||
+ sdata = get_bss_sdata(sdata);
|
||||
+ if (!check_sdata_in_driver(sdata))
|
||||
+ return -EIO;
|
||||
+
|
||||
+ trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state);
|
||||
+ if (local->ops->sta_state) {
|
||||
+ ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta,
|
||||
+ old_state, new_state);
|
||||
+ } else if (old_state == IEEE80211_STA_AUTH &&
|
||||
+ new_state == IEEE80211_STA_ASSOC) {
|
||||
+ ret = drv_sta_add(local, sdata, &sta->sta);
|
||||
+ if (ret == 0)
|
||||
+ sta->uploaded = true;
|
||||
+ } else if (old_state == IEEE80211_STA_ASSOC &&
|
||||
+ new_state == IEEE80211_STA_AUTH) {
|
||||
+ drv_sta_remove(local, sdata, &sta->sta);
|
||||
+ }
|
||||
+ trace_drv_return_int(local, ret);
|
||||
+ return ret;
|
||||
+}
|
||||
--- a/net/mac80211/driver-ops.h
|
||||
+++ b/net/mac80211/driver-ops.h
|
||||
@@ -573,37 +573,12 @@ static inline void drv_sta_pre_rcu_remov
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
-static inline __must_check
|
||||
+__must_check
|
||||
int drv_sta_state(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta,
|
||||
enum ieee80211_sta_state old_state,
|
||||
- enum ieee80211_sta_state new_state)
|
||||
-{
|
||||
- int ret = 0;
|
||||
-
|
||||
- might_sleep();
|
||||
-
|
||||
- sdata = get_bss_sdata(sdata);
|
||||
- if (!check_sdata_in_driver(sdata))
|
||||
- return -EIO;
|
||||
-
|
||||
- trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state);
|
||||
- if (local->ops->sta_state) {
|
||||
- ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta,
|
||||
- old_state, new_state);
|
||||
- } else if (old_state == IEEE80211_STA_AUTH &&
|
||||
- new_state == IEEE80211_STA_ASSOC) {
|
||||
- ret = drv_sta_add(local, sdata, &sta->sta);
|
||||
- if (ret == 0)
|
||||
- sta->uploaded = true;
|
||||
- } else if (old_state == IEEE80211_STA_ASSOC &&
|
||||
- new_state == IEEE80211_STA_AUTH) {
|
||||
- drv_sta_remove(local, sdata, &sta->sta);
|
||||
- }
|
||||
- trace_drv_return_int(local, ret);
|
||||
- return ret;
|
||||
-}
|
||||
+ enum ieee80211_sta_state new_state);
|
||||
|
||||
static inline void drv_sta_rc_update(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
@ -0,0 +1,30 @@ |
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Wed, 22 Jul 2015 10:42:43 +0200
|
||||
Subject: [PATCH] ath9k: Fix NF CCA limits for AR9287 and AR9227
|
||||
|
||||
The FreeBSD driver [0] uses the same 2G values as for the AR9280 chips.
|
||||
Using the same values in ath9k results in much better throughput for me.
|
||||
|
||||
Before this patch I had a huge amount of packet loss (sometimes up to
|
||||
40%) and the max transfer speed was somewhere around 5Mbit/s. With this
|
||||
patch applied I have zero packet loss and ten times the throughput.
|
||||
My device uses a AR9227 which is the PCI variant of the AR9287.
|
||||
|
||||
[0] http://bxr.su/FreeBSD/sys/dev/ath/ath_hal/ar9002/ar9287.h
|
||||
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
|
||||
@@ -610,8 +610,8 @@
|
||||
#define AR_PHY_CCA_MIN_GOOD_VAL_9271_2GHZ -127
|
||||
#define AR_PHY_CCA_MAX_GOOD_VAL_9271_2GHZ -116
|
||||
|
||||
-#define AR_PHY_CCA_NOM_VAL_9287_2GHZ -120
|
||||
+#define AR_PHY_CCA_NOM_VAL_9287_2GHZ -112
|
||||
#define AR_PHY_CCA_MIN_GOOD_VAL_9287_2GHZ -127
|
||||
-#define AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ -110
|
||||
+#define AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ -97
|
||||
|
||||
#endif
|
@ -1,216 +0,0 @@ |
||||
From: Arik Nemtsov <arik@wizery.com>
|
||||
Date: Wed, 8 Jul 2015 15:41:44 +0300
|
||||
Subject: [PATCH] cfg80211: use RTNL locked reg_can_beacon for IR-relaxation
|
||||
|
||||
The RTNL is required to check for IR-relaxation conditions that allow
|
||||
more channels to beacon. Export an RTNL locked version of reg_can_beacon
|
||||
and use it where possible in AP/STA interface type flows, where
|
||||
IR-relaxation may be applicable.
|
||||
|
||||
Fixes: 06f207fc5418 ("cfg80211: change GO_CONCURRENT to IR_CONCURRENT for STA")
|
||||
Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
|
||||
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
|
||||
---
|
||||
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -4871,6 +4871,23 @@ bool cfg80211_reg_can_beacon(struct wiph
|
||||
struct cfg80211_chan_def *chandef,
|
||||
enum nl80211_iftype iftype);
|
||||
|
||||
+/**
|
||||
+ * cfg80211_reg_can_beacon_relax - check if beaconing is allowed with relaxation
|
||||
+ * @wiphy: the wiphy
|
||||
+ * @chandef: the channel definition
|
||||
+ * @iftype: interface type
|
||||
+ *
|
||||
+ * Return: %true if there is no secondary channel or the secondary channel(s)
|
||||
+ * can be used for beaconing (i.e. is not a radar channel etc.). This version
|
||||
+ * also checks if IR-relaxation conditions apply, to allow beaconing under
|
||||
+ * more permissive conditions.
|
||||
+ *
|
||||
+ * Requires the RTNL to be held.
|
||||
+ */
|
||||
+bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
|
||||
+ struct cfg80211_chan_def *chandef,
|
||||
+ enum nl80211_iftype iftype);
|
||||
+
|
||||
/*
|
||||
* cfg80211_ch_switch_notify - update wdev channel and notify userspace
|
||||
* @dev: the device which switched channels
|
||||
--- a/net/mac80211/tdls.c
|
||||
+++ b/net/mac80211/tdls.c
|
||||
@@ -69,6 +69,7 @@ ieee80211_tdls_add_subband(struct ieee80
|
||||
struct ieee80211_channel *ch;
|
||||
struct cfg80211_chan_def chandef;
|
||||
int i, subband_start;
|
||||
+ struct wiphy *wiphy = sdata->local->hw.wiphy;
|
||||
|
||||
for (i = start; i <= end; i += spacing) {
|
||||
if (!ch_cnt)
|
||||
@@ -79,9 +80,8 @@ ieee80211_tdls_add_subband(struct ieee80
|
||||
/* we will be active on the channel */
|
||||
cfg80211_chandef_create(&chandef, ch,
|
||||
NL80211_CHAN_NO_HT);
|
||||
- if (cfg80211_reg_can_beacon(sdata->local->hw.wiphy,
|
||||
- &chandef,
|
||||
- sdata->wdev.iftype)) {
|
||||
+ if (cfg80211_reg_can_beacon_relax(wiphy, &chandef,
|
||||
+ sdata->wdev.iftype)) {
|
||||
ch_cnt++;
|
||||
/*
|
||||
* check if the next channel is also part of
|
||||
--- a/net/wireless/chan.c
|
||||
+++ b/net/wireless/chan.c
|
||||
@@ -797,23 +797,18 @@ static bool cfg80211_ir_permissive_chan(
|
||||
return false;
|
||||
}
|
||||
|
||||
-bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
|
||||
- struct cfg80211_chan_def *chandef,
|
||||
- enum nl80211_iftype iftype)
|
||||
+static bool _cfg80211_reg_can_beacon(struct wiphy *wiphy,
|
||||
+ struct cfg80211_chan_def *chandef,
|
||||
+ enum nl80211_iftype iftype,
|
||||
+ bool check_no_ir)
|
||||
{
|
||||
bool res;
|
||||
u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
|
||||
IEEE80211_CHAN_RADAR;
|
||||
|
||||
- trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype);
|
||||
+ trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
|
||||
|
||||
- /*
|
||||
- * Under certain conditions suggested by some regulatory bodies a
|
||||
- * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
|
||||
- * only if such relaxations are not enabled and the conditions are not
|
||||
- * met.
|
||||
- */
|
||||
- if (!cfg80211_ir_permissive_chan(wiphy, iftype, chandef->chan))
|
||||
+ if (check_no_ir)
|
||||
prohibited_flags |= IEEE80211_CHAN_NO_IR;
|
||||
|
||||
if (cfg80211_chandef_dfs_required(wiphy, chandef, iftype) > 0 &&
|
||||
@@ -827,8 +822,36 @@ bool cfg80211_reg_can_beacon(struct wiph
|
||||
trace_cfg80211_return_bool(res);
|
||||
return res;
|
||||
}
|
||||
+
|
||||
+bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
|
||||
+ struct cfg80211_chan_def *chandef,
|
||||
+ enum nl80211_iftype iftype)
|
||||
+{
|
||||
+ return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, true);
|
||||
+}
|
||||
EXPORT_SYMBOL(cfg80211_reg_can_beacon);
|
||||
|
||||
+bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
|
||||
+ struct cfg80211_chan_def *chandef,
|
||||
+ enum nl80211_iftype iftype)
|
||||
+{
|
||||
+ bool check_no_ir;
|
||||
+
|
||||
+ ASSERT_RTNL();
|
||||
+
|
||||
+ /*
|
||||
+ * Under certain conditions suggested by some regulatory bodies a
|
||||
+ * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
|
||||
+ * only if such relaxations are not enabled and the conditions are not
|
||||
+ * met.
|
||||
+ */
|
||||
+ check_no_ir = !cfg80211_ir_permissive_chan(wiphy, iftype,
|
||||
+ chandef->chan);
|
||||
+
|
||||
+ return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
|
||||
+}
|
||||
+EXPORT_SYMBOL(cfg80211_reg_can_beacon_relax);
|
||||
+
|
||||
int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -2007,7 +2007,8 @@ static int __nl80211_set_channel(struct
|
||||
switch (iftype) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
- if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, iftype)) {
|
||||
+ if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
|
||||
+ iftype)) {
|
||||
result = -EINVAL;
|
||||
break;
|
||||
}
|
||||
@@ -3408,8 +3409,8 @@ static int nl80211_start_ap(struct sk_bu
|
||||
} else if (!nl80211_get_ap_channel(rdev, ¶ms))
|
||||
return -EINVAL;
|
||||
|
||||
- if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef,
|
||||
- wdev->iftype))
|
||||
+ if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, ¶ms.chandef,
|
||||
+ wdev->iftype))
|
||||
return -EINVAL;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
|
||||
@@ -6500,8 +6501,8 @@ skip_beacons:
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
- if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef,
|
||||
- wdev->iftype))
|
||||
+ if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, ¶ms.chandef,
|
||||
+ wdev->iftype))
|
||||
return -EINVAL;
|
||||
|
||||
err = cfg80211_chandef_dfs_required(wdev->wiphy,
|
||||
@@ -10188,7 +10189,8 @@ static int nl80211_tdls_channel_switch(s
|
||||
return -EINVAL;
|
||||
|
||||
/* we will be active on the TDLS link */
|
||||
- if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, wdev->iftype))
|
||||
+ if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
|
||||
+ wdev->iftype))
|
||||
return -EINVAL;
|
||||
|
||||
/* don't allow switching to DFS channels */
|
||||
--- a/net/wireless/reg.c
|
||||
+++ b/net/wireless/reg.c
|
||||
@@ -1589,7 +1589,7 @@ static bool reg_wdev_chan_valid(struct w
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
- return cfg80211_reg_can_beacon(wiphy, &chandef, iftype);
|
||||
+ return cfg80211_reg_can_beacon_relax(wiphy, &chandef, iftype);
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
return cfg80211_chandef_usable(wiphy, &chandef,
|
||||
--- a/net/wireless/trace.h
|
||||
+++ b/net/wireless/trace.h
|
||||
@@ -2358,20 +2358,23 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify,
|
||||
|
||||
TRACE_EVENT(cfg80211_reg_can_beacon,
|
||||
TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef,
|
||||
- enum nl80211_iftype iftype),
|
||||
- TP_ARGS(wiphy, chandef, iftype),
|
||||
+ enum nl80211_iftype iftype, bool check_no_ir),
|
||||
+ TP_ARGS(wiphy, chandef, iftype, check_no_ir),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
CHAN_DEF_ENTRY
|
||||
__field(enum nl80211_iftype, iftype)
|
||||
+ __field(bool, check_no_ir)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
CHAN_DEF_ASSIGN(chandef);
|
||||
__entry->iftype = iftype;
|
||||
+ __entry->check_no_ir = check_no_ir;
|
||||
),
|
||||
- TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d",
|
||||
- WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype)
|
||||
+ TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d check_no_ir=%s",
|
||||
+ WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype,
|
||||
+ BOOL_TO_STR(__entry->check_no_ir))
|
||||
);
|
||||
|
||||
TRACE_EVENT(cfg80211_chandef_dfs_required,
|
@ -1,69 +0,0 @@ |
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Thu, 9 Jul 2015 16:53:30 +0200
|
||||
Subject: [PATCH] brcmfmac: set wiphy's addresses to provide valid MACs
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Broadcom's firmware requires every BSS to use MAC address with unique
|
||||
last few bits. The amount of bits may depend on a particular firmware,
|
||||
it was verified to be 2 for BCM43602 one.
|
||||
If this condition won't be fulfilled firmware will reject such MAC:
|
||||
brcmfmac: _brcmf_set_mac_address: Setting cur_etheraddr failed, -52
|
||||
|
||||
We don't want to simply set addr_mask as it would also disallow using
|
||||
locally administrated bit. Instead let's build a list of addresses
|
||||
manually enabling 0x2 bit for extra interfaces.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
|
||||
@@ -5813,6 +5813,7 @@ static void brcmf_wiphy_wowl_params(stru
|
||||
|
||||
static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
|
||||
{
|
||||
+ struct brcmf_pub *drvr = ifp->drvr;
|
||||
struct ieee80211_supported_band *band;
|
||||
__le32 bandlist[3];
|
||||
u32 n_bands;
|
||||
@@ -5826,6 +5827,19 @@ static int brcmf_setup_wiphy(struct wiph
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
+ for (i = 0; i < wiphy->iface_combinations->max_interfaces &&
|
||||
+ i < ARRAY_SIZE(drvr->addresses); i++) {
|
||||
+ u8 *addr = drvr->addresses[i].addr;
|
||||
+
|
||||
+ memcpy(addr, drvr->mac, ETH_ALEN);
|
||||
+ if (i) {
|
||||
+ addr[0] |= BIT(1);
|
||||
+ addr[ETH_ALEN - 1] ^= i;
|
||||
+ }
|
||||
+ }
|
||||
+ wiphy->addresses = drvr->addresses;
|
||||
+ wiphy->n_addresses = i;
|
||||
+
|
||||
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
|
||||
wiphy->cipher_suites = __wl_cipher_suites;
|
||||
wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
|
||||
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
|
||||
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
|
||||
@@ -21,6 +21,7 @@
|
||||
#ifndef BRCMFMAC_CORE_H
|
||||
#define BRCMFMAC_CORE_H
|
||||
|
||||
+#include <net/cfg80211.h>
|
||||
#include "fweh.h"
|
||||
|
||||
#define TOE_TX_CSUM_OL 0x00000001
|
||||
@@ -118,6 +119,8 @@ struct brcmf_pub {
|
||||
/* Multicast data packets sent to dongle */
|
||||
unsigned long tx_multicast;
|
||||
|
||||
+ struct mac_address addresses[BRCMF_MAX_IFS];
|
||||
+
|
||||
struct brcmf_if *iflist[BRCMF_MAX_IFS];
|
||||
|
||||
struct mutex proto_block;
|
Loading…
Reference in new issue