Skip to content

Commit 0f7cb26

Browse files
Wen GongKalle Valo
authored andcommitted
ath10k: add rx bitrate report for SDIO
For SDIO chip, its rx indication is struct htt_rx_indication_hl, which does not include the bitrate info as well as PCIe, for PCIe, it use function ath10k_htt_rx_h_rates to parse the bitrate info in struct rx_ppdu_start and then report it to mac80211 via ieee80211_rx_status. SDIO does not have the same info as PCIe, then iw command can not get the rx bitrate by "iw wlan0 station dump". for example, it always show 6.0 MBit/s localhost ~ # iw wlan0 link Connected to 3c:28:6d:96:fd:69 (on wlan0) SSID: kukui_test freq: 5180 RX: 111800 bytes (595 packets) TX: 35419 bytes (202 packets) signal: -41 dBm rx bitrate: 6.0 MBit/s This patch is to send WMI_TLV_REQUEST_PEER_STATS_INFO_CMDID to firmware for ath10k_sta_statistics and save the rx bitrate for WMI event WMI_TLV_PEER_STATS_INFO_EVENTID. This patch only effect SDIO chip, ath10k_mac_sta_get_peer_stats_info has check for bitrate_statistics of hw_params, this patch only enable it for "qca6174 hw3.2 sdio". Tested with QCA6174 SDIO firmware WLAN.RMH.4.4.1-00042. Signed-off-by: Wen Gong <[email protected]> Signed-off-by: Kalle Valo <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 2289bef commit 0f7cb26

File tree

8 files changed

+304
-0
lines changed

8 files changed

+304
-0
lines changed

drivers/net/wireless/ath/ath10k/core.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
190190
.uart_pin_workaround = true,
191191
.tx_stats_over_pktlog = false,
192192
.bmi_large_size_download = true,
193+
.supports_peer_stats_info = true,
193194
},
194195
{
195196
.id = QCA6174_HW_2_1_VERSION,
@@ -3277,6 +3278,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
32773278
init_completion(&ar->thermal.wmi_sync);
32783279
init_completion(&ar->bss_survey_done);
32793280
init_completion(&ar->peer_delete_done);
3281+
init_completion(&ar->peer_stats_info_complete);
32803282

32813283
INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work);
32823284

drivers/net/wireless/ath/ath10k/core.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,8 @@ struct ath10k_sta {
504504
u32 tx_failed;
505505
u32 last_tx_bitrate;
506506

507+
u32 rx_rate_code;
508+
u32 rx_bitrate_kbps;
507509
struct work_struct update_wk;
508510
u64 rx_duration;
509511
struct ath10k_htt_tx_stats *tx_stats;
@@ -1089,6 +1091,7 @@ struct ath10k {
10891091
int last_wmi_vdev_start_status;
10901092
struct completion vdev_setup_done;
10911093
struct completion vdev_delete_done;
1094+
struct completion peer_stats_info_complete;
10921095

10931096
struct workqueue_struct *workqueue;
10941097
/* Auxiliary workqueue */

drivers/net/wireless/ath/ath10k/hw.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,9 @@ struct ath10k_hw_params {
623623

624624
/* tx stats support over pktlog */
625625
bool tx_stats_over_pktlog;
626+
627+
/* provides bitrates for sta_statistics using WMI_TLV_PEER_STATS_INFO_EVENTID */
628+
bool supports_peer_stats_info;
626629
};
627630

628631
struct htt_rx_desc;

drivers/net/wireless/ath/ath10k/mac.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8305,6 +8305,44 @@ static void ath10k_mac_op_sta_pre_rcu_remove(struct ieee80211_hw *hw,
83058305
peer->removed = true;
83068306
}
83078307

8308+
static void ath10k_mac_sta_get_peer_stats_info(struct ath10k *ar,
8309+
struct ieee80211_sta *sta,
8310+
struct station_info *sinfo)
8311+
{
8312+
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
8313+
struct ath10k_peer *peer;
8314+
unsigned long time_left;
8315+
int ret;
8316+
8317+
if (!(ar->hw_params.supports_peer_stats_info &&
8318+
arsta->arvif->vdev_type == WMI_VDEV_TYPE_STA))
8319+
return;
8320+
8321+
spin_lock_bh(&ar->data_lock);
8322+
peer = ath10k_peer_find(ar, arsta->arvif->vdev_id, sta->addr);
8323+
spin_unlock_bh(&ar->data_lock);
8324+
if (!peer)
8325+
return;
8326+
8327+
reinit_completion(&ar->peer_stats_info_complete);
8328+
8329+
ret = ath10k_wmi_request_peer_stats_info(ar,
8330+
arsta->arvif->vdev_id,
8331+
WMI_REQUEST_ONE_PEER_STATS_INFO,
8332+
arsta->arvif->bssid,
8333+
0);
8334+
if (ret && ret != -EOPNOTSUPP) {
8335+
ath10k_warn(ar, "could not request peer stats info: %d\n", ret);
8336+
return;
8337+
}
8338+
8339+
time_left = wait_for_completion_timeout(&ar->peer_stats_info_complete, 3 * HZ);
8340+
if (time_left == 0) {
8341+
ath10k_warn(ar, "timed out waiting peer stats info\n");
8342+
return;
8343+
}
8344+
}
8345+
83088346
static void ath10k_sta_statistics(struct ieee80211_hw *hw,
83098347
struct ieee80211_vif *vif,
83108348
struct ieee80211_sta *sta,
@@ -8340,6 +8378,8 @@ static void ath10k_sta_statistics(struct ieee80211_hw *hw,
83408378
sinfo->tx_failed = arsta->tx_failed;
83418379
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
83428380
}
8381+
8382+
ath10k_mac_sta_get_peer_stats_info(ar, sta, sinfo);
83438383
}
83448384

83458385
static const struct ieee80211_ops ath10k_ops = {

drivers/net/wireless/ath/ath10k/wmi-ops.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,13 @@ struct wmi_ops {
126126
struct sk_buff *(*gen_pdev_set_wmm)(struct ath10k *ar,
127127
const struct wmi_wmm_params_all_arg *arg);
128128
struct sk_buff *(*gen_request_stats)(struct ath10k *ar, u32 stats_mask);
129+
struct sk_buff *(*gen_request_peer_stats_info)(struct ath10k *ar,
130+
u32 vdev_id,
131+
enum
132+
wmi_peer_stats_info_request_type
133+
type,
134+
u8 *addr,
135+
u32 reset);
129136
struct sk_buff *(*gen_force_fw_hang)(struct ath10k *ar,
130137
enum wmi_force_fw_hang_type type,
131138
u32 delay_ms);
@@ -1064,6 +1071,29 @@ ath10k_wmi_request_stats(struct ath10k *ar, u32 stats_mask)
10641071
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid);
10651072
}
10661073

1074+
static inline int
1075+
ath10k_wmi_request_peer_stats_info(struct ath10k *ar,
1076+
u32 vdev_id,
1077+
enum wmi_peer_stats_info_request_type type,
1078+
u8 *addr,
1079+
u32 reset)
1080+
{
1081+
struct sk_buff *skb;
1082+
1083+
if (!ar->wmi.ops->gen_request_peer_stats_info)
1084+
return -EOPNOTSUPP;
1085+
1086+
skb = ar->wmi.ops->gen_request_peer_stats_info(ar,
1087+
vdev_id,
1088+
type,
1089+
addr,
1090+
reset);
1091+
if (IS_ERR(skb))
1092+
return PTR_ERR(skb);
1093+
1094+
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_peer_stats_info_cmdid);
1095+
}
1096+
10671097
static inline int
10681098
ath10k_wmi_force_fw_hang(struct ath10k *ar,
10691099
enum wmi_force_fw_hang_type type, u32 delay_ms)

drivers/net/wireless/ath/ath10k/wmi-tlv.c

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,89 @@ static void ath10k_wmi_tlv_event_vdev_delete_resp(struct ath10k *ar,
219219
complete(&ar->vdev_delete_done);
220220
}
221221

222+
static int ath10k_wmi_tlv_parse_peer_stats_info(struct ath10k *ar, u16 tag, u16 len,
223+
const void *ptr, void *data)
224+
{
225+
const struct wmi_tlv_peer_stats_info *stat = ptr;
226+
struct ieee80211_sta *sta;
227+
struct ath10k_sta *arsta;
228+
229+
if (tag != WMI_TLV_TAG_STRUCT_PEER_STATS_INFO)
230+
return -EPROTO;
231+
232+
ath10k_dbg(ar, ATH10K_DBG_WMI,
233+
"wmi tlv stats peer addr %pMF rx rate code 0x%x bit rate %d kbps\n",
234+
stat->peer_macaddr.addr,
235+
__le32_to_cpu(stat->last_rx_rate_code),
236+
__le32_to_cpu(stat->last_rx_bitrate_kbps));
237+
238+
ath10k_dbg(ar, ATH10K_DBG_WMI,
239+
"wmi tlv stats tx rate code 0x%x bit rate %d kbps\n",
240+
__le32_to_cpu(stat->last_tx_rate_code),
241+
__le32_to_cpu(stat->last_tx_bitrate_kbps));
242+
243+
sta = ieee80211_find_sta_by_ifaddr(ar->hw, stat->peer_macaddr.addr, NULL);
244+
if (!sta) {
245+
ath10k_warn(ar, "not found station for peer stats\n");
246+
return -EINVAL;
247+
}
248+
249+
arsta = (struct ath10k_sta *)sta->drv_priv;
250+
arsta->rx_rate_code = __le32_to_cpu(stat->last_rx_rate_code);
251+
arsta->rx_bitrate_kbps = __le32_to_cpu(stat->last_rx_bitrate_kbps);
252+
253+
return 0;
254+
}
255+
256+
static int ath10k_wmi_tlv_op_pull_peer_stats_info(struct ath10k *ar,
257+
struct sk_buff *skb)
258+
{
259+
const void **tb;
260+
const struct wmi_tlv_peer_stats_info_ev *ev;
261+
const void *data;
262+
u32 num_peer_stats;
263+
int ret;
264+
265+
tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
266+
if (IS_ERR(tb)) {
267+
ret = PTR_ERR(tb);
268+
ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
269+
return ret;
270+
}
271+
272+
ev = tb[WMI_TLV_TAG_STRUCT_PEER_STATS_INFO_EVENT];
273+
data = tb[WMI_TLV_TAG_ARRAY_STRUCT];
274+
275+
if (!ev || !data) {
276+
kfree(tb);
277+
return -EPROTO;
278+
}
279+
280+
num_peer_stats = __le32_to_cpu(ev->num_peers);
281+
282+
ath10k_dbg(ar, ATH10K_DBG_WMI,
283+
"wmi tlv peer stats info update peer vdev id %d peers %i more data %d\n",
284+
__le32_to_cpu(ev->vdev_id),
285+
num_peer_stats,
286+
__le32_to_cpu(ev->more_data));
287+
288+
ret = ath10k_wmi_tlv_iter(ar, data, ath10k_wmi_tlv_len(data),
289+
ath10k_wmi_tlv_parse_peer_stats_info, NULL);
290+
if (ret)
291+
ath10k_warn(ar, "failed to parse stats info tlv: %d\n", ret);
292+
293+
kfree(tb);
294+
return 0;
295+
}
296+
297+
static void ath10k_wmi_tlv_event_peer_stats_info(struct ath10k *ar,
298+
struct sk_buff *skb)
299+
{
300+
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PEER_STATS_INFO_EVENTID\n");
301+
ath10k_wmi_tlv_op_pull_peer_stats_info(ar, skb);
302+
complete(&ar->peer_stats_info_complete);
303+
}
304+
222305
static int ath10k_wmi_tlv_event_diag_data(struct ath10k *ar,
223306
struct sk_buff *skb)
224307
{
@@ -576,6 +659,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
576659
case WMI_TLV_UPDATE_STATS_EVENTID:
577660
ath10k_wmi_event_update_stats(ar, skb);
578661
break;
662+
case WMI_TLV_PEER_STATS_INFO_EVENTID:
663+
ath10k_wmi_tlv_event_peer_stats_info(ar, skb);
664+
break;
579665
case WMI_TLV_VDEV_START_RESP_EVENTID:
580666
ath10k_wmi_event_vdev_start_resp(ar, skb);
581667
break;
@@ -2897,6 +2983,36 @@ ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask)
28972983
return skb;
28982984
}
28992985

2986+
static struct sk_buff *
2987+
ath10k_wmi_tlv_op_gen_request_peer_stats_info(struct ath10k *ar,
2988+
u32 vdev_id,
2989+
enum wmi_peer_stats_info_request_type type,
2990+
u8 *addr,
2991+
u32 reset)
2992+
{
2993+
struct wmi_tlv_request_peer_stats_info *cmd;
2994+
struct wmi_tlv *tlv;
2995+
struct sk_buff *skb;
2996+
2997+
skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
2998+
if (!skb)
2999+
return ERR_PTR(-ENOMEM);
3000+
3001+
tlv = (void *)skb->data;
3002+
tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_REQUEST_PEER_STATS_INFO_CMD);
3003+
tlv->len = __cpu_to_le16(sizeof(*cmd));
3004+
cmd = (void *)tlv->value;
3005+
cmd->vdev_id = __cpu_to_le32(vdev_id);
3006+
cmd->request_type = __cpu_to_le32(type);
3007+
3008+
if (type == WMI_REQUEST_ONE_PEER_STATS_INFO)
3009+
ether_addr_copy(cmd->peer_macaddr.addr, addr);
3010+
3011+
cmd->reset_after_request = reset;
3012+
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv request peer stats info\n");
3013+
return skb;
3014+
}
3015+
29003016
static int
29013017
ath10k_wmi_mgmt_tx_alloc_msdu_id(struct ath10k *ar, struct sk_buff *skb,
29023018
dma_addr_t paddr)
@@ -4113,6 +4229,7 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = {
41134229
.vdev_spectral_scan_configure_cmdid = WMI_TLV_SPECTRAL_SCAN_CONF_CMDID,
41144230
.vdev_spectral_scan_enable_cmdid = WMI_TLV_SPECTRAL_SCAN_ENABLE_CMDID,
41154231
.request_stats_cmdid = WMI_TLV_REQUEST_STATS_CMDID,
4232+
.request_peer_stats_info_cmdid = WMI_TLV_REQUEST_PEER_STATS_INFO_CMDID,
41164233
.set_arp_ns_offload_cmdid = WMI_TLV_SET_ARP_NS_OFFLOAD_CMDID,
41174234
.network_list_offload_config_cmdid =
41184235
WMI_TLV_NETWORK_LIST_OFFLOAD_CONFIG_CMDID,
@@ -4417,6 +4534,7 @@ static const struct wmi_ops wmi_tlv_ops = {
44174534
.gen_beacon_dma = ath10k_wmi_tlv_op_gen_beacon_dma,
44184535
.gen_pdev_set_wmm = ath10k_wmi_tlv_op_gen_pdev_set_wmm,
44194536
.gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats,
4537+
.gen_request_peer_stats_info = ath10k_wmi_tlv_op_gen_request_peer_stats_info,
44204538
.gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang,
44214539
/* .gen_mgmt_tx = not implemented; HTT is used */
44224540
.gen_mgmt_tx_send = ath10k_wmi_tlv_op_gen_mgmt_tx_send,

0 commit comments

Comments
 (0)