diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-11-09 09:07:02 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2012-11-26 06:42:59 -0500 |
commit | 5614618ec498320e3b686fea246e50b833865c34 (patch) | |
tree | a319fd5575bc7ee090136e6e7829200a152886cf /net | |
parent | db9c64cf8d9d3fcbc34b09d037f266d1fc9f928c (diff) |
mac80211: support drivers reporting VHT RX
Add support to mac80211 for having drivers report
received VHT MCS information.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/cfg.c | 26 | ||||
-rw-r--r-- | net/mac80211/rx.c | 20 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 4 | ||||
-rw-r--r-- | net/mac80211/util.c | 14 |
4 files changed, 55 insertions, 9 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index b9702d16d608..0b9de4fa54a6 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -374,7 +374,8 @@ static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, in | |||
374 | { | 374 | { |
375 | enum ieee80211_band band = ieee80211_get_sdata_band(sta->sdata); | 375 | enum ieee80211_band band = ieee80211_get_sdata_band(sta->sdata); |
376 | 376 | ||
377 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) { | 377 | if (!(rate->flags & RATE_INFO_FLAGS_MCS) && |
378 | !(rate->flags & RATE_INFO_FLAGS_VHT_MCS)) { | ||
378 | struct ieee80211_supported_band *sband; | 379 | struct ieee80211_supported_band *sband; |
379 | sband = sta->local->hw.wiphy->bands[band]; | 380 | sband = sta->local->hw.wiphy->bands[band]; |
380 | rate->legacy = sband->bitrates[idx].bitrate; | 381 | rate->legacy = sband->bitrates[idx].bitrate; |
@@ -444,13 +445,32 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
444 | sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); | 445 | sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); |
445 | 446 | ||
446 | sinfo->rxrate.flags = 0; | 447 | sinfo->rxrate.flags = 0; |
447 | if (sta->last_rx_rate_flag & RX_FLAG_HT) | 448 | if (sta->last_rx_rate_flag & RX_FLAG_HT) { |
448 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS; | 449 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS; |
450 | sinfo->rxrate.mcs = sta->last_rx_rate_idx; | ||
451 | } else if (sta->last_rx_rate_flag & RX_FLAG_VHT) { | ||
452 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_VHT_MCS; | ||
453 | sinfo->rxrate.nss = sta->last_rx_rate_vht_nss; | ||
454 | sinfo->rxrate.mcs = sta->last_rx_rate_idx; | ||
455 | } else { | ||
456 | struct ieee80211_supported_band *sband; | ||
457 | |||
458 | sband = sta->local->hw.wiphy->bands[ | ||
459 | ieee80211_get_sdata_band(sta->sdata)]; | ||
460 | sinfo->rxrate.legacy = | ||
461 | sband->bitrates[sta->last_rx_rate_idx].bitrate; | ||
462 | } | ||
463 | |||
449 | if (sta->last_rx_rate_flag & RX_FLAG_40MHZ) | 464 | if (sta->last_rx_rate_flag & RX_FLAG_40MHZ) |
450 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | 465 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; |
451 | if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI) | 466 | if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI) |
452 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI; | 467 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI; |
453 | rate_idx_to_bitrate(&sinfo->rxrate, sta, sta->last_rx_rate_idx); | 468 | if (sta->last_rx_rate_flag & RX_FLAG_80MHZ) |
469 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; | ||
470 | if (sta->last_rx_rate_flag & RX_FLAG_80P80MHZ) | ||
471 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH; | ||
472 | if (sta->last_rx_rate_flag & RX_FLAG_160MHZ) | ||
473 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; | ||
454 | 474 | ||
455 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 475 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
456 | #ifdef CONFIG_MAC80211_MESH | 476 | #ifdef CONFIG_MAC80211_MESH |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b2ae2baefc9a..825f33cf7bbc 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -193,7 +193,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
193 | pos++; | 193 | pos++; |
194 | 194 | ||
195 | /* IEEE80211_RADIOTAP_RATE */ | 195 | /* IEEE80211_RADIOTAP_RATE */ |
196 | if (!rate || status->flag & RX_FLAG_HT) { | 196 | if (!rate || status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) { |
197 | /* | 197 | /* |
198 | * Without rate information don't add it. If we have, | 198 | * Without rate information don't add it. If we have, |
199 | * MCS information is a separate field in radiotap, | 199 | * MCS information is a separate field in radiotap, |
@@ -213,7 +213,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
213 | if (status->band == IEEE80211_BAND_5GHZ) | 213 | if (status->band == IEEE80211_BAND_5GHZ) |
214 | put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, | 214 | put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, |
215 | pos); | 215 | pos); |
216 | else if (status->flag & RX_FLAG_HT) | 216 | else if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) |
217 | put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ, | 217 | put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ, |
218 | pos); | 218 | pos); |
219 | else if (rate && rate->flags & IEEE80211_RATE_ERP_G) | 219 | else if (rate && rate->flags & IEEE80211_RATE_ERP_G) |
@@ -1356,6 +1356,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1356 | if (ieee80211_is_data(hdr->frame_control)) { | 1356 | if (ieee80211_is_data(hdr->frame_control)) { |
1357 | sta->last_rx_rate_idx = status->rate_idx; | 1357 | sta->last_rx_rate_idx = status->rate_idx; |
1358 | sta->last_rx_rate_flag = status->flag; | 1358 | sta->last_rx_rate_flag = status->flag; |
1359 | sta->last_rx_rate_vht_nss = status->vht_nss; | ||
1359 | } | 1360 | } |
1360 | } | 1361 | } |
1361 | } else if (!is_multicast_ether_addr(hdr->addr1)) { | 1362 | } else if (!is_multicast_ether_addr(hdr->addr1)) { |
@@ -1367,6 +1368,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1367 | if (ieee80211_is_data(hdr->frame_control)) { | 1368 | if (ieee80211_is_data(hdr->frame_control)) { |
1368 | sta->last_rx_rate_idx = status->rate_idx; | 1369 | sta->last_rx_rate_idx = status->rate_idx; |
1369 | sta->last_rx_rate_flag = status->flag; | 1370 | sta->last_rx_rate_flag = status->flag; |
1371 | sta->last_rx_rate_vht_nss = status->vht_nss; | ||
1370 | } | 1372 | } |
1371 | } | 1373 | } |
1372 | 1374 | ||
@@ -2710,7 +2712,8 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx, | |||
2710 | status = IEEE80211_SKB_RXCB((rx->skb)); | 2712 | status = IEEE80211_SKB_RXCB((rx->skb)); |
2711 | 2713 | ||
2712 | sband = rx->local->hw.wiphy->bands[status->band]; | 2714 | sband = rx->local->hw.wiphy->bands[status->band]; |
2713 | if (!(status->flag & RX_FLAG_HT)) | 2715 | if (!(status->flag & RX_FLAG_HT) && |
2716 | !(status->flag & RX_FLAG_VHT)) | ||
2714 | rate = &sband->bitrates[status->rate_idx]; | 2717 | rate = &sband->bitrates[status->rate_idx]; |
2715 | 2718 | ||
2716 | ieee80211_rx_cooked_monitor(rx, rate); | 2719 | ieee80211_rx_cooked_monitor(rx, rate); |
@@ -2877,8 +2880,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, | |||
2877 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | 2880 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; |
2878 | } else if (!rx->sta) { | 2881 | } else if (!rx->sta) { |
2879 | int rate_idx; | 2882 | int rate_idx; |
2880 | if (status->flag & RX_FLAG_HT) | 2883 | if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) |
2881 | rate_idx = 0; /* TODO: HT rates */ | 2884 | rate_idx = 0; /* TODO: HT/VHT rates */ |
2882 | else | 2885 | else |
2883 | rate_idx = status->rate_idx; | 2886 | rate_idx = status->rate_idx; |
2884 | ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2, | 2887 | ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2, |
@@ -3154,6 +3157,13 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
3154 | status->rate_idx, | 3157 | status->rate_idx, |
3155 | status->rate_idx)) | 3158 | status->rate_idx)) |
3156 | goto drop; | 3159 | goto drop; |
3160 | } else if (status->flag & RX_FLAG_VHT) { | ||
3161 | if (WARN_ONCE(status->rate_idx > 9 || | ||
3162 | !status->vht_nss || | ||
3163 | status->vht_nss > 8, | ||
3164 | "Rate marked as a VHT rate but data is invalid: MCS: %d, NSS: %d\n", | ||
3165 | status->rate_idx, status->vht_nss)) | ||
3166 | goto drop; | ||
3157 | } else { | 3167 | } else { |
3158 | if (WARN_ON(status->rate_idx >= sband->n_bitrates)) | 3168 | if (WARN_ON(status->rate_idx >= sband->n_bitrates)) |
3159 | goto drop; | 3169 | goto drop; |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 2b2d5aac2bb1..6835cea4e402 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -227,6 +227,7 @@ struct sta_ampdu_mlme { | |||
227 | * "the" transmit rate | 227 | * "the" transmit rate |
228 | * @last_rx_rate_idx: rx status rate index of the last data packet | 228 | * @last_rx_rate_idx: rx status rate index of the last data packet |
229 | * @last_rx_rate_flag: rx status flag of the last data packet | 229 | * @last_rx_rate_flag: rx status flag of the last data packet |
230 | * @last_rx_rate_vht_nss: rx status nss of last data packet | ||
230 | * @lock: used for locking all fields that require locking, see comments | 231 | * @lock: used for locking all fields that require locking, see comments |
231 | * in the header file. | 232 | * in the header file. |
232 | * @drv_unblock_wk: used for driver PS unblocking | 233 | * @drv_unblock_wk: used for driver PS unblocking |
@@ -343,7 +344,8 @@ struct sta_info { | |||
343 | unsigned long tx_fragments; | 344 | unsigned long tx_fragments; |
344 | struct ieee80211_tx_rate last_tx_rate; | 345 | struct ieee80211_tx_rate last_tx_rate; |
345 | int last_rx_rate_idx; | 346 | int last_rx_rate_idx; |
346 | int last_rx_rate_flag; | 347 | u32 last_rx_rate_flag; |
348 | u8 last_rx_rate_vht_nss; | ||
347 | u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; | 349 | u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; |
348 | 350 | ||
349 | /* | 351 | /* |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 3b3dd32f121f..dc7f6b264593 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -2069,6 +2069,20 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, | |||
2069 | ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | 2069 | ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; |
2070 | if (status->flag & RX_FLAG_SHORT_GI) | 2070 | if (status->flag & RX_FLAG_SHORT_GI) |
2071 | ri.flags |= RATE_INFO_FLAGS_SHORT_GI; | 2071 | ri.flags |= RATE_INFO_FLAGS_SHORT_GI; |
2072 | } else if (status->flag & RX_FLAG_VHT) { | ||
2073 | ri.flags |= RATE_INFO_FLAGS_VHT_MCS; | ||
2074 | ri.mcs = status->rate_idx; | ||
2075 | ri.nss = status->vht_nss; | ||
2076 | if (status->flag & RX_FLAG_40MHZ) | ||
2077 | ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | ||
2078 | if (status->flag & RX_FLAG_80MHZ) | ||
2079 | ri.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; | ||
2080 | if (status->flag & RX_FLAG_80P80MHZ) | ||
2081 | ri.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH; | ||
2082 | if (status->flag & RX_FLAG_160MHZ) | ||
2083 | ri.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; | ||
2084 | if (status->flag & RX_FLAG_SHORT_GI) | ||
2085 | ri.flags |= RATE_INFO_FLAGS_SHORT_GI; | ||
2072 | } else { | 2086 | } else { |
2073 | struct ieee80211_supported_band *sband; | 2087 | struct ieee80211_supported_band *sband; |
2074 | 2088 | ||