Explorar o código

qcacmn: Compute the remaining max channel switch time

As per the spec,
"A STA affiliated with a non-AP MLD, that operates on Link2, transmits a
(Re)Association Request frame to AP2 requesting Link1 as one of the links
for multi-link setup. Since the (Re)Association Response frame is
transmitted by AP2 after the last Beacon frame on the initial operating
class/channel on Link1 and before the first beacon on the initial
operating class/channel is transmitted, AP2 includes the Max Channel
Switch Time element in the per-STA profile corresponding to AP1 in the
(Re)Association Response frame it transmits. The value carried in Max
Channel Switch Time element provides an estimate of time until the first
TBTT on the new channel on Link1."

Hence, calculate the remaining max channel switch time using the below
steps.

When host receives the CSA complete event with the CSA count 1, calculate
the Max channel switch time for each vdev by adding the below values,
	a) Host triggers the channel switch when CSA complete event is
	   received with the CSA count 0. The time difference between
	   CSA count 1 and CSA count 0 is one beacon interval. Hence, add
	   one beacon interval.
	b) Add the channel change time. The total time required to receive
	   CSA event handler from FW with CSA count 0, plus, the time required
	   to process the CSA complete event, plus, the time required to send
	   multi-vdev restart request for all the vdevs in the new channel and
	   send updated beacon template (only for non-DFS channel) is
	   approximately 1 second (added a few milliseconds as delta and
	   considered 16 AP vaps here).
	c) Add DFS CAC duration of the new channel if the new channel is DFS.
	d) Add one beacon interval time (time required to send the beacon on
	   the new channel after VDEV up).
	e) Store the sum of the above time values in max_chan_switch_time of
	   the vdev_mlme object.
	f) Save the current time when host receives CSA complete event with CSA
	   count as 1 in the last_bcn_ts_ms of the vdev_mlme object.

Calculate the remaining channels switch time using the below formula.
- Remaining channel switch time is equal to the time when the last beacon
  sent on the CSA triggered channel plus max channel switch time minus
  current time.

Reset the max channel switch time and the last beacon sent time after
sending the VDEV UP command to FW.

Change-Id: I7c03bfae5e159419a6c9462591aeb2d6c5b4fb87
CRs-Fixed: 3076245
Shashikala Prabhu %!s(int64=3) %!d(string=hai) anos
pai
achega
3090d55051

+ 11 - 0
target_if/mlme/vdev_mgr/src/target_if_vdev_mgr_rx_ops.c

@@ -775,6 +775,7 @@ static int target_if_pdev_csa_status_event_handler(
 	struct target_psoc_info *tgt_hdl;
 	int i;
 	QDF_STATUS status;
+	struct wlan_lmac_if_mlme_rx_ops *rx_ops = NULL;
 
 	if (!scn || !data) {
 		mlme_err("Invalid input");
@@ -787,6 +788,12 @@ static int target_if_pdev_csa_status_event_handler(
 		return -EINVAL;
 	}
 
+	rx_ops = target_if_vdev_mgr_get_rx_ops(psoc);
+	if (!rx_ops || !rx_ops->vdev_mgr_set_max_channel_switch_time) {
+		mlme_err("No Rx Ops");
+		return -EINVAL;
+	}
+
 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
 	if (!wmi_handle) {
 		mlme_err("wmi_handle is null");
@@ -807,6 +814,10 @@ static int target_if_pdev_csa_status_event_handler(
 		return -EINVAL;
 	}
 
+	if (csa_status.current_switch_count == 1)
+		rx_ops->vdev_mgr_set_max_channel_switch_time
+			(psoc, csa_status.vdev_ids, csa_status.num_vdevs);
+
 	if (wlan_psoc_nif_fw_ext_cap_get(psoc, WLAN_SOC_CEXT_CSA_TX_OFFLOAD)) {
 		for (i = 0; i < csa_status.num_vdevs; i++) {
 			if (!csa_status.current_switch_count)

+ 5 - 0
umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h

@@ -2020,6 +2020,8 @@ struct wlan_lmac_if_dfs_rx_ops {
  * @vdev_mgr_multi_vdev_restart_resp: function to handle mvr response
  * @vdev_mgr_set_mac_addr_response: Callback to get response for set MAC address
  *                                  command
+ * @vdev_mgr_set_max_channel_switch_time: Set max channel switch time for the
+ * given vdev list.
  */
 struct wlan_lmac_if_mlme_rx_ops {
 	QDF_STATUS (*vdev_mgr_start_response)(
@@ -2053,6 +2055,9 @@ struct wlan_lmac_if_mlme_rx_ops {
 #ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE
 	void (*vdev_mgr_set_mac_addr_response)(uint8_t vdev_id, uint8_t status);
 #endif
+	void (*vdev_mgr_set_max_channel_switch_time)
+		(struct wlan_objmgr_psoc *psoc,
+		 uint32_t *vdev_ids, uint32_t num_vdevs);
 };
 
 #ifdef WLAN_SUPPORT_GREEN_AP

+ 5 - 0
umac/mlme/include/wlan_vdev_mlme.h

@@ -370,11 +370,16 @@ struct wlan_vdev_aid_mgr {
  * @hidden_ssid: flag to indicate whether it is hidden ssid
  * @cac_duration_ms: cac duration in millseconds
  * @aid_mgr: AID bitmap mgr
+ * @max_chan_switch_time: Max channel switch time in milliseconds.
+ * @last_bcn_ts_ms: Timestamp (in milliseconds) of the last beacon sent on the
+ *                  CSA triggered channel.
  */
 struct vdev_mlme_mgmt_ap {
 	bool hidden_ssid;
 	uint32_t cac_duration_ms;
 	struct wlan_vdev_aid_mgr *aid_mgr;
+	uint32_t max_chan_switch_time;
+	unsigned long last_bcn_ts_ms;
 };
 
 /**

+ 6 - 0
umac/mlme/vdev_mgr/core/src/vdev_mgr_ops.c

@@ -636,6 +636,12 @@ QDF_STATUS vdev_mgr_up_send(struct vdev_mlme_obj *mlme_obj)
 	if (QDF_IS_STATUS_ERROR(status))
 		return status;
 
+	/* Reset the max channel switch time and last beacon sent time as the
+	 * VDEV UP command sent to FW.
+	 */
+	mlme_obj->mgmt.ap.max_chan_switch_time = 0;
+	mlme_obj->mgmt.ap.last_bcn_ts_ms = 0;
+
 	is_6g_sap_fd_enabled = wlan_vdev_mlme_feat_ext_cap_get(vdev,
 					WLAN_VDEV_FEXT_FILS_DISC_6G_SAP);
 	mlme_debug("SAP FD enabled %d", is_6g_sap_fd_enabled);

+ 49 - 0
umac/mlme/vdev_mgr/dispatcher/inc/wlan_vdev_mgr_utils_api.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -30,6 +31,16 @@
 #include <wlan_vdev_mgr_ucfg_api.h>
 #include <cdp_txrx_cmn_struct.h>
 
+/* The total time required to receive CSA event handler from FW with CSA count
+ * 0, plus, time required to process the CSA event, plus, time required to
+ * send multi-vdev restart request on the new channel and send updated beacon
+ * template is approximately 1 second (considered 16 AP vaps).
+ */
+#define VDEV_RESTART_TIME 1
+
+/* Convert seconds to milliseconds */
+#define SECONDS_TO_MS(seconds) ((seconds) * 1000)
+
 /**
  * wlan_util_vdev_get_cdp_txrx_opmode - get cdp txrx opmode from qdf mode
  * @vdev: pointer to vdev object
@@ -97,4 +108,42 @@ void wlan_util_vdev_get_param(struct wlan_objmgr_vdev *vdev,
 			      enum wlan_mlme_cfg_id param_id,
 			      uint32_t *param_value);
 
+/**
+ * wlan_util_vdev_mgr_get_csa_channel_switch_time() - Returns the time required
+ * to switch the channel after completing the CSA announcement. This does not
+ * include the CAC duration.
+ * @vdev: Pointer to vdev object
+ * @chan_switch_time: Pointer to save the CSA channel switch time. This does not
+ *                    include the DFS CAC duration
+ *
+ * Return: QDF_STATUS - Success or Failure
+ */
+QDF_STATUS wlan_util_vdev_mgr_get_csa_channel_switch_time(
+		struct wlan_objmgr_vdev *vdev,
+		uint32_t *chan_switch_time);
+
+/**
+ * wlan_util_vdev_mgr_compute_max_channel_switch_time() - Compute the max
+ * channel switch time for the given vdev
+ * @vdev: pointer to vdev object
+ * @max_chan_switch_time: Pointer to save the computed max channel switch time
+ *
+ * Return: QDF_STATUS - Success or Failure
+ */
+QDF_STATUS wlan_util_vdev_mgr_compute_max_channel_switch_time(
+		struct wlan_objmgr_vdev *vdev, uint32_t *max_chan_switch_time);
+
+/**
+ * wlan_utils_get_vdev_remaining_channel_switch_time() - Get the remaining
+ *                                                       channel switch time.
+ * @vdev: Pointer to vdev object
+ *
+ * Remaining channel switch time is equal to the time when last beacon sent on
+ * the CSA triggered vap plus max channel switch time minus current
+ * time.
+ *
+ * Return: Remaining cac time
+ */
+uint32_t wlan_utils_get_vdev_remaining_channel_switch_time(
+		struct wlan_objmgr_vdev *vdev);
 #endif /* __WLAN_VDEV_MGR_UTILS_API_H__ */

+ 51 - 0
umac/mlme/vdev_mgr/dispatcher/src/wlan_vdev_mgr_tgt_if_rx_api.c

@@ -33,6 +33,7 @@
 #include <wlan_psoc_mlme_main.h>
 #include <include/wlan_psoc_mlme.h>
 #include <include/wlan_mlme_cmn.h>
+#include <wlan_vdev_mgr_utils_api.h>
 
 void
 tgt_vdev_mgr_reset_response_timer_info(struct wlan_objmgr_psoc *psoc)
@@ -278,6 +279,54 @@ static inline void tgt_vdev_mgr_reg_set_mac_address_response(
 }
 #endif
 
+static void tgt_vdev_mgr_set_max_channel_switch_time(
+		struct wlan_objmgr_psoc *psoc, uint32_t *vdev_ids,
+		uint32_t num_vdevs)
+{
+	struct wlan_objmgr_vdev *vdev = NULL;
+	struct vdev_mlme_obj *vdev_mlme = NULL;
+	unsigned long current_time = qdf_mc_timer_get_system_time();
+	uint32_t max_chan_switch_time = 0;
+	int i = 0;
+	QDF_STATUS status;
+
+	/* Compute and populate the max channel switch time and time of the last
+	 * beacon sent on the CSA triggered channel for all the vdevs.
+	 */
+	for (i = 0; i < num_vdevs; i++) {
+		vdev = wlan_objmgr_get_vdev_by_id_from_psoc
+		    (psoc, vdev_ids[i], WLAN_VDEV_TARGET_IF_ID);
+		if (!vdev) {
+			mlme_err("VDEV is NULL");
+			continue;
+		}
+
+		vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
+		if (!vdev_mlme) {
+			mlme_err("VDEV_%d: PSOC_%d VDEV_MLME is NULL",
+				 vdev_ids[i],
+				 wlan_psoc_get_id(psoc));
+			wlan_objmgr_vdev_release_ref(vdev,
+						     WLAN_VDEV_TARGET_IF_ID);
+			continue;
+		}
+
+		status = wlan_util_vdev_mgr_compute_max_channel_switch_time
+			(vdev, &max_chan_switch_time);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			mlme_err("Failed to get the max channel switch time value");
+			wlan_objmgr_vdev_release_ref(vdev,
+						     WLAN_VDEV_TARGET_IF_ID);
+			continue;
+		}
+
+		vdev_mlme->mgmt.ap.last_bcn_ts_ms = current_time;
+		vdev_mlme->mgmt.ap.max_chan_switch_time = max_chan_switch_time;
+
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_VDEV_TARGET_IF_ID);
+	}
+}
+
 void tgt_vdev_mgr_register_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops)
 {
 	struct wlan_lmac_if_mlme_rx_ops *mlme_rx_ops = &rx_ops->mops;
@@ -298,6 +347,8 @@ void tgt_vdev_mgr_register_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops)
 		tgt_vdev_mgr_get_response_timer_info;
 	mlme_rx_ops->vdev_mgr_multi_vdev_restart_resp =
 		tgt_vdev_mgr_multi_vdev_restart_resp_handler;
+	mlme_rx_ops->vdev_mgr_set_max_channel_switch_time =
+		tgt_vdev_mgr_set_max_channel_switch_time;
 	tgt_psoc_reg_wakelock_info_rx_op(&rx_ops->mops);
 	tgt_vdev_mgr_reg_set_mac_address_response(mlme_rx_ops);
 }

+ 121 - 0
umac/mlme/vdev_mgr/dispatcher/src/wlan_vdev_mgr_utils_api.c

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -28,6 +29,10 @@
 #include <wlan_mlme_dbg.h>
 #include <qdf_module.h>
 #include <wlan_vdev_mgr_tgt_if_tx_api.h>
+#include <wlan_dfs_mlme_api.h>
+#ifndef MOBILE_DFS_SUPPORT
+#include <wlan_dfs_utils_api.h>
+#endif /* MOBILE_DFS_SUPPORT */
 
 static QDF_STATUS vdev_mgr_config_ratemask_update(
 				struct vdev_mlme_obj *mlme_obj,
@@ -674,3 +679,119 @@ void wlan_util_vdev_get_param(struct wlan_objmgr_vdev *vdev,
 }
 
 qdf_export_symbol(wlan_util_vdev_get_param);
+
+/**
+ * wlan_util_vdev_mgr_get_cac_timeout_for_vdev() - Get the CAC timeout value for
+ * a given vdev.
+ * @vdev: Pointer to vdev object.
+ *
+ * Return: CAC timeout value
+ */
+#ifndef MOBILE_DFS_SUPPORT
+static int wlan_util_vdev_mgr_get_cac_timeout_for_vdev(
+		struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_channel *des_chan = NULL;
+	struct wlan_channel *bss_chan = NULL;
+	bool continue_current_cac = 0;
+
+	des_chan = wlan_vdev_mlme_get_des_chan(vdev);
+	if (!des_chan)
+		return 0;
+
+	bss_chan = wlan_vdev_mlme_get_bss_chan(vdev);
+	if (!bss_chan)
+		return 0;
+
+	if (!utils_dfs_is_cac_required(wlan_vdev_get_pdev(vdev), des_chan,
+				       bss_chan, &continue_current_cac))
+		return 0;
+
+	return dfs_mlme_get_cac_timeout_for_freq(wlan_vdev_get_pdev(vdev),
+						 des_chan->ch_freq,
+						 des_chan->ch_cfreq2,
+						 des_chan->ch_flags);
+}
+#else
+static int wlan_util_vdev_mgr_get_cac_timeout_for_vdev(
+		struct wlan_objmgr_vdev *vdev)
+{
+	return 0;
+}
+#endif /* MOBILE_DFS_SUPPORT */
+
+QDF_STATUS wlan_util_vdev_mgr_get_csa_channel_switch_time(
+		struct wlan_objmgr_vdev *vdev,
+		uint32_t *chan_switch_time)
+{
+	struct vdev_mlme_obj *vdev_mlme = NULL;
+
+	*chan_switch_time = 0;
+
+	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
+	if (!vdev_mlme) {
+		mlme_err("vdev_mlme is null");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* Time between CSA count 1 and CSA count 0 is one beacon interval. */
+	*chan_switch_time = vdev_mlme->proto.generic.beacon_interval;
+
+	/* Vdev restart time */
+	*chan_switch_time += SECONDS_TO_MS(VDEV_RESTART_TIME);
+
+	/* Add one beacon interval time required to send beacon on the
+	 * new channel after switching to the new channel.
+	 */
+	*chan_switch_time += vdev_mlme->proto.generic.beacon_interval;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS wlan_util_vdev_mgr_compute_max_channel_switch_time(
+		struct wlan_objmgr_vdev *vdev, uint32_t *max_chan_switch_time)
+{
+	int dfs_cac_timeout = 0;
+	QDF_STATUS status;
+
+	status = wlan_util_vdev_mgr_get_csa_channel_switch_time(
+			vdev, max_chan_switch_time);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		mlme_err("Failed to get the CSA channel switch time");
+		return status;
+	}
+
+	/* Get the CAC time */
+	dfs_cac_timeout = wlan_util_vdev_mgr_get_cac_timeout_for_vdev(vdev);
+
+	/* Seconds to milliseconds */
+	*max_chan_switch_time += SECONDS_TO_MS(dfs_cac_timeout);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+uint32_t
+wlan_utils_get_vdev_remaining_channel_switch_time(struct wlan_objmgr_vdev *vdev)
+{
+	struct vdev_mlme_obj *vdev_mlme = NULL;
+	int32_t remaining_chan_switch_time;
+
+	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
+	if (!vdev_mlme)
+		return 0;
+
+	if (!vdev_mlme->mgmt.ap.last_bcn_ts_ms)
+		return 0;
+
+	/* Remaining channel switch time is equal to the time when last beacon
+	 * sent on the CSA triggered vap plus max channel switch time minus
+	 * current time.
+	 */
+	remaining_chan_switch_time =
+	    ((vdev_mlme->mgmt.ap.last_bcn_ts_ms +
+	      vdev_mlme->mgmt.ap.max_chan_switch_time) -
+	     qdf_mc_timer_get_system_time());
+
+	return (remaining_chan_switch_time > 0) ?
+		remaining_chan_switch_time : 0;
+}