ath10k: add bitrate parse for peer stats info
The rate code and rate kbps report by WMI_TLV_PEER_STATS_INFO_EVENTID from firmware contains all the bitrate info which include OFDM, CCK, HT/VHT, and mac80211 need the struct rate_info which include below parameters: flags: bitflag of flags from &enum rate_info_flags mcs: mcs index if struct describes an HT/VHT/HE rate legacy: bitrate in 100kbit/s for 802.11abg nss: number of streams (VHT & HE only) bw: bandwidth (from &enum rate_info_bw) For OFDM/CCK, its rate kbps indicate the bitrate, for HT/VHT, mac80211 need the above 5 parameters to cacluate the bitrate and show by iw. After parse the bitrate info, iw show the correct rx bitrate: localhost ~ # iw wlan0 link rx bitrate: 234.0 MBit/s VHT-MCS 3 80MHz VHT-NSS 2 rx bitrate: 40.5 MBit/s MCS 2 40MHz rx bitrate: 72.2 MBit/s MCS 7 short GI rx bitrate: 54.0 MBit/s rx bitrate: 48.0 MBit/s Tested with QCA6174 SDIO with firmware WLAN.RMH.4.4.1-00042. Signed-off-by: Wen Gong <wgong@codeaurora.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org> Link: https://lore.kernel.org/r/20200427080416.8265-4-wgong@codeaurora.org
This commit is contained in:
parent
0f7cb26830
commit
3344b99d69
|
@ -149,6 +149,26 @@ static inline u32 host_interest_item_address(u32 item_offset)
|
|||
return QCA988X_HOST_INTEREST_ADDRESS + item_offset;
|
||||
}
|
||||
|
||||
enum ath10k_phy_mode {
|
||||
ATH10K_PHY_MODE_LEGACY = 0,
|
||||
ATH10K_PHY_MODE_HT = 1,
|
||||
ATH10K_PHY_MODE_VHT = 2,
|
||||
};
|
||||
|
||||
/* Data rate 100KBPS based on IE Index */
|
||||
struct ath10k_index_ht_data_rate_type {
|
||||
u8 beacon_rate_index;
|
||||
u16 supported_rate[4];
|
||||
};
|
||||
|
||||
/* Data rate 100KBPS based on IE Index */
|
||||
struct ath10k_index_vht_data_rate_type {
|
||||
u8 beacon_rate_index;
|
||||
u16 supported_VHT80_rate[2];
|
||||
u16 supported_VHT40_rate[2];
|
||||
u16 supported_VHT20_rate[2];
|
||||
};
|
||||
|
||||
struct ath10k_bmi {
|
||||
bool done_sent;
|
||||
};
|
||||
|
|
|
@ -8305,6 +8305,157 @@ static void ath10k_mac_op_sta_pre_rcu_remove(struct ieee80211_hw *hw,
|
|||
peer->removed = true;
|
||||
}
|
||||
|
||||
/* HT MCS parameters with Nss = 1 */
|
||||
static const struct ath10k_index_ht_data_rate_type supported_ht_mcs_rate_nss1[] = {
|
||||
/* MCS L20 L40 S20 S40 */
|
||||
{0, { 65, 135, 72, 150} },
|
||||
{1, { 130, 270, 144, 300} },
|
||||
{2, { 195, 405, 217, 450} },
|
||||
{3, { 260, 540, 289, 600} },
|
||||
{4, { 390, 810, 433, 900} },
|
||||
{5, { 520, 1080, 578, 1200} },
|
||||
{6, { 585, 1215, 650, 1350} },
|
||||
{7, { 650, 1350, 722, 1500} }
|
||||
};
|
||||
|
||||
/* HT MCS parameters with Nss = 2 */
|
||||
static const struct ath10k_index_ht_data_rate_type supported_ht_mcs_rate_nss2[] = {
|
||||
/* MCS L20 L40 S20 S40 */
|
||||
{0, {130, 270, 144, 300} },
|
||||
{1, {260, 540, 289, 600} },
|
||||
{2, {390, 810, 433, 900} },
|
||||
{3, {520, 1080, 578, 1200} },
|
||||
{4, {780, 1620, 867, 1800} },
|
||||
{5, {1040, 2160, 1156, 2400} },
|
||||
{6, {1170, 2430, 1300, 2700} },
|
||||
{7, {1300, 2700, 1444, 3000} }
|
||||
};
|
||||
|
||||
/* MCS parameters with Nss = 1 */
|
||||
static const struct ath10k_index_vht_data_rate_type supported_vht_mcs_rate_nss1[] = {
|
||||
/* MCS L80 S80 L40 S40 L20 S20 */
|
||||
{0, {293, 325}, {135, 150}, {65, 72} },
|
||||
{1, {585, 650}, {270, 300}, {130, 144} },
|
||||
{2, {878, 975}, {405, 450}, {195, 217} },
|
||||
{3, {1170, 1300}, {540, 600}, {260, 289} },
|
||||
{4, {1755, 1950}, {810, 900}, {390, 433} },
|
||||
{5, {2340, 2600}, {1080, 1200}, {520, 578} },
|
||||
{6, {2633, 2925}, {1215, 1350}, {585, 650} },
|
||||
{7, {2925, 3250}, {1350, 1500}, {650, 722} },
|
||||
{8, {3510, 3900}, {1620, 1800}, {780, 867} },
|
||||
{9, {3900, 4333}, {1800, 2000}, {780, 867} }
|
||||
};
|
||||
|
||||
/*MCS parameters with Nss = 2 */
|
||||
static const struct ath10k_index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = {
|
||||
/* MCS L80 S80 L40 S40 L20 S20 */
|
||||
{0, {585, 650}, {270, 300}, {130, 144} },
|
||||
{1, {1170, 1300}, {540, 600}, {260, 289} },
|
||||
{2, {1755, 1950}, {810, 900}, {390, 433} },
|
||||
{3, {2340, 2600}, {1080, 1200}, {520, 578} },
|
||||
{4, {3510, 3900}, {1620, 1800}, {780, 867} },
|
||||
{5, {4680, 5200}, {2160, 2400}, {1040, 1156} },
|
||||
{6, {5265, 5850}, {2430, 2700}, {1170, 1300} },
|
||||
{7, {5850, 6500}, {2700, 3000}, {1300, 1444} },
|
||||
{8, {7020, 7800}, {3240, 3600}, {1560, 1733} },
|
||||
{9, {7800, 8667}, {3600, 4000}, {1560, 1733} }
|
||||
};
|
||||
|
||||
static void ath10k_mac_get_rate_flags_ht(struct ath10k *ar, u32 rate, u8 nss, u8 mcs,
|
||||
u8 *flags, u8 *bw)
|
||||
{
|
||||
struct ath10k_index_ht_data_rate_type *mcs_rate;
|
||||
|
||||
mcs_rate = (struct ath10k_index_ht_data_rate_type *)
|
||||
((nss == 1) ? &supported_ht_mcs_rate_nss1 :
|
||||
&supported_ht_mcs_rate_nss2);
|
||||
|
||||
if (rate == mcs_rate[mcs].supported_rate[0]) {
|
||||
*bw = RATE_INFO_BW_20;
|
||||
} else if (rate == mcs_rate[mcs].supported_rate[1]) {
|
||||
*bw |= RATE_INFO_BW_40;
|
||||
} else if (rate == mcs_rate[mcs].supported_rate[2]) {
|
||||
*bw |= RATE_INFO_BW_20;
|
||||
*flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
} else if (rate == mcs_rate[mcs].supported_rate[3]) {
|
||||
*bw |= RATE_INFO_BW_40;
|
||||
*flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
} else {
|
||||
ath10k_warn(ar, "invalid ht params rate %d 100kbps nss %d mcs %d",
|
||||
rate, nss, mcs);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath10k_mac_get_rate_flags_vht(struct ath10k *ar, u32 rate, u8 nss, u8 mcs,
|
||||
u8 *flags, u8 *bw)
|
||||
{
|
||||
struct ath10k_index_vht_data_rate_type *mcs_rate;
|
||||
|
||||
mcs_rate = (struct ath10k_index_vht_data_rate_type *)
|
||||
((nss == 1) ? &supported_vht_mcs_rate_nss1 :
|
||||
&supported_vht_mcs_rate_nss2);
|
||||
|
||||
if (rate == mcs_rate[mcs].supported_VHT80_rate[0]) {
|
||||
*bw = RATE_INFO_BW_80;
|
||||
} else if (rate == mcs_rate[mcs].supported_VHT80_rate[1]) {
|
||||
*bw = RATE_INFO_BW_80;
|
||||
*flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
} else if (rate == mcs_rate[mcs].supported_VHT40_rate[0]) {
|
||||
*bw = RATE_INFO_BW_40;
|
||||
} else if (rate == mcs_rate[mcs].supported_VHT40_rate[1]) {
|
||||
*bw = RATE_INFO_BW_40;
|
||||
*flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
} else if (rate == mcs_rate[mcs].supported_VHT20_rate[0]) {
|
||||
*bw = RATE_INFO_BW_20;
|
||||
} else if (rate == mcs_rate[mcs].supported_VHT20_rate[1]) {
|
||||
*bw = RATE_INFO_BW_20;
|
||||
*flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
} else {
|
||||
ath10k_warn(ar, "invalid vht params rate %d 100kbps nss %d mcs %d",
|
||||
rate, nss, mcs);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath10k_mac_get_rate_flags(struct ath10k *ar, u32 rate,
|
||||
enum ath10k_phy_mode mode, u8 nss, u8 mcs,
|
||||
u8 *flags, u8 *bw)
|
||||
{
|
||||
if (mode == ATH10K_PHY_MODE_HT) {
|
||||
*flags = RATE_INFO_FLAGS_MCS;
|
||||
ath10k_mac_get_rate_flags_ht(ar, rate, nss, mcs, flags, bw);
|
||||
} else if (mode == ATH10K_PHY_MODE_VHT) {
|
||||
*flags = RATE_INFO_FLAGS_VHT_MCS;
|
||||
ath10k_mac_get_rate_flags_vht(ar, rate, nss, mcs, flags, bw);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath10k_mac_parse_bitrate(struct ath10k *ar, u32 rate_code,
|
||||
u32 bitrate_kbps, struct rate_info *rate)
|
||||
{
|
||||
enum ath10k_phy_mode mode = ATH10K_PHY_MODE_LEGACY;
|
||||
enum wmi_rate_preamble preamble = WMI_TLV_GET_HW_RC_PREAM_V1(rate_code);
|
||||
u8 nss = WMI_TLV_GET_HW_RC_NSS_V1(rate_code) + 1;
|
||||
u8 mcs = WMI_TLV_GET_HW_RC_RATE_V1(rate_code);
|
||||
u8 flags = 0, bw = 0;
|
||||
|
||||
if (preamble == WMI_RATE_PREAMBLE_HT)
|
||||
mode = ATH10K_PHY_MODE_HT;
|
||||
else if (preamble == WMI_RATE_PREAMBLE_VHT)
|
||||
mode = ATH10K_PHY_MODE_VHT;
|
||||
|
||||
ath10k_mac_get_rate_flags(ar, bitrate_kbps / 100, mode, nss, mcs, &flags, &bw);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_MAC,
|
||||
"mac parse bitrate preamble %d mode %d nss %d mcs %d flags %x bw %d\n",
|
||||
preamble, mode, nss, mcs, flags, bw);
|
||||
|
||||
rate->flags = flags;
|
||||
rate->bw = bw;
|
||||
rate->legacy = bitrate_kbps / 100;
|
||||
rate->nss = nss;
|
||||
rate->mcs = mcs;
|
||||
}
|
||||
|
||||
static void ath10k_mac_sta_get_peer_stats_info(struct ath10k *ar,
|
||||
struct ieee80211_sta *sta,
|
||||
struct station_info *sinfo)
|
||||
|
@ -8341,6 +8492,16 @@ static void ath10k_mac_sta_get_peer_stats_info(struct ath10k *ar,
|
|||
ath10k_warn(ar, "timed out waiting peer stats info\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (arsta->rx_rate_code != 0 && arsta->rx_bitrate_kbps != 0) {
|
||||
ath10k_mac_parse_bitrate(ar, arsta->rx_rate_code,
|
||||
arsta->rx_bitrate_kbps,
|
||||
&sinfo->rxrate);
|
||||
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE);
|
||||
arsta->rx_rate_code = 0;
|
||||
arsta->rx_bitrate_kbps = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ath10k_sta_statistics(struct ieee80211_hw *hw,
|
||||
|
|
|
@ -2174,6 +2174,15 @@ struct wmi_tlv_peer_stats_info {
|
|||
__le32 peer_rssi_per_chain[WMI_TLV_MAX_CHAINS];
|
||||
} __packed;
|
||||
|
||||
#define HW_RATECODE_PREAM_V1_MASK GENMASK(10, 8)
|
||||
#define WMI_TLV_GET_HW_RC_PREAM_V1(rc) FIELD_GET(HW_RATECODE_PREAM_V1_MASK, rc)
|
||||
|
||||
#define HW_RATECODE_NSS_V1_MASK GENMASK(7, 5)
|
||||
#define WMI_TLV_GET_HW_RC_NSS_V1(rc) FIELD_GET(HW_RATECODE_NSS_V1_MASK, rc)
|
||||
|
||||
#define HW_RATECODE_RATE_V1_MASK GENMASK(4, 0)
|
||||
#define WMI_TLV_GET_HW_RC_RATE_V1(rc) FIELD_GET(HW_RATECODE_RATE_V1_MASK, rc)
|
||||
|
||||
struct wmi_tlv_p2p_noa_ev {
|
||||
__le32 vdev_id;
|
||||
} __packed;
|
||||
|
|
Loading…
Reference in New Issue