aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLorenzo Bianconi <lorenzo.bianconi83@gmail.com>2015-08-06 17:47:33 -0400
committerJohannes Berg <johannes.berg@intel.com>2015-08-14 11:49:51 -0400
commitb119ad6e726cc805f739f8f6843b9de4df1f895e (patch)
tree059dd7446c6e86eb3df1619efd7acab6a9e07a96
parente910867bd285bb8470c47076d99d0325aaea895c (diff)
mac80211: add rate mask logic for vht rates
Define rc_rateidx_vht_mcs_mask array and rate_idx_match_vht_mcs_mask() method in order to apply mcs mask for vht rates Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--net/mac80211/cfg.c16
-rw-r--r--net/mac80211/debugfs_netdev.c34
-rw-r--r--net/mac80211/ieee80211_i.h5
-rw-r--r--net/mac80211/iface.c14
-rw-r--r--net/mac80211/rate.c102
-rw-r--r--net/mac80211/vht.c26
6 files changed, 181 insertions, 16 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 5789d8353505..685ec13ed7c2 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2504,16 +2504,26 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
2504 sdata->rc_rateidx_mask[i] = mask->control[i].legacy; 2504 sdata->rc_rateidx_mask[i] = mask->control[i].legacy;
2505 memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].ht_mcs, 2505 memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].ht_mcs,
2506 sizeof(mask->control[i].ht_mcs)); 2506 sizeof(mask->control[i].ht_mcs));
2507 memcpy(sdata->rc_rateidx_vht_mcs_mask[i],
2508 mask->control[i].vht_mcs,
2509 sizeof(mask->control[i].vht_mcs));
2507 2510
2508 sdata->rc_has_mcs_mask[i] = false; 2511 sdata->rc_has_mcs_mask[i] = false;
2512 sdata->rc_has_vht_mcs_mask[i] = false;
2509 if (!sband) 2513 if (!sband)
2510 continue; 2514 continue;
2511 2515
2512 for (j = 0; j < IEEE80211_HT_MCS_MASK_LEN; j++) 2516 for (j = 0; j < IEEE80211_HT_MCS_MASK_LEN; j++) {
2513 if (~sdata->rc_rateidx_mcs_mask[i][j]) { 2517 if (~sdata->rc_rateidx_mcs_mask[i][j])
2514 sdata->rc_has_mcs_mask[i] = true; 2518 sdata->rc_has_mcs_mask[i] = true;
2519
2520 if (~sdata->rc_rateidx_vht_mcs_mask[i][j])
2521 sdata->rc_has_vht_mcs_mask[i] = true;
2522
2523 if (sdata->rc_has_mcs_mask[i] &&
2524 sdata->rc_has_vht_mcs_mask[i])
2515 break; 2525 break;
2516 } 2526 }
2517 } 2527 }
2518 2528
2519 return 0; 2529 return 0;
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index c09c0131bfa2..1021e87c051f 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -186,6 +186,38 @@ IEEE80211_IF_FILE(rc_rateidx_mcs_mask_2ghz,
186IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz, 186IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz,
187 rc_rateidx_mcs_mask[IEEE80211_BAND_5GHZ], HEXARRAY); 187 rc_rateidx_mcs_mask[IEEE80211_BAND_5GHZ], HEXARRAY);
188 188
189static ssize_t ieee80211_if_fmt_rc_rateidx_vht_mcs_mask_2ghz(
190 const struct ieee80211_sub_if_data *sdata,
191 char *buf, int buflen)
192{
193 int i, len = 0;
194 const u16 *mask = sdata->rc_rateidx_vht_mcs_mask[IEEE80211_BAND_2GHZ];
195
196 for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
197 len += scnprintf(buf + len, buflen - len, "%04x ", mask[i]);
198 len += scnprintf(buf + len, buflen - len, "\n");
199
200 return len;
201}
202
203IEEE80211_IF_FILE_R(rc_rateidx_vht_mcs_mask_2ghz);
204
205static ssize_t ieee80211_if_fmt_rc_rateidx_vht_mcs_mask_5ghz(
206 const struct ieee80211_sub_if_data *sdata,
207 char *buf, int buflen)
208{
209 int i, len = 0;
210 const u16 *mask = sdata->rc_rateidx_vht_mcs_mask[IEEE80211_BAND_5GHZ];
211
212 for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
213 len += scnprintf(buf + len, buflen - len, "%04x ", mask[i]);
214 len += scnprintf(buf + len, buflen - len, "\n");
215
216 return len;
217}
218
219IEEE80211_IF_FILE_R(rc_rateidx_vht_mcs_mask_5ghz);
220
189IEEE80211_IF_FILE(flags, flags, HEX); 221IEEE80211_IF_FILE(flags, flags, HEX);
190IEEE80211_IF_FILE(state, state, LHEX); 222IEEE80211_IF_FILE(state, state, LHEX);
191IEEE80211_IF_FILE(txpower, vif.bss_conf.txpower, DEC); 223IEEE80211_IF_FILE(txpower, vif.bss_conf.txpower, DEC);
@@ -565,6 +597,8 @@ static void add_common_files(struct ieee80211_sub_if_data *sdata)
565 DEBUGFS_ADD(rc_rateidx_mask_5ghz); 597 DEBUGFS_ADD(rc_rateidx_mask_5ghz);
566 DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); 598 DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
567 DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); 599 DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
600 DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_2ghz);
601 DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_5ghz);
568 DEBUGFS_ADD(hw_queues); 602 DEBUGFS_ADD(hw_queues);
569} 603}
570 604
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 36f217e842d8..6e52659f923f 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -901,6 +901,9 @@ struct ieee80211_sub_if_data {
901 bool rc_has_mcs_mask[IEEE80211_NUM_BANDS]; 901 bool rc_has_mcs_mask[IEEE80211_NUM_BANDS];
902 u8 rc_rateidx_mcs_mask[IEEE80211_NUM_BANDS][IEEE80211_HT_MCS_MASK_LEN]; 902 u8 rc_rateidx_mcs_mask[IEEE80211_NUM_BANDS][IEEE80211_HT_MCS_MASK_LEN];
903 903
904 bool rc_has_vht_mcs_mask[IEEE80211_NUM_BANDS];
905 u16 rc_rateidx_vht_mcs_mask[IEEE80211_NUM_BANDS][NL80211_VHT_NSS_MAX];
906
904 union { 907 union {
905 struct ieee80211_if_ap ap; 908 struct ieee80211_if_ap ap;
906 struct ieee80211_if_wds wds; 909 struct ieee80211_if_wds wds;
@@ -1713,6 +1716,8 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
1713 enum ieee80211_band band, bool nss_only); 1716 enum ieee80211_band band, bool nss_only);
1714void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata, 1717void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata,
1715 struct ieee80211_sta_vht_cap *vht_cap); 1718 struct ieee80211_sta_vht_cap *vht_cap);
1719void ieee80211_get_vht_mask_from_cap(__le16 vht_cap,
1720 u16 vht_mask[NL80211_VHT_NSS_MAX]);
1716 1721
1717/* Spectrum management */ 1722/* Spectrum management */
1718void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, 1723void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 0fba7f97a963..6964fc6a8ea2 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1788,13 +1788,23 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
1788 sband = local->hw.wiphy->bands[i]; 1788 sband = local->hw.wiphy->bands[i];
1789 sdata->rc_rateidx_mask[i] = 1789 sdata->rc_rateidx_mask[i] =
1790 sband ? (1 << sband->n_bitrates) - 1 : 0; 1790 sband ? (1 << sband->n_bitrates) - 1 : 0;
1791 if (sband) 1791 if (sband) {
1792 __le16 cap;
1793 u16 *vht_rate_mask;
1794
1792 memcpy(sdata->rc_rateidx_mcs_mask[i], 1795 memcpy(sdata->rc_rateidx_mcs_mask[i],
1793 sband->ht_cap.mcs.rx_mask, 1796 sband->ht_cap.mcs.rx_mask,
1794 sizeof(sdata->rc_rateidx_mcs_mask[i])); 1797 sizeof(sdata->rc_rateidx_mcs_mask[i]));
1795 else 1798
1799 cap = sband->vht_cap.vht_mcs.rx_mcs_map;
1800 vht_rate_mask = sdata->rc_rateidx_vht_mcs_mask[i];
1801 ieee80211_get_vht_mask_from_cap(cap, vht_rate_mask);
1802 } else {
1796 memset(sdata->rc_rateidx_mcs_mask[i], 0, 1803 memset(sdata->rc_rateidx_mcs_mask[i], 0,
1797 sizeof(sdata->rc_rateidx_mcs_mask[i])); 1804 sizeof(sdata->rc_rateidx_mcs_mask[i]));
1805 memset(sdata->rc_rateidx_vht_mcs_mask[i], 0,
1806 sizeof(sdata->rc_rateidx_vht_mcs_mask[i]));
1807 }
1798 } 1808 }
1799 1809
1800 ieee80211_set_default_queues(sdata); 1810 ieee80211_set_default_queues(sdata);
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index 7e71de98297c..9857693b91ec 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -414,16 +414,77 @@ static bool rate_idx_match_mcs_mask(s8 *rate_idx, u8 *mcs_mask)
414 return false; 414 return false;
415} 415}
416 416
417static bool rate_idx_match_vht_mcs_mask(s8 *rate_idx, u16 *vht_mask)
418{
419 int i, j;
420 int ridx, rbit;
421
422 ridx = *rate_idx >> 4;
423 rbit = *rate_idx & 0xf;
424
425 if (ridx < 0 || ridx >= NL80211_VHT_NSS_MAX)
426 return false;
417 427
428 /* See whether the selected rate or anything below it is allowed. */
429 for (i = ridx; i >= 0; i--) {
430 for (j = rbit; j >= 0; j--) {
431 if (vht_mask[i] & BIT(j)) {
432 *rate_idx = (i << 4) | j;
433 return true;
434 }
435 }
436 rbit = 15;
437 }
438
439 /* Try to find a higher rate that would be allowed */
440 ridx = (*rate_idx + 1) >> 4;
441 rbit = (*rate_idx + 1) & 0xf;
442
443 for (i = ridx; i < NL80211_VHT_NSS_MAX; i++) {
444 for (j = rbit; j < 16; j++) {
445 if (vht_mask[i] & BIT(j)) {
446 *rate_idx = (i << 4) | j;
447 return true;
448 }
449 }
450 rbit = 0;
451 }
452 return false;
453}
418 454
419static void rate_idx_match_mask(s8 *rate_idx, u16 *rate_flags, 455static void rate_idx_match_mask(s8 *rate_idx, u16 *rate_flags,
420 struct ieee80211_supported_band *sband, 456 struct ieee80211_supported_band *sband,
421 enum nl80211_chan_width chan_width, 457 enum nl80211_chan_width chan_width,
422 u32 mask, 458 u32 mask,
423 u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) 459 u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN],
460 u16 vht_mask[NL80211_VHT_NSS_MAX])
424{ 461{
425 /* handle HT rates */ 462 if (*rate_flags & IEEE80211_TX_RC_VHT_MCS) {
426 if (*rate_flags & IEEE80211_TX_RC_MCS) { 463 /* handle VHT rates */
464 if (rate_idx_match_vht_mcs_mask(rate_idx, vht_mask))
465 return;
466
467 *rate_idx = 0;
468 /* keep protection flags */
469 *rate_flags &= (IEEE80211_TX_RC_USE_RTS_CTS |
470 IEEE80211_TX_RC_USE_CTS_PROTECT |
471 IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
472
473 *rate_flags |= IEEE80211_TX_RC_MCS;
474 if (chan_width == NL80211_CHAN_WIDTH_40)
475 *rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
476
477 if (rate_idx_match_mcs_mask(rate_idx, mcs_mask))
478 return;
479
480 /* also try the legacy rates. */
481 *rate_flags &= ~(IEEE80211_TX_RC_MCS |
482 IEEE80211_TX_RC_40_MHZ_WIDTH);
483 if (rate_idx_match_legacy_mask(rate_idx, sband->n_bitrates,
484 mask))
485 return;
486 } else if (*rate_flags & IEEE80211_TX_RC_MCS) {
487 /* handle HT rates */
427 if (rate_idx_match_mcs_mask(rate_idx, mcs_mask)) 488 if (rate_idx_match_mcs_mask(rate_idx, mcs_mask))
428 return; 489 return;
429 490
@@ -436,7 +497,7 @@ static void rate_idx_match_mask(s8 *rate_idx, u16 *rate_flags,
436 if (rate_idx_match_legacy_mask(rate_idx, sband->n_bitrates, 497 if (rate_idx_match_legacy_mask(rate_idx, sband->n_bitrates,
437 mask)) 498 mask))
438 return; 499 return;
439 } else if (!(*rate_flags & IEEE80211_TX_RC_VHT_MCS)) { 500 } else {
440 /* handle legacy rates */ 501 /* handle legacy rates */
441 if (rate_idx_match_legacy_mask(rate_idx, sband->n_bitrates, 502 if (rate_idx_match_legacy_mask(rate_idx, sband->n_bitrates,
442 mask)) 503 mask))
@@ -620,7 +681,8 @@ static void rate_control_fill_sta_table(struct ieee80211_sta *sta,
620static bool rate_control_cap_mask(struct ieee80211_sub_if_data *sdata, 681static bool rate_control_cap_mask(struct ieee80211_sub_if_data *sdata,
621 struct ieee80211_supported_band *sband, 682 struct ieee80211_supported_band *sband,
622 struct ieee80211_sta *sta, u32 *mask, 683 struct ieee80211_sta *sta, u32 *mask,
623 u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) 684 u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN],
685 u16 vht_mask[NL80211_VHT_NSS_MAX])
624{ 686{
625 u32 i, flags; 687 u32 i, flags;
626 688
@@ -632,7 +694,8 @@ static bool rate_control_cap_mask(struct ieee80211_sub_if_data *sdata,
632 } 694 }
633 695
634 if (*mask == (1 << sband->n_bitrates) - 1 && 696 if (*mask == (1 << sband->n_bitrates) - 1 &&
635 !sdata->rc_has_mcs_mask[sband->band]) 697 !sdata->rc_has_mcs_mask[sband->band] &&
698 !sdata->rc_has_vht_mcs_mask[sband->band])
636 return false; 699 return false;
637 700
638 if (sdata->rc_has_mcs_mask[sband->band]) 701 if (sdata->rc_has_mcs_mask[sband->band])
@@ -641,11 +704,25 @@ static bool rate_control_cap_mask(struct ieee80211_sub_if_data *sdata,
641 else 704 else
642 memset(mcs_mask, 0xff, IEEE80211_HT_MCS_MASK_LEN); 705 memset(mcs_mask, 0xff, IEEE80211_HT_MCS_MASK_LEN);
643 706
707 if (sdata->rc_has_vht_mcs_mask[sband->band])
708 memcpy(vht_mask, sdata->rc_rateidx_vht_mcs_mask[sband->band],
709 sizeof(u16) * NL80211_VHT_NSS_MAX);
710 else
711 memset(vht_mask, 0xff, sizeof(u16) * NL80211_VHT_NSS_MAX);
712
644 if (sta) { 713 if (sta) {
714 __le16 sta_vht_cap;
715 u16 sta_vht_mask[NL80211_VHT_NSS_MAX];
716
645 /* Filter out rates that the STA does not support */ 717 /* Filter out rates that the STA does not support */
646 *mask &= sta->supp_rates[sband->band]; 718 *mask &= sta->supp_rates[sband->band];
647 for (i = 0; i < sizeof(mcs_mask); i++) 719 for (i = 0; i < sizeof(mcs_mask); i++)
648 mcs_mask[i] &= sta->ht_cap.mcs.rx_mask[i]; 720 mcs_mask[i] &= sta->ht_cap.mcs.rx_mask[i];
721
722 sta_vht_cap = sta->vht_cap.vht_mcs.rx_mcs_map;
723 ieee80211_get_vht_mask_from_cap(sta_vht_cap, sta_vht_mask);
724 for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
725 vht_mask[i] &= sta_vht_mask[i];
649 } 726 }
650 727
651 return true; 728 return true;
@@ -659,10 +736,11 @@ rate_control_apply_mask_ratetbl(struct sta_info *sta,
659 int i; 736 int i;
660 u32 mask; 737 u32 mask;
661 u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]; 738 u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN];
739 u16 vht_mask[NL80211_VHT_NSS_MAX];
662 enum nl80211_chan_width chan_width; 740 enum nl80211_chan_width chan_width;
663 741
664 if (!rate_control_cap_mask(sta->sdata, sband, &sta->sta, &mask, 742 if (!rate_control_cap_mask(sta->sdata, sband, &sta->sta, &mask,
665 mcs_mask)) 743 mcs_mask, vht_mask))
666 return; 744 return;
667 745
668 chan_width = sta->sdata->vif.bss_conf.chandef.width; 746 chan_width = sta->sdata->vif.bss_conf.chandef.width;
@@ -671,7 +749,8 @@ rate_control_apply_mask_ratetbl(struct sta_info *sta,
671 break; 749 break;
672 750
673 rate_idx_match_mask(&rates->rate[i].idx, &rates->rate[i].flags, 751 rate_idx_match_mask(&rates->rate[i].idx, &rates->rate[i].flags,
674 sband, chan_width, mask, mcs_mask); 752 sband, chan_width, mask, mcs_mask,
753 vht_mask);
675 } 754 }
676} 755}
677 756
@@ -684,7 +763,7 @@ static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata,
684 enum nl80211_chan_width chan_width; 763 enum nl80211_chan_width chan_width;
685 u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]; 764 u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN];
686 u32 mask; 765 u32 mask;
687 u16 rate_flags; 766 u16 rate_flags, vht_mask[NL80211_VHT_NSS_MAX];
688 int i; 767 int i;
689 768
690 /* 769 /*
@@ -692,7 +771,8 @@ static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata,
692 * default mask (allow all rates) is used to save some processing for 771 * default mask (allow all rates) is used to save some processing for
693 * the common case. 772 * the common case.
694 */ 773 */
695 if (!rate_control_cap_mask(sdata, sband, sta, &mask, mcs_mask)) 774 if (!rate_control_cap_mask(sdata, sband, sta, &mask, mcs_mask,
775 vht_mask))
696 return; 776 return;
697 777
698 /* 778 /*
@@ -708,7 +788,7 @@ static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata,
708 788
709 rate_flags = rates[i].flags; 789 rate_flags = rates[i].flags;
710 rate_idx_match_mask(&rates[i].idx, &rate_flags, sband, 790 rate_idx_match_mask(&rates[i].idx, &rate_flags, sband,
711 chan_width, mask, mcs_mask); 791 chan_width, mask, mcs_mask, vht_mask);
712 rates[i].flags = rate_flags; 792 rates[i].flags = rate_flags;
713 } 793 }
714} 794}
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index f05808d0d80f..834ccdbc74be 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -426,3 +426,29 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
426 if (changed > 0) 426 if (changed > 0)
427 rate_control_rate_update(local, sband, sta, changed); 427 rate_control_rate_update(local, sband, sta, changed);
428} 428}
429
430void ieee80211_get_vht_mask_from_cap(__le16 vht_cap,
431 u16 vht_mask[NL80211_VHT_NSS_MAX])
432{
433 int i;
434 u16 mask, cap = le16_to_cpu(vht_cap);
435
436 for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
437 mask = (cap >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
438 switch (mask) {
439 case IEEE80211_VHT_MCS_SUPPORT_0_7:
440 vht_mask[i] = 0x00FF;
441 break;
442 case IEEE80211_VHT_MCS_SUPPORT_0_8:
443 vht_mask[i] = 0x01FF;
444 break;
445 case IEEE80211_VHT_MCS_SUPPORT_0_9:
446 vht_mask[i] = 0x03FF;
447 break;
448 case IEEE80211_VHT_MCS_NOT_SUPPORTED:
449 default:
450 vht_mask[i] = 0;
451 break;
452 }
453 }
454}