wlan-ap-Telecominfraproject/feeds/wifi-ax/mac80211/patches/qca/022-ath11k-add-ap-ps-support.patch
John Crispin 528a778e38 open-converged-wireless: Import 21.02 based uCentral tree
Signed-off-by: John Crispin <john@phrozen.org>
2021-03-25 12:19:47 +01:00

325 lines
9.2 KiB
Diff

--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -24,6 +24,7 @@
#include "thermal.h"
#include "dbring.h"
#include "spectral.h"
+#include "vendor.h"
#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
@@ -454,6 +455,11 @@ struct ath11k_coex_info {
u32 pta_priority;
};
+enum ath11k_ap_ps_state {
+ ATH11K_AP_PS_STATE_OFF,
+ ATH11K_AP_PS_STATE_ON,
+};
+
struct ath11k {
struct ath11k_base *ab;
struct ath11k_pdev *pdev;
@@ -581,6 +587,8 @@ struct ath11k {
bool dfs_block_radar_events;
struct ath11k_thermal thermal;
struct completion fw_mode_reset;
+ int ap_ps_enabled;
+ enum ath11k_ap_ps_state ap_ps_state;
};
struct ath11k_band_cap {
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -2913,6 +2913,33 @@ static void ath11k_mac_dec_num_stations(
ar->num_stations--;
}
+int ath11k_mac_ap_ps_recalc(struct ath11k *ar)
+{
+ struct ath11k_vif *arvif;
+ bool has_sta_iface = false;
+ enum ath11k_ap_ps_state state = ATH11K_AP_PS_STATE_OFF;
+ int ret = 0;
+
+ list_for_each_entry(arvif, &ar->arvifs, list) {
+ if (arvif->vdev_type == WMI_VDEV_TYPE_STA) {
+ has_sta_iface = true;
+ break;
+ }
+ }
+
+ if (!has_sta_iface && !ar->num_stations && ar->ap_ps_enabled)
+ state = ATH11K_AP_PS_STATE_ON;
+
+ if (ar->ap_ps_state == state)
+ return ret;
+
+ ret = ath11k_wmi_pdev_ap_ps_cmd_send(ar, ar->pdev->pdev_id, state);
+ if (!ret)
+ ar->ap_ps_state = state;
+
+ return ret;
+}
+
static int ath11k_mac_station_add(struct ath11k *ar,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
@@ -2952,6 +2979,12 @@ static int ath11k_mac_station_add(struct
ath11k_dbg(ab, ATH11K_DBG_MAC, "Added peer: %pM for VDEV: %d\n",
sta->addr, arvif->vdev_id);
+ ret = ath11k_mac_ap_ps_recalc(ar);
+ if (ret) {
+ ath11k_warn(ar->ab, "failed to send ap ps ret %d\n", ret);
+ goto exit;
+ }
+
if (ath11k_debug_is_extd_tx_stats_enabled(ar)) {
arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats), GFP_KERNEL);
if (!arsta->tx_stats) {
@@ -3058,6 +3091,9 @@ static int ath11k_mac_op_sta_state(struc
kfree(arsta->tx_stats);
arsta->tx_stats = NULL;
+ ret = ath11k_mac_ap_ps_recalc(ar);
+ if (ret)
+ ath11k_warn(ar->ab, "failed to send ap ps ret %d\n", ret);
kfree(arsta->rx_stats);
arsta->rx_stats = NULL;
@@ -4229,6 +4265,7 @@ static void ath11k_mac_op_stop(struct ie
clear_bit(ATH11K_CAC_RUNNING, &ar->dev_flags);
ar->state = ATH11K_STATE_OFF;
+ ar->ap_ps_state = ATH11K_AP_PS_STATE_OFF;
mutex_unlock(&ar->conf_mutex);
cancel_delayed_work_sync(&ar->scan.timeout);
@@ -4430,7 +4467,6 @@ static int ath11k_mac_op_add_interface(s
arvif->vdev_id, ret);
goto err;
}
-
ar->num_created_vdevs++;
ath11k_dbg(ab, ATH11K_DBG_MAC, "vdev %pM created, vdev_id %d\n",
vif->addr, arvif->vdev_id);
@@ -4555,6 +4591,10 @@ static int ath11k_mac_op_add_interface(s
ath11k_dp_vdev_tx_attach(ar, arvif);
+ ret = ath11k_mac_ap_ps_recalc(ar);
+ if (ret)
+ ath11k_warn(ar->ab, "failed to set ap ps ret %d\n", ret);
+
mutex_unlock(&ar->conf_mutex);
return 0;
@@ -4641,6 +4681,7 @@ static void ath11k_mac_op_remove_interfa
/* Recalc txpower for remaining vdev */
ath11k_mac_txpower_recalc(ar);
+ ath11k_mac_ap_ps_recalc(ar);
clear_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags);
/* TODO: recal traffic pause state based on the available vdevs */
--- a/drivers/net/wireless/ath/ath11k/mac.h
+++ b/drivers/net/wireless/ath/ath11k/mac.h
@@ -118,6 +118,7 @@ struct ath11k_generic_iter {
extern const struct htt_rx_ring_tlv_filter ath11k_mac_mon_status_filter_default;
+int ath11k_mac_ap_ps_recalc(struct ath11k *ar);
void ath11k_mac_destroy(struct ath11k_base *ab);
void ath11k_mac_unregister(struct ath11k_base *ab);
int ath11k_mac_register(struct ath11k_base *ab);
--- a/drivers/net/wireless/ath/ath11k/vendor.c
+++ b/drivers/net/wireless/ath/ath11k/vendor.c
@@ -6,7 +6,6 @@
#include <net/netlink.h>
#include <net/mac80211.h>
#include "core.h"
-#include "vendor.h"
#include "debug.h"
static const struct nla_policy
@@ -21,6 +20,11 @@ ath11k_vendor_wlan_prio_policy[QCA_WLAN_
[QCA_WLAN_VENDOR_ATTR_WLAN_PRIO_WEIGHT] = { .type = NLA_U8 },
};
+static const struct nla_policy
+ath11k_vendor_set_wifi_config_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1] = {
+ [QCA_WLAN_VENDOR_ATTR_CONFIG_GTX] = {.type = NLA_FLAG}
+};
+
static int ath11k_vendor_btcoex_configure(struct wiphy *wiphy,
struct wireless_dev *wdev,
const void *data,
@@ -101,6 +105,51 @@ out:
return ret;
}
+static int ath11k_vendor_set_wifi_config(struct wiphy *wihpy,
+ struct wireless_dev *wdev,
+ const void *data,
+ int data_len)
+{
+ struct ieee80211_vif *vif;
+ struct ath11k_vif *arvif;
+ struct ath11k *ar;
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1];
+ int ret = 0;
+
+ if (!wdev)
+ return -EINVAL;
+
+ vif = wdev_to_ieee80211_vif(wdev);
+ if (!vif)
+ return -EINVAL;
+
+ arvif = (struct ath11k_vif*)vif->drv_priv;
+ if (!arvif)
+ return -EINVAL;
+
+ ar = arvif->ar;
+
+ mutex_lock(&ar->conf_mutex);
+
+ ret = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_CONFIG_MAX, data, data_len,
+ ath11k_vendor_set_wifi_config_policy, NULL);
+ if (ret) {
+ ath11k_warn(ar->ab, "invalid set wifi config policy attribute\n");
+ goto exit;
+ }
+
+ ar->ap_ps_enabled = nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_CONFIG_GTX]);
+ ret = ath11k_mac_ap_ps_recalc(ar);
+ if (ret) {
+ ath11k_warn(ar->ab, "failed to send ap ps ret %d\n", ret);
+ goto exit;
+ }
+
+exit:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
static struct wiphy_vendor_command ath11k_vendor_commands[] = {
{
.info.vendor_id = QCA_NL80211_VENDOR_ID,
@@ -108,8 +157,18 @@ static struct wiphy_vendor_command ath11
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
WIPHY_VENDOR_CMD_NEED_RUNNING,
.doit = ath11k_vendor_btcoex_configure,
- .policy = ath11k_vendor_btcoex_config_policy
- }
+ .policy = ath11k_vendor_btcoex_config_policy,
+ .maxattr = QCA_WLAN_VENDOR_ATTR_BTCOEX_CONFIG_MAX
+ },
+ {
+ .info.vendor_id = QCA_NL80211_VENDOR_ID,
+ .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION,
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = ath11k_vendor_set_wifi_config,
+ .policy = ath11k_vendor_set_wifi_config_policy,
+ .maxattr = QCA_WLAN_VENDOR_ATTR_CONFIG_MAX
+ },
};
int ath11k_vendor_register(struct ath11k *ar)
--- a/drivers/net/wireless/ath/ath11k/vendor.h
+++ b/drivers/net/wireless/ath/ath11k/vendor.h
@@ -9,6 +9,9 @@
#define QCA_NL80211_VENDOR_ID 0x001374
enum qca_nl80211_vendor_subcmds {
+ /* Wi-Fi configuration subcommand */
+ QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION = 74,
+
/* QCA_NL80211_VENDOR_SUBCMD_BTCOEX_CONFIG: This command is used to
* enable/disable BTCOEX and set priority for different type of WLAN
* traffic over BT low priority traffic. This uses attributes in
@@ -58,7 +61,17 @@ enum qca_wlan_vendor_attr_wlan_prio {
QCA_WLAN_VENDOR_ATTR_WLAN_PRIO_LAST - 1,
};
+/* Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION
+ */
+enum qca_wlan_vendor_attr_config {
+ QCA_WLAN_VENDOR_ATTR_CONFIG_GTX = 57,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
+ QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST - 1,
+};
/**
* enum qca_wlan_vendor_attr_btcoex_config - Used by the vendor command
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -1193,6 +1193,38 @@ ath11k_wmi_rx_reord_queue_remove(struct
return ret;
}
+int ath11k_wmi_pdev_ap_ps_cmd_send(struct ath11k *ar, u8 pdev_id,
+ u32 param_value)
+{
+ struct ath11k_pdev_wmi *wmi = ar->wmi;
+ struct wmi_pdev_ap_ps_cmd *cmd;
+ struct sk_buff *skb;
+ int ret;
+
+ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_pdev_ap_ps_cmd *)skb->data;
+ cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
+ WMI_TAG_PDEV_GREEN_AP_PS_ENABLE_CMD) |
+ FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+ cmd->pdev_id = pdev_id;
+ cmd->param_value = param_value;
+
+ ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID);
+ if (ret) {
+ ath11k_warn(ar->ab, "failed to send ap ps enable/disable cmd\n");
+ dev_kfree_skb(skb);
+ }
+
+ ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+ "wmi pdev ap ps set pdev id %d value %d\n",
+ pdev_id, param_value);
+
+ return ret;
+}
+
int ath11k_wmi_pdev_set_param(struct ath11k *ar, u32 param_id,
u32 param_value, u8 pdev_id)
{
--- a/drivers/net/wireless/ath/ath11k/wmi.h
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
@@ -2902,6 +2902,12 @@ struct set_fwtest_params {
u32 value;
};
+struct wmi_pdev_ap_ps_cmd {
+ u32 tlv_header;
+ u32 pdev_id;
+ u32 param_value;
+} __packed;
+
struct wmi_fwtest_set_param_cmd_param {
u32 tlv_header;
u32 param_id;
@@ -5185,6 +5191,7 @@ int ath11k_wmi_send_obss_spr_cmd(struct
struct ieee80211_he_obss_pd *he_obss_pd);
int ath11k_send_coex_config_cmd(struct ath11k *ar,
struct coex_config_arg *coex_config);
+int ath11k_wmi_pdev_ap_ps_cmd_send(struct ath11k *ar, u8 pdev_id, u32 value);
int ath11k_wmi_send_obss_color_collision_cfg_cmd(struct ath11k *ar, u32 vdev_id,
u8 bss_color, u32 period,
bool enable);