2016-03-31 17:04:15

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 01/10] mac80211: allow passing transmitter station on RX

From: Johannes Berg <[email protected]>

Sometimes drivers already looked up, or know out-of-band
from their device, which station transmitted a given RX
frame. Allow them to pass the station pointer to mac80211
to save the extra lookup.

Signed-off-by: Johannes Berg <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/dvm/rx.c | 2 +-
drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 2 +-
drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 2 +-
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 2 +-
include/net/mac80211.h | 7 ++++---
net/mac80211/rx.c | 18 +++++++++++++-----
6 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c
index 52ab1e0..27ea61e 100644
--- a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c
@@ -686,7 +686,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,

memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));

- ieee80211_rx_napi(priv->hw, skb, priv->napi);
+ ieee80211_rx_napi(priv->hw, NULL, skb, priv->napi);
}

static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
index 535134d..4918d5e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
@@ -1497,5 +1497,5 @@ void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm,
memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));

/* pass it as regular rx to mac80211 */
- ieee80211_rx_napi(mvm->hw, skb, NULL);
+ ieee80211_rx_napi(mvm->hw, NULL, skb, NULL);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
index 145ec68..29dbfaf 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
@@ -130,7 +130,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
fraglen, rxb->truesize);
}

- ieee80211_rx_napi(mvm->hw, skb, napi);
+ ieee80211_rx_napi(mvm->hw, NULL, skb, napi);
}

/*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
index 615dea1..00d90e9 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
@@ -194,7 +194,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
if (iwl_mvm_check_pn(mvm, skb, queue, sta))
kfree_skb(skb);
else
- ieee80211_rx_napi(mvm->hw, skb, napi);
+ ieee80211_rx_napi(mvm->hw, NULL, skb, napi);
}

static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 6e34675..fd5ec44 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3855,11 +3855,12 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw);
* This function must be called with BHs disabled.
*
* @hw: the hardware this frame came in on
+ * @sta: the station the frame was received from, or %NULL
* @skb: the buffer to receive, owned by mac80211 after this call
* @napi: the NAPI context
*/
-void ieee80211_rx_napi(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct napi_struct *napi);
+void ieee80211_rx_napi(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+ struct sk_buff *skb, struct napi_struct *napi);

/**
* ieee80211_rx - receive frame
@@ -3883,7 +3884,7 @@ void ieee80211_rx_napi(struct ieee80211_hw *hw, struct sk_buff *skb,
*/
static inline void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
- ieee80211_rx_napi(hw, skb, NULL);
+ ieee80211_rx_napi(hw, NULL, skb, NULL);
}

/**
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 57a0ccd..6c3829d 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -3533,6 +3533,7 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
* be called with rcu_read_lock protection.
*/
static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
+ struct ieee80211_sta *pubsta,
struct sk_buff *skb,
struct napi_struct *napi)
{
@@ -3542,7 +3543,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
__le16 fc;
struct ieee80211_rx_data rx;
struct ieee80211_sub_if_data *prev;
- struct sta_info *sta, *prev_sta;
struct rhash_head *tmp;
int err = 0;

@@ -3578,7 +3578,14 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
ieee80211_is_beacon(hdr->frame_control)))
ieee80211_scan_rx(local, skb);

- if (ieee80211_is_data(fc)) {
+ if (pubsta) {
+ rx.sta = container_of(pubsta, struct sta_info, sta);
+ rx.sdata = rx.sta->sdata;
+ if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
+ return;
+ goto out;
+ } else if (ieee80211_is_data(fc)) {
+ struct sta_info *sta, *prev_sta;
const struct bucket_table *tbl;

prev_sta = NULL;
@@ -3652,8 +3659,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
* This is the receive path handler. It is called by a low level driver when an
* 802.11 MPDU is received from the hardware.
*/
-void ieee80211_rx_napi(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct napi_struct *napi)
+void ieee80211_rx_napi(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
+ struct sk_buff *skb, struct napi_struct *napi)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_rate *rate = NULL;
@@ -3752,7 +3759,8 @@ void ieee80211_rx_napi(struct ieee80211_hw *hw, struct sk_buff *skb,
ieee80211_tpt_led_trig_rx(local,
((struct ieee80211_hdr *)skb->data)->frame_control,
skb->len);
- __ieee80211_rx_handle_packet(hw, skb, napi);
+
+ __ieee80211_rx_handle_packet(hw, pubsta, skb, napi);

rcu_read_unlock();

--
2.5.0



2016-03-31 17:04:18

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 04/10] mac80211: move averaged values out of rx_stats

From: Johannes Berg <[email protected]>

Move the averaged values out of rx_stats and into rx_stats_avg,
to cleanly split them out. The averaged ones cannot be supported
for parallel RX in a per-CPU fashion, while the other values can
be collected per CPU and then combined/selected when needed.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/mesh_plink.c | 2 +-
net/mac80211/rx.c | 4 ++--
net/mac80211/sta_info.c | 10 +++++-----
net/mac80211/sta_info.h | 6 ++++--
4 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index a07e93c..a261fdf 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -61,7 +61,7 @@ static bool rssi_threshold_check(struct ieee80211_sub_if_data *sdata,
s32 rssi_threshold = sdata->u.mesh.mshcfg.rssi_threshold;
return rssi_threshold == 0 ||
(sta &&
- (s8)-ewma_signal_read(&sta->rx_stats.avg_signal) >
+ (s8)-ewma_signal_read(&sta->rx_stats_avg.signal) >
rssi_threshold);
}

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 1df3a3e..4ae3bf8 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1455,7 +1455,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
sta->rx_stats.bytes += rx->skb->len;
if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
sta->rx_stats.last_signal = status->signal;
- ewma_signal_add(&sta->rx_stats.avg_signal, -status->signal);
+ ewma_signal_add(&sta->rx_stats_avg.signal, -status->signal);
}

if (status->chains) {
@@ -1467,7 +1467,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
continue;

sta->rx_stats.chain_signal_last[i] = signal;
- ewma_signal_add(&sta->rx_stats.chain_signal_avg[i],
+ ewma_signal_add(&sta->rx_stats_avg.chain_signal[i],
-signal);
}
}
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 01e070c..4f19505 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -341,9 +341,9 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
sta->reserved_tid = IEEE80211_TID_UNRESERVED;

sta->last_connected = ktime_get_seconds();
- ewma_signal_init(&sta->rx_stats.avg_signal);
- for (i = 0; i < ARRAY_SIZE(sta->rx_stats.chain_signal_avg); i++)
- ewma_signal_init(&sta->rx_stats.chain_signal_avg[i]);
+ ewma_signal_init(&sta->rx_stats_avg.signal);
+ for (i = 0; i < ARRAY_SIZE(sta->rx_stats_avg.chain_signal); i++)
+ ewma_signal_init(&sta->rx_stats_avg.chain_signal[i]);

if (local->ops->wake_tx_queue) {
void *txq_data;
@@ -2056,7 +2056,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)

if (!(sinfo->filled & BIT(NL80211_STA_INFO_SIGNAL_AVG))) {
sinfo->signal_avg =
- -ewma_signal_read(&sta->rx_stats.avg_signal);
+ -ewma_signal_read(&sta->rx_stats_avg.signal);
sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG);
}
}
@@ -2072,7 +2072,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
sinfo->chain_signal[i] =
sta->rx_stats.chain_signal_last[i];
sinfo->chain_signal_avg[i] =
- -ewma_signal_read(&sta->rx_stats.chain_signal_avg[i]);
+ -ewma_signal_read(&sta->rx_stats_avg.chain_signal[i]);
}
}

diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index fc91290..67a604c 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -450,16 +450,18 @@ struct sta_info {
unsigned long fragments;
unsigned long dropped;
int last_signal;
- struct ewma_signal avg_signal;
u8 chains;
s8 chain_signal_last[IEEE80211_MAX_CHAINS];
- struct ewma_signal chain_signal_avg[IEEE80211_MAX_CHAINS];
int last_rate_idx;
u32 last_rate_flag;
u32 last_rate_vht_flag;
u8 last_rate_vht_nss;
u64 msdu[IEEE80211_NUM_TIDS + 1];
} rx_stats;
+ struct {
+ struct ewma_signal signal;
+ struct ewma_signal chain_signal[IEEE80211_MAX_CHAINS];
+ } rx_stats_avg;

/* Plus 1 for non-QoS frames */
__le16 last_seq_ctrl[IEEE80211_NUM_TIDS + 1];
--
2.5.0


2016-03-31 17:04:21

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 06/10] mac80211: add separate last_ack variable

From: Johannes Berg <[email protected]>

Instead of touching the rx_stats.last_rx from the status path, introduce
and use a status_stats.last_ack variable. This will make rx_stats.last_rx
indicate when the last frame was received, making it available for real
"last_rx" and statistics gathering; statistics, when done per-CPU, will
need to figure out which place was updated last for those items where the
"last" value is exposed.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/ibss.c | 13 ++++++++-----
net/mac80211/sta_info.c | 13 +++++++++++--
net/mac80211/sta_info.h | 3 +++
net/mac80211/status.c | 4 ++--
4 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index b3407db..4babd8a 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -668,10 +668,11 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
rcu_read_lock();

list_for_each_entry_rcu(sta, &local->sta_list, list) {
+ unsigned long last_active = ieee80211_sta_last_active(sta);
+
if (sta->sdata == sdata &&
- time_after(sta->rx_stats.last_rx +
- IEEE80211_IBSS_MERGE_INTERVAL,
- jiffies)) {
+ time_is_after_jiffies(last_active +
+ IEEE80211_IBSS_MERGE_INTERVAL)) {
active++;
break;
}
@@ -1255,11 +1256,13 @@ static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata)
mutex_lock(&local->sta_mtx);

list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
+ unsigned long last_active = ieee80211_sta_last_active(sta);
+
if (sdata != sta->sdata)
continue;

- if (time_after(jiffies, sta->rx_stats.last_rx + exp_time) ||
- (time_after(jiffies, sta->rx_stats.last_rx + exp_rsn) &&
+ if (time_is_after_jiffies(last_active + exp_time) ||
+ (time_is_after_jiffies(last_active + exp_rsn) &&
sta->sta_state != IEEE80211_STA_AUTHORIZED)) {
sta_dbg(sta->sdata, "expiring inactive %sSTA %pM\n",
sta->sta_state != IEEE80211_STA_AUTHORIZED ?
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 4f19505..b49e2fb 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -1094,10 +1094,12 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
mutex_lock(&local->sta_mtx);

list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
+ unsigned long last_active = ieee80211_sta_last_active(sta);
+
if (sdata != sta->sdata)
continue;

- if (time_after(jiffies, sta->rx_stats.last_rx + exp_time)) {
+ if (time_is_after_jiffies(last_active + exp_time)) {
sta_dbg(sta->sdata, "expiring inactive STA %pM\n",
sta->sta.addr);

@@ -2000,7 +2002,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)

sinfo->connected_time = ktime_get_seconds() - sta->last_connected;
sinfo->inactive_time =
- jiffies_to_msecs(jiffies - sta->rx_stats.last_rx);
+ jiffies_to_msecs(jiffies - ieee80211_sta_last_active(sta));

if (!(sinfo->filled & (BIT(NL80211_STA_INFO_TX_BYTES64) |
BIT(NL80211_STA_INFO_TX_BYTES)))) {
@@ -2186,3 +2188,10 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
sinfo->expected_throughput = thr;
}
}
+
+unsigned long ieee80211_sta_last_active(struct sta_info *sta)
+{
+ if (time_after(sta->rx_stats.last_rx, sta->status_stats.last_ack))
+ return sta->rx_stats.last_rx;
+ return sta->status_stats.last_ack;
+}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 67a604c..0ad9a67 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -474,6 +474,7 @@ struct sta_info {
unsigned long last_tdls_pkt_time;
u64 msdu_retries[IEEE80211_NUM_TIDS + 1];
u64 msdu_failed[IEEE80211_NUM_TIDS + 1];
+ unsigned long last_ack;
} status_stats;

/* Updated from TX path only, no locking requirements */
@@ -683,4 +684,6 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta);
void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta);
void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta);

+unsigned long ieee80211_sta_last_active(struct sta_info *sta);
+
#endif /* STA_INFO_H */
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 6101deb..93a4608 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -188,7 +188,7 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
struct ieee80211_sub_if_data *sdata = sta->sdata;

if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
- sta->rx_stats.last_rx = jiffies;
+ sta->status_stats.last_ack = jiffies;

if (ieee80211_is_data_qos(mgmt->frame_control)) {
struct ieee80211_hdr *hdr = (void *) skb->data;
@@ -647,7 +647,7 @@ void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
sta->status_stats.retry_count += retry_count;

if (acked) {
- sta->rx_stats.last_rx = jiffies;
+ sta->status_stats.last_ack = jiffies;

if (sta->status_stats.lost_packets)
sta->status_stats.lost_packets = 0;
--
2.5.0


2016-03-31 17:04:29

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 10/10] mac80211: enable collecting station statistics per-CPU

From: Johannes Berg <[email protected]>

If the driver advertises the new HW flag USE_RSS, make the
station statistics on the fast-rx path per-CPU. This will
enable calling the RX in parallel, only hitting locking or
shared cachelines when the fast-RX path isn't available.

Signed-off-by: Johannes Berg <[email protected]>
---
include/net/mac80211.h | 4 ++
net/mac80211/debugfs.c | 1 +
net/mac80211/rx.c | 37 ++++++++++-------
net/mac80211/sta_info.c | 108 +++++++++++++++++++++++++++++++++++++++++-------
net/mac80211/sta_info.h | 36 +++++++++-------
5 files changed, 140 insertions(+), 46 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index fd5ec44..5f4b4c7 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1980,6 +1980,9 @@ struct ieee80211_txq {
* order and does not need to manage its own reorder buffer or BA session
* timeout.
*
+ * @IEEE80211_HW_USES_RSS: The device uses RSS and thus requires parallel RX,
+ * which implies using per-CPU station statistics.
+ *
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
*/
enum ieee80211_hw_flags {
@@ -2017,6 +2020,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_BEACON_TX_STATUS,
IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR,
IEEE80211_HW_SUPPORTS_REORDERING_BUFFER,
+ IEEE80211_HW_USES_RSS,

/* keep last, obviously */
NUM_IEEE80211_HW_FLAGS
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 4ab5c52..52ed2af 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -127,6 +127,7 @@ static const char *hw_flag_names[] = {
FLAG(BEACON_TX_STATUS),
FLAG(NEEDS_UNIQUE_STA_ADDR),
FLAG(SUPPORTS_REORDERING_BUFFER),
+ FLAG(USES_RSS),
#undef FLAG
};

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 9bdb009..012be85 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -3509,6 +3509,8 @@ void ieee80211_check_fast_rx(struct sta_info *sta)
ether_addr_copy(fastrx.rfc1042_hdr, rfc1042_header);
ether_addr_copy(fastrx.vif_addr, sdata->vif.addr);

+ fastrx.uses_rss = ieee80211_hw_check(&local->hw, USES_RSS);
+
/* fast-rx doesn't do reordering */
if (ieee80211_hw_check(&local->hw, AMPDU_AGGREGATION) &&
!ieee80211_hw_check(&local->hw, SUPPORTS_REORDERING_BUFFER))
@@ -3652,6 +3654,10 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
u8 da[ETH_ALEN];
u8 sa[ETH_ALEN];
} addrs __aligned(2);
+ struct ieee80211_sta_rx_stats *stats = &sta->rx_stats;
+
+ if (fast_rx->uses_rss)
+ stats = this_cpu_ptr(sta->pcpu_rx_stats);

/* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write
* to a common data structure; drivers can implement that per queue
@@ -3733,29 +3739,32 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
}

/* statistics part of ieee80211_rx_h_sta_process() */
- sta->rx_stats.last_rx = jiffies;
- sta->rx_stats.last_rate = sta_stats_encode_rate(status);
+ stats->last_rx = jiffies;
+ stats->last_rate = sta_stats_encode_rate(status);

- sta->rx_stats.fragments++;
+ stats->fragments++;

if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
- sta->rx_stats.last_signal = status->signal;
- ewma_signal_add(&sta->rx_stats_avg.signal, -status->signal);
+ stats->last_signal = status->signal;
+ if (!fast_rx->uses_rss)
+ ewma_signal_add(&sta->rx_stats_avg.signal,
+ -status->signal);
}

if (status->chains) {
int i;

- sta->rx_stats.chains = status->chains;
+ stats->chains = status->chains;
for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) {
int signal = status->chain_signal[i];

if (!(status->chains & BIT(i)))
continue;

- sta->rx_stats.chain_signal_last[i] = signal;
- ewma_signal_add(&sta->rx_stats_avg.chain_signal[i],
- -signal);
+ stats->chain_signal_last[i] = signal;
+ if (!fast_rx->uses_rss)
+ ewma_signal_add(&sta->rx_stats_avg.chain_signal[i],
+ -signal);
}
}
/* end of statistics */
@@ -3780,10 +3789,10 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
* for non-QoS-data frames. Here we know it's a data
* frame, so count MSDUs.
*/
- u64_stats_update_begin(&sta->rx_stats.syncp);
- sta->rx_stats.msdu[rx->seqno_idx]++;
- sta->rx_stats.bytes += orig_len;
- u64_stats_update_end(&sta->rx_stats.syncp);
+ u64_stats_update_begin(&stats->syncp);
+ stats->msdu[rx->seqno_idx]++;
+ stats->bytes += orig_len;
+ u64_stats_update_end(&stats->syncp);

if (fast_rx->internal_forward) {
struct sta_info *dsta = sta_info_get(rx->sdata, skb->data);
@@ -3814,7 +3823,7 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
return true;
drop:
dev_kfree_skb(skb);
- sta->rx_stats.dropped++;
+ stats->dropped++;
return true;
}

diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 877e983..70d6cda 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -254,6 +254,7 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
#ifdef CONFIG_MAC80211_MESH
kfree(sta->mesh);
#endif
+ free_percpu(sta->pcpu_rx_stats);
kfree(sta);
}

@@ -311,6 +312,13 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
if (!sta)
return NULL;

+ if (ieee80211_hw_check(hw, USES_RSS)) {
+ sta->pcpu_rx_stats =
+ alloc_percpu(struct ieee80211_sta_rx_stats);
+ if (!sta->pcpu_rx_stats)
+ goto free;
+ }
+
spin_lock_init(&sta->lock);
spin_lock_init(&sta->ps_lock);
INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames);
@@ -1932,6 +1940,28 @@ u8 sta_info_tx_streams(struct sta_info *sta)
>> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1;
}

+static struct ieee80211_sta_rx_stats *
+sta_get_last_rx_stats(struct sta_info *sta)
+{
+ struct ieee80211_sta_rx_stats *stats = &sta->rx_stats;
+ struct ieee80211_local *local = sta->local;
+ int cpu;
+
+ if (!ieee80211_hw_check(&local->hw, USES_RSS))
+ return stats;
+
+ for_each_possible_cpu(cpu) {
+ struct ieee80211_sta_rx_stats *cpustats;
+
+ cpustats = per_cpu_ptr(sta->pcpu_rx_stats, cpu);
+
+ if (time_after(cpustats->last_rx, stats->last_rx))
+ stats = cpustats;
+ }
+
+ return stats;
+}
+
static void sta_stats_decode_rate(struct ieee80211_local *local, u16 rate,
struct rate_info *rinfo)
{
@@ -1967,7 +1997,7 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u16 rate,

static void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo)
{
- u16 rate = ACCESS_ONCE(sta->rx_stats.last_rate);
+ u16 rate = ACCESS_ONCE(sta_get_last_rx_stats(sta)->last_rate);

if (rate == STA_STATS_RATE_INVALID)
rinfo->flags = 0;
@@ -2010,13 +2040,29 @@ static void sta_set_tidstats(struct sta_info *sta,
}
}

+static inline u64 sta_get_stats_bytes(struct ieee80211_sta_rx_stats *rxstats)
+{
+ unsigned int start;
+ u64 value;
+
+ do {
+ start = u64_stats_fetch_begin(&rxstats->syncp);
+ value = rxstats->bytes;
+ } while (u64_stats_fetch_retry(&rxstats->syncp, start));
+
+ return value;
+}
+
void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct rate_control_ref *ref = NULL;
u32 thr = 0;
- int i, ac;
+ int i, ac, cpu;
+ struct ieee80211_sta_rx_stats *last_rxstats;
+
+ last_rxstats = sta_get_last_rx_stats(sta);

if (test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
ref = local->rate_ctrl;
@@ -2064,17 +2110,30 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)

if (!(sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES64) |
BIT(NL80211_STA_INFO_RX_BYTES)))) {
- unsigned int start;
+ sinfo->rx_bytes += sta_get_stats_bytes(&sta->rx_stats);
+
+ if (sta->pcpu_rx_stats) {
+ for_each_possible_cpu(cpu) {
+ struct ieee80211_sta_rx_stats *cpurxs;
+
+ cpurxs = per_cpu_ptr(sta->pcpu_rx_stats, cpu);
+ sinfo->rx_bytes += sta_get_stats_bytes(cpurxs);
+ }
+ }

- do {
- start = u64_stats_fetch_begin(&sta->rx_stats.syncp);
- sinfo->rx_bytes = sta->rx_stats.bytes;
- } while (u64_stats_fetch_retry(&sta->rx_stats.syncp, start));
sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64);
}

if (!(sinfo->filled & BIT(NL80211_STA_INFO_RX_PACKETS))) {
sinfo->rx_packets = sta->rx_stats.packets;
+ if (sta->pcpu_rx_stats) {
+ for_each_possible_cpu(cpu) {
+ struct ieee80211_sta_rx_stats *cpurxs;
+
+ cpurxs = per_cpu_ptr(sta->pcpu_rx_stats, cpu);
+ sinfo->rx_packets += cpurxs->packets;
+ }
+ }
sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
}

@@ -2089,6 +2148,14 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
}

sinfo->rx_dropped_misc = sta->rx_stats.dropped;
+ if (sta->pcpu_rx_stats) {
+ for_each_possible_cpu(cpu) {
+ struct ieee80211_sta_rx_stats *cpurxs;
+
+ cpurxs = per_cpu_ptr(sta->pcpu_rx_stats, cpu);
+ sinfo->rx_packets += cpurxs->dropped;
+ }
+ }

if (sdata->vif.type == NL80211_IFTYPE_STATION &&
!(sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER)) {
@@ -2100,27 +2167,34 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
if (ieee80211_hw_check(&sta->local->hw, SIGNAL_DBM) ||
ieee80211_hw_check(&sta->local->hw, SIGNAL_UNSPEC)) {
if (!(sinfo->filled & BIT(NL80211_STA_INFO_SIGNAL))) {
- sinfo->signal = (s8)sta->rx_stats.last_signal;
+ sinfo->signal = (s8)last_rxstats->last_signal;
sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
}

- if (!(sinfo->filled & BIT(NL80211_STA_INFO_SIGNAL_AVG))) {
+ if (!sta->pcpu_rx_stats &&
+ !(sinfo->filled & BIT(NL80211_STA_INFO_SIGNAL_AVG))) {
sinfo->signal_avg =
-ewma_signal_read(&sta->rx_stats_avg.signal);
sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG);
}
}

- if (sta->rx_stats.chains &&
+ /* for the average - if pcpu_rx_stats isn't set - rxstats must point to
+ * the sta->rx_stats struct, so the check here is fine with and without
+ * pcpu statistics
+ */
+ if (last_rxstats->chains &&
!(sinfo->filled & (BIT(NL80211_STA_INFO_CHAIN_SIGNAL) |
BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)))) {
- sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL) |
- BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);
+ sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL);
+ if (!sta->pcpu_rx_stats)
+ sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);
+
+ sinfo->chains = last_rxstats->chains;

- sinfo->chains = sta->rx_stats.chains;
for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) {
sinfo->chain_signal[i] =
- sta->rx_stats.chain_signal_last[i];
+ last_rxstats->chain_signal_last[i];
sinfo->chain_signal_avg[i] =
-ewma_signal_read(&sta->rx_stats_avg.chain_signal[i]);
}
@@ -2213,7 +2287,9 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)

unsigned long ieee80211_sta_last_active(struct sta_info *sta)
{
- if (time_after(sta->rx_stats.last_rx, sta->status_stats.last_ack))
- return sta->rx_stats.last_rx;
+ struct ieee80211_sta_rx_stats *stats = sta_get_last_rx_stats(sta);
+
+ if (time_after(stats->last_rx, sta->status_stats.last_ack))
+ return stats->last_rx;
return sta->status_stats.last_ack;
}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 6ee37e3..266bd4a 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -297,6 +297,7 @@ struct ieee80211_fast_tx {
* @key: bool indicating encryption is expected (key is set)
* @sta_notify: notify the MLME code (once)
* @internal_forward: forward froms internally on AP/VLAN type interfaces
+ * @uses_rss: copy of USES_RSS hw flag
* @da_offs: offset of the DA in the header (for header conversion)
* @sa_offs: offset of the SA in the header (for header conversion)
* @rcu_head: RCU head for freeing this structure
@@ -311,7 +312,8 @@ struct ieee80211_fast_rx {
u8 icv_len;
u8 key:1,
sta_notify:1,
- internal_forward:1;
+ internal_forward:1,
+ uses_rss:1;
u8 da_offs, sa_offs;

struct rcu_head rcu_head;
@@ -367,6 +369,21 @@ struct mesh_sta {

DECLARE_EWMA(signal, 1024, 8)

+struct ieee80211_sta_rx_stats {
+ unsigned long packets;
+ unsigned long last_rx;
+ unsigned long num_duplicates;
+ unsigned long fragments;
+ unsigned long dropped;
+ int last_signal;
+ u8 chains;
+ s8 chain_signal_last[IEEE80211_MAX_CHAINS];
+ u16 last_rate;
+ struct u64_stats_sync syncp;
+ u64 bytes;
+ u64 msdu[IEEE80211_NUM_TIDS + 1];
+};
+
/**
* struct sta_info - STA information
*
@@ -448,6 +465,7 @@ struct sta_info {

struct ieee80211_fast_tx __rcu *fast_tx;
struct ieee80211_fast_rx __rcu *fast_rx;
+ struct ieee80211_sta_rx_stats __percpu *pcpu_rx_stats;

#ifdef CONFIG_MAC80211_MESH
struct mesh_sta *mesh;
@@ -477,21 +495,7 @@ struct sta_info {
long last_connected;

/* Updated from RX path only, no locking requirements */
- struct {
- unsigned long packets;
- unsigned long last_rx;
- unsigned long num_duplicates;
- unsigned long fragments;
- unsigned long dropped;
- int last_signal;
- u8 chains;
- s8 chain_signal_last[IEEE80211_MAX_CHAINS];
- u16 last_rate;
-
- struct u64_stats_sync syncp;
- u64 bytes;
- u64 msdu[IEEE80211_NUM_TIDS + 1];
- } rx_stats;
+ struct ieee80211_sta_rx_stats rx_stats;
struct {
struct ewma_signal signal;
struct ewma_signal chain_signal[IEEE80211_MAX_CHAINS];
--
2.5.0


2016-03-31 17:04:17

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 03/10] mac80211: move semicolon out of CALL_RXH macro

From: Johannes Berg <[email protected]>

Move the semicolon, people typically assume that and
once line already put a semicolon behind the "call".

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/rx.c | 34 +++++++++++++++++-----------------
1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index d979818..1df3a3e 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -3183,7 +3183,7 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
res = rxh(rx); \
if (res != RX_CONTINUE) \
goto rxh_next; \
- } while (0);
+ } while (0)

/* Lock here to avoid hitting all of the data used in the RX
* path (e.g. key data, station data, ...) concurrently when
@@ -3201,30 +3201,30 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
*/
rx->skb = skb;

- CALL_RXH(ieee80211_rx_h_check_more_data)
- CALL_RXH(ieee80211_rx_h_uapsd_and_pspoll)
- CALL_RXH(ieee80211_rx_h_sta_process)
- CALL_RXH(ieee80211_rx_h_decrypt)
- CALL_RXH(ieee80211_rx_h_defragment)
- CALL_RXH(ieee80211_rx_h_michael_mic_verify)
+ CALL_RXH(ieee80211_rx_h_check_more_data);
+ CALL_RXH(ieee80211_rx_h_uapsd_and_pspoll);
+ CALL_RXH(ieee80211_rx_h_sta_process);
+ CALL_RXH(ieee80211_rx_h_decrypt);
+ CALL_RXH(ieee80211_rx_h_defragment);
+ CALL_RXH(ieee80211_rx_h_michael_mic_verify);
/* must be after MMIC verify so header is counted in MPDU mic */
#ifdef CONFIG_MAC80211_MESH
if (ieee80211_vif_is_mesh(&rx->sdata->vif))
CALL_RXH(ieee80211_rx_h_mesh_fwding);
#endif
- CALL_RXH(ieee80211_rx_h_amsdu)
- CALL_RXH(ieee80211_rx_h_data)
+ CALL_RXH(ieee80211_rx_h_amsdu);
+ CALL_RXH(ieee80211_rx_h_data);

/* special treatment -- needs the queue */
res = ieee80211_rx_h_ctrl(rx, frames);
if (res != RX_CONTINUE)
goto rxh_next;

- CALL_RXH(ieee80211_rx_h_mgmt_check)
- CALL_RXH(ieee80211_rx_h_action)
- CALL_RXH(ieee80211_rx_h_userspace_mgmt)
- CALL_RXH(ieee80211_rx_h_action_return)
- CALL_RXH(ieee80211_rx_h_mgmt)
+ CALL_RXH(ieee80211_rx_h_mgmt_check);
+ CALL_RXH(ieee80211_rx_h_action);
+ CALL_RXH(ieee80211_rx_h_userspace_mgmt);
+ CALL_RXH(ieee80211_rx_h_action_return);
+ CALL_RXH(ieee80211_rx_h_mgmt);

rxh_next:
ieee80211_rx_handlers_result(rx, res);
@@ -3247,10 +3247,10 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
res = rxh(rx); \
if (res != RX_CONTINUE) \
goto rxh_next; \
- } while (0);
+ } while (0)

- CALL_RXH(ieee80211_rx_h_check_dup)
- CALL_RXH(ieee80211_rx_h_check)
+ CALL_RXH(ieee80211_rx_h_check_dup);
+ CALL_RXH(ieee80211_rx_h_check);

ieee80211_rx_reorder_ampdu(rx, &reorder_release);

--
2.5.0


2016-03-31 17:04:21

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 07/10] mac80211: fix last RX rate data consistency

From: Johannes Berg <[email protected]>

When storing the last_rate_* values in the RX code, there's nothing
to guarantee consistency, so a concurrent reader could see, e.g.
last_rate_idx on the new value, but last_rate_flag still on the old,
getting completely bogus values in the end.

To fix this, I lifted the sta_stats_encode_rate() function from my
old rate statistics code, which encodes the entire rate data into a
single 16-bit value, avoiding the consistency issue.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/rx.c | 21 +++++------------
net/mac80211/sta_info.c | 60 ++++++++++++++++++++++++++-----------------------
net/mac80211/sta_info.h | 45 ++++++++++++++++++++++++++++++++-----
3 files changed, 77 insertions(+), 49 deletions(-)

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 4ae3bf8..40981f8 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1421,16 +1421,9 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
test_sta_flag(sta, WLAN_STA_AUTHORIZED)) {
sta->rx_stats.last_rx = jiffies;
if (ieee80211_is_data(hdr->frame_control) &&
- !is_multicast_ether_addr(hdr->addr1)) {
- sta->rx_stats.last_rate_idx =
- status->rate_idx;
- sta->rx_stats.last_rate_flag =
- status->flag;
- sta->rx_stats.last_rate_vht_flag =
- status->vht_flag;
- sta->rx_stats.last_rate_vht_nss =
- status->vht_nss;
- }
+ !is_multicast_ether_addr(hdr->addr1))
+ sta->rx_stats.last_rate =
+ sta_stats_encode_rate(status);
}
} else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) {
sta->rx_stats.last_rx = jiffies;
@@ -1440,12 +1433,8 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
* match the current local configuration when processed.
*/
sta->rx_stats.last_rx = jiffies;
- if (ieee80211_is_data(hdr->frame_control)) {
- sta->rx_stats.last_rate_idx = status->rate_idx;
- sta->rx_stats.last_rate_flag = status->flag;
- sta->rx_stats.last_rate_vht_flag = status->vht_flag;
- sta->rx_stats.last_rate_vht_nss = status->vht_nss;
- }
+ if (ieee80211_is_data(hdr->frame_control))
+ sta->rx_stats.last_rate = sta_stats_encode_rate(status);
}

if (rx->sdata->vif.type == NL80211_IFTYPE_STATION)
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index b49e2fb..81f1d6c 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -1928,43 +1928,47 @@ u8 sta_info_tx_streams(struct sta_info *sta)
>> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1;
}

-static void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo)
+static void sta_stats_decode_rate(struct ieee80211_local *local, u16 rate,
+ struct rate_info *rinfo)
{
- rinfo->flags = 0;
-
- if (sta->rx_stats.last_rate_flag & RX_FLAG_HT) {
- rinfo->flags |= RATE_INFO_FLAGS_MCS;
- rinfo->mcs = sta->rx_stats.last_rate_idx;
- } else if (sta->rx_stats.last_rate_flag & RX_FLAG_VHT) {
- rinfo->flags |= RATE_INFO_FLAGS_VHT_MCS;
- rinfo->nss = sta->rx_stats.last_rate_vht_nss;
- rinfo->mcs = sta->rx_stats.last_rate_idx;
- } else {
+ rinfo->bw = (rate & STA_STATS_RATE_BW_MASK) >>
+ STA_STATS_RATE_BW_SHIFT;
+
+ if (rate & STA_STATS_RATE_VHT) {
+ rinfo->flags = RATE_INFO_FLAGS_VHT_MCS;
+ rinfo->mcs = rate & 0xf;
+ rinfo->nss = (rate & 0xf0) >> 4;
+ } else if (rate & STA_STATS_RATE_HT) {
+ rinfo->flags = RATE_INFO_FLAGS_MCS;
+ rinfo->mcs = rate & 0xff;
+ } else if (rate & STA_STATS_RATE_LEGACY) {
struct ieee80211_supported_band *sband;
- int shift = ieee80211_vif_get_shift(&sta->sdata->vif);
u16 brate;
-
- sband = sta->local->hw.wiphy->bands[
- ieee80211_get_sdata_band(sta->sdata)];
- brate = sband->bitrates[sta->rx_stats.last_rate_idx].bitrate;
+ unsigned int shift;
+
+ sband = local->hw.wiphy->bands[(rate >> 4) & 0xf];
+ brate = sband->bitrates[rate & 0xf].bitrate;
+ if (rinfo->bw == RATE_INFO_BW_5)
+ shift = 2;
+ else if (rinfo->bw == RATE_INFO_BW_10)
+ shift = 1;
+ else
+ shift = 0;
rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift);
}

- if (sta->rx_stats.last_rate_flag & RX_FLAG_SHORT_GI)
+ if (rate & STA_STATS_RATE_SGI)
rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
+}
+
+static void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo)
+{
+ u16 rate = ACCESS_ONCE(sta->rx_stats.last_rate);

- if (sta->rx_stats.last_rate_flag & RX_FLAG_5MHZ)
- rinfo->bw = RATE_INFO_BW_5;
- else if (sta->rx_stats.last_rate_flag & RX_FLAG_10MHZ)
- rinfo->bw = RATE_INFO_BW_10;
- else if (sta->rx_stats.last_rate_flag & RX_FLAG_40MHZ)
- rinfo->bw = RATE_INFO_BW_40;
- else if (sta->rx_stats.last_rate_vht_flag & RX_VHT_FLAG_80MHZ)
- rinfo->bw = RATE_INFO_BW_80;
- else if (sta->rx_stats.last_rate_vht_flag & RX_VHT_FLAG_160MHZ)
- rinfo->bw = RATE_INFO_BW_160;
+ if (rate == STA_STATS_RATE_INVALID)
+ rinfo->flags = 0;
else
- rinfo->bw = RATE_INFO_BW_20;
+ sta_stats_decode_rate(sta->local, rate, rinfo);
}

void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 0ad9a67..f36f560 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -1,7 +1,7 @@
/*
* Copyright 2002-2005, Devicescape Software, Inc.
* Copyright 2013-2014 Intel Mobile Communications GmbH
- * Copyright(c) 2015 Intel Deutschland GmbH
+ * Copyright(c) 2015-2016 Intel Deutschland GmbH
*
* 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
@@ -452,10 +452,7 @@ struct sta_info {
int last_signal;
u8 chains;
s8 chain_signal_last[IEEE80211_MAX_CHAINS];
- int last_rate_idx;
- u32 last_rate_flag;
- u32 last_rate_vht_flag;
- u8 last_rate_vht_nss;
+ u16 last_rate;
u64 msdu[IEEE80211_NUM_TIDS + 1];
} rx_stats;
struct {
@@ -686,4 +683,42 @@ void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta);

unsigned long ieee80211_sta_last_active(struct sta_info *sta);

+#define STA_STATS_RATE_INVALID 0
+#define STA_STATS_RATE_VHT 0x8000
+#define STA_STATS_RATE_HT 0x4000
+#define STA_STATS_RATE_LEGACY 0x2000
+#define STA_STATS_RATE_SGI 0x1000
+#define STA_STATS_RATE_BW_SHIFT 9
+#define STA_STATS_RATE_BW_MASK (0x7 << STA_STATS_RATE_BW_SHIFT)
+
+static inline u16 sta_stats_encode_rate(struct ieee80211_rx_status *s)
+{
+ u16 r = s->rate_idx;
+
+ if (s->vht_flag & RX_VHT_FLAG_80MHZ)
+ r |= RATE_INFO_BW_80 << STA_STATS_RATE_BW_SHIFT;
+ else if (s->vht_flag & RX_VHT_FLAG_160MHZ)
+ r |= RATE_INFO_BW_160 << STA_STATS_RATE_BW_SHIFT;
+ else if (s->flag & RX_FLAG_40MHZ)
+ r |= RATE_INFO_BW_40 << STA_STATS_RATE_BW_SHIFT;
+ else if (s->flag & RX_FLAG_10MHZ)
+ r |= RATE_INFO_BW_10 << STA_STATS_RATE_BW_SHIFT;
+ else if (s->flag & RX_FLAG_5MHZ)
+ r |= RATE_INFO_BW_5 << STA_STATS_RATE_BW_SHIFT;
+ else
+ r |= RATE_INFO_BW_20 << STA_STATS_RATE_BW_SHIFT;
+
+ if (s->flag & RX_FLAG_SHORT_GI)
+ r |= STA_STATS_RATE_SGI;
+
+ if (s->flag & RX_FLAG_VHT)
+ r |= STA_STATS_RATE_VHT | (s->vht_nss << 4);
+ else if (s->flag & RX_FLAG_HT)
+ r |= STA_STATS_RATE_HT;
+ else
+ r |= STA_STATS_RATE_LEGACY | (s->band << 4);
+
+ return r;
+}
+
#endif /* STA_INFO_H */
--
2.5.0


2016-03-31 17:04:26

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 09/10] mac80211: add fast-rx path

From: Johannes Berg <[email protected]>

The regular RX path has a lot of code, but with a few
assumptions on the hardware it's possible to reduce the
amount of code significantly. Currently the assumptions
on the driver are the following:
* hardware/driver reordering buffer (if supporting aggregation)
* hardware/driver decryption & PN checking (if using encryption)
* hardware/driver did de-duplication
* hardware/driver did A-MSDU deaggregation
* AP_LINK_PS is used (in AP mode)
* no client powersave handling in mac80211 (in client mode)

of which some are actually checked per packet:
* de-duplication
* PN checking
* decryption
and additionally packets must
* not be A-MSDU (have been deaggregated by driver/device)
* be data packets
* not be fragmented
* be unicast
* have RFC 1042 header

Additionally dynamically we assume:
* no encryption or CCMP/GCMP, TKIP/WEP/other not allowed
* station must be authorized
* 4-addr format not enabled

Some data needed for the RX path is cached in a new per-station
"fast_rx" structure, so that we only need to look at this and
the packet, no other memory when processing packets on the fast
RX path.

After doing the above per-packet checks, the data path collapses
down to a pretty simple conversion function taking advantage of
the data cached in the small fast_rx struct.

This should speed up the RX processing, and will make it easier
to reason about parallelizing RX (for which statistics will need
to be per-CPU still.)

Signed-off-by: Johannes Berg <[email protected]>
---
include/linux/ieee80211.h | 10 ++
net/mac80211/cfg.c | 10 +-
net/mac80211/ieee80211_i.h | 4 +
net/mac80211/key.c | 1 +
net/mac80211/mlme.c | 7 +
net/mac80211/rx.c | 344 +++++++++++++++++++++++++++++++++++++++++++++
net/mac80211/sta_info.c | 2 +
net/mac80211/sta_info.h | 34 +++++
8 files changed, 409 insertions(+), 3 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index bf9706c..113bfc4 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -638,6 +638,16 @@ static inline bool ieee80211_is_first_frag(__le16 seq_ctrl)
return (seq_ctrl & cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0;
}

+/**
+ * ieee80211_is_frag - check if a frame is a fragment
+ * @hdr: 802.11 header of the frame
+ */
+static inline bool ieee80211_is_frag(struct ieee80211_hdr *hdr)
+{
+ return ieee80211_has_morefrags(hdr->frame_control) ||
+ hdr->seq_ctrl & cpu_to_le16(IEEE80211_SCTL_FRAG);
+}
+
struct ieee80211s_hdr {
u8 flags;
u8 ttl;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 62a90f2..484bcdb 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -65,11 +65,13 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
return ret;

if (type == NL80211_IFTYPE_AP_VLAN &&
- params && params->use_4addr == 0)
+ params && params->use_4addr == 0) {
RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
- else if (type == NL80211_IFTYPE_STATION &&
- params && params->use_4addr >= 0)
+ ieee80211_check_fast_rx_iface(sdata);
+ } else if (type == NL80211_IFTYPE_STATION &&
+ params && params->use_4addr >= 0) {
sdata->u.mgd.use_4addr = params->use_4addr;
+ }

if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) {
struct ieee80211_local *local = sdata->local;
@@ -1367,6 +1369,7 @@ static int ieee80211_change_station(struct wiphy *wiphy,

rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
new_4addr = true;
+ ieee80211_check_fast_rx_iface(vlansdata);
}

if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
@@ -1889,6 +1892,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
sdata->flags |= IEEE80211_SDATA_DONT_BRIDGE_PACKETS;
else
sdata->flags &= ~IEEE80211_SDATA_DONT_BRIDGE_PACKETS;
+ ieee80211_check_fast_rx_iface(sdata);
}

if (params->ht_opmode >= 0) {
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 0008f28..d0f6534 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1496,6 +1496,10 @@ u64 ieee80211_mgmt_tx_cookie(struct ieee80211_local *local);
int ieee80211_attach_ack_skb(struct ieee80211_local *local, struct sk_buff *skb,
u64 *cookie, gfp_t gfp);

+void ieee80211_check_fast_rx(struct sta_info *sta);
+void ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data *sdata);
+void ieee80211_clear_fast_rx(struct sta_info *sta);
+
/* STA code */
void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata);
int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 3df7b03..edd6f29 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -338,6 +338,7 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
} else {
rcu_assign_pointer(sta->gtk[idx], new);
}
+ ieee80211_check_fast_rx(sta);
} else {
defunikey = old &&
old == key_mtx_dereference(sdata->local,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 219e34d..34e8846 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2221,6 +2221,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
const u8 *ssid;
u8 *dst = ifmgd->associated->bssid;
u8 unicast_limit = max(1, max_probe_tries - 3);
+ struct sta_info *sta;

/*
* Try sending broadcast probe requests for the last three
@@ -2239,6 +2240,12 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
*/
ifmgd->probe_send_count++;

+ mutex_lock(&sdata->local->sta_mtx);
+ sta = sta_info_get(sdata, dst);
+ if (!WARN_ON(!sta))
+ ieee80211_check_fast_rx(sta);
+ mutex_unlock(&sdata->local->sta_mtx);
+
if (ieee80211_hw_check(&sdata->local->hw, REPORTS_TX_ACK_STATUS)) {
ifmgd->nullfunc_failed = false;
ieee80211_send_nullfunc(sdata->local, sdata, false);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 1511bd1..9bdb009 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -3489,6 +3489,335 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
return false;
}

+void ieee80211_check_fast_rx(struct sta_info *sta)
+{
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_key *key;
+ struct ieee80211_fast_rx fastrx = {
+ .dev = sdata->dev,
+ .vif_type = sdata->vif.type,
+ .control_port_protocol = sdata->control_port_protocol,
+ }, *old, *new = NULL;
+ bool assign = false;
+
+ /* use sparse to check that we don't return without updating */
+ __acquire(check_fast_rx);
+
+ BUILD_BUG_ON(sizeof(fastrx.rfc1042_hdr) != sizeof(rfc1042_header));
+ BUILD_BUG_ON(sizeof(fastrx.rfc1042_hdr) != ETH_ALEN);
+ ether_addr_copy(fastrx.rfc1042_hdr, rfc1042_header);
+ ether_addr_copy(fastrx.vif_addr, sdata->vif.addr);
+
+ /* fast-rx doesn't do reordering */
+ if (ieee80211_hw_check(&local->hw, AMPDU_AGGREGATION) &&
+ !ieee80211_hw_check(&local->hw, SUPPORTS_REORDERING_BUFFER))
+ goto clear;
+
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_STATION:
+ /* 4-addr is harder to deal with, later maybe */
+ if (sdata->u.mgd.use_4addr)
+ goto clear;
+ /* software powersave is a huge mess, avoid all of it */
+ if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK))
+ goto clear;
+ if (ieee80211_hw_check(&local->hw, SUPPORTS_PS) &&
+ !ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS))
+ goto clear;
+ if (sta->sta.tdls) {
+ fastrx.da_offs = offsetof(struct ieee80211_hdr, addr1);
+ fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr2);
+ fastrx.expected_ds_bits = 0;
+ } else {
+ fastrx.sta_notify = sdata->u.mgd.probe_send_count > 0;
+ fastrx.da_offs = offsetof(struct ieee80211_hdr, addr1);
+ fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr3);
+ fastrx.expected_ds_bits =
+ cpu_to_le16(IEEE80211_FCTL_FROMDS);
+ }
+ break;
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_AP:
+ /* parallel-rx requires this, at least with calls to
+ * ieee80211_sta_ps_transition()
+ */
+ if (!ieee80211_hw_check(&local->hw, AP_LINK_PS))
+ goto clear;
+ fastrx.da_offs = offsetof(struct ieee80211_hdr, addr3);
+ fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr2);
+ fastrx.expected_ds_bits = cpu_to_le16(IEEE80211_FCTL_TODS);
+
+ fastrx.internal_forward =
+ !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
+ (sdata->vif.type != NL80211_IFTYPE_AP_VLAN ||
+ !sdata->u.vlan.sta);
+ break;
+ default:
+ goto clear;
+ }
+
+ if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+ goto clear;
+
+ rcu_read_lock();
+ key = rcu_dereference(sta->ptk[sta->ptk_idx]);
+ if (key) {
+ switch (key->conf.cipher) {
+ case WLAN_CIPHER_SUITE_TKIP:
+ /* we don't want to deal with MMIC in fast-rx */
+ goto clear_rcu;
+ case WLAN_CIPHER_SUITE_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP_256:
+ case WLAN_CIPHER_SUITE_GCMP:
+ case WLAN_CIPHER_SUITE_GCMP_256:
+ break;
+ default:
+ /* we also don't want to deal with WEP or cipher scheme
+ * since those require looking up the key idx in the
+ * frame, rather than assuming the PTK is used
+ * (we need to revisit this once we implement the real
+ * PTK index, which is now valid in the spec, but we
+ * haven't implemented that part yet)
+ */
+ goto clear_rcu;
+ }
+
+ fastrx.key = true;
+ fastrx.icv_len = key->conf.icv_len;
+ }
+
+ assign = true;
+ clear_rcu:
+ rcu_read_unlock();
+ clear:
+ __release(check_fast_rx);
+
+ if (assign)
+ new = kmemdup(&fastrx, sizeof(fastrx), GFP_KERNEL);
+
+ spin_lock_bh(&sta->lock);
+ old = rcu_dereference_protected(sta->fast_rx, true);
+ rcu_assign_pointer(sta->fast_rx, new);
+ spin_unlock_bh(&sta->lock);
+
+ if (old)
+ kfree_rcu(old, rcu_head);
+}
+
+void ieee80211_clear_fast_rx(struct sta_info *sta)
+{
+ struct ieee80211_fast_rx *old;
+
+ spin_lock_bh(&sta->lock);
+ old = rcu_dereference_protected(sta->fast_rx, true);
+ RCU_INIT_POINTER(sta->fast_rx, NULL);
+ spin_unlock_bh(&sta->lock);
+
+ if (old)
+ kfree_rcu(old, rcu_head);
+}
+
+void ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct sta_info *sta;
+
+ mutex_lock(&local->sta_mtx);
+
+ list_for_each_entry_rcu(sta, &local->sta_list, list) {
+ if (sdata != sta->sdata &&
+ (!sta->sdata->bss || sta->sdata->bss != sdata->bss))
+ continue;
+ ieee80211_check_fast_rx(sta);
+ }
+
+ mutex_unlock(&local->sta_mtx);
+}
+
+static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
+ struct ieee80211_fast_rx *fast_rx)
+{
+ struct sk_buff *skb = rx->skb;
+ struct ieee80211_hdr *hdr = (void *)skb->data;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+ struct sta_info *sta = rx->sta;
+ int orig_len = skb->len;
+ int snap_offs = ieee80211_hdrlen(hdr->frame_control);
+ struct {
+ u8 snap[sizeof(rfc1042_header)];
+ __be16 proto;
+ } *payload __aligned(2);
+ struct {
+ u8 da[ETH_ALEN];
+ u8 sa[ETH_ALEN];
+ } addrs __aligned(2);
+
+ /* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write
+ * to a common data structure; drivers can implement that per queue
+ * but we don't have that information in mac80211
+ */
+ if (!(status->flag & RX_FLAG_DUP_VALIDATED))
+ return false;
+
+#define FAST_RX_CRYPT_FLAGS (RX_FLAG_PN_VALIDATED | RX_FLAG_DECRYPTED)
+
+ /* If using encryption, we also need to have:
+ * - PN_VALIDATED: similar, but the implementation is tricky
+ * - DECRYPTED: necessary for PN_VALIDATED
+ */
+ if (fast_rx->key &&
+ (status->flag & FAST_RX_CRYPT_FLAGS) != FAST_RX_CRYPT_FLAGS)
+ return false;
+
+ /* we don't deal with A-MSDU deaggregation here */
+ if (status->rx_flags & IEEE80211_RX_AMSDU)
+ return false;
+
+ if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
+ return false;
+
+ if (unlikely(ieee80211_is_frag(hdr)))
+ return false;
+
+ /* Since our interface address cannot be multicast, this
+ * implicitly also rejects multicast frames without the
+ * explicit check.
+ *
+ * We shouldn't get any *data* frames not addressed to us
+ * (AP mode will accept multicast *management* frames), but
+ * punting here will make it go through the full checks in
+ * ieee80211_accept_frame().
+ */
+ if (!ether_addr_equal(fast_rx->vif_addr, hdr->addr1))
+ return false;
+
+ if ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FROMDS |
+ IEEE80211_FCTL_TODS)) !=
+ fast_rx->expected_ds_bits)
+ goto drop;
+
+ /* assign the key to drop unencrypted frames (later)
+ * and strip the IV/MIC if necessary
+ */
+ if (fast_rx->key && !(status->flag & RX_FLAG_IV_STRIPPED)) {
+ /* GCMP header length is the same */
+ snap_offs += IEEE80211_CCMP_HDR_LEN;
+ }
+
+ if (!pskb_may_pull(skb, snap_offs + sizeof(*payload)))
+ goto drop;
+ payload = (void *)(skb->data + snap_offs);
+
+ if (!ether_addr_equal(payload->snap, fast_rx->rfc1042_hdr))
+ return false;
+
+ /* Don't handle these here since they require special code.
+ * Accept AARP and IPX even though they should come with a
+ * bridge-tunnel header - but if we get them this way then
+ * there's little point in discarding them.
+ */
+ if (unlikely(payload->proto == cpu_to_be16(ETH_P_TDLS) ||
+ payload->proto == fast_rx->control_port_protocol))
+ return false;
+
+ /* after this point, don't punt to the slowpath! */
+
+ if (rx->key && !(status->flag & RX_FLAG_MIC_STRIPPED) &&
+ pskb_trim(skb, skb->len - fast_rx->icv_len))
+ goto drop;
+
+ if (unlikely(fast_rx->sta_notify)) {
+ ieee80211_sta_rx_notify(rx->sdata, hdr);
+ fast_rx->sta_notify = false;
+ }
+
+ /* statistics part of ieee80211_rx_h_sta_process() */
+ sta->rx_stats.last_rx = jiffies;
+ sta->rx_stats.last_rate = sta_stats_encode_rate(status);
+
+ sta->rx_stats.fragments++;
+
+ if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
+ sta->rx_stats.last_signal = status->signal;
+ ewma_signal_add(&sta->rx_stats_avg.signal, -status->signal);
+ }
+
+ if (status->chains) {
+ int i;
+
+ sta->rx_stats.chains = status->chains;
+ for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) {
+ int signal = status->chain_signal[i];
+
+ if (!(status->chains & BIT(i)))
+ continue;
+
+ sta->rx_stats.chain_signal_last[i] = signal;
+ ewma_signal_add(&sta->rx_stats_avg.chain_signal[i],
+ -signal);
+ }
+ }
+ /* end of statistics */
+
+ if (rx->key && !ieee80211_has_protected(hdr->frame_control))
+ goto drop;
+
+ /* do the header conversion - first grab the addresses */
+ ether_addr_copy(addrs.da, skb->data + fast_rx->da_offs);
+ ether_addr_copy(addrs.sa, skb->data + fast_rx->sa_offs);
+ /* remove the SNAP but leave the ethertype */
+ skb_pull(skb, snap_offs + sizeof(rfc1042_header));
+ /* push the addresses in front */
+ memcpy(skb_push(skb, sizeof(addrs)), &addrs, sizeof(addrs));
+
+ skb->dev = fast_rx->dev;
+
+ ieee80211_rx_stats(fast_rx->dev, skb->len);
+
+ /* The seqno index has the same property as needed
+ * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS
+ * for non-QoS-data frames. Here we know it's a data
+ * frame, so count MSDUs.
+ */
+ u64_stats_update_begin(&sta->rx_stats.syncp);
+ sta->rx_stats.msdu[rx->seqno_idx]++;
+ sta->rx_stats.bytes += orig_len;
+ u64_stats_update_end(&sta->rx_stats.syncp);
+
+ if (fast_rx->internal_forward) {
+ struct sta_info *dsta = sta_info_get(rx->sdata, skb->data);
+
+ if (dsta) {
+ /*
+ * Send to wireless media and increase priority by 256
+ * to keep the received priority instead of
+ * reclassifying the frame (see cfg80211_classify8021d).
+ */
+ skb->priority += 256;
+ skb->protocol = htons(ETH_P_802_3);
+ skb_reset_network_header(skb);
+ skb_reset_mac_header(skb);
+ dev_queue_xmit(skb);
+ return true;
+ }
+ }
+
+ /* deliver to local stack */
+ skb->protocol = eth_type_trans(skb, fast_rx->dev);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ if (rx->napi)
+ napi_gro_receive(rx->napi, skb);
+ else
+ netif_receive_skb(skb);
+
+ return true;
+ drop:
+ dev_kfree_skb(skb);
+ sta->rx_stats.dropped++;
+ return true;
+}
+
/*
* This function returns whether or not the SKB
* was destined for RX processing or not, which,
@@ -3503,6 +3832,21 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,

rx->skb = skb;

+ /* See if we can do fast-rx; if we have to copy we already lost,
+ * so punt in that case. We should never have to deliver a data
+ * frame to multiple interfaces anyway.
+ *
+ * We skip the ieee80211_accept_frame() call and do the necessary
+ * checking inside ieee80211_invoke_fast_rx().
+ */
+ if (consume && rx->sta) {
+ struct ieee80211_fast_rx *fast_rx;
+
+ fast_rx = rcu_dereference(rx->sta->fast_rx);
+ if (fast_rx && ieee80211_invoke_fast_rx(rx, fast_rx))
+ return true;
+ }
+
if (!ieee80211_accept_frame(rx))
return false;

diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index f097a5e..877e983 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -1874,6 +1874,7 @@ int sta_info_move_state(struct sta_info *sta,
atomic_dec(&sta->sdata->bss->num_mcast_sta);
clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
ieee80211_clear_fast_xmit(sta);
+ ieee80211_clear_fast_rx(sta);
}
break;
case IEEE80211_STA_AUTHORIZED:
@@ -1884,6 +1885,7 @@ int sta_info_move_state(struct sta_info *sta,
atomic_inc(&sta->sdata->bss->num_mcast_sta);
set_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
ieee80211_check_fast_xmit(sta);
+ ieee80211_check_fast_rx(sta);
}
break;
default:
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index cbce43f..6ee37e3 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -286,6 +286,38 @@ struct ieee80211_fast_tx {
};

/**
+ * struct ieee80211_fast_rx - RX fastpath information
+ * @dev: netdevice for reporting the SKB
+ * @vif_type: (P2P-less) interface type of the original sdata (sdata->vif.type)
+ * @vif_addr: interface address
+ * @rfc1042_hdr: copy of the RFC 1042 SNAP header (to have in cache)
+ * @control_port_protocol: control port protocol copied from sdata
+ * @expected_ds_bits: from/to DS bits expected
+ * @icv_len: length of the MIC if present
+ * @key: bool indicating encryption is expected (key is set)
+ * @sta_notify: notify the MLME code (once)
+ * @internal_forward: forward froms internally on AP/VLAN type interfaces
+ * @da_offs: offset of the DA in the header (for header conversion)
+ * @sa_offs: offset of the SA in the header (for header conversion)
+ * @rcu_head: RCU head for freeing this structure
+ */
+struct ieee80211_fast_rx {
+ struct net_device *dev;
+ enum nl80211_iftype vif_type;
+ u8 vif_addr[ETH_ALEN] __aligned(2);
+ u8 rfc1042_hdr[6] __aligned(2);
+ __be16 control_port_protocol;
+ __le16 expected_ds_bits;
+ u8 icv_len;
+ u8 key:1,
+ sta_notify:1,
+ internal_forward:1;
+ u8 da_offs, sa_offs;
+
+ struct rcu_head rcu_head;
+};
+
+/**
* struct mesh_sta - mesh STA information
* @plink_lock: serialize access to plink fields
* @llid: Local link ID
@@ -391,6 +423,7 @@ DECLARE_EWMA(signal, 1024, 8)
* @cipher_scheme: optional cipher scheme for this station
* @reserved_tid: reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED)
* @fast_tx: TX fastpath information
+ * @fast_rx: RX fastpath information
* @tdls_chandef: a TDLS peer can have a wider chandef that is compatible to
* the BSS one.
* @tx_stats: TX statistics
@@ -414,6 +447,7 @@ struct sta_info {
spinlock_t lock;

struct ieee80211_fast_tx __rcu *fast_tx;
+ struct ieee80211_fast_rx __rcu *fast_rx;

#ifdef CONFIG_MAC80211_MESH
struct mesh_sta *mesh;
--
2.5.0


2016-03-31 17:04:16

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 02/10] mac80211: count MSDUs in A-MSDU properly

From: Johannes Berg <[email protected]>

For the RX MSDU statistics, we need to count the number of
MSDUs created and accepted from an A-MSDU. Right now, all
frames in any A-MSDUs were completely ignored. Fix this by
moving the RX MSDU statistics accounting into the deliver
function.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/rx.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 6c3829d..d979818 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2111,6 +2111,15 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)

ieee80211_rx_stats(dev, skb->len);

+ if (rx->sta) {
+ /* The seqno index has the same property as needed
+ * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS
+ * for non-QoS-data frames. Here we know it's a data
+ * frame, so count MSDUs.
+ */
+ rx->sta->rx_stats.msdu[rx->seqno_idx]++;
+ }
+
if ((sdata->vif.type == NL80211_IFTYPE_AP ||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
!(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
@@ -2397,15 +2406,6 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
return RX_DROP_MONITOR;

- if (rx->sta) {
- /* The seqno index has the same property as needed
- * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS
- * for non-QoS-data frames. Here we know it's a data
- * frame, so count MSDUs.
- */
- rx->sta->rx_stats.msdu[rx->seqno_idx]++;
- }
-
/*
* Send unexpected-4addr-frame event to hostapd. For older versions,
* also drop the frame to cooked monitor interfaces.
--
2.5.0


2016-03-31 17:04:19

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 05/10] mac80211: remove rx_stats.last_rx update after sta alloc

From: Johannes Berg <[email protected]>

There's no need to update rx_stats.last_rx after allocating
a station since it's already updated during allocation.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/ibss.c | 4 ----
net/mac80211/ocb.c | 2 --
2 files changed, 6 deletions(-)

diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index fc32383..b3407db 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -649,8 +649,6 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid,
return NULL;
}

- sta->rx_stats.last_rx = jiffies;
-
/* make sure mandatory rates are always added */
sband = local->hw.wiphy->bands[band];
sta->sta.supp_rates[band] = supp_rates |
@@ -1236,8 +1234,6 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
if (!sta)
return;

- sta->rx_stats.last_rx = jiffies;
-
/* make sure mandatory rates are always added */
sband = local->hw.wiphy->bands[band];
sta->sta.supp_rates[band] = supp_rates |
diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c
index 0be0aad..88e6ebb 100644
--- a/net/mac80211/ocb.c
+++ b/net/mac80211/ocb.c
@@ -75,8 +75,6 @@ void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata,
if (!sta)
return;

- sta->rx_stats.last_rx = jiffies;
-
/* Add only mandatory rates for now */
sband = local->hw.wiphy->bands[band];
sta->sta.supp_rates[band] =
--
2.5.0


2016-03-31 17:04:22

by Grumbach, Emmanuel

[permalink] [raw]
Subject: [PATCH 08/10] mac80211: fix RX u64 stats consistency on 32-bit platforms

From: Johannes Berg <[email protected]>

On 32-bit platforms, the 64-bit counters we keep need to be protected
to be consistently read. Use the u64_stats_sync mechanism to do that.

In order to not end up with overly long lines, refactor the tidstats
assignments a bit.

Signed-off-by: Johannes Berg <[email protected]>
---
net/mac80211/rx.c | 6 +++++
net/mac80211/sta_info.c | 72 ++++++++++++++++++++++++++++++-------------------
net/mac80211/sta_info.h | 5 +++-
3 files changed, 54 insertions(+), 29 deletions(-)

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 40981f8..1511bd1 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1441,7 +1441,11 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
ieee80211_sta_rx_notify(rx->sdata, hdr);

sta->rx_stats.fragments++;
+
+ u64_stats_update_begin(&rx->sta->rx_stats.syncp);
sta->rx_stats.bytes += rx->skb->len;
+ u64_stats_update_end(&rx->sta->rx_stats.syncp);
+
if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
sta->rx_stats.last_signal = status->signal;
ewma_signal_add(&sta->rx_stats_avg.signal, -status->signal);
@@ -2106,7 +2110,9 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
* for non-QoS-data frames. Here we know it's a data
* frame, so count MSDUs.
*/
+ u64_stats_update_begin(&rx->sta->rx_stats.syncp);
rx->sta->rx_stats.msdu[rx->seqno_idx]++;
+ u64_stats_update_end(&rx->sta->rx_stats.syncp);
}

if ((sdata->vif.type == NL80211_IFTYPE_AP ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 81f1d6c..f097a5e 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -335,6 +335,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
sta->sdata = sdata;
sta->rx_stats.last_rx = jiffies;

+ u64_stats_init(&sta->rx_stats.syncp);
+
sta->sta_state = IEEE80211_STA_NONE;

/* Mark TID as unreserved */
@@ -1971,6 +1973,41 @@ static void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo)
sta_stats_decode_rate(sta->local, rate, rinfo);
}

+static void sta_set_tidstats(struct sta_info *sta,
+ struct cfg80211_tid_stats *tidstats,
+ int tid)
+{
+ struct ieee80211_local *local = sta->local;
+
+ if (!(tidstats->filled & BIT(NL80211_TID_STATS_RX_MSDU))) {
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin(&sta->rx_stats.syncp);
+ tidstats->rx_msdu = sta->rx_stats.msdu[tid];
+ } while (u64_stats_fetch_retry(&sta->rx_stats.syncp, start));
+
+ tidstats->filled |= BIT(NL80211_TID_STATS_RX_MSDU);
+ }
+
+ if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU))) {
+ tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU);
+ tidstats->tx_msdu = sta->tx_stats.msdu[tid];
+ }
+
+ if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU_RETRIES)) &&
+ ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
+ tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU_RETRIES);
+ tidstats->tx_msdu_retries = sta->status_stats.msdu_retries[tid];
+ }
+
+ if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU_FAILED)) &&
+ ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
+ tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU_FAILED);
+ tidstats->tx_msdu_failed = sta->status_stats.msdu_failed[tid];
+ }
+}
+
void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
@@ -2025,7 +2062,12 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)

if (!(sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES64) |
BIT(NL80211_STA_INFO_RX_BYTES)))) {
- sinfo->rx_bytes = sta->rx_stats.bytes;
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin(&sta->rx_stats.syncp);
+ sinfo->rx_bytes = sta->rx_stats.bytes;
+ } while (u64_stats_fetch_retry(&sta->rx_stats.syncp, start));
sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64);
}

@@ -2097,33 +2139,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) {
struct cfg80211_tid_stats *tidstats = &sinfo->pertid[i];

- if (!(tidstats->filled & BIT(NL80211_TID_STATS_RX_MSDU))) {
- tidstats->filled |= BIT(NL80211_TID_STATS_RX_MSDU);
- tidstats->rx_msdu = sta->rx_stats.msdu[i];
- }
-
- if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU))) {
- tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU);
- tidstats->tx_msdu = sta->tx_stats.msdu[i];
- }
-
- if (!(tidstats->filled &
- BIT(NL80211_TID_STATS_TX_MSDU_RETRIES)) &&
- ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
- tidstats->filled |=
- BIT(NL80211_TID_STATS_TX_MSDU_RETRIES);
- tidstats->tx_msdu_retries =
- sta->status_stats.msdu_retries[i];
- }
-
- if (!(tidstats->filled &
- BIT(NL80211_TID_STATS_TX_MSDU_FAILED)) &&
- ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
- tidstats->filled |=
- BIT(NL80211_TID_STATS_TX_MSDU_FAILED);
- tidstats->tx_msdu_failed =
- sta->status_stats.msdu_failed[i];
- }
+ sta_set_tidstats(sta, tidstats, i);
}

if (ieee80211_vif_is_mesh(&sdata->vif)) {
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index f36f560..cbce43f 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -18,6 +18,7 @@
#include <linux/average.h>
#include <linux/etherdevice.h>
#include <linux/rhashtable.h>
+#include <linux/u64_stats_sync.h>
#include "key.h"

/**
@@ -444,7 +445,6 @@ struct sta_info {
/* Updated from RX path only, no locking requirements */
struct {
unsigned long packets;
- u64 bytes;
unsigned long last_rx;
unsigned long num_duplicates;
unsigned long fragments;
@@ -453,6 +453,9 @@ struct sta_info {
u8 chains;
s8 chain_signal_last[IEEE80211_MAX_CHAINS];
u16 last_rate;
+
+ struct u64_stats_sync syncp;
+ u64 bytes;
u64 msdu[IEEE80211_NUM_TIDS + 1];
} rx_stats;
struct {
--
2.5.0


2016-04-01 04:16:39

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 10/10] mac80211: enable collecting station statistics per-CPU

Hi Johannes,

[auto build test WARNING on v4.6-rc1]
[also build test WARNING on next-20160331]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url: https://github.com/0day-ci/linux/commits/Emmanuel-Grumbach/mac80211-allow-passing-transmitter-station-on-RX/20160401-010817
reproduce: make htmldocs

All warnings (new ones prefixed by >>):

include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
include/net/mac80211.h:1094: warning: Enum value 'RX_FLAG_DUP_VALIDATED' not described in enum 'mac80211_rx_flags'
>> net/mac80211/sta_info.h:547: warning: No description found for parameter 'pcpu_rx_stats'
net/mac80211/sta_info.h:547: warning: Excess struct/union/enum/typedef member 'beacon_loss_count' description in 'sta_info'
>> net/mac80211/sta_info.h:547: warning: No description found for parameter 'pcpu_rx_stats'
net/mac80211/sta_info.h:547: warning: Excess struct/union/enum/typedef member 'beacon_loss_count' description in 'sta_info'
>> net/mac80211/sta_info.h:547: warning: No description found for parameter 'pcpu_rx_stats'
net/mac80211/sta_info.h:547: warning: Excess struct/union/enum/typedef member 'beacon_loss_count' description in 'sta_info'
>> net/mac80211/sta_info.h:547: warning: No description found for parameter 'pcpu_rx_stats'
net/mac80211/sta_info.h:547: warning: Excess struct/union/enum/typedef member 'beacon_loss_count' description in 'sta_info'
>> net/mac80211/sta_info.h:547: warning: No description found for parameter 'pcpu_rx_stats'
net/mac80211/sta_info.h:547: warning: Excess struct/union/enum/typedef member 'beacon_loss_count' description in 'sta_info'

vim +/pcpu_rx_stats +547 net/mac80211/sta_info.h

e9f207f0f Jiri Benc 2007-05-05 531 struct dentry *dir;
63044e9f5 Johannes Berg 2008-10-07 532 bool add_has_run;
e9f207f0f Jiri Benc 2007-05-05 533 } debugfs;
e9f207f0f Jiri Benc 2007-05-05 534 #endif
17741cdc2 Johannes Berg 2008-09-11 535
0af83d3df Johannes Berg 2012-12-27 536 enum ieee80211_sta_rx_bandwidth cur_max_bandwidth;
0af83d3df Johannes Berg 2012-12-27 537
687da1322 Emmanuel Grumbach 2013-10-01 538 enum ieee80211_smps_mode known_smps_mode;
2475b1cc0 Max Stepanov 2013-03-24 539 const struct ieee80211_cipher_scheme *cipher_scheme;
687da1322 Emmanuel Grumbach 2013-10-01 540
b6da911b3 Liad Kaufman 2014-11-19 541 u8 reserved_tid;
b6da911b3 Liad Kaufman 2014-11-19 542
0fabfaafe Arik Nemtsov 2015-06-10 543 struct cfg80211_chan_def tdls_chandef;
0fabfaafe Arik Nemtsov 2015-06-10 544
17741cdc2 Johannes Berg 2008-09-11 545 /* keep last! */
17741cdc2 Johannes Berg 2008-09-11 546 struct ieee80211_sta sta;
f0706e828 Jiri Benc 2007-05-05 @547 };
f0706e828 Jiri Benc 2007-05-05 548
57cf8043a Javier Cardona 2011-05-13 549 static inline enum nl80211_plink_state sta_plink_state(struct sta_info *sta)
d6d1a5a70 Johannes Berg 2008-02-25 550 {
d6d1a5a70 Johannes Berg 2008-02-25 551 #ifdef CONFIG_MAC80211_MESH
433f5bc1c Johannes Berg 2015-06-17 552 return sta->mesh->plink_state;
d6d1a5a70 Johannes Berg 2008-02-25 553 #endif
57cf8043a Javier Cardona 2011-05-13 554 return NL80211_PLINK_LISTEN;
d6d1a5a70 Johannes Berg 2008-02-25 555 }

:::::: The code at line 547 was first introduced by commit
:::::: f0706e828e96d0fa4e80c0d25aa98523f6d589a0 [MAC80211]: Add mac80211 wireless stack.

:::::: TO: Jiri Benc <[email protected]>
:::::: CC: David S. Miller <[email protected]>

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (13.85 kB)
.config.gz (6.14 kB)
Download all attachments