All of lore.kernel.org
 help / color / mirror / Atom feed
From: Maharaja Kennadyrajan <quic_mkenna@quicinc.com>
To: <ath11k@lists.infradead.org>
Cc: <linux-wireless@vger.kernel.org>,
	Venkateswara Naralasetty <quic_vnaralas@quicinc.com>,
	Maharaja Kennadyrajan <quic_mkenna@quicinc.com>
Subject: [PATCH v2 4/4] wifi: ath11k: add AP power save support
Date: Mon, 20 Mar 2023 22:13:34 +0530	[thread overview]
Message-ID: <20230320164334.3325886-5-quic_mkenna@quicinc.com> (raw)
In-Reply-To: <20230320164334.3325886-1-quic_mkenna@quicinc.com>

From: Venkateswara Naralasetty <quic_vnaralas@quicinc.com>

AP goes into the power save mode if no stations
are connected and it will come out of power save
as and when any of the station associate to it.

Driver will advertise this flag SUPPORTS_AP_PS to
enable the AP power save in mac80211.

This AP power save capability can be used to save
power with the drawback of reduced range or delayed
discovery of the AP.

This feature is enabled in QCN9074, IPQ8074, IPQ5018, QCN6122.

Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1

Signed-off-by: Maharaja Kennadyrajan <quic_mkenna@quicinc.com>
Signed-off-by: Venkateswara Naralasetty <quic_vnaralas@quicinc.com>
---
 drivers/net/wireless/ath/ath11k/core.c |  8 ++++
 drivers/net/wireless/ath/ath11k/core.h |  8 ++++
 drivers/net/wireless/ath/ath11k/hw.h   |  1 +
 drivers/net/wireless/ath/ath11k/mac.c  | 58 ++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath11k/wmi.c  | 32 ++++++++++++++
 drivers/net/wireless/ath/ath11k/wmi.h  |  8 ++++
 6 files changed, 115 insertions(+)

diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index 75fdbe4ef83a..5cf9203b751e 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -117,6 +117,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.tx_ring_size = DP_TCL_DATA_RING_SIZE,
 		.smp2p_wow_exit = false,
 		.ftm_responder = true,
+		.supports_ap_ps = true,
 	},
 	{
 		.hw_rev = ATH11K_HW_IPQ6018_HW10,
@@ -200,6 +201,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.smp2p_wow_exit = false,
 		.support_fw_mac_sequence = false,
 		.ftm_responder = true,
+		.supports_ap_ps = true,
 	},
 	{
 		.name = "qca6390 hw2.0",
@@ -285,6 +287,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.smp2p_wow_exit = false,
 		.support_fw_mac_sequence = true,
 		.ftm_responder = false,
+		.supports_ap_ps = false,
 	},
 	{
 		.name = "qcn9074 hw1.0",
@@ -367,6 +370,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.smp2p_wow_exit = false,
 		.support_fw_mac_sequence = false,
 		.ftm_responder = true,
+		.supports_ap_ps = true,
 	},
 	{
 		.name = "wcn6855 hw2.0",
@@ -452,6 +456,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.smp2p_wow_exit = false,
 		.support_fw_mac_sequence = true,
 		.ftm_responder = false,
+		.supports_ap_ps = false,
 	},
 	{
 		.name = "wcn6855 hw2.1",
@@ -535,6 +540,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.smp2p_wow_exit = false,
 		.support_fw_mac_sequence = true,
 		.ftm_responder = false,
+		.supports_ap_ps = false,
 	},
 	{
 		.name = "wcn6750 hw1.0",
@@ -616,6 +622,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.smp2p_wow_exit = true,
 		.support_fw_mac_sequence = true,
 		.ftm_responder = false,
+		.supports_ap_ps = false,
 	},
 	{
 		.hw_rev = ATH11K_HW_IPQ5018_HW10,
@@ -696,6 +703,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.smp2p_wow_exit = false,
 		.support_fw_mac_sequence = false,
 		.ftm_responder = true,
+		.supports_ap_ps = true,
 	},
 };
 
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index 0830276e5028..fefb1fb5220d 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -363,6 +363,7 @@ struct ath11k_vif {
 	struct ieee80211_chanctx_conf chanctx;
 	struct ath11k_arp_ns_offload arp_ns_offload;
 	struct ath11k_rekey_data rekey_data;
+	bool vif_ap_ps_enabled;
 
 #ifdef CONFIG_ATH11K_DEBUGFS
 	struct dentry *debugfs_twt;
@@ -589,6 +590,11 @@ struct ath11k_per_peer_tx_stats {
 #define ATH11K_FLUSH_TIMEOUT (5 * HZ)
 #define ATH11K_VDEV_DELETE_TIMEOUT_HZ (5 * HZ)
 
+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;
@@ -732,6 +738,8 @@ struct ath11k {
 	/* protected by conf_mutex */
 	bool ps_state_enable;
 	bool ps_timekeeper_enable;
+	bool ap_ps_enabled;
+	enum ath11k_ap_ps_state ap_ps_state;
 };
 
 struct ath11k_band_cap {
diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h
index 0be4e1232384..40953e117cc5 100644
--- a/drivers/net/wireless/ath/ath11k/hw.h
+++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -225,6 +225,7 @@ struct ath11k_hw_params {
 	bool smp2p_wow_exit;
 	bool support_fw_mac_sequence;
 	bool ftm_responder;
+	bool supports_ap_ps;
 };
 
 struct ath11k_hw_ops {
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index cad832e0e6b8..db0d772ff7c7 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -3215,6 +3215,43 @@ static int ath11k_mac_config_obss_pd(struct ath11k *ar,
 	return 0;
 }
 
+void ath11k_mac_ap_ps_recalc(struct ath11k *ar)
+{
+	struct ath11k_vif *arvif;
+	enum ath11k_ap_ps_state state = ATH11K_AP_PS_STATE_OFF;
+	int ret;
+	bool allow_ap_ps = true;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	list_for_each_entry(arvif, &ar->arvifs, list) {
+		if (arvif->vdev_type == WMI_VDEV_TYPE_STA ||
+		    !arvif->vif_ap_ps_enabled) {
+			allow_ap_ps = false;
+			break;
+		}
+	}
+
+	if (!allow_ap_ps)
+		ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "ap ps is not allowed\n");
+
+	if (allow_ap_ps && !ar->num_stations && ar->ap_ps_enabled)
+		state = ATH11K_AP_PS_STATE_ON;
+
+	if (ar->ap_ps_state == state)
+		return;
+
+	ret = ath11k_wmi_pdev_ap_ps_cmd_send(ar, ar->pdev->pdev_id, state);
+	if (ret) {
+		ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
+			   "failed to send ap ps command pdev_id %u state %u\n",
+			   ar->pdev->pdev_id, state);
+		return;
+	}
+
+	ar->ap_ps_state = state;
+}
+
 static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
 					   struct ieee80211_vif *vif,
 					   struct ieee80211_bss_conf *info,
@@ -3567,6 +3604,16 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
 			   vif->addr, arvif->arp_ns_offload.ipv4_addr);
 	}
 
+	if ((changed & BSS_CHANGED_PS) && vif->type == NL80211_IFTYPE_AP) {
+		if (!info->ap_ps_enable)
+			arvif->vif_ap_ps_enabled = false;
+		else
+			arvif->vif_ap_ps_enabled = true;
+
+		ar->ap_ps_enabled = info->ap_ps_enable;
+		ath11k_mac_ap_ps_recalc(ar);
+	}
+
 	mutex_unlock(&ar->conf_mutex);
 }
 
@@ -4651,6 +4698,8 @@ static int ath11k_mac_station_add(struct ath11k *ar,
 	ath11k_dbg(ab, ATH11K_DBG_MAC, "Added peer: %pM for VDEV: %d\n",
 		   sta->addr, arvif->vdev_id);
 
+	ath11k_mac_ap_ps_recalc(ar);
+
 	if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) {
 		arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats), GFP_KERNEL);
 		if (!arsta->tx_stats) {
@@ -4810,6 +4859,8 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw,
 
 		kfree(arsta->rx_stats);
 		arsta->rx_stats = NULL;
+
+		ath11k_mac_ap_ps_recalc(ar);
 	} else if (old_state == IEEE80211_STA_AUTH &&
 		   new_state == IEEE80211_STA_ASSOC &&
 		   (vif->type == NL80211_IFTYPE_AP ||
@@ -6599,6 +6650,8 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
 				    ret);
 	}
 
+	ath11k_mac_ap_ps_recalc(ar);
+
 	mutex_unlock(&ar->conf_mutex);
 
 	return 0;
@@ -6703,6 +6756,8 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw,
 
 	ath11k_debugfs_remove_interface(arvif);
 
+	ath11k_mac_ap_ps_recalc(ar);
+
 	/* TODO: recal traffic pause state based on the available vdevs */
 
 	mutex_unlock(&ar->conf_mutex);
@@ -9122,6 +9177,9 @@ static int __ath11k_mac_register(struct ath11k *ar)
 		ieee80211_hw_set(ar->hw, USES_RSS);
 	}
 
+	if (ar->ab->hw_params.supports_ap_ps)
+		ieee80211_hw_set(ar->hw, SUPPORTS_AP_PS);
+
 	ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
 	ar->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
 
diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c
index 27f3fceb33c5..02b14ba6ad45 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -1290,6 +1290,38 @@ ath11k_wmi_rx_reord_queue_remove(struct ath11k *ar,
 	return ret;
 }
 
+int ath11k_wmi_pdev_ap_ps_cmd_send(struct ath11k *ar, u32 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)
 {
diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h
index b23b7a22bc9a..8b37dd935a95 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.h
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
@@ -3037,6 +3037,12 @@ struct wmi_fwtest_set_param_cmd_param {
 	u32 param_value;
 };
 
+struct wmi_pdev_ap_ps_cmd {
+	u32 tlv_header;
+	u32 pdev_id;
+	u32 param_value;
+} __packed;
+
 struct wmi_pdev_set_param_cmd {
 	u32 tlv_header;
 	u32 pdev_id;
@@ -6445,5 +6451,7 @@ int ath11k_wmi_pdev_set_bios_sar_table_param(struct ath11k *ar, const u8 *sar_va
 int ath11k_wmi_pdev_set_bios_geo_table_param(struct ath11k *ar);
 int ath11k_wmi_sta_keepalive(struct ath11k *ar,
 			     const struct wmi_sta_keepalive_arg *arg);
+int ath11k_wmi_pdev_ap_ps_cmd_send(struct ath11k *ar, u32 pdev_id,
+				   u32 value);
 
 #endif
-- 
2.25.1


-- 
ath11k mailing list
ath11k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath11k

WARNING: multiple messages have this Message-ID (diff)
From: Maharaja Kennadyrajan <quic_mkenna@quicinc.com>
To: <ath11k@lists.infradead.org>
Cc: <linux-wireless@vger.kernel.org>,
	Venkateswara Naralasetty <quic_vnaralas@quicinc.com>,
	Maharaja Kennadyrajan <quic_mkenna@quicinc.com>
Subject: [PATCH v2 4/4] wifi: ath11k: add AP power save support
Date: Mon, 20 Mar 2023 22:13:34 +0530	[thread overview]
Message-ID: <20230320164334.3325886-5-quic_mkenna@quicinc.com> (raw)
In-Reply-To: <20230320164334.3325886-1-quic_mkenna@quicinc.com>

From: Venkateswara Naralasetty <quic_vnaralas@quicinc.com>

AP goes into the power save mode if no stations
are connected and it will come out of power save
as and when any of the station associate to it.

Driver will advertise this flag SUPPORTS_AP_PS to
enable the AP power save in mac80211.

This AP power save capability can be used to save
power with the drawback of reduced range or delayed
discovery of the AP.

This feature is enabled in QCN9074, IPQ8074, IPQ5018, QCN6122.

Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1

Signed-off-by: Maharaja Kennadyrajan <quic_mkenna@quicinc.com>
Signed-off-by: Venkateswara Naralasetty <quic_vnaralas@quicinc.com>
---
 drivers/net/wireless/ath/ath11k/core.c |  8 ++++
 drivers/net/wireless/ath/ath11k/core.h |  8 ++++
 drivers/net/wireless/ath/ath11k/hw.h   |  1 +
 drivers/net/wireless/ath/ath11k/mac.c  | 58 ++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath11k/wmi.c  | 32 ++++++++++++++
 drivers/net/wireless/ath/ath11k/wmi.h  |  8 ++++
 6 files changed, 115 insertions(+)

diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index 75fdbe4ef83a..5cf9203b751e 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -117,6 +117,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.tx_ring_size = DP_TCL_DATA_RING_SIZE,
 		.smp2p_wow_exit = false,
 		.ftm_responder = true,
+		.supports_ap_ps = true,
 	},
 	{
 		.hw_rev = ATH11K_HW_IPQ6018_HW10,
@@ -200,6 +201,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.smp2p_wow_exit = false,
 		.support_fw_mac_sequence = false,
 		.ftm_responder = true,
+		.supports_ap_ps = true,
 	},
 	{
 		.name = "qca6390 hw2.0",
@@ -285,6 +287,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.smp2p_wow_exit = false,
 		.support_fw_mac_sequence = true,
 		.ftm_responder = false,
+		.supports_ap_ps = false,
 	},
 	{
 		.name = "qcn9074 hw1.0",
@@ -367,6 +370,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.smp2p_wow_exit = false,
 		.support_fw_mac_sequence = false,
 		.ftm_responder = true,
+		.supports_ap_ps = true,
 	},
 	{
 		.name = "wcn6855 hw2.0",
@@ -452,6 +456,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.smp2p_wow_exit = false,
 		.support_fw_mac_sequence = true,
 		.ftm_responder = false,
+		.supports_ap_ps = false,
 	},
 	{
 		.name = "wcn6855 hw2.1",
@@ -535,6 +540,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.smp2p_wow_exit = false,
 		.support_fw_mac_sequence = true,
 		.ftm_responder = false,
+		.supports_ap_ps = false,
 	},
 	{
 		.name = "wcn6750 hw1.0",
@@ -616,6 +622,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.smp2p_wow_exit = true,
 		.support_fw_mac_sequence = true,
 		.ftm_responder = false,
+		.supports_ap_ps = false,
 	},
 	{
 		.hw_rev = ATH11K_HW_IPQ5018_HW10,
@@ -696,6 +703,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.smp2p_wow_exit = false,
 		.support_fw_mac_sequence = false,
 		.ftm_responder = true,
+		.supports_ap_ps = true,
 	},
 };
 
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index 0830276e5028..fefb1fb5220d 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -363,6 +363,7 @@ struct ath11k_vif {
 	struct ieee80211_chanctx_conf chanctx;
 	struct ath11k_arp_ns_offload arp_ns_offload;
 	struct ath11k_rekey_data rekey_data;
+	bool vif_ap_ps_enabled;
 
 #ifdef CONFIG_ATH11K_DEBUGFS
 	struct dentry *debugfs_twt;
@@ -589,6 +590,11 @@ struct ath11k_per_peer_tx_stats {
 #define ATH11K_FLUSH_TIMEOUT (5 * HZ)
 #define ATH11K_VDEV_DELETE_TIMEOUT_HZ (5 * HZ)
 
+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;
@@ -732,6 +738,8 @@ struct ath11k {
 	/* protected by conf_mutex */
 	bool ps_state_enable;
 	bool ps_timekeeper_enable;
+	bool ap_ps_enabled;
+	enum ath11k_ap_ps_state ap_ps_state;
 };
 
 struct ath11k_band_cap {
diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h
index 0be4e1232384..40953e117cc5 100644
--- a/drivers/net/wireless/ath/ath11k/hw.h
+++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -225,6 +225,7 @@ struct ath11k_hw_params {
 	bool smp2p_wow_exit;
 	bool support_fw_mac_sequence;
 	bool ftm_responder;
+	bool supports_ap_ps;
 };
 
 struct ath11k_hw_ops {
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index cad832e0e6b8..db0d772ff7c7 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -3215,6 +3215,43 @@ static int ath11k_mac_config_obss_pd(struct ath11k *ar,
 	return 0;
 }
 
+void ath11k_mac_ap_ps_recalc(struct ath11k *ar)
+{
+	struct ath11k_vif *arvif;
+	enum ath11k_ap_ps_state state = ATH11K_AP_PS_STATE_OFF;
+	int ret;
+	bool allow_ap_ps = true;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	list_for_each_entry(arvif, &ar->arvifs, list) {
+		if (arvif->vdev_type == WMI_VDEV_TYPE_STA ||
+		    !arvif->vif_ap_ps_enabled) {
+			allow_ap_ps = false;
+			break;
+		}
+	}
+
+	if (!allow_ap_ps)
+		ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "ap ps is not allowed\n");
+
+	if (allow_ap_ps && !ar->num_stations && ar->ap_ps_enabled)
+		state = ATH11K_AP_PS_STATE_ON;
+
+	if (ar->ap_ps_state == state)
+		return;
+
+	ret = ath11k_wmi_pdev_ap_ps_cmd_send(ar, ar->pdev->pdev_id, state);
+	if (ret) {
+		ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
+			   "failed to send ap ps command pdev_id %u state %u\n",
+			   ar->pdev->pdev_id, state);
+		return;
+	}
+
+	ar->ap_ps_state = state;
+}
+
 static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
 					   struct ieee80211_vif *vif,
 					   struct ieee80211_bss_conf *info,
@@ -3567,6 +3604,16 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
 			   vif->addr, arvif->arp_ns_offload.ipv4_addr);
 	}
 
+	if ((changed & BSS_CHANGED_PS) && vif->type == NL80211_IFTYPE_AP) {
+		if (!info->ap_ps_enable)
+			arvif->vif_ap_ps_enabled = false;
+		else
+			arvif->vif_ap_ps_enabled = true;
+
+		ar->ap_ps_enabled = info->ap_ps_enable;
+		ath11k_mac_ap_ps_recalc(ar);
+	}
+
 	mutex_unlock(&ar->conf_mutex);
 }
 
@@ -4651,6 +4698,8 @@ static int ath11k_mac_station_add(struct ath11k *ar,
 	ath11k_dbg(ab, ATH11K_DBG_MAC, "Added peer: %pM for VDEV: %d\n",
 		   sta->addr, arvif->vdev_id);
 
+	ath11k_mac_ap_ps_recalc(ar);
+
 	if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) {
 		arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats), GFP_KERNEL);
 		if (!arsta->tx_stats) {
@@ -4810,6 +4859,8 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw,
 
 		kfree(arsta->rx_stats);
 		arsta->rx_stats = NULL;
+
+		ath11k_mac_ap_ps_recalc(ar);
 	} else if (old_state == IEEE80211_STA_AUTH &&
 		   new_state == IEEE80211_STA_ASSOC &&
 		   (vif->type == NL80211_IFTYPE_AP ||
@@ -6599,6 +6650,8 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
 				    ret);
 	}
 
+	ath11k_mac_ap_ps_recalc(ar);
+
 	mutex_unlock(&ar->conf_mutex);
 
 	return 0;
@@ -6703,6 +6756,8 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw,
 
 	ath11k_debugfs_remove_interface(arvif);
 
+	ath11k_mac_ap_ps_recalc(ar);
+
 	/* TODO: recal traffic pause state based on the available vdevs */
 
 	mutex_unlock(&ar->conf_mutex);
@@ -9122,6 +9177,9 @@ static int __ath11k_mac_register(struct ath11k *ar)
 		ieee80211_hw_set(ar->hw, USES_RSS);
 	}
 
+	if (ar->ab->hw_params.supports_ap_ps)
+		ieee80211_hw_set(ar->hw, SUPPORTS_AP_PS);
+
 	ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
 	ar->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
 
diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c
index 27f3fceb33c5..02b14ba6ad45 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -1290,6 +1290,38 @@ ath11k_wmi_rx_reord_queue_remove(struct ath11k *ar,
 	return ret;
 }
 
+int ath11k_wmi_pdev_ap_ps_cmd_send(struct ath11k *ar, u32 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)
 {
diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h
index b23b7a22bc9a..8b37dd935a95 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.h
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
@@ -3037,6 +3037,12 @@ struct wmi_fwtest_set_param_cmd_param {
 	u32 param_value;
 };
 
+struct wmi_pdev_ap_ps_cmd {
+	u32 tlv_header;
+	u32 pdev_id;
+	u32 param_value;
+} __packed;
+
 struct wmi_pdev_set_param_cmd {
 	u32 tlv_header;
 	u32 pdev_id;
@@ -6445,5 +6451,7 @@ int ath11k_wmi_pdev_set_bios_sar_table_param(struct ath11k *ar, const u8 *sar_va
 int ath11k_wmi_pdev_set_bios_geo_table_param(struct ath11k *ar);
 int ath11k_wmi_sta_keepalive(struct ath11k *ar,
 			     const struct wmi_sta_keepalive_arg *arg);
+int ath11k_wmi_pdev_ap_ps_cmd_send(struct ath11k *ar, u32 pdev_id,
+				   u32 value);
 
 #endif
-- 
2.25.1


  parent reply	other threads:[~2023-03-20 16:44 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-03-20 16:43 [PATCH v2 0/4] Add AP power save support Maharaja Kennadyrajan
2023-03-20 16:43 ` Maharaja Kennadyrajan
2023-03-20 16:43 ` [PATCH v2 1/4] wifi: nl80211: rename NL80211_CMD_SET_BEACON to NL80211_CMD_UDPATE_AP Maharaja Kennadyrajan
2023-03-20 16:43   ` Maharaja Kennadyrajan
2023-03-20 16:43 ` [PATCH v2 2/4] wifi: nl80211: add configuration support for ap power save Maharaja Kennadyrajan
2023-03-20 16:43   ` Maharaja Kennadyrajan
2023-03-20 16:43 ` [PATCH v2 3/4] wifi: mac80211: notify BSS change upon AP power save change Maharaja Kennadyrajan
2023-03-20 16:43   ` Maharaja Kennadyrajan
2023-03-24  2:27   ` kernel test robot
2023-03-24  2:27     ` kernel test robot
2023-03-20 16:43 ` Maharaja Kennadyrajan [this message]
2023-03-20 16:43   ` [PATCH v2 4/4] wifi: ath11k: add AP power save support Maharaja Kennadyrajan
2023-03-21  0:31   ` kernel test robot
2023-03-21  0:31     ` kernel test robot
2023-03-21  1:56   ` kernel test robot
2023-03-21  1:56     ` kernel test robot
2023-03-20 17:04 ` [PATCH v2 0/4] Add " Johannes Berg
2023-03-20 17:04   ` Johannes Berg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230320164334.3325886-5-quic_mkenna@quicinc.com \
    --to=quic_mkenna@quicinc.com \
    --cc=ath11k@lists.infradead.org \
    --cc=linux-wireless@vger.kernel.org \
    --cc=quic_vnaralas@quicinc.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.