Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d70c0d46 authored by Maharaja Kennadyrajan's avatar Maharaja Kennadyrajan Committed by Kalle Valo
Browse files

ath10k: add debugfs support to get power save state change of STA



This patch helps to get the power save state change of each peer
connected to the AP. With WMI_10_4_PEER_STA_PS_STATECHG_EVENTID
event, ps state of each peer is reported to user space via
debugfs.

Use the below command to get the ps state of each sta:
cat /sys/kernel/debug/ieee80211/phyX/netdev::wlanX/stations/
XX:XX:XX:XX:XX:XX/peer_ps_state

If STA is in power save state, we get the peer_ps_state value as 1.
if STA is not in power save state, we get the peer_ps_state value as 0.
If ps_state event is disabled, we get the peer_ps_state value as 2.

We can enable/disable the ps_state events using the debugfs flag
"ps_state_enable"

echo Y > /sys/kernel/debug/ieee80211/phyX/ath10k/ps_state_enable

Y = 1 to enable and Y = 0 to disable

Tested in QCA4019 with firmware ver 10.4-3.2.1.1-00011

Signed-off-by: default avatarMaharaja Kennadyrajan <mkenna@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 4be3b05e
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -505,6 +505,8 @@ struct ath10k_sta {
	/* Protected with ar->data_lock */
	struct ath10k_sta_tid_stats tid_stats[IEEE80211_NUM_TIDS + 1];
#endif
	/* Protected with ar->data_lock */
	u32 peer_ps_state;
};

#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ)
@@ -946,6 +948,8 @@ struct ath10k {
	u32 low_5ghz_chan;
	u32 high_5ghz_chan;
	bool ani_enabled;
	/* protected by conf_mutex */
	u8 ps_state_enable;

	bool p2p;

+82 −0
Original line number Diff line number Diff line
@@ -2398,6 +2398,85 @@ static const struct file_operations fops_warm_hw_reset = {
	.llseek = default_llseek,
};

static void ath10k_peer_ps_state_disable(void *data,
					 struct ieee80211_sta *sta)
{
	struct ath10k *ar = data;
	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;

	spin_lock_bh(&ar->data_lock);
	arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED;
	spin_unlock_bh(&ar->data_lock);
}

static ssize_t ath10k_write_ps_state_enable(struct file *file,
					    const char __user *user_buf,
					    size_t count, loff_t *ppos)
{
	struct ath10k *ar = file->private_data;
	int ret;
	u32 param;
	u8 ps_state_enable;

	if (kstrtou8_from_user(user_buf, count, 0, &ps_state_enable))
		return -EINVAL;

	if (ps_state_enable > 1 || ps_state_enable < 0)
		return -EINVAL;

	mutex_lock(&ar->conf_mutex);

	if (ar->ps_state_enable == ps_state_enable) {
		ret = count;
		goto exit;
	}

	param = ar->wmi.pdev_param->peer_sta_ps_statechg_enable;
	ret = ath10k_wmi_pdev_set_param(ar, param, ps_state_enable);
	if (ret) {
		ath10k_warn(ar, "failed to enable ps_state_enable: %d\n",
			    ret);
		goto exit;
	}
	ar->ps_state_enable = ps_state_enable;

	if (!ar->ps_state_enable)
		ieee80211_iterate_stations_atomic(ar->hw,
						  ath10k_peer_ps_state_disable,
						  ar);

	ret = count;

exit:
	mutex_unlock(&ar->conf_mutex);

	return ret;
}

static ssize_t ath10k_read_ps_state_enable(struct file *file,
					   char __user *user_buf,
					   size_t count, loff_t *ppos)
{
	struct ath10k *ar = file->private_data;
	int len = 0;
	char buf[32];

	mutex_lock(&ar->conf_mutex);
	len = scnprintf(buf, sizeof(buf) - len, "%d\n",
			ar->ps_state_enable);
	mutex_unlock(&ar->conf_mutex);

	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}

static const struct file_operations fops_ps_state_enable = {
	.read = ath10k_read_ps_state_enable,
	.write = ath10k_write_ps_state_enable,
	.open = simple_open,
	.owner = THIS_MODULE,
	.llseek = default_llseek,
};

int ath10k_debug_create(struct ath10k *ar)
{
	ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN);
@@ -2534,6 +2613,9 @@ int ath10k_debug_register(struct ath10k *ar)
	debugfs_create_file("warm_hw_reset", 0600, ar->debug.debugfs_phy, ar,
			    &fops_warm_hw_reset);

	debugfs_create_file("ps_state_enable", 0600, ar->debug.debugfs_phy, ar,
			    &fops_ps_state_enable);

	return 0;
}

+29 −0
Original line number Diff line number Diff line
@@ -460,6 +460,33 @@ static const struct file_operations fops_peer_debug_trigger = {
	.llseek = default_llseek,
};

static ssize_t ath10k_dbg_sta_read_peer_ps_state(struct file *file,
						 char __user *user_buf,
						 size_t count, loff_t *ppos)
{
	struct ieee80211_sta *sta = file->private_data;
	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
	struct ath10k *ar = arsta->arvif->ar;
	char buf[20];
	int len = 0;

	spin_lock_bh(&ar->data_lock);

	len = scnprintf(buf, sizeof(buf) - len, "%d\n",
			arsta->peer_ps_state);

	spin_unlock_bh(&ar->data_lock);

	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}

static const struct file_operations fops_peer_ps_state = {
	.open = simple_open,
	.read = ath10k_dbg_sta_read_peer_ps_state,
	.owner = THIS_MODULE,
	.llseek = default_llseek,
};

static char *get_err_str(enum ath10k_pkt_rx_err i)
{
	switch (i) {
@@ -738,4 +765,6 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
	    ath10k_debug_is_extd_tx_stats_enabled(ar))
		debugfs_create_file("tx_stats", 0400, dir, sta,
				    &fops_tx_stats);
	debugfs_create_file("peer_ps_state", 0400, dir, sta,
			    &fops_peer_ps_state);
}
+1 −0
Original line number Diff line number Diff line
@@ -6256,6 +6256,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
	    new_state == IEEE80211_STA_NONE) {
		memset(arsta, 0, sizeof(*arsta));
		arsta->arvif = arvif;
		arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED;
		INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk);

		for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
+38 −1
Original line number Diff line number Diff line
@@ -1307,7 +1307,8 @@ static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = {
	.set_mcast2ucast_mode = WMI_PDEV_PARAM_UNSUPPORTED,
	.set_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED,
	.remove_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED,
	.peer_sta_ps_statechg_enable = WMI_PDEV_PARAM_UNSUPPORTED,
	.peer_sta_ps_statechg_enable =
				WMI_10X_PDEV_PARAM_PEER_STA_PS_STATECHG_ENABLE,
	.igmpmld_ac_override = WMI_PDEV_PARAM_UNSUPPORTED,
	.block_interbss = WMI_PDEV_PARAM_UNSUPPORTED,
	.set_disable_reset_cmdid = WMI_PDEV_PARAM_UNSUPPORTED,
@@ -5048,6 +5049,36 @@ ath10k_wmi_handle_tdls_peer_event(struct ath10k *ar, struct sk_buff *skb)
	}
}

static void
ath10k_wmi_event_peer_sta_ps_state_chg(struct ath10k *ar, struct sk_buff *skb)
{
	struct wmi_peer_sta_ps_state_chg_event *ev;
	struct ieee80211_sta *sta;
	struct ath10k_sta *arsta;
	u8 peer_addr[ETH_ALEN];

	lockdep_assert_held(&ar->data_lock);

	ev = (struct wmi_peer_sta_ps_state_chg_event *)skb->data;
	ether_addr_copy(peer_addr, ev->peer_macaddr.addr);

	rcu_read_lock();

	sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer_addr, NULL);

	if (!sta) {
		ath10k_warn(ar, "failed to find station entry %pM\n",
			    peer_addr);
		goto exit;
	}

	arsta = (struct ath10k_sta *)sta->drv_priv;
	arsta->peer_ps_state = __le32_to_cpu(ev->peer_ps_state);

exit:
	rcu_read_unlock();
}

void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb)
{
	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n");
@@ -5978,6 +6009,9 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
		ath10k_dbg(ar, ATH10K_DBG_WMI,
			   "received event id %d not implemented\n", id);
		break;
	case WMI_10_2_PEER_STA_PS_STATECHG_EVENTID:
		ath10k_wmi_event_peer_sta_ps_state_chg(ar, skb);
		break;
	default:
		ath10k_warn(ar, "Unknown eventid: %d\n", id);
		break;
@@ -6095,6 +6129,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
	case WMI_10_4_DFS_STATUS_CHECK_EVENTID:
		ath10k_wmi_event_dfs_status_check(ar, skb);
		break;
	case WMI_10_4_PEER_STA_PS_STATECHG_EVENTID:
		ath10k_wmi_event_peer_sta_ps_state_chg(ar, skb);
		break;
	default:
		ath10k_warn(ar, "Unknown eventid: %d\n", id);
		break;
Loading