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 <wgong@codeaurora.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org> Link: https://lore.kernel.org/r/20200427080416.8265-3-wgong@codeaurora.org
This commit is contained in:
@@ -219,6 +219,89 @@ static void ath10k_wmi_tlv_event_vdev_delete_resp(struct ath10k *ar,
|
||||
complete(&ar->vdev_delete_done);
|
||||
}
|
||||
|
||||
static int ath10k_wmi_tlv_parse_peer_stats_info(struct ath10k *ar, u16 tag, u16 len,
|
||||
const void *ptr, void *data)
|
||||
{
|
||||
const struct wmi_tlv_peer_stats_info *stat = ptr;
|
||||
struct ieee80211_sta *sta;
|
||||
struct ath10k_sta *arsta;
|
||||
|
||||
if (tag != WMI_TLV_TAG_STRUCT_PEER_STATS_INFO)
|
||||
return -EPROTO;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI,
|
||||
"wmi tlv stats peer addr %pMF rx rate code 0x%x bit rate %d kbps\n",
|
||||
stat->peer_macaddr.addr,
|
||||
__le32_to_cpu(stat->last_rx_rate_code),
|
||||
__le32_to_cpu(stat->last_rx_bitrate_kbps));
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI,
|
||||
"wmi tlv stats tx rate code 0x%x bit rate %d kbps\n",
|
||||
__le32_to_cpu(stat->last_tx_rate_code),
|
||||
__le32_to_cpu(stat->last_tx_bitrate_kbps));
|
||||
|
||||
sta = ieee80211_find_sta_by_ifaddr(ar->hw, stat->peer_macaddr.addr, NULL);
|
||||
if (!sta) {
|
||||
ath10k_warn(ar, "not found station for peer stats\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
arsta->rx_rate_code = __le32_to_cpu(stat->last_rx_rate_code);
|
||||
arsta->rx_bitrate_kbps = __le32_to_cpu(stat->last_rx_bitrate_kbps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_wmi_tlv_op_pull_peer_stats_info(struct ath10k *ar,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
const void **tb;
|
||||
const struct wmi_tlv_peer_stats_info_ev *ev;
|
||||
const void *data;
|
||||
u32 num_peer_stats;
|
||||
int ret;
|
||||
|
||||
tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
|
||||
if (IS_ERR(tb)) {
|
||||
ret = PTR_ERR(tb);
|
||||
ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ev = tb[WMI_TLV_TAG_STRUCT_PEER_STATS_INFO_EVENT];
|
||||
data = tb[WMI_TLV_TAG_ARRAY_STRUCT];
|
||||
|
||||
if (!ev || !data) {
|
||||
kfree(tb);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
num_peer_stats = __le32_to_cpu(ev->num_peers);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI,
|
||||
"wmi tlv peer stats info update peer vdev id %d peers %i more data %d\n",
|
||||
__le32_to_cpu(ev->vdev_id),
|
||||
num_peer_stats,
|
||||
__le32_to_cpu(ev->more_data));
|
||||
|
||||
ret = ath10k_wmi_tlv_iter(ar, data, ath10k_wmi_tlv_len(data),
|
||||
ath10k_wmi_tlv_parse_peer_stats_info, NULL);
|
||||
if (ret)
|
||||
ath10k_warn(ar, "failed to parse stats info tlv: %d\n", ret);
|
||||
|
||||
kfree(tb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_wmi_tlv_event_peer_stats_info(struct ath10k *ar,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PEER_STATS_INFO_EVENTID\n");
|
||||
ath10k_wmi_tlv_op_pull_peer_stats_info(ar, skb);
|
||||
complete(&ar->peer_stats_info_complete);
|
||||
}
|
||||
|
||||
static int ath10k_wmi_tlv_event_diag_data(struct ath10k *ar,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
@@ -576,6 +659,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
|
||||
case WMI_TLV_UPDATE_STATS_EVENTID:
|
||||
ath10k_wmi_event_update_stats(ar, skb);
|
||||
break;
|
||||
case WMI_TLV_PEER_STATS_INFO_EVENTID:
|
||||
ath10k_wmi_tlv_event_peer_stats_info(ar, skb);
|
||||
break;
|
||||
case WMI_TLV_VDEV_START_RESP_EVENTID:
|
||||
ath10k_wmi_event_vdev_start_resp(ar, skb);
|
||||
break;
|
||||
@@ -2897,6 +2983,36 @@ ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask)
|
||||
return skb;
|
||||
}
|
||||
|
||||
static struct sk_buff *
|
||||
ath10k_wmi_tlv_op_gen_request_peer_stats_info(struct ath10k *ar,
|
||||
u32 vdev_id,
|
||||
enum wmi_peer_stats_info_request_type type,
|
||||
u8 *addr,
|
||||
u32 reset)
|
||||
{
|
||||
struct wmi_tlv_request_peer_stats_info *cmd;
|
||||
struct wmi_tlv *tlv;
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
|
||||
if (!skb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
tlv = (void *)skb->data;
|
||||
tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_REQUEST_PEER_STATS_INFO_CMD);
|
||||
tlv->len = __cpu_to_le16(sizeof(*cmd));
|
||||
cmd = (void *)tlv->value;
|
||||
cmd->vdev_id = __cpu_to_le32(vdev_id);
|
||||
cmd->request_type = __cpu_to_le32(type);
|
||||
|
||||
if (type == WMI_REQUEST_ONE_PEER_STATS_INFO)
|
||||
ether_addr_copy(cmd->peer_macaddr.addr, addr);
|
||||
|
||||
cmd->reset_after_request = reset;
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv request peer stats info\n");
|
||||
return skb;
|
||||
}
|
||||
|
||||
static int
|
||||
ath10k_wmi_mgmt_tx_alloc_msdu_id(struct ath10k *ar, struct sk_buff *skb,
|
||||
dma_addr_t paddr)
|
||||
@@ -4113,6 +4229,7 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = {
|
||||
.vdev_spectral_scan_configure_cmdid = WMI_TLV_SPECTRAL_SCAN_CONF_CMDID,
|
||||
.vdev_spectral_scan_enable_cmdid = WMI_TLV_SPECTRAL_SCAN_ENABLE_CMDID,
|
||||
.request_stats_cmdid = WMI_TLV_REQUEST_STATS_CMDID,
|
||||
.request_peer_stats_info_cmdid = WMI_TLV_REQUEST_PEER_STATS_INFO_CMDID,
|
||||
.set_arp_ns_offload_cmdid = WMI_TLV_SET_ARP_NS_OFFLOAD_CMDID,
|
||||
.network_list_offload_config_cmdid =
|
||||
WMI_TLV_NETWORK_LIST_OFFLOAD_CONFIG_CMDID,
|
||||
@@ -4417,6 +4534,7 @@ static const struct wmi_ops wmi_tlv_ops = {
|
||||
.gen_beacon_dma = ath10k_wmi_tlv_op_gen_beacon_dma,
|
||||
.gen_pdev_set_wmm = ath10k_wmi_tlv_op_gen_pdev_set_wmm,
|
||||
.gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats,
|
||||
.gen_request_peer_stats_info = ath10k_wmi_tlv_op_gen_request_peer_stats_info,
|
||||
.gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang,
|
||||
/* .gen_mgmt_tx = not implemented; HTT is used */
|
||||
.gen_mgmt_tx_send = ath10k_wmi_tlv_op_gen_mgmt_tx_send,
|
||||
|
Reference in New Issue
Block a user