Commit 0f7cb268 authored by Wen Gong's avatar Wen Gong Committed by Kalle Valo
Browse files

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: default avatarWen Gong <wgong@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20200427080416.8265-3-wgong@codeaurora.org
parent 2289bef2
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -190,6 +190,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
		.uart_pin_workaround = true,
		.tx_stats_over_pktlog = false,
		.bmi_large_size_download = true,
		.supports_peer_stats_info = true,
	},
	{
		.id = QCA6174_HW_2_1_VERSION,
@@ -3277,6 +3278,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
	init_completion(&ar->thermal.wmi_sync);
	init_completion(&ar->bss_survey_done);
	init_completion(&ar->peer_delete_done);
	init_completion(&ar->peer_stats_info_complete);

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

+3 −0
Original line number Diff line number Diff line
@@ -504,6 +504,8 @@ struct ath10k_sta {
	u32 tx_failed;
	u32 last_tx_bitrate;

	u32 rx_rate_code;
	u32 rx_bitrate_kbps;
	struct work_struct update_wk;
	u64 rx_duration;
	struct ath10k_htt_tx_stats *tx_stats;
@@ -1089,6 +1091,7 @@ struct ath10k {
	int last_wmi_vdev_start_status;
	struct completion vdev_setup_done;
	struct completion vdev_delete_done;
	struct completion peer_stats_info_complete;

	struct workqueue_struct *workqueue;
	/* Auxiliary workqueue */
+3 −0
Original line number Diff line number Diff line
@@ -623,6 +623,9 @@ struct ath10k_hw_params {

	/* tx stats support over pktlog */
	bool tx_stats_over_pktlog;

	/* provides bitrates for sta_statistics using WMI_TLV_PEER_STATS_INFO_EVENTID */
	bool supports_peer_stats_info;
};

struct htt_rx_desc;
+40 −0
Original line number Diff line number Diff line
@@ -8305,6 +8305,44 @@ static void ath10k_mac_op_sta_pre_rcu_remove(struct ieee80211_hw *hw,
			peer->removed = true;
}

static void ath10k_mac_sta_get_peer_stats_info(struct ath10k *ar,
					       struct ieee80211_sta *sta,
					       struct station_info *sinfo)
{
	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
	struct ath10k_peer *peer;
	unsigned long time_left;
	int ret;

	if (!(ar->hw_params.supports_peer_stats_info &&
	      arsta->arvif->vdev_type == WMI_VDEV_TYPE_STA))
		return;

	spin_lock_bh(&ar->data_lock);
	peer = ath10k_peer_find(ar, arsta->arvif->vdev_id, sta->addr);
	spin_unlock_bh(&ar->data_lock);
	if (!peer)
		return;

	reinit_completion(&ar->peer_stats_info_complete);

	ret = ath10k_wmi_request_peer_stats_info(ar,
						 arsta->arvif->vdev_id,
						 WMI_REQUEST_ONE_PEER_STATS_INFO,
						 arsta->arvif->bssid,
						 0);
	if (ret && ret != -EOPNOTSUPP) {
		ath10k_warn(ar, "could not request peer stats info: %d\n", ret);
		return;
	}

	time_left = wait_for_completion_timeout(&ar->peer_stats_info_complete, 3 * HZ);
	if (time_left == 0) {
		ath10k_warn(ar, "timed out waiting peer stats info\n");
		return;
	}
}

static void ath10k_sta_statistics(struct ieee80211_hw *hw,
				  struct ieee80211_vif *vif,
				  struct ieee80211_sta *sta,
@@ -8340,6 +8378,8 @@ static void ath10k_sta_statistics(struct ieee80211_hw *hw,
		sinfo->tx_failed = arsta->tx_failed;
		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
	}

	ath10k_mac_sta_get_peer_stats_info(ar, sta, sinfo);
}

static const struct ieee80211_ops ath10k_ops = {
+30 −0
Original line number Diff line number Diff line
@@ -126,6 +126,13 @@ struct wmi_ops {
	struct sk_buff *(*gen_pdev_set_wmm)(struct ath10k *ar,
					    const struct wmi_wmm_params_all_arg *arg);
	struct sk_buff *(*gen_request_stats)(struct ath10k *ar, u32 stats_mask);
	struct sk_buff *(*gen_request_peer_stats_info)(struct ath10k *ar,
						       u32 vdev_id,
						       enum
						       wmi_peer_stats_info_request_type
						       type,
						       u8 *addr,
						       u32 reset);
	struct sk_buff *(*gen_force_fw_hang)(struct ath10k *ar,
					     enum wmi_force_fw_hang_type type,
					     u32 delay_ms);
@@ -1064,6 +1071,29 @@ ath10k_wmi_request_stats(struct ath10k *ar, u32 stats_mask)
	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid);
}

static inline int
ath10k_wmi_request_peer_stats_info(struct ath10k *ar,
				   u32 vdev_id,
				   enum wmi_peer_stats_info_request_type type,
				   u8 *addr,
				   u32 reset)
{
	struct sk_buff *skb;

	if (!ar->wmi.ops->gen_request_peer_stats_info)
		return -EOPNOTSUPP;

	skb = ar->wmi.ops->gen_request_peer_stats_info(ar,
						       vdev_id,
						       type,
						       addr,
						       reset);
	if (IS_ERR(skb))
		return PTR_ERR(skb);

	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_peer_stats_info_cmdid);
}

static inline int
ath10k_wmi_force_fw_hang(struct ath10k *ar,
			 enum wmi_force_fw_hang_type type, u32 delay_ms)
Loading