Browse Source

qcacmn: Add APIs to configure and switch to postNOL channel

Introduce APIs to perform postNOL channel switch to user
configured channel after the NOL expiry of said channel.

This channel change will involve regular CAC after vdev start.

Change-Id: I426b0c4b51c84789870841dd4c3af942be185f20
Vignesh Mohan 5 years ago
parent
commit
1e876d8f14

+ 89 - 0
umac/dfs/core/src/dfs.h

@@ -1139,6 +1139,10 @@ struct dfs_rcac_params {
  *                                   MHZ.
  *                                   MHZ.
  * @dfs_rcac_param:                  Primary frequency and Channel params of
  * @dfs_rcac_param:                  Primary frequency and Channel params of
  *                                   the selected RCAC channel.
  *                                   the selected RCAC channel.
+ * @dfs_chan_postnol_freq:           Frequency the AP switches to, post NOL.
+ * @dfs_chan_postnol_mode:           Phymode the AP switches to, post NOL.
+ * @dfs_chan_postnol_cfreq2:         Secondary center frequency the AP
+ *                                   switches to, post NOL.
  */
  */
 struct wlan_dfs {
 struct wlan_dfs {
 	uint32_t       dfs_debug_mask;
 	uint32_t       dfs_debug_mask;
@@ -1311,6 +1315,11 @@ struct wlan_dfs {
 	struct dfs_rcac_params dfs_rcac_param;
 	struct dfs_rcac_params dfs_rcac_param;
 #endif
 #endif
 	uint16_t       dfs_lowest_pri_limit;
 	uint16_t       dfs_lowest_pri_limit;
+#if defined(QCA_SUPPORT_DFS_CHAN_POSTNOL)
+	qdf_freq_t     dfs_chan_postnol_freq;
+	enum phy_ch_width dfs_chan_postnol_mode;
+	qdf_freq_t     dfs_chan_postnol_cfreq2;
+#endif
 };
 };
 
 
 #if defined(QCA_SUPPORT_AGILE_DFS) || defined(ATH_SUPPORT_ZERO_CAC_DFS)
 #if defined(QCA_SUPPORT_AGILE_DFS) || defined(ATH_SUPPORT_ZERO_CAC_DFS)
@@ -2987,4 +2996,84 @@ uint8_t dfs_find_dfs_sub_channels_for_freq(struct  wlan_dfs *dfs,
 					   struct dfs_channel *chan,
 					   struct dfs_channel *chan,
 					   uint16_t *subchan_arr);
 					   uint16_t *subchan_arr);
 
 
+#ifdef QCA_SUPPORT_DFS_CHAN_POSTNOL
+/**
+ * dfs_set_postnol_freq() - DFS API to set postNOL frequency.
+ * @dfs: Pointer to wlan_dfs object.
+ * @postnol_freq: PostNOL frequency value configured by the user.
+ */
+void dfs_set_postnol_freq(struct wlan_dfs *dfs, qdf_freq_t postnol_freq);
+
+/**
+ * dfs_set_postnol_mode() - DFS API to set postNOL mode.
+ * @dfs: Pointer to wlan_dfs object.
+ * @postnol_mode: PostNOL frequency value configured by the user.
+ */
+void dfs_set_postnol_mode(struct wlan_dfs *dfs, uint8_t postnol_mode);
+
+/**
+ * dfs_set_postnol_cfreq2() - DFS API to set postNOL secondary center frequency.
+ * @dfs: Pointer to wlan_dfs object.
+ * @postnol_cfreq2: PostNOL secondary center frequency value configured by the
+ * user.
+ */
+void dfs_set_postnol_cfreq2(struct wlan_dfs *dfs, qdf_freq_t postnol_cfreq2);
+
+/**
+ * dfs_get_postnol_freq() - DFS API to get postNOL frequency.
+ * @dfs: Pointer to wlan_dfs object.
+ * @postnol_freq: PostNOL frequency value configured by the user.
+ */
+void dfs_get_postnol_freq(struct wlan_dfs *dfs, qdf_freq_t *postnol_freq);
+
+/**
+ * dfs_get_postnol_mode() - DFS API to get postNOL mode.
+ * @dfs: Pointer to wlan_dfs object.
+ * @postnol_mode: PostNOL frequency value configured by the user.
+ */
+void dfs_get_postnol_mode(struct wlan_dfs *dfs, uint8_t *postnol_mode);
+
+/**
+ * dfs_get_postnol_cfreq2() - DFS API to get postNOL secondary center frequency.
+ * @dfs: Pointer to wlan_dfs object.
+ * @postnol_cfreq2: PostNOL secondary center frequency value configured by the
+ * user.
+ */
+void dfs_get_postnol_cfreq2(struct wlan_dfs *dfs, qdf_freq_t *postnol_cfreq2);
+#else
+static inline void
+dfs_set_postnol_freq(struct wlan_dfs *dfs, qdf_freq_t postnol_freq)
+{
+}
+
+static inline void
+dfs_set_postnol_mode(struct wlan_dfs *dfs, uint8_t postnol_mode)
+{
+}
+
+static inline void
+dfs_set_postnol_cfreq2(struct wlan_dfs *dfs, qdf_freq_t postnol_cfreq2)
+{
+}
+
+static inline void
+dfs_get_postnol_freq(struct wlan_dfs *dfs, qdf_freq_t *postnol_freq)
+{
+	*postnol_freq = 0;
+}
+
+static inline void
+dfs_get_postnol_mode(struct wlan_dfs *dfs, uint8_t *postnol_mode)
+{
+	*postnol_mode = CH_WIDTH_INVALID;
+}
+
+static inline void
+dfs_get_postnol_cfreq2(struct wlan_dfs *dfs, qdf_freq_t *postnol_cfreq2)
+{
+	*postnol_cfreq2 = 0;
+}
+
+#endif /* QCA_SUPPORT_DFS_CHAN_POSTNOL */
+
 #endif  /* _DFS_H_ */
 #endif  /* _DFS_H_ */

+ 71 - 0
umac/dfs/core/src/misc/dfs.c

@@ -996,3 +996,74 @@ uint8_t dfs_get_agile_detector_id(struct wlan_dfs *dfs)
 	return dfs->dfs_agile_detector_id;
 	return dfs->dfs_agile_detector_id;
 }
 }
 #endif
 #endif
+
+#ifdef QCA_SUPPORT_DFS_CHAN_POSTNOL
+void dfs_set_postnol_freq(struct wlan_dfs *dfs, qdf_freq_t postnol_freq)
+{
+	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
+		 "dfs_chan_postnol_freq configured as %d", postnol_freq);
+
+	dfs->dfs_chan_postnol_freq = postnol_freq;
+}
+
+void dfs_set_postnol_mode(struct wlan_dfs *dfs, uint8_t postnol_mode)
+{
+	if (dfs->dfs_chan_postnol_cfreq2) {
+		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
+			 "postNOL cfreq2 has been set,reset it to change mode");
+		return;
+	}
+
+	switch (postnol_mode) {
+	case DFS_CHWIDTH_20_VAL:
+		dfs->dfs_chan_postnol_mode = CH_WIDTH_20MHZ;
+		break;
+	case DFS_CHWIDTH_40_VAL:
+		dfs->dfs_chan_postnol_mode = CH_WIDTH_40MHZ;
+		break;
+	case DFS_CHWIDTH_80_VAL:
+		dfs->dfs_chan_postnol_mode = CH_WIDTH_80MHZ;
+		break;
+	case DFS_CHWIDTH_160_VAL:
+		dfs->dfs_chan_postnol_mode = CH_WIDTH_160MHZ;
+		break;
+	default:
+		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
+			"Invalid postNOL mode configured");
+		return;
+	}
+
+	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
+		 "DFS postnol mode configured as %d",
+		 dfs->dfs_chan_postnol_mode);
+}
+
+void dfs_set_postnol_cfreq2(struct wlan_dfs *dfs, qdf_freq_t postnol_cfreq2)
+{
+	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
+		 "dfs_chan_postnol_cfreq2 configured as %d", postnol_cfreq2);
+
+	dfs->dfs_chan_postnol_cfreq2 = postnol_cfreq2;
+
+	if (postnol_cfreq2) {
+		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
+			 "postNOL cfreq2 is set, changing mode to 80P80");
+		dfs->dfs_chan_postnol_mode = CH_WIDTH_80P80MHZ;
+	}
+}
+
+void dfs_get_postnol_freq(struct wlan_dfs *dfs, qdf_freq_t *postnol_freq)
+{
+	*postnol_freq = dfs->dfs_chan_postnol_freq;
+}
+
+void dfs_get_postnol_mode(struct wlan_dfs *dfs, uint8_t *postnol_mode)
+{
+	*postnol_mode = dfs->dfs_chan_postnol_mode;
+}
+
+void dfs_get_postnol_cfreq2(struct wlan_dfs *dfs, qdf_freq_t *postnol_cfreq2)
+{
+	*postnol_cfreq2 = dfs->dfs_chan_postnol_cfreq2;
+}
+#endif

+ 130 - 2
umac/dfs/core/src/misc/dfs_nol.c

@@ -283,6 +283,119 @@ static void dfs_nol_delete(struct wlan_dfs *dfs,
 	}
 	}
 }
 }
 
 
+#ifdef QCA_SUPPORT_DFS_CHAN_POSTNOL
+/**
+ * dfs_switch_to_postnol_chan_if_nol_expired() - Find if NOL is expired
+ * in the postNOL channel configured. If true, trigger channel change.
+ * @dfs: Pointer to DFS of wlan_dfs structure.
+ *
+ * Return: True, if channel change is triggered, else false.
+ */
+static bool
+dfs_switch_to_postnol_chan_if_nol_expired(struct wlan_dfs *dfs)
+{
+	struct dfs_channel chan;
+	struct dfs_channel *curchan = dfs->dfs_curchan;
+	bool is_curchan_11ac = false, is_curchan_11axa = false;
+	enum wlan_phymode postnol_phymode;
+
+	if (!dfs->dfs_chan_postnol_freq)
+		return false;
+
+	if (WLAN_IS_CHAN_11AC_VHT20(curchan) ||
+	    WLAN_IS_CHAN_11AC_VHT40(curchan) ||
+	    WLAN_IS_CHAN_11AC_VHT80(curchan) ||
+	    WLAN_IS_CHAN_11AC_VHT160(curchan) ||
+	    WLAN_IS_CHAN_11AC_VHT80_80(curchan))
+		is_curchan_11ac = true;
+	else if (WLAN_IS_CHAN_11AXA_HE20(curchan) ||
+		 WLAN_IS_CHAN_11AXA_HE40PLUS(curchan) ||
+		 WLAN_IS_CHAN_11AXA_HE40MINUS(curchan) ||
+		 WLAN_IS_CHAN_11AXA_HE80(curchan) ||
+		 WLAN_IS_CHAN_11AXA_HE160(curchan) ||
+		 WLAN_IS_CHAN_11AXA_HE80_80(curchan))
+		is_curchan_11axa = true;
+
+	switch (dfs->dfs_chan_postnol_mode) {
+	case CH_WIDTH_20MHZ:
+		if (is_curchan_11ac)
+			postnol_phymode = WLAN_PHYMODE_11AC_VHT20;
+		else if (is_curchan_11axa)
+			postnol_phymode = WLAN_PHYMODE_11AXA_HE20;
+		else
+			return false;
+		break;
+	case CH_WIDTH_40MHZ:
+		if (is_curchan_11ac)
+			postnol_phymode = WLAN_PHYMODE_11AC_VHT40;
+		else if (is_curchan_11axa)
+			postnol_phymode = WLAN_PHYMODE_11AXA_HE40;
+		else
+			return false;
+		break;
+	case CH_WIDTH_80MHZ:
+		if (is_curchan_11ac)
+			postnol_phymode = WLAN_PHYMODE_11AC_VHT80;
+		else if (is_curchan_11axa)
+			postnol_phymode = WLAN_PHYMODE_11AXA_HE80;
+		else
+			return false;
+		break;
+	case CH_WIDTH_160MHZ:
+		if (is_curchan_11ac)
+			postnol_phymode = WLAN_PHYMODE_11AC_VHT160;
+		else if (is_curchan_11axa)
+			postnol_phymode = WLAN_PHYMODE_11AXA_HE160;
+		else
+			return false;
+		break;
+	default:
+		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
+			"Invalid postNOL mode set. Cannot switch to the chan");
+		return false;
+	}
+
+	qdf_mem_zero(&chan, sizeof(struct dfs_channel));
+	if (QDF_STATUS_SUCCESS !=
+		dfs_mlme_find_dot11_chan_for_freq(
+			dfs->dfs_pdev_obj,
+			dfs->dfs_chan_postnol_freq,
+			dfs->dfs_chan_postnol_cfreq2,
+			postnol_phymode,
+			&chan.dfs_ch_freq,
+			&chan.dfs_ch_flags,
+			&chan.dfs_ch_flagext,
+			&chan.dfs_ch_ieee,
+			&chan.dfs_ch_vhtop_ch_freq_seg1,
+			&chan.dfs_ch_vhtop_ch_freq_seg2,
+			&chan.dfs_ch_mhz_freq_seg1,
+			&chan.dfs_ch_mhz_freq_seg2)) {
+		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
+			"Channel %d not found for mode %d and cfreq2 %d",
+			dfs->dfs_chan_postnol_freq,
+			postnol_phymode,
+			dfs->dfs_chan_postnol_cfreq2);
+		return false;
+	}
+	if (WLAN_IS_CHAN_RADAR(&chan))
+		return false;
+
+	if (global_dfs_to_mlme.mlme_postnol_chan_switch)
+		global_dfs_to_mlme.mlme_postnol_chan_switch(
+				dfs->dfs_pdev_obj,
+				dfs->dfs_chan_postnol_freq,
+				dfs->dfs_chan_postnol_cfreq2,
+				postnol_phymode);
+	return true;
+}
+#else
+static inline bool
+dfs_switch_to_postnol_chan_if_nol_expired(struct wlan_dfs *dfs)
+{
+	return false;
+}
+#endif
+
 /**
 /**
  * dfs_remove_from_nol() - Remove the freq from NOL list.
  * dfs_remove_from_nol() - Remove the freq from NOL list.
  *
  *
@@ -316,11 +429,26 @@ static os_timer_func(dfs_remove_from_nol)
 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
 		  "remove channel %d from nol", chan);
 		  "remove channel %d from nol", chan);
 	utils_dfs_unmark_precac_nol_for_freq(dfs->dfs_pdev_obj, delfreq);
 	utils_dfs_unmark_precac_nol_for_freq(dfs->dfs_pdev_obj, delfreq);
-	utils_dfs_agile_sm_deliver_evt(dfs->dfs_pdev_obj,
-				       DFS_AGILE_SM_EV_AGILE_START);
+
 	utils_dfs_reg_update_nol_chan_for_freq(dfs->dfs_pdev_obj,
 	utils_dfs_reg_update_nol_chan_for_freq(dfs->dfs_pdev_obj,
 					     &delfreq, 1, DFS_NOL_RESET);
 					     &delfreq, 1, DFS_NOL_RESET);
 	utils_dfs_save_nol(dfs->dfs_pdev_obj);
 	utils_dfs_save_nol(dfs->dfs_pdev_obj);
+
+	/*
+	 * Check if a channel is configured by the user to which we have to
+	 * switch after it's NOL expiry. If that is the case, change
+	 * channel immediately.
+	 *
+	 * If a channel switch is required (indicated by the return value of
+	 * dfs_switch_to_postnol_chan_if_nol_expired), return from this function
+	 * without posting Start event to Agile SM. That will be taken care
+	 * of, after VAP start.
+	 */
+	if (dfs_switch_to_postnol_chan_if_nol_expired(dfs))
+		return;
+
+	utils_dfs_agile_sm_deliver_evt(dfs->dfs_pdev_obj,
+				       DFS_AGILE_SM_EV_AGILE_START);
 }
 }
 #else
 #else
 #ifdef CONFIG_CHAN_NUM_API
 #ifdef CONFIG_CHAN_NUM_API

+ 112 - 0
umac/dfs/dispatcher/inc/wlan_dfs_ucfg_api.h

@@ -67,6 +67,8 @@
  * @mlme_dfs_deliver_event:            Deliver DFS events to user space
  * @mlme_dfs_deliver_event:            Deliver DFS events to user space
  * @mlme_precac_chan_change_csa_for_freq:Channel change triggered by PrCAC using
  * @mlme_precac_chan_change_csa_for_freq:Channel change triggered by PrCAC using
  *                                     Channel Switch Announcement.
  *                                     Channel Switch Announcement.
+ * @mlme_postnol_chan_switch:          Channel change post NOL using Channel
+ *                                     Switch Announcement.
  * @mlme_mark_dfs_for_freq:            Mark DFS channel frequency as radar.
  * @mlme_mark_dfs_for_freq:            Mark DFS channel frequency as radar.
  * @mlme_get_extchan_for_freq:         Get the extension channel.
  * @mlme_get_extchan_for_freq:         Get the extension channel.
  * @mlme_find_dot11_chan_for_freq:     Find a channel pointer.
  * @mlme_find_dot11_chan_for_freq:     Find a channel pointer.
@@ -211,6 +213,13 @@ struct dfs_to_mlme {
 					       uint8_t des_chan,
 					       uint8_t des_chan,
 					       enum wlan_phymode des_mode);
 					       enum wlan_phymode des_mode);
 #endif
 #endif
+#endif
+#ifdef QCA_SUPPORT_DFS_CHAN_POSTNOL
+	QDF_STATUS
+	(*mlme_postnol_chan_switch)(struct wlan_objmgr_pdev *pdev,
+				    qdf_freq_t des_chan_freq,
+				    qdf_freq_t des_cfreq2,
+				    enum wlan_phymode des_mode);
 #endif
 #endif
 	QDF_STATUS (*mlme_nol_timeout_notification)(
 	QDF_STATUS (*mlme_nol_timeout_notification)(
 			struct wlan_objmgr_pdev *pdev);
 			struct wlan_objmgr_pdev *pdev);
@@ -652,6 +661,109 @@ ucfg_dfs_set_rcac_freq(struct wlan_objmgr_pdev *pdev,
 }
 }
 #endif
 #endif
 
 
+#ifdef QCA_SUPPORT_DFS_CHAN_POSTNOL
+/**
+ * ucfg_dfs_set_postnol_freq() - Set PostNOL freq.
+ * @pdev: Pointer to DFS pdev object.
+ * @postnol_freq: User configured freq to switch to, post NOL, in MHZ.
+ *
+ */
+QDF_STATUS ucfg_dfs_set_postnol_freq(struct wlan_objmgr_pdev *pdev,
+				     qdf_freq_t postnol_freq);
+
+/**
+ * ucfg_dfs_set_postnol_mode() - Set PostNOL mode.
+ * @pdev: Pointer to DFS pdev object.
+ * @postnol_mode: User configured mode to switch to, post NOL, in MHZ.
+ *
+ */
+QDF_STATUS ucfg_dfs_set_postnol_mode(struct wlan_objmgr_pdev *pdev,
+				     uint8_t postnol_mode);
+
+/**
+ * ucfg_dfs_set_postnol_cfreq2() - Set PostNOL secondary center frequency.
+ * @pdev: Pointer to DFS pdev object.
+ * @postnol_freq: User configured secondary center frequency to switch to,
+ * post NOL, in MHZ.
+ *
+ */
+QDF_STATUS ucfg_dfs_set_postnol_cfreq2(struct wlan_objmgr_pdev *pdev,
+				       qdf_freq_t postnol_cfreq2);
+
+/**
+ * ucfg_dfs_get_postnol_freq() - Get PostNOL freq.
+ * @pdev: Pointer to DFS pdev object.
+ * @postnol_freq: Pointer to user configured freq to switch to, post NOL.
+ *
+ */
+QDF_STATUS ucfg_dfs_get_postnol_freq(struct wlan_objmgr_pdev *pdev,
+				     qdf_freq_t *postnol_freq);
+
+/**
+ * ucfg_dfs_get_postnol_mode() - Set PostNOL mode.
+ * @pdev: Pointer to DFS pdev object.
+ * @postnol_mode: Pointer to user configured mode to switch to, post NOL.
+ *
+ */
+QDF_STATUS ucfg_dfs_get_postnol_mode(struct wlan_objmgr_pdev *pdev,
+				     uint8_t *postnol_mode);
+
+/**
+ * ucfg_dfs_get_postnol_cfreq2() - Set PostNOL secondary center frequency.
+ * @pdev: Pointer to DFS pdev object.
+ * @postnol_freq: Pointer to user configured secondary center frequency to
+ * switch to post NOL.
+ *
+ */
+QDF_STATUS ucfg_dfs_get_postnol_cfreq2(struct wlan_objmgr_pdev *pdev,
+				       qdf_freq_t *postnol_cfreq2);
+#else
+static inline QDF_STATUS
+ucfg_dfs_set_postnol_freq(struct wlan_objmgr_pdev *pdev,
+			  qdf_freq_t postnol_freq)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS
+ucfg_dfs_set_postnol_mode(struct wlan_objmgr_pdev *pdev,
+			  uint8_t postnol_mode)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS
+ucfg_dfs_set_postnol_cfreq2(struct wlan_objmgr_pdev *pdev,
+			    qdf_freq_t postnol_cfreq2)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS
+ucfg_dfs_get_postnol_freq(struct wlan_objmgr_pdev *pdev,
+			  qdf_freq_t *postnol_freq)
+{
+	*postnol_freq = 0;
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS
+ucfg_dfs_get_postnol_mode(struct wlan_objmgr_pdev *pdev,
+			  uint8_t *postnol_mode)
+{
+	*postnol_mode = CH_WIDTH_INVALID;
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS
+ucfg_dfs_get_postnol_cfreq2(struct wlan_objmgr_pdev *pdev,
+			    qdf_freq_t *postnol_cfreq2)
+{
+	*postnol_cfreq2 = 0;
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 /**
 /**
  * ucfg_dfs_get_rcac_freq() - Get rcac freq.
  * ucfg_dfs_get_rcac_freq() - Get rcac freq.
  * @pdev: Pointer to DFS pdev object.
  * @pdev: Pointer to DFS pdev object.

+ 24 - 0
umac/dfs/dispatcher/src/wlan_dfs_init_deinit_api.c

@@ -74,6 +74,29 @@ register_dfs_precac_auto_chan_callbacks_freq(struct dfs_to_mlme *mlme_callback)
 #endif
 #endif
 #endif
 #endif
 
 
+/**
+ * register_dfs_postnol_csa_callback - Register postNOL channel switch callbacks
+ * @mlme_callback: Pointer to dfs_to_mlme.
+ */
+#ifndef QCA_MCL_DFS_SUPPORT
+#ifdef QCA_SUPPORT_DFS_CHAN_POSTNOL
+static inline void
+register_dfs_postnol_csa_callback(struct dfs_to_mlme *mlme_callback)
+{
+	if (!mlme_callback)
+		return;
+
+	mlme_callback->mlme_postnol_chan_switch =
+		mlme_dfs_postnol_chan_switch;
+}
+#else
+static inline void
+register_dfs_postnol_csa_callback(struct dfs_to_mlme *mlme_callback)
+{
+}
+#endif
+#endif
+
 /*
 /*
  * register_dfs_callbacks_for_freq() - Register dfs callbacks.
  * register_dfs_callbacks_for_freq() - Register dfs callbacks.
  * @mlme_callback: Pointer to dfs_to_mlme.
  * @mlme_callback: Pointer to dfs_to_mlme.
@@ -149,6 +172,7 @@ void register_dfs_callbacks(void)
 	register_dfs_precac_auto_chan_callbacks_freq(tmp_dfs_to_mlme);
 	register_dfs_precac_auto_chan_callbacks_freq(tmp_dfs_to_mlme);
 	/* Register freq based callbacks */
 	/* Register freq based callbacks */
 	register_dfs_callbacks_for_freq(tmp_dfs_to_mlme);
 	register_dfs_callbacks_for_freq(tmp_dfs_to_mlme);
+	register_dfs_postnol_csa_callback(tmp_dfs_to_mlme);
 }
 }
 #else
 #else
 void register_dfs_callbacks(void)
 void register_dfs_callbacks(void)

+ 110 - 0
umac/dfs/dispatcher/src/wlan_dfs_ucfg_api.c

@@ -537,3 +537,113 @@ bool ucfg_dfs_is_agile_rcac_enabled(struct wlan_objmgr_pdev *pdev)
 
 
 qdf_export_symbol(ucfg_dfs_is_agile_rcac_enabled);
 qdf_export_symbol(ucfg_dfs_is_agile_rcac_enabled);
 #endif
 #endif
+
+#ifdef QCA_SUPPORT_DFS_CHAN_POSTNOL
+QDF_STATUS ucfg_dfs_set_postnol_freq(struct wlan_objmgr_pdev *pdev,
+				     qdf_freq_t postnol_freq)
+{
+	struct wlan_dfs *dfs;
+
+	dfs = wlan_pdev_get_dfs_obj(pdev);
+	if (!dfs) {
+		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "null dfs");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	dfs_set_postnol_freq(dfs, postnol_freq);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+qdf_export_symbol(ucfg_dfs_set_postnol_freq);
+
+QDF_STATUS ucfg_dfs_set_postnol_mode(struct wlan_objmgr_pdev *pdev,
+				     uint8_t postnol_mode)
+{
+	struct wlan_dfs *dfs;
+
+	dfs = wlan_pdev_get_dfs_obj(pdev);
+	if (!dfs) {
+		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "null dfs");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	dfs_set_postnol_mode(dfs, postnol_mode);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+qdf_export_symbol(ucfg_dfs_set_postnol_mode);
+
+QDF_STATUS ucfg_dfs_set_postnol_cfreq2(struct wlan_objmgr_pdev *pdev,
+				       qdf_freq_t postnol_cfreq2)
+{
+	struct wlan_dfs *dfs;
+
+	dfs = wlan_pdev_get_dfs_obj(pdev);
+	if (!dfs) {
+		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "null dfs");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	dfs_set_postnol_cfreq2(dfs, postnol_cfreq2);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+qdf_export_symbol(ucfg_dfs_set_postnol_cfreq2);
+
+QDF_STATUS ucfg_dfs_get_postnol_freq(struct wlan_objmgr_pdev *pdev,
+				     qdf_freq_t *postnol_freq)
+{
+	struct wlan_dfs *dfs;
+
+	dfs = wlan_pdev_get_dfs_obj(pdev);
+	if (!dfs) {
+		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "null dfs");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	dfs_get_postnol_freq(dfs, postnol_freq);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+qdf_export_symbol(ucfg_dfs_get_postnol_freq);
+
+QDF_STATUS ucfg_dfs_get_postnol_mode(struct wlan_objmgr_pdev *pdev,
+				     uint8_t *postnol_mode)
+{
+	struct wlan_dfs *dfs;
+
+	dfs = wlan_pdev_get_dfs_obj(pdev);
+	if (!dfs) {
+		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "null dfs");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	dfs_get_postnol_mode(dfs, postnol_mode);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+qdf_export_symbol(ucfg_dfs_get_postnol_mode);
+
+QDF_STATUS ucfg_dfs_get_postnol_cfreq2(struct wlan_objmgr_pdev *pdev,
+				       qdf_freq_t *postnol_cfreq2)
+{
+	struct wlan_dfs *dfs;
+
+	dfs = wlan_pdev_get_dfs_obj(pdev);
+	if (!dfs) {
+		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "null dfs");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	dfs_get_postnol_cfreq2(dfs, postnol_cfreq2);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+qdf_export_symbol(ucfg_dfs_get_postnol_cfreq2);
+#endif

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

@@ -1524,6 +1524,14 @@ struct wlan_lmac_if_wifi_pos_rx_ops {
  * @dfs_complete_deferred_tasks:      Process mode switch completion in DFS.
  * @dfs_complete_deferred_tasks:      Process mode switch completion in DFS.
  * @dfs_is_agile_rcac_enabled:        Checks if Agile RCAC is enabled.
  * @dfs_is_agile_rcac_enabled:        Checks if Agile RCAC is enabled.
  * @dfs_agile_sm_deliver_evt:         API to post events to DFS Agile  SM.
  * @dfs_agile_sm_deliver_evt:         API to post events to DFS Agile  SM.
+ * @dfs_set_postnol_freq:             API to set frequency to switch, post NOL.
+ * @dfs_set_postnol_mode:             API to set phymode to switch to, post NOL.
+ * @dfs_set_postnol_cfreq2            API to set secondary center frequency to
+ *                                    switch to, post NOL.
+ * @dfs_get_postnol_freq:             API to get frequency to switch, post NOL.
+ * @dfs_get_postnol_mode:             API to get phymode to switch to, post NOL.
+ * @dfs_get_postnol_cfreq2:           API to get secondary center frequency to
+ *                                    switch to, post NOL.
  */
  */
 struct wlan_lmac_if_dfs_rx_ops {
 struct wlan_lmac_if_dfs_rx_ops {
 	QDF_STATUS (*dfs_get_radars)(struct wlan_objmgr_pdev *pdev);
 	QDF_STATUS (*dfs_get_radars)(struct wlan_objmgr_pdev *pdev);
@@ -1721,6 +1729,20 @@ struct wlan_lmac_if_dfs_rx_ops {
 	void (*dfs_agile_sm_deliver_evt)(struct wlan_objmgr_pdev *pdev,
 	void (*dfs_agile_sm_deliver_evt)(struct wlan_objmgr_pdev *pdev,
 					 enum dfs_agile_sm_evt event);
 					 enum dfs_agile_sm_evt event);
 #endif
 #endif
+#ifdef QCA_SUPPORT_DFS_CHAN_POSTNOL
+	QDF_STATUS (*dfs_set_postnol_freq)(struct wlan_objmgr_pdev *pdev,
+					   qdf_freq_t postnol_freq);
+	QDF_STATUS (*dfs_set_postnol_mode)(struct wlan_objmgr_pdev *pdev,
+					   uint8_t postnol_mode);
+	QDF_STATUS (*dfs_set_postnol_cfreq2)(struct wlan_objmgr_pdev *pdev,
+					     qdf_freq_t postnol_cfreq2);
+	QDF_STATUS (*dfs_get_postnol_freq)(struct wlan_objmgr_pdev *pdev,
+					   qdf_freq_t *postnol_freq);
+	QDF_STATUS (*dfs_get_postnol_mode)(struct wlan_objmgr_pdev *pdev,
+					   uint8_t *postnol_mode);
+	QDF_STATUS (*dfs_get_postnol_cfreq2)(struct wlan_objmgr_pdev *pdev,
+					     qdf_freq_t *postnol_cfreq2);
+#endif
 };
 };
 
 
 /**
 /**

+ 26 - 0
umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c

@@ -513,6 +513,31 @@ register_agile_dfs_rx_ops(struct wlan_lmac_if_dfs_rx_ops *rx_ops)
 }
 }
 #endif
 #endif
 
 
+#ifdef QCA_SUPPORT_DFS_CHAN_POSTNOL
+/* register_dfs_chan_postnol_rx_ops() - Register DFS Rx-Ops for postNOL
+ * channel change APIs.
+ * @rx_ops: Pointer to wlan_lmac_if_dfs_rx_ops.
+ */
+static void
+register_dfs_chan_postnol_rx_ops(struct wlan_lmac_if_dfs_rx_ops *rx_ops)
+{
+	if (!rx_ops)
+		return;
+
+	rx_ops->dfs_set_postnol_freq = ucfg_dfs_set_postnol_freq;
+	rx_ops->dfs_set_postnol_mode = ucfg_dfs_set_postnol_mode;
+	rx_ops->dfs_set_postnol_cfreq2 = ucfg_dfs_set_postnol_cfreq2;
+	rx_ops->dfs_get_postnol_freq = ucfg_dfs_get_postnol_freq;
+	rx_ops->dfs_get_postnol_mode = ucfg_dfs_get_postnol_mode;
+	rx_ops->dfs_get_postnol_cfreq2 = ucfg_dfs_get_postnol_cfreq2;
+}
+#else
+static inline void
+register_dfs_chan_postnol_rx_ops(struct wlan_lmac_if_dfs_rx_ops *rx_ops)
+{
+}
+#endif
+
 static QDF_STATUS
 static QDF_STATUS
 wlan_lmac_if_umac_dfs_rx_ops_register(struct wlan_lmac_if_rx_ops *rx_ops)
 wlan_lmac_if_umac_dfs_rx_ops_register(struct wlan_lmac_if_rx_ops *rx_ops)
 {
 {
@@ -598,6 +623,7 @@ wlan_lmac_if_umac_dfs_rx_ops_register(struct wlan_lmac_if_rx_ops *rx_ops)
 	register_dfs_rx_ops_for_freq(dfs_rx_ops);
 	register_dfs_rx_ops_for_freq(dfs_rx_ops);
 	register_rcac_dfs_rx_ops(dfs_rx_ops);
 	register_rcac_dfs_rx_ops(dfs_rx_ops);
 	register_agile_dfs_rx_ops(dfs_rx_ops);
 	register_agile_dfs_rx_ops(dfs_rx_ops);
+	register_dfs_chan_postnol_rx_ops(dfs_rx_ops);
 
 
 	return QDF_STATUS_SUCCESS;
 	return QDF_STATUS_SUCCESS;
 }
 }