diff mbox series

[v2,04/10] wifi: ath12k: implement remain on channel for P2P mode

Message ID 20240112092824.7664-5-quic_kangyang@quicinc.com
State Superseded
Headers show
Series wifi: ath12k: P2P support for WCN7850 | expand

Commit Message

Kang Yang Jan. 12, 2024, 9:28 a.m. UTC
Implement remain on channel for p2p mode in ath12k_ops:
        ath12k_mac_op_remain_on_channel
        ath12k_mac_op_cancel_remain_on_channel

P2P device can trigger ROC scan. Then keep listening or sending management
frames on particular channels.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1

Signed-off-by: Kang Yang <quic_kangyang@quicinc.com>
---

v2:
    1. add Tested-on tag of QCN9274.
    2. update copyright.

--
 drivers/net/wireless/ath/ath12k/core.c |   3 +-
 drivers/net/wireless/ath/ath12k/mac.c  | 113 +++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.c  |   4 +
 3 files changed, 119 insertions(+), 1 deletion(-)

Comments

Jeff Johnson Jan. 13, 2024, 1:23 a.m. UTC | #1
On 1/12/2024 1:28 AM, Kang Yang wrote:
> Implement remain on channel for p2p mode in ath12k_ops:
>         ath12k_mac_op_remain_on_channel
>         ath12k_mac_op_cancel_remain_on_channel
> 
> P2P device can trigger ROC scan. Then keep listening or sending management
> frames on particular channels.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
> 
> Signed-off-by: Kang Yang <quic_kangyang@quicinc.com>
Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
Karthikeyan Periyasamy Jan. 13, 2024, 1:44 a.m. UTC | #2
On 1/12/2024 2:58 PM, Kang Yang wrote:
> Implement remain on channel for p2p mode in ath12k_ops:
>          ath12k_mac_op_remain_on_channel
>          ath12k_mac_op_cancel_remain_on_channel
>
> P2P device can trigger ROC scan. Then keep listening or sending management
> frames on particular channels.
>
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
>
> Signed-off-by: Kang Yang <quic_kangyang@quicinc.com>
> ---
>
> v2:
>      1. add Tested-on tag of QCN9274.
>      2. update copyright.
>
> --
>   drivers/net/wireless/ath/ath12k/core.c |   3 +-
>   drivers/net/wireless/ath/ath12k/mac.c  | 113 +++++++++++++++++++++++++
>   drivers/net/wireless/ath/ath12k/wmi.c  |   4 +
>   3 files changed, 119 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
> index d73e2d33a41e..d030534a3ef0 100644
> --- a/drivers/net/wireless/ath/ath12k/core.c
> +++ b/drivers/net/wireless/ath/ath12k/core.c
> @@ -1,7 +1,7 @@
>   // SPDX-License-Identifier: BSD-3-Clause-Clear
>   /*
>    * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
> - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
>    */
>   
>   #include <linux/module.h>
> @@ -942,6 +942,7 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
>   		ath12k_mac_drain_tx(ar);
>   		complete(&ar->scan.started);
>   		complete(&ar->scan.completed);
> +		complete(&ar->scan.on_channel);
>   		complete(&ar->peer_assoc_done);
>   		complete(&ar->peer_delete_done);
>   		complete(&ar->install_key_done);
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index a4a00a6606b4..92ba88d5e4e9 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -7193,6 +7193,116 @@ static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw,
>   	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
>   }
>   
> +static int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw,
> +						  struct ieee80211_vif *vif)
> +{
> +	struct ath12k *ar = hw->priv;


Accessing the radio (ar) from hw->priv is modified in the patchset 
"[PATCH v2 2/2] wifi: ath12k: Introduce the container for mac80211 hw".

This change has conflict.

@jeff,

Any comments ?

> +
> +	mutex_lock(&ar->conf_mutex);
> +
> +	spin_lock_bh(&ar->data_lock);
> +	ar->scan.roc_notify = false;
> +	spin_unlock_bh(&ar->data_lock);
> +
> +	ath12k_scan_abort(ar);
> +
> +	mutex_unlock(&ar->conf_mutex);
> +
> +	cancel_delayed_work_sync(&ar->scan.timeout);
> +
> +	return 0;
> +}
> +
> +static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
> +					   struct ieee80211_vif *vif,
> +					   struct ieee80211_channel *chan,
> +					   int duration,
> +					   enum ieee80211_roc_type type)
> +{
> +	struct ath12k *ar = hw->priv;


Accessing the radio (ar) from hw->priv is modified in the patchset 
"[PATCH v2 2/2] wifi: ath12k: Introduce the container for mac80211 hw".

This change has conflict.

@jeff,

Any comments ?


> +	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_wmi_scan_req_arg arg;
> +	int ret;
> +	u32 scan_time_msec;
> +
> +	mutex_lock(&ar->conf_mutex);
> +	spin_lock_bh(&ar->data_lock);
> +	switch (ar->scan.state) {
> +	case ATH12K_SCAN_IDLE:
> +		reinit_completion(&ar->scan.started);
> +		reinit_completion(&ar->scan.completed);
> +		reinit_completion(&ar->scan.on_channel);
> +		ar->scan.state = ATH12K_SCAN_STARTING;
> +		ar->scan.is_roc = true;
> +		ar->scan.vdev_id = arvif->vdev_id;
> +		ar->scan.roc_freq = chan->center_freq;
> +		ar->scan.roc_notify = true;
> +		ret = 0;
> +		break;
> +	case ATH12K_SCAN_STARTING:
> +	case ATH12K_SCAN_RUNNING:
> +	case ATH12K_SCAN_ABORTING:
> +		ret = -EBUSY;
> +		break;
> +	}
> +	spin_unlock_bh(&ar->data_lock);
> +
> +	if (ret)
> +		goto exit;
> +
> +	scan_time_msec = ar->hw->wiphy->max_remain_on_channel_duration * 2;
> +
> +	memset(&arg, 0, sizeof(arg));
> +	ath12k_wmi_start_scan_init(ar, &arg);
> +	arg.num_chan = 1;
> +	arg.chan_list = kcalloc(arg.num_chan, sizeof(*arg.chan_list),
> +				GFP_KERNEL);
> +	if (!arg.chan_list) {
> +		ret = -ENOMEM;
> +		goto exit;
> +	}
> +
> +	arg.vdev_id = arvif->vdev_id;
> +	arg.scan_id = ATH12K_SCAN_ID;
> +	arg.chan_list[0] = chan->center_freq;
> +	arg.dwell_time_active = scan_time_msec;
> +	arg.dwell_time_passive = scan_time_msec;
> +	arg.max_scan_time = scan_time_msec;
> +	arg.scan_flags |= WMI_SCAN_FLAG_PASSIVE;
> +	arg.burst_duration = duration;
> +
> +	ret = ath12k_start_scan(ar, &arg);
> +	if (ret) {
> +		ath12k_warn(ar->ab, "failed to start roc scan: %d\n", ret);
> +
> +		spin_lock_bh(&ar->data_lock);
> +		ar->scan.state = ATH12K_SCAN_IDLE;
> +		spin_unlock_bh(&ar->data_lock);
> +		goto free_chan_list;
> +	}
> +
> +	ret = wait_for_completion_timeout(&ar->scan.on_channel, 3 * HZ);
> +	if (ret == 0) {
> +		ath12k_warn(ar->ab, "failed to switch to channel for roc scan\n");
> +		ret = ath12k_scan_stop(ar);
> +		if (ret)
> +			ath12k_warn(ar->ab, "failed to stop scan: %d\n", ret);
> +		ret = -ETIMEDOUT;
> +		goto free_chan_list;
> +	}
> +
> +	ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
> +				     msecs_to_jiffies(duration));


ath12k_ar_to_hw(ar) is introduced to avoid direct access of hw from 
radio (ie, ar->hw).

This new helper function introduced by the patchset "[PATCH v2 1/2] 
wifi: ath12k: Refactor the mac80211 hw access from link/radio"


@jeff

Any comments ?

> +
> +	ret = 0;
> +
> +free_chan_list:
> +	kfree(arg.chan_list);
> +exit:
> +	mutex_unlock(&ar->conf_mutex);
> +	return ret;
> +}
> +
>   static const struct ieee80211_ops ath12k_ops = {
>   	.tx				= ath12k_mac_op_tx,
>   	.wake_tx_queue			= ieee80211_handle_wake_tx_queue,
> @@ -7227,6 +7337,8 @@ static const struct ieee80211_ops ath12k_ops = {
>   	.get_survey			= ath12k_mac_op_get_survey,
>   	.flush				= ath12k_mac_op_flush,
>   	.sta_statistics			= ath12k_mac_op_sta_statistics,
> +	.remain_on_channel              = ath12k_mac_op_remain_on_channel,
> +	.cancel_remain_on_channel       = ath12k_mac_op_cancel_remain_on_channel,


Both these new mac_op callback need to rework based on the patchset 
"[PATCH v2 0/2] wifi: ath12k: Introduce hw abstraction"


>   };
>   
>   static void ath12k_mac_update_ch_list(struct ath12k *ar,
> @@ -7777,6 +7889,7 @@ int ath12k_mac_allocate(struct ath12k_base *ab)
>   		init_completion(&ar->bss_survey_done);
>   		init_completion(&ar->scan.started);
>   		init_completion(&ar->scan.completed);
> +		init_completion(&ar->scan.on_channel);
>   
>   		INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work);
>   		INIT_WORK(&ar->regd_update_work, ath12k_regd_update_work);
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index 861565eaab3d..e10289de84c1 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -5050,6 +5050,8 @@ static void ath12k_wmi_event_scan_started(struct ath12k *ar)
>   		break;
>   	case ATH12K_SCAN_STARTING:
>   		ar->scan.state = ATH12K_SCAN_RUNNING;
> +		if (ar->scan.is_roc)
> +			ieee80211_ready_on_channel(ar->hw);
>   		complete(&ar->scan.started);
>   		break;
>   	}
> @@ -5132,6 +5134,8 @@ static void ath12k_wmi_event_scan_foreign_chan(struct ath12k *ar, u32 freq)
>   	case ATH12K_SCAN_RUNNING:
>   	case ATH12K_SCAN_ABORTING:
>   		ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq);
> +		if (ar->scan.is_roc && ar->scan.roc_freq == freq)
> +			complete(&ar->scan.on_channel);
>   		break;
>   	}
>   }


Thanks,

Karthikeyan
diff mbox series

Patch

diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index d73e2d33a41e..d030534a3ef0 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -1,7 +1,7 @@ 
 // SPDX-License-Identifier: BSD-3-Clause-Clear
 /*
  * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/module.h>
@@ -942,6 +942,7 @@  static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
 		ath12k_mac_drain_tx(ar);
 		complete(&ar->scan.started);
 		complete(&ar->scan.completed);
+		complete(&ar->scan.on_channel);
 		complete(&ar->peer_assoc_done);
 		complete(&ar->peer_delete_done);
 		complete(&ar->install_key_done);
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index a4a00a6606b4..92ba88d5e4e9 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -7193,6 +7193,116 @@  static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw,
 	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
 }
 
+static int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw,
+						  struct ieee80211_vif *vif)
+{
+	struct ath12k *ar = hw->priv;
+
+	mutex_lock(&ar->conf_mutex);
+
+	spin_lock_bh(&ar->data_lock);
+	ar->scan.roc_notify = false;
+	spin_unlock_bh(&ar->data_lock);
+
+	ath12k_scan_abort(ar);
+
+	mutex_unlock(&ar->conf_mutex);
+
+	cancel_delayed_work_sync(&ar->scan.timeout);
+
+	return 0;
+}
+
+static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
+					   struct ieee80211_vif *vif,
+					   struct ieee80211_channel *chan,
+					   int duration,
+					   enum ieee80211_roc_type type)
+{
+	struct ath12k *ar = hw->priv;
+	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+	struct ath12k_wmi_scan_req_arg arg;
+	int ret;
+	u32 scan_time_msec;
+
+	mutex_lock(&ar->conf_mutex);
+	spin_lock_bh(&ar->data_lock);
+	switch (ar->scan.state) {
+	case ATH12K_SCAN_IDLE:
+		reinit_completion(&ar->scan.started);
+		reinit_completion(&ar->scan.completed);
+		reinit_completion(&ar->scan.on_channel);
+		ar->scan.state = ATH12K_SCAN_STARTING;
+		ar->scan.is_roc = true;
+		ar->scan.vdev_id = arvif->vdev_id;
+		ar->scan.roc_freq = chan->center_freq;
+		ar->scan.roc_notify = true;
+		ret = 0;
+		break;
+	case ATH12K_SCAN_STARTING:
+	case ATH12K_SCAN_RUNNING:
+	case ATH12K_SCAN_ABORTING:
+		ret = -EBUSY;
+		break;
+	}
+	spin_unlock_bh(&ar->data_lock);
+
+	if (ret)
+		goto exit;
+
+	scan_time_msec = ar->hw->wiphy->max_remain_on_channel_duration * 2;
+
+	memset(&arg, 0, sizeof(arg));
+	ath12k_wmi_start_scan_init(ar, &arg);
+	arg.num_chan = 1;
+	arg.chan_list = kcalloc(arg.num_chan, sizeof(*arg.chan_list),
+				GFP_KERNEL);
+	if (!arg.chan_list) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	arg.vdev_id = arvif->vdev_id;
+	arg.scan_id = ATH12K_SCAN_ID;
+	arg.chan_list[0] = chan->center_freq;
+	arg.dwell_time_active = scan_time_msec;
+	arg.dwell_time_passive = scan_time_msec;
+	arg.max_scan_time = scan_time_msec;
+	arg.scan_flags |= WMI_SCAN_FLAG_PASSIVE;
+	arg.burst_duration = duration;
+
+	ret = ath12k_start_scan(ar, &arg);
+	if (ret) {
+		ath12k_warn(ar->ab, "failed to start roc scan: %d\n", ret);
+
+		spin_lock_bh(&ar->data_lock);
+		ar->scan.state = ATH12K_SCAN_IDLE;
+		spin_unlock_bh(&ar->data_lock);
+		goto free_chan_list;
+	}
+
+	ret = wait_for_completion_timeout(&ar->scan.on_channel, 3 * HZ);
+	if (ret == 0) {
+		ath12k_warn(ar->ab, "failed to switch to channel for roc scan\n");
+		ret = ath12k_scan_stop(ar);
+		if (ret)
+			ath12k_warn(ar->ab, "failed to stop scan: %d\n", ret);
+		ret = -ETIMEDOUT;
+		goto free_chan_list;
+	}
+
+	ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
+				     msecs_to_jiffies(duration));
+
+	ret = 0;
+
+free_chan_list:
+	kfree(arg.chan_list);
+exit:
+	mutex_unlock(&ar->conf_mutex);
+	return ret;
+}
+
 static const struct ieee80211_ops ath12k_ops = {
 	.tx				= ath12k_mac_op_tx,
 	.wake_tx_queue			= ieee80211_handle_wake_tx_queue,
@@ -7227,6 +7337,8 @@  static const struct ieee80211_ops ath12k_ops = {
 	.get_survey			= ath12k_mac_op_get_survey,
 	.flush				= ath12k_mac_op_flush,
 	.sta_statistics			= ath12k_mac_op_sta_statistics,
+	.remain_on_channel              = ath12k_mac_op_remain_on_channel,
+	.cancel_remain_on_channel       = ath12k_mac_op_cancel_remain_on_channel,
 };
 
 static void ath12k_mac_update_ch_list(struct ath12k *ar,
@@ -7777,6 +7889,7 @@  int ath12k_mac_allocate(struct ath12k_base *ab)
 		init_completion(&ar->bss_survey_done);
 		init_completion(&ar->scan.started);
 		init_completion(&ar->scan.completed);
+		init_completion(&ar->scan.on_channel);
 
 		INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work);
 		INIT_WORK(&ar->regd_update_work, ath12k_regd_update_work);
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 861565eaab3d..e10289de84c1 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -5050,6 +5050,8 @@  static void ath12k_wmi_event_scan_started(struct ath12k *ar)
 		break;
 	case ATH12K_SCAN_STARTING:
 		ar->scan.state = ATH12K_SCAN_RUNNING;
+		if (ar->scan.is_roc)
+			ieee80211_ready_on_channel(ar->hw);
 		complete(&ar->scan.started);
 		break;
 	}
@@ -5132,6 +5134,8 @@  static void ath12k_wmi_event_scan_foreign_chan(struct ath12k *ar, u32 freq)
 	case ATH12K_SCAN_RUNNING:
 	case ATH12K_SCAN_ABORTING:
 		ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq);
+		if (ar->scan.is_roc && ar->scan.roc_freq == freq)
+			complete(&ar->scan.on_channel);
 		break;
 	}
 }