qcacmn: Reinit DFS after HW mode switch (phase 2)

Supported dynamic HW mode switches:
DBS (full band 5G and 2G) <-> DBS_SBS (low band 5G, high band 5G and 2G)

Description of the changes:

1. NOL conversion:
  a. Introduce a temporary NOL list copy structure in DFS psoc obj.
  b. When mode switch is triggered:
    i.   Stop the NOL timers and clear the data, to avoid processing NOL
         expiry during mode switch.
    ii.  Allocate the psoc NOL copy for the target num_radios.
    iii. Store the NOL data of each radio to the target pdev ID
         (pdev ID after mode switch) in the psoc NOL copy,
	 using a unified mux/demux API.
  c. After mode switch is completed:
    i.   Resume NOL by re-initializing the list from the temporary psoc
         copy.
    ii.  Free the psoc copy after mode switch is complete.
    iii. Note: changes are made to support pause and resume of NOL,
         increasing NOL timeout by a few milliseconds.

2. PreCAC list conversion:
  a. When mode switch is triggered:
    i. Stop the existing preCAC timer and send ADFS abort command to FW.
  b. When mode switch is completed:
    i.  Unify/separate the preCAC list if the target mode is DBS/DBS_SBS
        respectively, using a single API.
    ii. Start ADFS again.

3. Radar detection lock:
  a. While detecting radar, acquire a lock to avoid handling user triggered
     mode_switch during this process. Release the lock once radar
     processing is completed and CSA start is triggered.

4. Radar detection/CAC completion defer during mode switch:
  a. While detecting radar or CAC completion, check if mode switch is
     in progress. If yes, defer the processing and wait for mode switch to
     complete before handling the events.
  b. Note: Precedence is Radar over CAC, i.e., if CAC processing is waiting
     and radar is received, CAC completion is no longer handled.

CRs-Fixed: 2580403
Change-Id: I506f3b569bad2e351c6f336e50f203cf5fa8b223
diff --git a/umac/dfs/core/src/dfs.h b/umac/dfs/core/src/dfs.h
index 1aa1bde..24f5a84 100644
--- a/umac/dfs/core/src/dfs.h
+++ b/umac/dfs/core/src/dfs.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016-2019 The Linux Foundation.  All rights reserved.
+ * Copyright (c) 2013, 2016-2020 The Linux Foundation.  All rights reserved.
  * Copyright (c) 2005-2006 Atheros Communications, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
@@ -197,6 +197,12 @@
 #define WLAN_DFS_DATA_STRUCT_LOCK_DESTROY(_dfs) \
 	qdf_spinlock_destroy(&(_dfs)->dfs_data_struct_lock)
 
+/* Wrappers to call MLME radar during mode switch lock. */
+#define DFS_RADAR_MODE_SWITCH_LOCK(_dfs) \
+	dfs_mlme_acquire_radar_mode_switch_lock((_dfs)->dfs_pdev_obj)
+#define DFS_RADAR_MODE_SWITCH_UNLOCK(_dfs) \
+	dfs_mlme_release_radar_mode_switch_lock((_dfs)->dfs_pdev_obj)
+
 /* Mask for time stamp from descriptor */
 #define DFS_TSMASK    0xFFFFFFFF
 /* Shift for time stamp from descriptor */
@@ -898,6 +904,20 @@
 #define FREQ_OFFSET_BOUNDARY_FOR_80MHZ 40
 
 /**
+ * struct dfs_mode_switch_defer_params - Parameters storing DFS information
+ * before defer, as part of HW mode switch.
+ *
+ * @radar_params: Deferred radar parameters.
+ * @is_cac_completed: Boolean representing CAC completion event.
+ * @is_radar_detected: Boolean representing radar event.
+ */
+struct dfs_mode_switch_defer_params {
+	struct radar_found_info *radar_params;
+	bool is_cac_completed;
+	bool is_radar_detected;
+};
+
+/**
  * struct wlan_dfs -                 The main dfs structure.
  * @dfs_debug_mask:                  Current debug bitmask.
  * @dfs_curchan_radindex:            Current channel radar index.
@@ -1061,6 +1081,9 @@
  *                                   be blocked and this variable should be
  *                                   false so that HW pulses and synthetic
  *                                   pulses do not get mixed up.
+ *                                   defer timer running.
+ * @dfs_defer_params:                DFS deferred event parameters (allocated
+ *                                   only for the duration of defer alone).
  */
 struct wlan_dfs {
 	uint32_t       dfs_debug_mask;
@@ -1224,6 +1247,7 @@
 #if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(WLAN_DFS_SYNTHETIC_RADAR)
 	bool           dfs_allow_hw_pulses;
 #endif
+	struct dfs_mode_switch_defer_params dfs_defer_params;
 };
 
 #if defined(QCA_SUPPORT_AGILE_DFS) || defined(ATH_SUPPORT_ZERO_CAC_DFS)
@@ -1254,6 +1278,7 @@
  * @dfs_precac_timer: agile precac timer
  * @dfs_precac_timer_running: precac timer running flag
  * @ocac_status: Off channel CAC complete status
+ * @dfs_nol_ctx: dfs NOL data for all radios.
  */
 struct dfs_soc_priv_obj {
 	struct wlan_objmgr_psoc *psoc;
@@ -1268,6 +1293,7 @@
 	bool precac_state_started;
 	bool ocac_status;
 #endif
+	struct dfsreq_nolinfo *dfs_psoc_nolinfo;
 };
 
 /**
@@ -2725,4 +2751,81 @@
  * Return: None.
  */
 void dfs_reset_dfs_prevchan(struct wlan_dfs *dfs);
+
+/**
+ * dfs_init_tmp_psoc_nol() - Init temporary psoc NOL structure.
+ * @dfs: Pointer to wlan_dfs object.
+ * @num_radios: Num of radios in the PSOC.
+ *
+ * Return: void.
+ */
+void dfs_init_tmp_psoc_nol(struct wlan_dfs *dfs, uint8_t num_radios);
+
+/**
+ * dfs_deinit_tmp_psoc_nol() - De-init temporary psoc NOL structure.
+ * @dfs: Pointer to wlan_dfs object.
+ *
+ * Return: void.
+ */
+void dfs_deinit_tmp_psoc_nol(struct wlan_dfs *dfs);
+
+/**
+ * dfs_save_dfs_nol_in_psoc() - Save NOL data of given pdev.
+ * @dfs: Pointer to wlan_dfs object.
+ * @pdev_id: The pdev ID which will have the NOL data.
+ * @low_5ghz_freq: The low 5GHz frequency value of the target pdev id.
+ * @high_5ghz_freq: The high 5GHz frequency value of the target pdev id.
+ *
+ * Based on the frequency of the NOL channel, copy it to the target pdev_id
+ * structure in psoc.
+ *
+ * Return: void.
+ */
+void dfs_save_dfs_nol_in_psoc(struct wlan_dfs *dfs,
+			      uint8_t pdev_id,
+			      uint16_t low_5ghz_freq,
+			      uint16_t high_5ghz_freq);
+
+/**
+ * dfs_reinit_nol_from_psoc_copy() - Reinit saved NOL data to corresponding
+ * DFS object.
+ * @dfs: Pointer to wlan_dfs object.
+ * @pdev_id: pdev_id of the given dfs object.
+ *
+ * Return: void.
+ */
+void dfs_reinit_nol_from_psoc_copy(struct wlan_dfs *dfs, uint8_t pdev_id);
+
+/**
+ * dfs_is_hw_mode_switch_in_progress() - Check if HW mode switch in progress.
+ * @dfs: Pointer to wlan_dfs object.
+ *
+ * Return: True if mode switch is in progress, else false.
+ */
+bool dfs_is_hw_mode_switch_in_progress(struct wlan_dfs *dfs);
+
+/**
+ * dfs_start_mode_switch_defer_timer() - start mode switch defer timer.
+ * @dfs: Pointer to wlan_dfs object.
+ *
+ * Return: void.
+ */
+void dfs_start_mode_switch_defer_timer(struct wlan_dfs *dfs);
+
+/**
+ * dfs_complete_deferred_tasks() - Process mode switch completion event and
+ * handle deffered tasks.
+ * @dfs: Pointer to wlan_dfs object.
+ *
+ * Return: void.
+ */
+void dfs_complete_deferred_tasks(struct wlan_dfs *dfs);
+
+/**
+ * dfs_process_cac_completion() - Process DFS CAC completion event.
+ * @dfs: Pointer to wlan_dfs object.
+ *
+ * Return: void.
+ */
+void dfs_process_cac_completion(struct wlan_dfs *dfs);
 #endif  /* _DFS_H_ */
diff --git a/umac/dfs/core/src/dfs_zero_cac.h b/umac/dfs/core/src/dfs_zero_cac.h
index 405916f..dd718e9 100644
--- a/umac/dfs/core/src/dfs_zero_cac.h
+++ b/umac/dfs/core/src/dfs_zero_cac.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
  * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
  * All rights reserved.
  *
@@ -824,6 +824,32 @@
 void dfs_zero_cac_reset(struct wlan_dfs *dfs);
 
 /**
+ * dfs_reinit_precac_lists() - Reinit DFS preCAC lists.
+ * @src_dfs: Source DFS from which the preCAC list is copied.
+ * @dest_dfs: Destination DFS to which the preCAC list is copied.
+ * @low_5g_freq: Low 5G frequency value of the destination DFS.
+ * @high_5g_freq: High 5G frequency value of the destination DFS.
+ *
+ * Copy all the preCAC list entries from the source DFS to the destination DFS
+ * which fall within the frequency range of low_5g_freq and high_5g_freq.
+ *
+ * Return: None (void).
+ */
+#if defined(WLAN_DFS_PARTIAL_OFFLOAD) && !defined(QCA_MCL_DFS_SUPPORT)
+void dfs_reinit_precac_lists(struct wlan_dfs *src_dfs,
+			     struct wlan_dfs *dest_dfs,
+			     uint16_t low_5g_freq,
+			     uint16_t high_5g_freq);
+#else
+static inline void dfs_reinit_precac_lists(struct wlan_dfs *src_dfs,
+					   struct wlan_dfs *dest_dfs,
+					   uint16_t low_5g_freq,
+					   uint16_t high_5g_freq)
+{
+}
+#endif
+
+/**
  * dfs_is_precac_done_on_ht20_40_80_chan() - Is precac done on a
  *                                           VHT20/40/80 channel.
  *@dfs: Pointer to wlan_dfs structure.
diff --git a/umac/dfs/core/src/misc/dfs.c b/umac/dfs/core/src/misc/dfs.c
index a1abe7f..e05d6be 100644
--- a/umac/dfs/core/src/misc/dfs.c
+++ b/umac/dfs/core/src/misc/dfs.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
  * Copyright (c) 2002-2006, Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
@@ -31,6 +31,7 @@
 #include "../dfs_full_offload.h"
 #include <wlan_objmgr_vdev_obj.h>
 #include "wlan_dfs_utils_api.h"
+#include "../dfs_process_radar_found_ind.h"
 #include "../dfs_partial_offload_radar.h"
 
 /* Disable NOL in FW. */
@@ -917,3 +918,26 @@
 {
 	qdf_mem_zero(dfs->dfs_prevchan, sizeof(struct dfs_channel));
 }
+
+bool dfs_is_hw_mode_switch_in_progress(struct wlan_dfs *dfs)
+{
+	return lmac_dfs_is_hw_mode_switch_in_progress(dfs->dfs_pdev_obj);
+}
+
+void dfs_complete_deferred_tasks(struct wlan_dfs *dfs)
+{
+	if (dfs->dfs_defer_params.is_radar_detected) {
+		/* Handle radar event that was deferred and free the temporary
+		 * storage of the radar event parameters.
+		 */
+		dfs_process_radar_ind(dfs, dfs->dfs_defer_params.radar_params);
+		qdf_mem_free(dfs->dfs_defer_params.radar_params);
+		dfs->dfs_defer_params.is_radar_detected = false;
+	} else if (dfs->dfs_defer_params.is_cac_completed) {
+		/* Handle CAC completion event that was deferred for HW mode
+		 * switch.
+		 */
+		dfs_process_cac_completion(dfs);
+		dfs->dfs_defer_params.is_cac_completed = false;
+	}
+}
diff --git a/umac/dfs/core/src/misc/dfs_cac.c b/umac/dfs/core/src/misc/dfs_cac.c
index 7f35ea9..0bbeb00 100644
--- a/umac/dfs/core/src/misc/dfs_cac.c
+++ b/umac/dfs/core/src/misc/dfs_cac.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
  * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
  * All rights reserved.
  *
@@ -122,24 +122,16 @@
 		     sizeof(dfs->dfs_cac_started_chan));
 }
 
-/**
- * dfs_cac_timeout() - DFS cactimeout function.
- *
- * Sets dfs_cac_timer_running to 0  and dfs_cac_valid_timer.
- */
-#ifdef CONFIG_CHAN_FREQ_API
-static os_timer_func(dfs_cac_timeout)
+void dfs_process_cac_completion(struct wlan_dfs *dfs)
 {
-	struct wlan_dfs *dfs = NULL;
 	enum phy_ch_width ch_width = CH_WIDTH_INVALID;
 	uint16_t primary_chan_freq = 0, secondary_chan_freq = 0;
 	struct dfs_channel *dfs_curchan;
 
-	OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
 	dfs->dfs_cac_timer_running = 0;
 	dfs_curchan = dfs->dfs_curchan;
 
-	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "cac expired, chan %d curr time %d",
+	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "cac expired, chan %d cur time %d",
 		 dfs->dfs_curchan->dfs_ch_freq,
 		 (qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000));
 
@@ -154,12 +146,13 @@
 					   dfs_curchan->dfs_ch_mhz_freq_seg2,
 					   dfs_curchan->dfs_ch_flags);
 		dfs_debug(dfs, WLAN_DEBUG_DFS,
-			  "CAC timer on channel %u (%u MHz) stopped due to radar",
+			  "CAC timer on chan %u (%u MHz) stopped due to radar",
 			  dfs_curchan->dfs_ch_ieee,
 			  dfs_curchan->dfs_ch_freq);
 	} else {
 		dfs_debug(dfs, WLAN_DEBUG_DFS,
-			  "CAC timer on channel %u (%u MHz) expired; no radar detected",
+			  "CAC timer on channel %u (%u MHz) expired;"
+			  "no radar detected",
 			  dfs_curchan->dfs_ch_ieee,
 			  dfs_curchan->dfs_ch_freq);
 
@@ -195,6 +188,24 @@
 		dfs->dfs_defer_precac_channel_change = 0;
 	}
 }
+
+/**
+ * dfs_cac_timeout() - DFS cactimeout function.
+ *
+ * Sets dfs_cac_timer_running to 0  and dfs_cac_valid_timer.
+ */
+#ifdef CONFIG_CHAN_FREQ_API
+static os_timer_func(dfs_cac_timeout)
+{
+	struct wlan_dfs *dfs = NULL;
+
+	OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
+
+	if (dfs_is_hw_mode_switch_in_progress(dfs))
+		dfs->dfs_defer_params.is_cac_completed = true;
+	else
+		dfs_process_cac_completion(dfs);
+}
 #else
 #ifdef CONFIG_CHAN_NUM_API
 static os_timer_func(dfs_cac_timeout)
diff --git a/umac/dfs/core/src/misc/dfs_nol.c b/umac/dfs/core/src/misc/dfs_nol.c
index 31f096c..eda749a 100644
--- a/umac/dfs/core/src/misc/dfs_nol.c
+++ b/umac/dfs/core/src/misc/dfs_nol.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
  * Copyright (c) 2002-2010, Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
@@ -899,3 +899,101 @@
 }
 #endif
 #endif
+
+void dfs_init_tmp_psoc_nol(struct wlan_dfs *dfs, uint8_t num_radios)
+{
+	struct dfs_soc_priv_obj *dfs_soc_obj = dfs->dfs_soc_obj;
+
+	if (WLAN_UMAC_MAX_PDEVS < num_radios) {
+		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
+			"num_radios (%u) exceeds limit", num_radios);
+		return;
+	}
+
+	/* Allocate the temporary psoc NOL copy structure for the number
+	 * of radios provided.
+	 */
+	dfs_soc_obj->dfs_psoc_nolinfo =
+		qdf_mem_malloc(sizeof(struct dfsreq_nolinfo) * num_radios);
+}
+
+void dfs_deinit_tmp_psoc_nol(struct wlan_dfs *dfs)
+{
+	struct dfs_soc_priv_obj *dfs_soc_obj = dfs->dfs_soc_obj;
+
+	if (!dfs_soc_obj->dfs_psoc_nolinfo)
+		return;
+
+	qdf_mem_free(dfs_soc_obj->dfs_psoc_nolinfo);
+	dfs_soc_obj->dfs_psoc_nolinfo = NULL;
+}
+
+void dfs_save_dfs_nol_in_psoc(struct wlan_dfs *dfs,
+			      uint8_t pdev_id,
+			      uint16_t low_5ghz_freq,
+			      uint16_t high_5ghz_freq)
+{
+	struct dfs_soc_priv_obj *dfs_soc_obj = dfs->dfs_soc_obj;
+	struct dfsreq_nolinfo tmp_nolinfo, *nolinfo;
+	uint32_t i, num_chans = 0;
+	uint16_t tmp_freq;
+
+	if (!dfs->dfs_nol_count)
+		return;
+
+	if (!dfs_soc_obj->dfs_psoc_nolinfo)
+		return;
+
+	nolinfo = &dfs_soc_obj->dfs_psoc_nolinfo[pdev_id];
+	/* Fetch the NOL entries for the DFS object. */
+	dfs_getnol(dfs, &tmp_nolinfo);
+
+	/* nolinfo might already have some data. Do not overwrite it */
+	num_chans = nolinfo->dfs_ch_nchans;
+	for (i = 0; i < tmp_nolinfo.dfs_ch_nchans; i++) {
+		tmp_freq = tmp_nolinfo.dfs_nol[i].nol_freq;
+
+		/* Add to nolinfo only if within the pdev's frequency range. */
+		if ((low_5ghz_freq < tmp_freq) && (high_5ghz_freq > tmp_freq)) {
+			/* Figure out the completed duration of each NOL. */
+			uint32_t nol_completed_ms =
+				qdf_system_ticks_to_msecs(qdf_system_ticks() -
+				tmp_nolinfo.dfs_nol[i].nol_start_ticks);
+
+			nolinfo->dfs_nol[num_chans] = tmp_nolinfo.dfs_nol[i];
+			/* Remember the remaining NOL time in the timeout
+			 * variable.
+			 */
+			nolinfo->dfs_nol[num_chans++].nol_timeout_ms -=
+				nol_completed_ms;
+		}
+	}
+
+	nolinfo->dfs_ch_nchans = num_chans;
+}
+
+void dfs_reinit_nol_from_psoc_copy(struct wlan_dfs *dfs, uint8_t pdev_id)
+{
+	struct dfs_soc_priv_obj *dfs_soc_obj = dfs->dfs_soc_obj;
+	struct dfsreq_nolinfo *nol;
+	uint8_t i;
+
+	if (!dfs_soc_obj->dfs_psoc_nolinfo)
+		return;
+
+	if (!dfs_soc_obj->dfs_psoc_nolinfo[pdev_id].dfs_ch_nchans)
+		return;
+
+	nol = &dfs_soc_obj->dfs_psoc_nolinfo[pdev_id];
+
+	/* The NOL timeout value in each entry points to the remaining time
+	 * of the NOL. This is to indicate that the NOL entries are paused
+	 * and are not left to continue.
+	 * While adding these NOL, update the start ticks to current time
+	 * to avoid losing entries which might have timed out during
+	 * the pause and resume mechanism.
+	 */
+	for (i = 0; i < nol->dfs_ch_nchans; i++)
+		nol->dfs_nol[i].nol_start_ticks = qdf_system_ticks();
+	dfs_set_nol(dfs, nol->dfs_nol, nol->dfs_ch_nchans);
+}
diff --git a/umac/dfs/core/src/misc/dfs_process_radar_found_ind.c b/umac/dfs/core/src/misc/dfs_process_radar_found_ind.c
index bba638f..6c02b70 100644
--- a/umac/dfs/core/src/misc/dfs_process_radar_found_ind.c
+++ b/umac/dfs/core/src/misc/dfs_process_radar_found_ind.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020 The Linux Foundation. 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
@@ -951,16 +951,50 @@
 	bool wait_for_csa = false;
 	uint16_t freq_list[NUM_CHANNELS_160MHZ];
 	uint8_t num_channels;
-	QDF_STATUS status;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
 	uint32_t freq_center;
 	uint32_t radarfound_freq;
 	struct dfs_channel *dfs_curchan;
 
+	/* Acquire a lock to avoid initiating mode switch till radar
+	 * processing is completed.
+	 */
+	DFS_RADAR_MODE_SWITCH_LOCK(dfs);
+
+	/* Before processing radar, check if HW mode switch is in progress.
+	 * If in progress, defer the processing of radar event received till
+	 * the mode switch is completed.
+	 */
+	if (dfs_is_hw_mode_switch_in_progress(dfs)) {
+		struct radar_found_info *radar_params = NULL;
+
+		radar_params = qdf_mem_malloc(sizeof(*radar_params));
+		if (!radar_params)
+			goto exit;
+
+		/* If CAC timer is running, cancel it here rather than
+		 * after processing to avoid handling unnecessary CAC timeouts.
+		 */
+		if (dfs->dfs_cac_timer_running)
+			dfs_cac_stop(dfs);
+
+		/* If CAC timer is to be handled after mode switch and then
+		 * we receive radar, no point in handling CAC completion.
+		 */
+		if (dfs->dfs_defer_params.is_cac_completed)
+			dfs->dfs_defer_params.is_cac_completed = false;
+		qdf_mem_copy(radar_params, radar_found, sizeof(*radar_params));
+		dfs->dfs_defer_params.radar_params = radar_params;
+		dfs->dfs_defer_params.is_radar_detected = true;
+		status = QDF_STATUS_SUCCESS;
+		goto exit;
+	}
+
 	dfs_curchan = dfs->dfs_curchan;
 
 	if (!dfs_curchan) {
 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs->dfs_curchan is NULL");
-		return QDF_STATUS_E_FAILURE;
+		goto exit;
 	}
 
 	/* Check if the current channel is a non DFS channel
@@ -972,7 +1006,7 @@
 	    !(radar_found->detector_id == AGILE_DETECTOR_ID)) {
 		dfs_err(dfs, WLAN_DEBUG_DFS,
 			"radar event on a non-DFS channel");
-		return QDF_STATUS_E_FAILURE;
+		goto exit;
 	}
 
 	/* Sanity checks for radar on Agile detector */
@@ -981,7 +1015,7 @@
 	{
 		dfs_err(dfs, WLAN_DEBUG_DFS,
 			"radar on Agile detector when ADFS is not running");
-		return QDF_STATUS_E_FAILURE;
+		goto exit;
 	}
 
 	/* For Full Offload, FW sends segment id,freq_offset and chirp
@@ -1019,7 +1053,8 @@
 	if (!dfs->dfs_use_nol) {
 		dfs_reset_bangradar(dfs);
 		dfs_send_csa_to_current_chan(dfs);
-		return QDF_STATUS_SUCCESS;
+		status = QDF_STATUS_SUCCESS;
+		goto exit;
 	}
 
 	if (dfs->dfs_bangradar_type == DFS_BANGRADAR_FOR_ALL_SUBCHANS)
@@ -1049,7 +1084,7 @@
 	if (QDF_IS_STATUS_ERROR(status)) {
 		dfs_err(dfs, WLAN_DEBUG_DFS,
 			"radar event received on invalid channel");
-		return status;
+		goto exit;
 	}
 
 	dfs->dfs_is_nol_ie_sent = false;
@@ -1105,7 +1140,7 @@
 	 * channel change is not required.
 	 */
 	if (radar_found->detector_id == AGILE_DETECTOR_ID)
-		return QDF_STATUS_SUCCESS;
+		goto exit;
 	if (!dfs->dfs_is_offload_enabled &&
 	    dfs->is_radar_found_on_secondary_seg) {
 		dfs_second_segment_radar_disable(dfs);
@@ -1113,7 +1148,7 @@
 
 		if (dfs->is_radar_during_precac) {
 			dfs->is_radar_during_precac = 0;
-			return QDF_STATUS_SUCCESS;
+			goto exit;
 		}
 	}
 
@@ -1124,7 +1159,7 @@
 	 * needs to be fixed. See EV 105776.
 	 */
 	if (wait_for_csa)
-		return QDF_STATUS_SUCCESS;
+		goto exit;
 
 	/*
 	 * EV 129487 : We have detected radar in the channel,
@@ -1144,6 +1179,8 @@
 				   dfs->dfs_curchan->dfs_ch_mhz_freq_seg2,
 				   dfs->dfs_curchan->dfs_ch_flags);
 
-	return QDF_STATUS_SUCCESS;
+exit:
+	DFS_RADAR_MODE_SWITCH_UNLOCK(dfs);
+	return status;
 }
 #endif
diff --git a/umac/dfs/dispatcher/inc/wlan_dfs_ioctl.h b/umac/dfs/dispatcher/inc/wlan_dfs_ioctl.h
index 1ec4e97..a17d29b 100644
--- a/umac/dfs/dispatcher/inc/wlan_dfs_ioctl.h
+++ b/umac/dfs/dispatcher/inc/wlan_dfs_ioctl.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011, 2016-2020 The Linux Foundation. All rights reserved.
  * Copyright (c) 2010, Atheros Communications Inc.
  * All Rights Reserved.
  *
@@ -77,7 +77,7 @@
 #define DFS_LAST_IOCTL 29
 
 #ifndef DFS_CHAN_MAX
-#define DFS_CHAN_MAX 1023
+#define DFS_CHAN_MAX 25
 #endif
 
 /**
diff --git a/umac/dfs/dispatcher/inc/wlan_dfs_lmac_api.h b/umac/dfs/dispatcher/inc/wlan_dfs_lmac_api.h
index 99b671e..5ed030d 100644
--- a/umac/dfs/dispatcher/inc/wlan_dfs_lmac_api.h
+++ b/umac/dfs/dispatcher/inc/wlan_dfs_lmac_api.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
@@ -118,4 +118,13 @@
 	return false;
 }
 #endif
+
+/**
+ * lmac_dfs_is_hw_mode_switch_in_progress() - Check if HW mode switch is in
+ * progress.
+ * @pdev: Pointer to PDEV structure.
+ *
+ * Return: true if HW mode switch is in progress, else false.
+ */
+bool lmac_dfs_is_hw_mode_switch_in_progress(struct wlan_objmgr_pdev *pdev);
 #endif /* _WLAN_DFS_LMAC_API_H_ */
diff --git a/umac/dfs/dispatcher/inc/wlan_dfs_mlme_api.h b/umac/dfs/dispatcher/inc/wlan_dfs_mlme_api.h
index f8d9a31..3593f06 100644
--- a/umac/dfs/dispatcher/inc/wlan_dfs_mlme_api.h
+++ b/umac/dfs/dispatcher/inc/wlan_dfs_mlme_api.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
@@ -440,4 +440,22 @@
  * Return: true if pdev opmode is STA, else false.
  */
 bool dfs_mlme_is_opmode_sta(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * dfs_mlme_acquire_radar_mode_switch_lock() - Acquire lock for radar processing
+ * over mode switch handling.
+ * @pdev: Pointer to DFS pdev object.
+ *
+ * Return: void.
+ */
+void dfs_mlme_acquire_radar_mode_switch_lock(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * dfs_mlme_release_radar_mode_switch_lock() - Release lock taken for radar
+ * processing over mode switch handling.
+ * @pdev: Pointer to DFS pdev object.
+ *
+ * Return: void.
+ */
+void dfs_mlme_release_radar_mode_switch_lock(struct wlan_objmgr_pdev *pdev);
 #endif /* _WLAN_DFS_MLME_API_H_ */
diff --git a/umac/dfs/dispatcher/inc/wlan_dfs_tgt_api.h b/umac/dfs/dispatcher/inc/wlan_dfs_tgt_api.h
index 724dea5..c49a497 100644
--- a/umac/dfs/dispatcher/inc/wlan_dfs_tgt_api.h
+++ b/umac/dfs/dispatcher/inc/wlan_dfs_tgt_api.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
@@ -604,4 +604,77 @@
 {
 }
 #endif
+
+/**
+ * tgt_dfs_init_tmp_psoc_nol() - Init temporary psoc NOL structure.
+ * @pdev: Pointer to pdev object.
+ * @num_radios: Number of radios in the psoc.
+ *
+ * Return: void.
+ */
+void tgt_dfs_init_tmp_psoc_nol(struct wlan_objmgr_pdev *pdev,
+			       uint8_t num_radios);
+
+/**
+ * tgt_dfs_deinit_tmp_psoc_nol() - De-init temporary psoc NOL structure.
+ * @pdev: Pointer to pdev object.
+ *
+ * Return: void.
+ */
+void tgt_dfs_deinit_tmp_psoc_nol(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * tgt_dfs_save_dfs_nol_in_psoc() - Save NOL data of given pdev.
+ * @pdev: Pointer to pdev object.
+ * @pdev_id: The pdev ID which will have the NOL data.
+ * @low_5ghz_freq: The low 5GHz frequency value of the target pdev id.
+ * @high_5ghz_freq: The high 5GHz frequency value of the target pdev id.
+ *
+ * Based on the frequency of the NOL channel, copy it to the target pdev_id
+ * structure in psoc.
+ *
+ * Return: void.
+ */
+void tgt_dfs_save_dfs_nol_in_psoc(struct wlan_objmgr_pdev *pdev,
+				  uint8_t pdev_id,
+				  uint16_t low_5ghz_freq,
+				  uint16_t high_5ghz_freq);
+
+/**
+ * tgt_dfs_reinit_nol_from_psoc_copy() - Reinit saved NOL data to corresponding
+ * pdevs.
+ * @pdev: Pointer to pdev object.
+ * @pdev_id: pdev_id of the given pdev.
+ *
+ * Return: void.
+ */
+void tgt_dfs_reinit_nol_from_psoc_copy(struct wlan_objmgr_pdev *pdev,
+				       uint8_t pdev_id);
+
+/**
+ * tgt_dfs_reinit_precac_lists() - Reinit preCAC lists.
+ * @src_pdev: Source pdev object from which the preCAC list is copied.
+ * @dest_pdev: Destination pdev object to which the preCAC list is copied.
+ * @low_5g_freq: Low 5G frequency value of the destination DFS.
+ * @high_5g_freq: High 5G frequency value of the destination DFS.
+ *
+ * Copy all the preCAC list entries from the source pdev object to the
+ * destination pdev object which fall within the frequency range of
+ * low_5g_freq and high_5g_freq.
+ *
+ * Return: None (void).
+ */
+void tgt_dfs_reinit_precac_lists(struct wlan_objmgr_pdev *src_pdev,
+				 struct wlan_objmgr_pdev *dest_pdev,
+				 uint16_t low_5g_freq,
+				 uint16_t high_5g_freq);
+
+/**
+ * tgt_dfs_complete_deferred_tasks() - Process HW mode switch completion and
+ * handle deferred tasks.
+ * @pdev: Pointer to primary pdev object.
+ *
+ * Return: void.
+ */
+void tgt_dfs_complete_deferred_tasks(struct wlan_objmgr_pdev *pdev);
 #endif /* _WLAN_DFS_TGT_API_H_ */
diff --git a/umac/dfs/dispatcher/inc/wlan_dfs_ucfg_api.h b/umac/dfs/dispatcher/inc/wlan_dfs_ucfg_api.h
index bbf9b0e..2d7d7fb 100644
--- a/umac/dfs/dispatcher/inc/wlan_dfs_ucfg_api.h
+++ b/umac/dfs/dispatcher/inc/wlan_dfs_ucfg_api.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
@@ -73,6 +73,10 @@
  *                                     list.
  * @mlme_get_cac_timeout_for_freq:     Get CAC timeout for a given channel
  *                                     frequency.
+ * @mlme_acquire_radar_mode_switch_lock: Acquire lock for radar processing over
+ *                                     mode switch.
+ * @mlme_release_radar_mode_switch_lock: Release lock taken for radar processing
+ *                                     over mode switch.
  */
 struct dfs_to_mlme {
 	QDF_STATUS (*pdev_component_obj_attach)(struct wlan_objmgr_pdev *pdev,
@@ -242,6 +246,10 @@
 			(struct wlan_objmgr_pdev *pdev,
 			 uint16_t freq,
 			 enum WLAN_DFS_EVENTS event);
+	void (*mlme_acquire_radar_mode_switch_lock)
+			(struct wlan_objmgr_pdev *pdev);
+	void (*mlme_release_radar_mode_switch_lock)
+			(struct wlan_objmgr_pdev *pdev);
 };
 
 extern struct dfs_to_mlme global_dfs_to_mlme;
diff --git a/umac/dfs/dispatcher/src/wlan_dfs_init_deinit_api.c b/umac/dfs/dispatcher/src/wlan_dfs_init_deinit_api.c
index ee87b8d..db9cc0c 100644
--- a/umac/dfs/dispatcher/src/wlan_dfs_init_deinit_api.c
+++ b/umac/dfs/dispatcher/src/wlan_dfs_init_deinit_api.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
@@ -139,6 +139,10 @@
 	tmp_dfs_to_mlme->mlme_dfs_deliver_event =
 		mlme_dfs_deliver_event;
 
+	tmp_dfs_to_mlme->mlme_acquire_radar_mode_switch_lock =
+		mlme_acquire_radar_mode_switch_lock;
+	tmp_dfs_to_mlme->mlme_release_radar_mode_switch_lock =
+		mlme_release_radar_mode_switch_lock;
 	/*
 	 * Register precac auto channel switch feature related callbacks
 	 */
diff --git a/umac/dfs/dispatcher/src/wlan_dfs_lmac_api.c b/umac/dfs/dispatcher/src/wlan_dfs_lmac_api.c
index bfa0b4e..48c0bb4 100644
--- a/umac/dfs/dispatcher/src/wlan_dfs_lmac_api.c
+++ b/umac/dfs/dispatcher/src/wlan_dfs_lmac_api.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
@@ -197,3 +197,20 @@
 	return enabled;
 }
 #endif
+
+bool lmac_dfs_is_hw_mode_switch_in_progress(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_lmac_if_dfs_tx_ops *dfs_tx_ops;
+	bool is_hw_mode_switch_in_progress = false;
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	dfs_tx_ops = &psoc->soc_cb.tx_ops.dfs_tx_ops;
+
+	if (dfs_tx_ops->dfs_check_mode_switch_state)
+		dfs_tx_ops->dfs_check_mode_switch_state(
+			pdev,
+			&is_hw_mode_switch_in_progress);
+
+	return is_hw_mode_switch_in_progress;
+}
diff --git a/umac/dfs/dispatcher/src/wlan_dfs_mlme_api.c b/umac/dfs/dispatcher/src/wlan_dfs_mlme_api.c
index d881a20..54e68c6 100644
--- a/umac/dfs/dispatcher/src/wlan_dfs_mlme_api.c
+++ b/umac/dfs/dispatcher/src/wlan_dfs_mlme_api.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
@@ -567,3 +567,19 @@
 
 	return global_dfs_to_mlme.mlme_is_opmode_sta(pdev);
 }
+
+void dfs_mlme_acquire_radar_mode_switch_lock(struct wlan_objmgr_pdev *pdev)
+{
+	if (!global_dfs_to_mlme.mlme_acquire_radar_mode_switch_lock)
+		return;
+
+	global_dfs_to_mlme.mlme_acquire_radar_mode_switch_lock(pdev);
+}
+
+void dfs_mlme_release_radar_mode_switch_lock(struct wlan_objmgr_pdev *pdev)
+{
+	if (!global_dfs_to_mlme.mlme_release_radar_mode_switch_lock)
+		return;
+
+	global_dfs_to_mlme.mlme_release_radar_mode_switch_lock(pdev);
+}
diff --git a/umac/dfs/dispatcher/src/wlan_dfs_tgt_api.c b/umac/dfs/dispatcher/src/wlan_dfs_tgt_api.c
index fc955e3..577976d 100644
--- a/umac/dfs/dispatcher/src/wlan_dfs_tgt_api.c
+++ b/umac/dfs/dispatcher/src/wlan_dfs_tgt_api.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
@@ -944,3 +944,102 @@
 
 qdf_export_symbol(tgt_dfs_set_fw_adfs_support);
 #endif
+
+void tgt_dfs_init_tmp_psoc_nol(struct wlan_objmgr_pdev *pdev,
+			       uint8_t num_radios)
+{
+	struct wlan_dfs *dfs;
+
+	dfs = wlan_pdev_get_dfs_obj(pdev);
+	if (!dfs) {
+		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
+		return;
+	}
+
+	dfs_init_tmp_psoc_nol(dfs, num_radios);
+}
+
+qdf_export_symbol(tgt_dfs_init_tmp_psoc_nol);
+
+void tgt_dfs_deinit_tmp_psoc_nol(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_dfs *dfs;
+
+	dfs = wlan_pdev_get_dfs_obj(pdev);
+	if (!dfs) {
+		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
+		return;
+	}
+
+	dfs_deinit_tmp_psoc_nol(dfs);
+}
+
+qdf_export_symbol(tgt_dfs_deinit_tmp_psoc_nol);
+
+void tgt_dfs_save_dfs_nol_in_psoc(struct wlan_objmgr_pdev *pdev,
+				  uint8_t pdev_id,
+				  uint16_t low_5ghz_freq,
+				  uint16_t high_5ghz_freq)
+{
+	struct wlan_dfs *dfs;
+
+	dfs = wlan_pdev_get_dfs_obj(pdev);
+	if (!dfs) {
+		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
+		return;
+	}
+
+	dfs_save_dfs_nol_in_psoc(dfs, pdev_id, low_5ghz_freq, high_5ghz_freq);
+}
+
+qdf_export_symbol(tgt_dfs_save_dfs_nol_in_psoc);
+
+void tgt_dfs_reinit_nol_from_psoc_copy(struct wlan_objmgr_pdev *pdev,
+				       uint8_t pdev_id)
+{
+	struct wlan_dfs *dfs;
+
+	dfs = wlan_pdev_get_dfs_obj(pdev);
+	if (!dfs) {
+		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
+		return;
+	}
+
+	dfs_reinit_nol_from_psoc_copy(dfs, pdev_id);
+}
+
+qdf_export_symbol(tgt_dfs_reinit_nol_from_psoc_copy);
+
+void tgt_dfs_reinit_precac_lists(struct wlan_objmgr_pdev *src_pdev,
+				 struct wlan_objmgr_pdev *dest_pdev,
+				 uint16_t low_5g_freq,
+				 uint16_t high_5g_freq)
+{
+	struct wlan_dfs *src_dfs, *dest_dfs;
+
+	src_dfs = wlan_pdev_get_dfs_obj(src_pdev);
+	if (!src_dfs) {
+		dfs_err(src_dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
+		return;
+	}
+	dest_dfs = wlan_pdev_get_dfs_obj(dest_pdev);
+	if (!dest_dfs) {
+		dfs_err(dest_dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
+		return;
+	}
+
+	dfs_reinit_precac_lists(src_dfs, dest_dfs, low_5g_freq, high_5g_freq);
+}
+
+void tgt_dfs_complete_deferred_tasks(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_dfs *dfs;
+
+	dfs = wlan_pdev_get_dfs_obj(pdev);
+	if (!dfs) {
+		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
+		return;
+	}
+
+	dfs_complete_deferred_tasks(dfs);
+}
diff --git a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h
index 2e8c7a8..0b3f839 100644
--- a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h
+++ b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h
@@ -802,6 +802,7 @@
  * @dfs_send_avg_radar_params_to_fw:    Send average radar parameters to FW.
  * @dfs_send_usenol_pdev_param:         Send usenol pdev param to FW.
  * @dfs_send_subchan_marking_pdev_param: Send subchan marking pdev param to FW.
+ * @dfs_check_mode_switch_state:        Find if HW mode switch is in progress.
  */
 
 struct wlan_lmac_if_dfs_tx_ops {
@@ -855,6 +856,9 @@
 	QDF_STATUS (*dfs_send_subchan_marking_pdev_param)(
 			struct wlan_objmgr_pdev *pdev,
 			bool subchanmark);
+	QDF_STATUS (*dfs_check_mode_switch_state)(
+			struct wlan_objmgr_pdev *pdev,
+			bool *is_hw_mode_switch_in_progress);
 };
 
 /**
@@ -1356,6 +1360,12 @@
  * @dfs_is_hw_pulses_allowed:         Check if HW pulses are allowed or not.
  * @dfs_set_fw_adfs_support:          Set the agile DFS FW support in DFS.
  * @dfs_reset_dfs_prevchan:           Reset DFS previous channel structure.
+ * @dfs_init_tmp_psoc_nol:            Init temporary PSOC NOL structure.
+ * @dfs_deinit_tmp_psoc_nol:          Deinit temporary PSOC NOL structure.
+ * @dfs_save_dfs_nol_in_psoc:         Copy DFS NOL data to the PSOC copy.
+ * @dfs_reinit_nol_from_psoc_copy:    Reinit DFS NOL from the PSOC NOL copy.
+ * @dfs_reinit_precac_lists:          Reinit precac lists from other pdev.
+ * @dfs_complete_deferred_tasks:      Process mode switch completion in DFS.
  */
 struct wlan_lmac_if_dfs_rx_ops {
 	QDF_STATUS (*dfs_get_radars)(struct wlan_objmgr_pdev *pdev);
@@ -1523,6 +1533,20 @@
 					bool fw_adfs_support_160,
 					bool fw_adfs_support_non_160);
 	void (*dfs_reset_dfs_prevchan)(struct wlan_objmgr_pdev *pdev);
+	void (*dfs_init_tmp_psoc_nol)(struct wlan_objmgr_pdev *pdev,
+				      uint8_t num_radios);
+	void (*dfs_deinit_tmp_psoc_nol)(struct wlan_objmgr_pdev *pdev);
+	void (*dfs_save_dfs_nol_in_psoc)(struct wlan_objmgr_pdev *pdev,
+					 uint8_t pdev_id,
+					 uint16_t low_5ghz_freq,
+					 uint16_t high_5ghz_freq);
+	void (*dfs_reinit_nol_from_psoc_copy)(struct wlan_objmgr_pdev *pdev,
+					      uint8_t pdev_id);
+	void (*dfs_reinit_precac_lists)(struct wlan_objmgr_pdev *src_pdev,
+					struct wlan_objmgr_pdev *dest_pdev,
+					uint16_t low_5g_freq,
+					uint16_t high_5g_freq);
+	void (*dfs_complete_deferred_tasks)(struct wlan_objmgr_pdev *pdev);
 };
 
 /**
diff --git a/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c b/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c
index 4c8359d..cd8fdf1 100644
--- a/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c
+++ b/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
@@ -523,7 +523,18 @@
 		tgt_dfs_set_fw_adfs_support;
 	dfs_rx_ops->dfs_reset_dfs_prevchan =
 		utils_dfs_reset_dfs_prevchan;
-
+	dfs_rx_ops->dfs_init_tmp_psoc_nol =
+		tgt_dfs_init_tmp_psoc_nol;
+	dfs_rx_ops->dfs_deinit_tmp_psoc_nol =
+		tgt_dfs_deinit_tmp_psoc_nol;
+	dfs_rx_ops->dfs_save_dfs_nol_in_psoc =
+		tgt_dfs_save_dfs_nol_in_psoc;
+	dfs_rx_ops->dfs_reinit_nol_from_psoc_copy =
+		tgt_dfs_reinit_nol_from_psoc_copy;
+	dfs_rx_ops->dfs_reinit_precac_lists =
+		tgt_dfs_reinit_precac_lists;
+	dfs_rx_ops->dfs_complete_deferred_tasks =
+		tgt_dfs_complete_deferred_tasks;
 	register_precac_auto_chan_rx_ops(dfs_rx_ops);
 	register_precac_auto_chan_rx_ops_ieee(dfs_rx_ops);
 	register_precac_auto_chan_rx_ops_freq(dfs_rx_ops);