mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-19 02:11:28 +00:00
645 lines
19 KiB
Diff
645 lines
19 KiB
Diff
From 9999ec48cadf1a6b25d608dbad8f7e66bbd2747d Mon Sep 17 00:00:00 2001
|
|
From: Nishant Pandey <nishpand@codeaurora.org>
|
|
Date: Sat, 28 Nov 2020 20:52:18 +0530
|
|
Subject: [PATCH] ath11k: Add power save state change and power_save_duration
|
|
in the debugfs for each client.
|
|
|
|
This patch adds support to get the below power_save information
|
|
of each connected peer to AP. With WMI_PEER_STA_PS_STATECHG_EVENTID
|
|
event, below power save information is reported to user space via
|
|
debugfs.
|
|
|
|
Use the below commands in AP DUT to get the above power_save information.
|
|
|
|
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/ath11k/ps_state_enable
|
|
|
|
Y = 1 to enable and Y = 0 to disable
|
|
1.power_save_duration
|
|
2.time_since_station_in_power_save and
|
|
3.PS timekeeper to show a timeline about all PS state changes coming to AP,
|
|
with each event having information about MAC address of the peer connected,
|
|
Timestamp (real system time to milli seconds granularity) and
|
|
power save state.
|
|
|
|
To know the time_since_station_in_power_save:
|
|
cat /sys/kernel/debug/ieee80211/phyX/netdev:wlanX/stations/
|
|
XX:XX:XX:XX:XX:XX/current_ps_duration
|
|
|
|
To know power_save_duration:
|
|
cat /sys/kernel/debug/ieee80211/phyX/netdev:wlanX/stations/
|
|
XX:XX:XX:XX:XX:XX/total_ps_duration
|
|
|
|
To reset the power_save_duration of all stations connected to AP:
|
|
echo 1 > /sys/kernel/debug/ieee80211/phyX/ath11k/reset_ps_duration
|
|
|
|
To enable/disable the ps_timekeeper:
|
|
echo Y > /sys/kernel/debug/ieee80211/phyX/ath11k/ps_timekeeper_enable
|
|
Y = 1 to enable and Y = 0 to disable.
|
|
|
|
To record PS timekeeer logs after enabling ps_timekeeper:
|
|
trace-cmd record -e ath11k_ps_timekeeper
|
|
|
|
Signed-off-by: Nishant Pandey <nishpand@codeaurora.org>
|
|
---
|
|
drivers/net/wireless/ath/ath11k/core.h | 12 ++
|
|
drivers/net/wireless/ath/ath11k/debugfs.c | 215 ++++++++++++++++++++++++++
|
|
drivers/net/wireless/ath/ath11k/debugfs_sta.c | 106 +++++++++++++
|
|
drivers/net/wireless/ath/ath11k/mac.c | 1 +
|
|
drivers/net/wireless/ath/ath11k/trace.h | 25 +++
|
|
drivers/net/wireless/ath/ath11k/wmi.c | 82 ++++++++++
|
|
drivers/net/wireless/ath/ath11k/wmi.h | 21 +++
|
|
7 files changed, 462 insertions(+)
|
|
|
|
Index: backports-20210222-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/core.h
|
|
===================================================================
|
|
--- backports-20210222-4.4.60-b157d2276.orig/drivers/net/wireless/ath/ath11k/core.h
|
|
+++ backports-20210222-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/core.h
|
|
@@ -424,6 +424,12 @@ struct ath11k_sta {
|
|
struct ath11k_nss_sta_stats *nss_stats;
|
|
#endif
|
|
u16 tcl_metadata;
|
|
+ /* Protected with ar->data_lock */
|
|
+ u32 peer_ps_state;
|
|
+ u32 ps_start_time;
|
|
+ u32 ps_start_jiffies;
|
|
+ u8 peer_current_ps_valid;
|
|
+ u32 ps_total_duration;
|
|
};
|
|
|
|
#define ATH11K_MIN_5G_FREQ 4150
|
|
@@ -680,6 +686,11 @@ struct ath11k {
|
|
enum ath11k_ap_ps_state ap_ps_state;
|
|
|
|
bool monitor_vdev_created;
|
|
+
|
|
+ /* protected by conf_mutex */
|
|
+ u8 ps_state_enable;
|
|
+ u8 ps_timekeeper_enable;
|
|
+ u8 reset_ps_duration;
|
|
};
|
|
|
|
struct ath11k_band_cap {
|
|
Index: backports-20210222-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/debugfs.c
|
|
===================================================================
|
|
--- backports-20210222-4.4.60-b157d2276.orig/drivers/net/wireless/ath/ath11k/debugfs.c
|
|
+++ backports-20210222-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/debugfs.c
|
|
@@ -1782,6 +1782,207 @@ static const struct file_operations fops
|
|
.open = simple_open
|
|
};
|
|
|
|
+static ssize_t ath11k_write_ps_timekeeper_enable(struct file *file,
|
|
+ const char __user *user_buf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ struct ath11k *ar = file->private_data;
|
|
+ ssize_t ret;
|
|
+ u8 ps_timekeeper_enable;
|
|
+
|
|
+ if (kstrtou8_from_user(user_buf, count, 0, &ps_timekeeper_enable))
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (ps_timekeeper_enable > 1)
|
|
+ return -EINVAL;
|
|
+
|
|
+ mutex_lock(&ar->conf_mutex);
|
|
+
|
|
+ if (ar->state != ATH11K_STATE_ON) {
|
|
+ ret = -ENETDOWN;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ if (!ar->ps_state_enable) {
|
|
+ ret = -EINVAL;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ if (ar->ps_timekeeper_enable == ps_timekeeper_enable) {
|
|
+ ret = count;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ ar->ps_timekeeper_enable = ps_timekeeper_enable;
|
|
+ ret = count;
|
|
+exit:
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static ssize_t ath11k_read_ps_timekeeper_enable(struct file *file,
|
|
+ char __user *user_buf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ struct ath11k *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_timekeeper_enable);
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+
|
|
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
|
+}
|
|
+
|
|
+static const struct file_operations fops_ps_timekeeper_enable = {
|
|
+ .read = ath11k_read_ps_timekeeper_enable,
|
|
+ .write = ath11k_write_ps_timekeeper_enable,
|
|
+ .open = simple_open,
|
|
+ .owner = THIS_MODULE,
|
|
+ .llseek = default_llseek,
|
|
+};
|
|
+
|
|
+static void ath11k_reset_peer_ps_duration(void *data, struct ieee80211_sta *sta)
|
|
+{
|
|
+ struct ath11k *ar = data;
|
|
+ struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
|
|
+
|
|
+ spin_lock_bh(&ar->data_lock);
|
|
+ arsta->ps_total_duration = WMI_PEER_RESET_PS_DURATION;
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
+}
|
|
+
|
|
+static ssize_t ath11k_write_reset_ps_duration(struct file *file,
|
|
+ const char __user *user_buf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ struct ath11k *ar = file->private_data;
|
|
+ int ret;
|
|
+ u8 reset_ps_duration;
|
|
+
|
|
+ if (kstrtou8_from_user(user_buf, count, 0, &reset_ps_duration))
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (reset_ps_duration != 1)
|
|
+ return -EINVAL;
|
|
+
|
|
+ mutex_lock(&ar->conf_mutex);
|
|
+
|
|
+ if (ar->state != ATH11K_STATE_ON) {
|
|
+ ret = -ENETDOWN;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ if (!ar->ps_state_enable) {
|
|
+ ret = -EINVAL;
|
|
+ goto exit;
|
|
+ }
|
|
+ ar->reset_ps_duration = reset_ps_duration;
|
|
+ ieee80211_iterate_stations_atomic(ar->hw,
|
|
+ ath11k_reset_peer_ps_duration,
|
|
+ ar);
|
|
+
|
|
+ ret = count;
|
|
+exit:
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const struct file_operations fops_reset_ps_duration = {
|
|
+ .write = ath11k_write_reset_ps_duration,
|
|
+ .open = simple_open,
|
|
+ .owner = THIS_MODULE,
|
|
+ .llseek = default_llseek,
|
|
+};
|
|
+
|
|
+static void ath11k_peer_ps_state_disable(void *data,
|
|
+ struct ieee80211_sta *sta)
|
|
+{
|
|
+ struct ath11k *ar = data;
|
|
+ struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
|
|
+
|
|
+ spin_lock_bh(&ar->data_lock);
|
|
+ arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED;
|
|
+ arsta->ps_start_time = WMI_PEER_RESET_PS_TIME;
|
|
+ arsta->ps_total_duration = WMI_PEER_RESET_PS_DURATION;
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
+}
|
|
+
|
|
+static ssize_t ath11k_write_ps_state_enable(struct file *file,
|
|
+ const char __user *user_buf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ struct ath11k *ar = file->private_data;
|
|
+ struct ath11k_pdev *pdev = ar->pdev;
|
|
+ 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 = WMI_PDEV_PEER_STA_PS_STATECHG_ENABLE;
|
|
+ ret = ath11k_wmi_pdev_set_param(ar, param, ps_state_enable, pdev->pdev_id);
|
|
+ if (ret) {
|
|
+ ath11k_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) {
|
|
+ ar->ps_timekeeper_enable = WMI_PEER_RESET_PS_TIME_KEEPER;
|
|
+ ieee80211_iterate_stations_atomic(ar->hw,
|
|
+ ath11k_peer_ps_state_disable,
|
|
+ ar);
|
|
+ }
|
|
+
|
|
+ ret = count;
|
|
+
|
|
+exit:
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static ssize_t ath11k_read_ps_state_enable(struct file *file,
|
|
+ char __user *user_buf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ struct ath11k *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 = ath11k_read_ps_state_enable,
|
|
+ .write = ath11k_write_ps_state_enable,
|
|
+ .open = simple_open,
|
|
+ .owner = THIS_MODULE,
|
|
+ .llseek = default_llseek,
|
|
+};
|
|
+
|
|
+
|
|
static ssize_t ath11k_dump_mgmt_stats(struct file *file, char __user *ubuf,
|
|
size_t count, loff_t *ppos)
|
|
{
|
|
@@ -2651,6 +2852,20 @@ int ath11k_debugfs_register(struct ath11
|
|
ar->debug.debugfs_pdev, ar,
|
|
&fops_dump_mgmt_stats);
|
|
|
|
+ debugfs_create_file("ps_state_enable", 0600, ar->debug.debugfs_pdev, ar,
|
|
+ &fops_ps_state_enable);
|
|
+
|
|
+ if (test_bit(WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT,
|
|
+ ar->ab->wmi_ab.svc_map)) {
|
|
+ debugfs_create_file("ps_timekeeper_enable", 0600,
|
|
+ ar->debug.debugfs_pdev, ar,
|
|
+ &fops_ps_timekeeper_enable);
|
|
+
|
|
+ debugfs_create_file("reset_ps_duration", 0200,
|
|
+ ar->debug.debugfs_pdev, ar,
|
|
+ &fops_reset_ps_duration);
|
|
+ }
|
|
+
|
|
if (ar->hw->wiphy->bands[NL80211_BAND_5GHZ]) {
|
|
debugfs_create_file("dfs_simulate_radar", 0200,
|
|
ar->debug.debugfs_pdev, ar,
|
|
Index: backports-20210222-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/debugfs_sta.c
|
|
===================================================================
|
|
--- backports-20210222-4.4.60-b157d2276.orig/drivers/net/wireless/ath/ath11k/debugfs_sta.c
|
|
+++ backports-20210222-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/debugfs_sta.c
|
|
@@ -1096,11 +1096,117 @@ static const struct file_operations fops
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
+static ssize_t ath11k_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 ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
|
|
+ struct ath11k *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 = ath11k_dbg_sta_read_peer_ps_state,
|
|
+ .owner = THIS_MODULE,
|
|
+ .llseek = default_llseek,
|
|
+};
|
|
+
|
|
+static ssize_t ath11k_dbg_sta_read_current_ps_duration(struct file *file,
|
|
+ char __user *user_buf,
|
|
+ size_t count,
|
|
+ loff_t *ppos)
|
|
+{
|
|
+ struct ieee80211_sta *sta = file->private_data;
|
|
+ struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
|
|
+ struct ath11k *ar = arsta->arvif->ar;
|
|
+ u32 time_since_station_in_power_save;
|
|
+ char buf[20];
|
|
+ int len = 0;
|
|
+
|
|
+ spin_lock_bh(&ar->data_lock);
|
|
+
|
|
+ if (arsta->peer_ps_state == WMI_PEER_STA_PS_MODE && arsta->peer_current_ps_valid)
|
|
+ time_since_station_in_power_save = jiffies_to_msecs(jiffies
|
|
+ - arsta->ps_start_jiffies);
|
|
+ else
|
|
+ time_since_station_in_power_save = 0;
|
|
+
|
|
+ len = scnprintf(buf, sizeof(buf) - len, "%d\n",
|
|
+ time_since_station_in_power_save);
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
+
|
|
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
|
+}
|
|
+
|
|
+static const struct file_operations fops_current_ps_duration = {
|
|
+ .open = simple_open,
|
|
+ .read = ath11k_dbg_sta_read_current_ps_duration,
|
|
+ .owner = THIS_MODULE,
|
|
+ .llseek = default_llseek,
|
|
+};
|
|
+
|
|
+static ssize_t ath11k_dbg_sta_read_total_ps_duration(struct file *file,
|
|
+ char __user *user_buf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ struct ieee80211_sta *sta = file->private_data;
|
|
+ struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
|
|
+ struct ath11k *ar = arsta->arvif->ar;
|
|
+ char buf[20];
|
|
+ u32 power_save_duration;
|
|
+ int len = 0;
|
|
+
|
|
+ spin_lock_bh(&ar->data_lock);
|
|
+
|
|
+ if (arsta->peer_ps_state == WMI_PEER_STA_PS_MODE && arsta->peer_current_ps_valid)
|
|
+ power_save_duration = jiffies_to_msecs(jiffies
|
|
+ - arsta->ps_start_jiffies)
|
|
+ + arsta->ps_total_duration;
|
|
+ else
|
|
+ power_save_duration = arsta->ps_total_duration;
|
|
+
|
|
+ len = scnprintf(buf, sizeof(buf) - len, "%d\n",
|
|
+ power_save_duration);
|
|
+
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
+
|
|
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
|
+}
|
|
+
|
|
+static const struct file_operations fops_total_ps_duration = {
|
|
+ .open = simple_open,
|
|
+ .read = ath11k_dbg_sta_read_total_ps_duration,
|
|
+ .owner = THIS_MODULE,
|
|
+ .llseek = default_llseek,
|
|
+};
|
|
+
|
|
void ath11k_debugfs_sta_op_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
|
struct ieee80211_sta *sta, struct dentry *dir)
|
|
{
|
|
struct ath11k *ar = hw->priv;
|
|
|
|
+ debugfs_create_file("peer_ps_state", 0400, dir, sta,
|
|
+ &fops_peer_ps_state);
|
|
+
|
|
+ if (test_bit(WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT,
|
|
+ ar->ab->wmi_ab.svc_map)) {
|
|
+ debugfs_create_file("current_ps_duration", 0440, dir, sta,
|
|
+ &fops_current_ps_duration);
|
|
+ debugfs_create_file("total_ps_duration", 0440, dir, sta,
|
|
+ &fops_total_ps_duration);
|
|
+ }
|
|
if (ath11k_debugfs_is_extd_tx_stats_enabled(ar))
|
|
debugfs_create_file("tx_stats", 0400, dir, sta,
|
|
&fops_tx_stats);
|
|
Index: backports-20210222-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/mac.c
|
|
===================================================================
|
|
--- backports-20210222-4.4.60-b157d2276.orig/drivers/net/wireless/ath/ath11k/mac.c
|
|
+++ backports-20210222-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/mac.c
|
|
@@ -4382,6 +4382,7 @@ static int ath11k_mac_op_sta_state(struc
|
|
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, ath11k_sta_rc_update_wk);
|
|
INIT_WORK(&arsta->use_4addr_wk, ath11k_sta_use_4addr_wk);
|
|
|
|
Index: backports-20210222-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/trace.h
|
|
===================================================================
|
|
--- backports-20210222-4.4.60-b157d2276.orig/drivers/net/wireless/ath/ath11k/trace.h
|
|
+++ backports-20210222-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/trace.h
|
|
@@ -51,6 +51,31 @@ TRACE_EVENT(ath11k_htt_pktlog,
|
|
)
|
|
);
|
|
|
|
+TRACE_EVENT(ath11k_ps_timekeeper,
|
|
+ TP_PROTO(struct ath11k *ar, void *peer_addr,
|
|
+ u32 peer_ps_timestamp, u8 peer_ps_state),
|
|
+ TP_ARGS(ar, peer_addr, peer_ps_timestamp, peer_ps_state),
|
|
+ TP_STRUCT__entry(__string(device, dev_name(ar->ab->dev))
|
|
+ __string(driver, dev_driver_string(ar->ab->dev))
|
|
+ __dynamic_array(u8, peer_addr, ETH_ALEN)
|
|
+ __field(u8, peer_ps_state)
|
|
+ __field(u32, peer_ps_timestamp)
|
|
+ ),
|
|
+ TP_fast_assign(__assign_str(device, dev_name(ar->ab->dev));
|
|
+ __assign_str(driver, dev_driver_string(ar->ab->dev));
|
|
+ memcpy(__get_dynamic_array(peer_addr), peer_addr,
|
|
+ ETH_ALEN);
|
|
+ __entry->peer_ps_state = peer_ps_state;
|
|
+ __entry->peer_ps_timestamp = peer_ps_timestamp;
|
|
+ ),
|
|
+ TP_printk("%s %s %u %u",
|
|
+ __get_str(driver),
|
|
+ __get_str(device),
|
|
+ __entry->peer_ps_state,
|
|
+ __entry->peer_ps_timestamp
|
|
+ )
|
|
+);
|
|
+
|
|
TRACE_EVENT(ath11k_htt_ppdu_stats,
|
|
TP_PROTO(struct ath11k *ar, const void *data, size_t len),
|
|
|
|
Index: backports-20210222-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/wmi.c
|
|
===================================================================
|
|
--- backports-20210222-4.4.60-b157d2276.orig/drivers/net/wireless/ath/ath11k/wmi.c
|
|
+++ backports-20210222-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/wmi.c
|
|
@@ -8379,6 +8379,96 @@ static void ath11k_bcn_tx_status_event(s
|
|
}
|
|
|
|
|
|
+void
|
|
+ath11k_wmi_event_peer_sta_ps_state_chg(struct ath11k_base *ab, struct sk_buff *skb)
|
|
+{
|
|
+ struct wmi_peer_sta_ps_state_chg_event *ev;
|
|
+ struct ieee80211_sta *sta;
|
|
+ struct ath11k_peer *peer;
|
|
+ struct ath11k *ar;
|
|
+ struct ath11k_sta *arsta;
|
|
+ u32 peer_previous_ps_state;
|
|
+ u8 peer_addr[ETH_ALEN];
|
|
+
|
|
+ ev = (struct wmi_peer_sta_ps_state_chg_event *)skb->data;
|
|
+ ether_addr_copy(peer_addr, ev->peer_macaddr.addr);
|
|
+
|
|
+ rcu_read_lock();
|
|
+
|
|
+ spin_lock_bh(&ab->base_lock);
|
|
+
|
|
+ peer = ath11k_peer_find_by_addr(ab, peer_addr);
|
|
+
|
|
+ if (!peer) {
|
|
+ ath11k_warn(ab, "peer not found %pM\n",
|
|
+ peer_addr);
|
|
+
|
|
+
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ ar = ath11k_mac_get_ar_by_vdev_id(ab, peer->vdev_id);
|
|
+
|
|
+ if (!ar) {
|
|
+ ath11k_warn(ab, "invalid vdev id in peer sta ps state change ev %d",
|
|
+ peer->vdev_id);
|
|
+
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ sta = peer->sta;
|
|
+
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+
|
|
+ if (!sta) {
|
|
+ ath11k_warn(ab, "failed to find station entry %pM\n",
|
|
+ peer_addr);
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ arsta = (struct ath11k_sta *)sta->drv_priv;
|
|
+
|
|
+ spin_lock_bh(&ar->data_lock);
|
|
+
|
|
+ peer_previous_ps_state = arsta->peer_ps_state;
|
|
+ arsta->peer_ps_state = ev->peer_ps_state;
|
|
+ arsta->peer_current_ps_valid = !WMI_PEER_CURRENT_VALID_PS_STATE;
|
|
+
|
|
+ if (test_bit(WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT,
|
|
+ ar->ab->wmi_ab.svc_map)) {
|
|
+ if (!(ev->ps_supported_bitmap & WMI_PEER_PS_VALID_SUPPORTED))
|
|
+ goto out;
|
|
+
|
|
+ if (!(ev->ps_supported_bitmap & WMI_PEER_PS_STATE_TIMESTAMP_SUPPORTED))
|
|
+ goto out;
|
|
+
|
|
+ if (!ev->peer_ps_valid)
|
|
+ goto out;
|
|
+
|
|
+ arsta->peer_current_ps_valid = WMI_PEER_CURRENT_VALID_PS_STATE;
|
|
+
|
|
+ if (arsta->peer_ps_state == WMI_PEER_STA_PS_MODE) {
|
|
+ arsta->ps_start_time = ev->peer_ps_timestamp;
|
|
+ arsta->ps_start_jiffies = jiffies;
|
|
+ } else if (!arsta->peer_ps_state && peer_previous_ps_state == WMI_PEER_STA_PS_MODE)
|
|
+ arsta->ps_total_duration = arsta->ps_total_duration +
|
|
+ (ev->peer_ps_timestamp - arsta->ps_start_time);
|
|
+
|
|
+ if (ar->ps_timekeeper_enable)
|
|
+ trace_ath11k_ps_timekeeper(ar, peer_addr, ev->peer_ps_timestamp,
|
|
+ arsta->peer_ps_state);
|
|
+
|
|
+ }
|
|
+
|
|
+out:
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
+
|
|
+exit:
|
|
+ rcu_read_unlock();
|
|
+}
|
|
+
|
|
static void ath11k_wmi_wds_peer_event(struct ath11k_base *ab,
|
|
struct sk_buff *skb)
|
|
{
|
|
@@ -8552,6 +8642,9 @@ static void ath11k_wmi_tlv_op_rx(struct
|
|
case WMI_MUEDCA_PARAMS_CONFIG_EVENTID:
|
|
ath11k_wmi_pdev_update_muedca_params_status_event(ab, skb);
|
|
break;
|
|
+ case WMI_PEER_STA_PS_STATECHG_EVENTID:
|
|
+ ath11k_wmi_event_peer_sta_ps_state_chg(ab, skb);
|
|
+ break;
|
|
case WMI_DIAG_EVENTID:
|
|
ath11k_wmi_diag_event(ab, skb);
|
|
break;
|
|
Index: backports-20210222-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/wmi.h
|
|
===================================================================
|
|
--- backports-20210222-4.4.60-b157d2276.orig/drivers/net/wireless/ath/ath11k/wmi.h
|
|
+++ backports-20210222-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/wmi.h
|
|
@@ -5792,6 +5792,33 @@ struct wmi_qos_null_tx_cmd {
|
|
#define WMI_SERVICE_READY_TIMEOUT_HZ (5 * HZ)
|
|
#define WMI_SEND_TIMEOUT_HZ (3 * HZ)
|
|
|
|
+enum ath11k_wmi_peer_ps_param {
|
|
+ WMI_PEER_STA_WAKEUP_MODE = 0,
|
|
+ WMI_PEER_STA_PS_MODE = 1,
|
|
+ WMI_PEER_PS_STATE_DISABLED = 2,
|
|
+};
|
|
+
|
|
+#define WMI_PEER_RESET_PS_TIME_KEEPER 0
|
|
+#define WMI_PEER_RESET_PS_TIME 0
|
|
+#define WMI_PEER_RESET_PS_DURATION 0
|
|
+#define WMI_PEER_CURRENT_VALID_PS_STATE 1
|
|
+
|
|
+
|
|
+enum wmi_peer_ps_supported_bitmap {
|
|
+ /* Used to indicate that power save state change is valid */
|
|
+ WMI_PEER_PS_VALID_SUPPORTED = 0x00000001,
|
|
+ WMI_PEER_PS_STATE_TIMESTAMP_SUPPORTED = 0x00000002,
|
|
+};
|
|
+
|
|
+struct wmi_peer_sta_ps_state_chg_event {
|
|
+ u32 tlv_header;
|
|
+ struct wmi_mac_addr peer_macaddr;
|
|
+ u32 peer_ps_state;
|
|
+ u32 ps_supported_bitmap;
|
|
+ u32 peer_ps_valid;
|
|
+ u32 peer_ps_timestamp;
|
|
+} __packed;
|
|
+
|
|
struct ath11k_wmi_base {
|
|
struct ath11k_base *ab;
|
|
struct ath11k_pdev_wmi wmi[MAX_RADIOS];
|