Ver código fonte

qcacmn: DFS componentization (Zero CAC)

Operation in a DFS channel requires CAC that adds additional
delay as well as  loss of connection even when CSA is used. ETSI allows
pre-CAC, i.e. performing CAC at a convenient time and using that channel
later. Once Pre-CAC is done in a channel, it is no longer required to
perform a CAC in the channel before TX/RX as long as radar is not found
in it or we reset or restart the device.

Change-Id: Ic1896f7881c12606f1edc20c60cd4bb2ab63821c
CRs-Fixed: 2001106
Abhijit Pradhan 8 anos atrás
pai
commit
189e80817f
2 arquivos alterados com 1142 adições e 0 exclusões
  1. 254 0
      umac/dfs/core/src/dfs_zero_cac.h
  2. 888 0
      umac/dfs/core/src/misc/dfs_zero_cac.c

+ 254 - 0
umac/dfs/core/src/dfs_zero_cac.h

@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * DOC: This file has Zero CAC DFS APIs.
+ */
+
+#ifndef _DFS_ZERO_CAC_H_
+#define _DFS_ZERO_CAC_H_
+
+#include "dfs.h"
+
+#define DFS_SECOND_SEGMENT_BANGRADAR  23
+#define DFS_SHOW_PRECAC_LISTS         24
+#define DFS_RESET_PRECAC_LISTS        25
+
+#define VHT160_IEEE_FREQ_DIFF 16
+#define TARGET_TYPE_AR900B    9
+#define TARGET_TYPE_QCA9984   10
+#define TARGET_TYPE_IPQ4019   11
+#define TARGET_TYPE_QCA9888   12
+
+/**
+ * struct dfs_precac_entry - PreCAC entry.
+ * @pe_list:           PreCAC entry.
+ * @vht80_freq:        VHT80 freq.
+ * @precac_nol_timer:  Per element precac NOL timer.
+ * @dfs:               Pointer to wlan_dfs structure.
+ */
+struct dfs_precac_entry {
+	TAILQ_ENTRY(dfs_precac_entry) pe_list;
+	uint8_t             vht80_freq;
+	os_timer_t          precac_nol_timer;
+	struct wlan_dfs      *dfs;
+};
+
+/**
+ * dfs_print_precaclists() - Print precac list.
+ * @dfs: Pointer to wlan_dfs structure.
+ */
+void dfs_print_precaclists(struct wlan_dfs *dfs);
+
+/**
+ * dfs_reset_precac_lists() - Resets the precac lists.
+ * @dfs: Pointer to wlan_dfs structure.
+ */
+void dfs_reset_precac_lists(struct wlan_dfs *dfs);
+
+/**
+ * dfs_reset_precaclists() - Clears and initiakizes precac_required_list,
+ *                           precac_done_list and precac_nol_list.
+ *
+ * @dfs: Pointer to wlan_dfs structure.
+ */
+void dfs_reset_precaclists(struct wlan_dfs *dfs);
+
+/**
+ * dfs_deinit_precac_list() - Clears the precac list.
+ * @dfs: Pointer to wlan_dfs dtructure.
+ */
+void dfs_deinit_precac_list(struct wlan_dfs *dfs);
+
+/**
+ * dfs_init_precac_list() - Init precac list.
+ * @dfs: Pointer to wlan_dfs dtructure.
+ */
+void dfs_init_precac_list(struct wlan_dfs *dfs);
+
+/**
+ * dfs_start_precac_timer() - Start precac timer.
+ * @dfs: Pointer to wlan_dfs structure.
+ * @precac_chan: Start thr precac timer in this channel.
+ */
+void dfs_start_precac_timer(struct wlan_dfs *dfs,
+		uint8_t precac_chan);
+
+/**
+ * dfs_cancel_precac_timer() - Cancel the precac timer.
+ * @dfs: Pointer to wlan_dfs structure.
+ */
+void dfs_cancel_precac_timer(struct wlan_dfs *dfs);
+
+/**
+ * dfs_zero_cac_attach() - Initializes Zero cac DFS variables.
+ * @dfs: Pointer to wlan_dfs structure.
+ */
+void dfs_zero_cac_attach(struct wlan_dfs *dfs);
+
+/**
+ * dfs_zero_cac_reset() - Reset Zero cac DFS variables.
+ * @dfs: Pointer to wlan_dfs structure.
+ */
+void dfs_zero_cac_reset(struct wlan_dfs *dfs);
+
+/**
+ * dfs_is_precac_done() - Is precac done.
+ * @dfs: Pointer to wlan_dfs structure.
+ */
+bool dfs_is_precac_done(struct wlan_dfs *dfs);
+
+/**
+ * dfs_get_freq_from_precac_required_list() - Get VHT80 freq from
+ *                                            precac_required_list.
+ * @dfs: Pointer to wlan_dfs structure.
+ * @exclude_ieee_freq: Find a VHT80 freqency that is not equal to
+ *                     exclude_ieee_freq.
+ */
+uint8_t dfs_get_freq_from_precac_required_list(struct wlan_dfs *dfs,
+		uint8_t exclude_ieee_freq);
+
+/**
+ * dfs_override_precac_timeout() - Override the default precac timeout.
+ * @dfs: Pointer to wlan_dfs structure.
+ * @precac_timeout: Precac timeout value.
+ */
+int dfs_override_precac_timeout(struct wlan_dfs *dfs,
+		int precac_timeout);
+
+/**
+ * dfs_get_override_precac_timeout() - Get precac timeout.
+ * @dfs: Pointer wlan_dfs structure.
+ * @precac_timeout: Get precac timeout value in this variable.
+ */
+int dfs_get_override_precac_timeout(struct wlan_dfs *dfs,
+		int *precac_timeout);
+
+/**
+ * dfs_find_vht80_chan_for_precac() - Find VHT80 channel for precac.
+ * @dfs: Pointer to wlan_dfs structure.
+ * @chan_mode: Channel mode.
+ * @ch_freq_seg1: Segment1 channel freq.
+ * @cfreq1: cfreq1.
+ * @cfreq2: cfreq2.
+ * @phy_mode: Precac phymode.
+ * @dfs_set_cfreq2: Precac cfreq2
+ * @set_agile: Agile mode flag.
+ *
+ * Zero-CAC-DFS algorithm:-
+ * Zero-CAC-DFS algorithm works in stealth mode.
+ * 1) When any channel change happens in VHT80 mode the algorithm
+ * changes the HW channel mode to VHT80_80/VHT160 mode and adds a
+ * new channel in the secondary VHT80 to perform precac and a
+ * precac timer is started. However the upper layer/UMAC is unaware
+ * of this change.
+ * 2) When the precac timer expires without being interrupted by
+ * any channel change the secondary VHT80 channel is moved from
+ * precac-required-list to precac-done-list.
+ * 3) If there is a radar detect at any time in any segment
+ * (segment-1 is preimary VHT80 and segment-2 is VHT80)then the
+ * channel is searched in both precac-reuired-list and precac-done-list
+ * and moved to precac-nol-list.
+ * 4) Whenever channel change happens if the new channel is a DFS
+ * channel then precac-done-list is searched and if the channel is
+ * found in the precac-done-list then the CAC is skipped.
+ * 5) The precac expiry timer makes a vedv_restart(channel change
+ * with current-upper-layer-channel-mode which is VHT80). In channel
+ * change the algorithm tries to pick a new channel from the
+ * precac-required list. If none found then channel mode remains same.
+ * Which means when all the channels in precac-required-list are
+ * exhausted the VHT80_80/VHT160 comes back to VHT80 mode.
+ */
+void dfs_find_vht80_chan_for_precac(struct wlan_dfs *dfs,
+		uint32_t chan_mode,
+		uint8_t ch_freq_seg1,
+		uint32_t *cfreq1,
+		uint32_t *cfreq2,
+		uint32_t *phy_mode,
+		bool *dfs_set_cfreq2,
+		bool *set_agile);
+
+/**
+ * dfs_set_precac_enable() - Set precac enable flag.
+ * @dfs: Pointer to wlan_dfs structure.
+ * @value: input value for dfs_precac_enable flag.
+ */
+void dfs_set_precac_enable(struct wlan_dfs *dfs,
+		uint32_t value);
+
+/**
+ * dfs_get_precac_enable() - Get precac enable flag.
+ * @dfs: Pointer to wlan_dfs structure.
+ */
+uint32_t dfs_get_precac_enable(struct wlan_dfs *dfs);
+
+/**
+ * dfs_zero_cac_reset() - Reset Zero cac DFS variables.
+ * @dfs: Pointer to wlan_dfs structure.
+ */
+void dfs_zero_cac_reset(struct wlan_dfs *dfs);
+
+/**
+ * dfs_zero_cac_attach() - Initializes Zero cac DFS variables.
+ * @dfs: Pointer to wlan_dfs structure.
+ */
+void dfs_zero_cac_attach(struct wlan_dfs *dfs);
+
+/**
+ * dfs_is_ht20_40_80_chan_in_precac_done_list() - Is precac done on a
+ *                                                VHT20/40/80 channel.
+ *@dfs: Pointer to wlan_dfs structure.
+ */
+bool dfs_is_ht20_40_80_chan_in_precac_done_list(struct wlan_dfs *dfs);
+
+/**
+ * dfs_is_ht80_80_chan_in_precac_done_list() - Is precac done on a VHT80+80
+ *                                             channel.
+ *@dfs: Pointer to wlan_dfs structure.
+ */
+bool dfs_is_ht80_80_chan_in_precac_done_list(struct wlan_dfs *dfs);
+
+/**
+ * dfs_mark_precac_dfs() - Mark the precac channel as radar.
+ * @dfs: Pointer to wlan_dfs structure.
+ */
+void dfs_mark_precac_dfs(struct wlan_dfs *dfs,
+		uint8_t is_radar_found_on_secondary_seg);
+
+/**
+ * dfs_is_precac_timer_running() - Check whether precac timer is running.
+ * @dfs: Pointer to wlan_dfs structure.
+ */
+bool dfs_is_precac_timer_running(struct wlan_dfs *dfs);
+
+/**
+ * dfs_find_precac_secondary_vht80_chan() - Get a VHT80 channel with the
+ *                                          precac primary center frequency.
+ * @dfs: Pointer to wlan_dfs structure.
+ */
+void dfs_find_precac_secondary_vht80_chan(struct wlan_dfs *dfs,
+		struct dfs_ieee80211_channel **chan);
+#endif /* _DFS_ZERO_CAC_H_ */

+ 888 - 0
umac/dfs/core/src/misc/dfs_zero_cac.c

@@ -0,0 +1,888 @@
+/*
+ * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * DOC: This file has ZERO CAC DFS functions.
+ * Abstract:- Operation in a DFS channel requires CAC that adds additional
+ * delay as well as loss of connection even when CSA is used. ETSI allows
+ * pre-CAC, i.e. performing CAC at a convenient time and using that channel
+ * later. Once Pre-CAC is done in a channel, it is no longer required to
+ * perform a CAC in the channel before TX/RX as long as radar is not found in
+ * it or we reset or restart the device.
+ *
+ * Design:-
+ * The pre-CAC is done in a RADIO that has  VHT80_80 capable radio where the
+ * primary and secondary HT80s can be programmed independently with two
+ * different HT80 channels. Three new lists are introduced to handle pre-CAC.
+ * The lists are:
+ * 1)Pre-CAC-required list
+ * 2)Pre-CAC-done list
+ * 3)Pre-CAC-NOL list
+ * At the beginning the Pre-CAC-required list is populated with the unique
+ * secondary HT80 frequencies of HT80_80 channels.  Whenever a HT80 channel
+ * change happens we convert the HT80 channel change to a HT80_80 channel and
+ * the secondary HT80 is set to the first element(HT80 frequency) from the
+ * Pre-CAC-required list.  Pre-CAC period is same same as the CAC period. After
+ * the pre-CAC period is over the pre-CAC timer expires and the HT80 frequency
+ * (the pre-CAC-required list element) is removed from the Pre-CAC-required
+ * list and inserted into the Pre-CAC-done list. While Pre-CAC timer is running
+ * if there is any RADAR detect then the current HT80 frequency is removed from
+ * the Pre-CAC-required list and inserted into the Pre-CAC-NOL list. Each
+ * element of pre-CAC-NOL times out individually after 30 minutes of its
+ * insertion. Pre-CAC-NOL timeout is just like the regular NOL timeout. Upon
+ * Pre-CAC-NOL expiry of an element (HT80 frequency), the element is removed
+ * from the Pre-CAC-NOL list and inserted into the Pre-CAC-required list.
+ * At any point of time if there is a channel change and the new channel is
+ * DFS, the Pre-CAC-done list is consulted to check if pre-CAC has been
+ * completed for the entire bandwidth of the new channel. If Pre-CAC has
+ * already been done  for the entire bandwidth of the channel then regular CAC
+ * can be skipped(this is what is known as Zero wait DFS) if we are in ETSI
+ * domain.
+ *
+ * New RadarTool commands:-
+ * 1)radartool -i wifi[X] secondSegmentBangradar
+ * It simulates RADAR from the secondary HT80 when the
+ * secondary HT80 is doing pre-CAC. If secondary is not
+ * doing any pre-CAC then this command has no effect.
+ * 2)radartool -i wifi[X] showPreCACLists
+ * It shows all 3 pre-CAC Lists' contents.
+ *
+ * New iwpriv commands:-
+ * 1)iwpriv wifi[X] preCACEn 0/1
+ * This command enables/disables the zero-cac-DFS.
+ * 2)iwpriv wifi[X] pCACTimeout <timeout>
+ * Override the pCACTimeout.
+ *
+ * FAQ(Frequently Asked Questions):-
+ * 1)
+ * Question)We already have NOL list. Why do we need separate pre-CAC-NOL
+ * list?
+ * Answer) pre-CAC is done on an HT80 channel and  the same HT80 channel is
+ * inserted into pre-CAC-NOL list after pre-CAC radar detection. NOL list
+ * contains HT20 channels. Since after pre-CAC-NOL expiry we need
+ * to move the HT80 channel from pre-CAC-NOL list  to pre-CAC-required list
+ * it is very easy to remove the HT80 channel and insert it. Having
+ * a separate pre-CAC-NOL also provides some separation from the existing
+ * code and helps modularize.
+ */
+
+#include "../dfs_zero_cac.h"
+#include "wlan_dfs_lmac_api.h"
+#include "wlan_dfs_mlme_api.h"
+#include "../dfs_internal.h"
+
+static os_timer_func(dfs_precac_timeout);
+
+void dfs_zero_cac_attach(struct wlan_dfs *dfs)
+{
+	dfs->dfs_precac_timeout_override = -1;
+	dfs_init_precac_list(dfs);
+	qdf_timer_init(NULL,
+			&(dfs->dfs_precac_timer),
+			dfs_precac_timeout,
+			(void *) dfs,
+			QDF_TIMER_TYPE_WAKE_APPS);
+}
+
+void dfs_zero_cac_reset(struct wlan_dfs *dfs)
+{
+	dfs->dfs_precac_timeout_override = -1;
+	qdf_timer_stop(&dfs->dfs_precac_timer);
+	dfs->dfs_precac_primary_freq = 0;
+	dfs->dfs_precac_secondary_freq = 0;
+}
+
+int dfs_override_precac_timeout(struct wlan_dfs *dfs, int precac_timeout)
+{
+	if (dfs == NULL)
+		return -EIO;
+
+	dfs->dfs_precac_timeout_override = precac_timeout;
+	DFS_PRINTK("%s: PreCAC timeout is now %s (%d)\n",
+		__func__,
+		(precac_timeout == -1) ? "default" : "overridden",
+		precac_timeout);
+
+	return 0;
+}
+
+int dfs_get_override_precac_timeout(struct wlan_dfs *dfs, int *precac_timeout)
+{
+	if (dfs == NULL)
+		return -EIO;
+
+	(*precac_timeout) = dfs->dfs_precac_timeout_override;
+
+	return 0;
+}
+
+#define VHT80_OFFSET 6
+#define IS_WITHIN_RANGE(_A, _B, _C)  \
+	(((_A) >= ((_B)-(_C))) && ((_A) <= ((_B)+(_C))))
+
+bool dfs_is_ht20_40_80_chan_in_precac_done_list(struct wlan_dfs *dfs)
+{
+	struct dfs_precac_entry *precac_entry;
+	bool ret_val = 0;
+
+	/*
+	 * A is within B-C and B+C
+	 * (B-C) <= A <= (B+C)
+	 */
+	PRECAC_LIST_LOCK(dfs);
+	if (!TAILQ_EMPTY(&dfs->dfs_precac_done_list))
+		TAILQ_FOREACH(precac_entry,
+				&dfs->dfs_precac_done_list,
+				pe_list) {
+			/* Find if the VHT80 freq1 is in Pre-CAC done list */
+			if (IS_WITHIN_RANGE(dfs->dfs_curchan->ic_ieee,
+						precac_entry->vht80_freq,
+						VHT80_OFFSET)) {
+				ret_val = 1;
+				break;
+			}
+		}
+	PRECAC_LIST_UNLOCK(dfs);
+
+	DFS_DPRINTK(dfs, WLAN_DEBUG_DFS, "%s : vht80_freq = %u ret_val = %d\n",
+		__func__, dfs->dfs_curchan->ic_ieee, ret_val);
+
+	return ret_val;
+}
+
+bool dfs_is_ht80_80_chan_in_precac_done_list(struct wlan_dfs *dfs)
+{
+	struct dfs_precac_entry *precac_entry;
+	bool ret_val = 0;
+
+	PRECAC_LIST_LOCK(dfs);
+	if (!TAILQ_EMPTY(&dfs->dfs_precac_done_list)) {
+		bool primary_found = 0;
+		/* Check if primary is DFS then search */
+		if (IEEE80211_IS_CHAN_DFS(dfs->dfs_curchan)) {
+			TAILQ_FOREACH(precac_entry,
+					&dfs->dfs_precac_done_list,
+					pe_list) {
+				if (dfs->dfs_curchan->ic_vhtop_ch_freq_seg1
+						== precac_entry->vht80_freq) {
+					primary_found = 1;
+					break;
+				}
+			}
+		} else {
+			primary_found = 1;
+		}
+
+		/* Check if secondary DFS then search */
+		if (IEEE80211_IS_CHAN_DFS_CFREQ2(dfs->dfs_curchan) &&
+				primary_found) {
+			TAILQ_FOREACH(precac_entry,
+					&dfs->dfs_precac_done_list,
+					pe_list) {
+				if (dfs->dfs_curchan->ic_vhtop_ch_freq_seg2
+						== precac_entry->vht80_freq) {
+					/* Now secondary also found */
+					ret_val = 1;
+					break;
+				}
+			}
+		} else {
+			if (primary_found)
+				ret_val = 1;
+		}
+	}
+	PRECAC_LIST_UNLOCK(dfs);
+
+	DFS_DPRINTK(dfs, WLAN_DEBUG_DFS,
+		"%s : freq_seg1 = %u freq_seq2 = %u ret_val = %d\n",
+		__func__,
+		dfs->dfs_curchan->ic_vhtop_ch_freq_seg1,
+		dfs->dfs_curchan->ic_vhtop_ch_freq_seg2,
+		ret_val);
+
+	return ret_val;
+}
+
+bool dfs_is_precac_done(struct wlan_dfs *dfs)
+{
+	bool ret_val = 0;
+
+	if (IEEE80211_IS_CHAN_11AC_VHT20(dfs->dfs_curchan) ||
+			IEEE80211_IS_CHAN_11AC_VHT40(dfs->dfs_curchan) ||
+			IEEE80211_IS_CHAN_11AC_VHT80(dfs->dfs_curchan)) {
+		ret_val = dfs_is_ht20_40_80_chan_in_precac_done_list(dfs);
+	} else if (IEEE80211_IS_CHAN_11AC_VHT80_80(dfs->dfs_curchan) ||
+			IEEE80211_IS_CHAN_11AC_VHT160(dfs->dfs_curchan)) {
+		ret_val = dfs_is_ht80_80_chan_in_precac_done_list(dfs);
+	}
+
+	DFS_DPRINTK(dfs, WLAN_DEBUG_DFS,
+		"%s : ret_val = %d\n", __func__, ret_val);
+
+	return ret_val;
+}
+
+#define VHT80_IEEE_FREQ_OFFSET 6
+
+void dfs_mark_precac_dfs(struct wlan_dfs *dfs,
+		uint8_t is_radar_found_on_secondary_seg)
+{
+	struct dfs_precac_entry *precac_entry = NULL, *tmp_precac_entry = NULL;
+	uint8_t found = 0;
+
+	DFS_DPRINTK(dfs, WLAN_DEBUG_DFS,
+		"%s : is_radar_found_on_secondary_seg = %u secondary_freq = %u primary_freq = %u\n",
+		__func__,
+		is_radar_found_on_secondary_seg,
+		dfs->dfs_precac_secondary_freq,
+		dfs->dfs_precac_primary_freq);
+
+	/*
+	 * Even if radar found on primary, we need to move the channel from
+	 * precac-required-list and precac-done-list to precac-nol-list.
+	 */
+	PRECAC_LIST_LOCK(dfs);
+	if (!TAILQ_EMPTY(&dfs->dfs_precac_required_list)) {
+		TAILQ_FOREACH_SAFE(precac_entry,
+				&dfs->dfs_precac_required_list,
+				pe_list,
+				tmp_precac_entry) {
+			/*
+			 * If on primary then use IS_WITHIN_RANGE else use
+			 * equality directly.
+			 */
+			if (is_radar_found_on_secondary_seg ?
+				(dfs->dfs_precac_secondary_freq ==
+				 precac_entry->vht80_freq) : IS_WITHIN_RANGE(
+				     dfs->dfs_curchan->ic_ieee,
+				     precac_entry->vht80_freq,
+				     VHT80_IEEE_FREQ_OFFSET)) {
+				TAILQ_REMOVE(&dfs->dfs_precac_required_list,
+						precac_entry, pe_list);
+
+				DFS_DPRINTK(dfs, WLAN_DEBUG_DFS,
+					"%s : removing the freq = %u from required list and adding to NOL list\n",
+					__func__,
+					precac_entry->vht80_freq);
+				TAILQ_INSERT_TAIL(&dfs->dfs_precac_nol_list,
+						precac_entry, pe_list);
+				OS_SET_TIMER(&precac_entry->precac_nol_timer,
+						dfs_get_nol_timeout(dfs)*1000);
+				found = 1;
+				break;
+			}
+		}
+	}
+
+	/* If not found in precac-required-list remove from precac-done-list */
+	if (!found && !TAILQ_EMPTY(&dfs->dfs_precac_done_list)) {
+		TAILQ_FOREACH_SAFE(precac_entry,
+				&dfs->dfs_precac_done_list,
+				pe_list,
+				tmp_precac_entry) {
+			/*
+			 * If on primary then use IS_WITHIN_RANGE else use
+			 * equality directly.
+			 */
+			if (is_radar_found_on_secondary_seg ?
+					(dfs->dfs_precac_secondary_freq ==
+					 precac_entry->vht80_freq) :
+					IS_WITHIN_RANGE(
+						dfs->dfs_curchan->ic_ieee,
+						precac_entry->vht80_freq, 6)) {
+				TAILQ_REMOVE(&dfs->dfs_precac_done_list,
+					precac_entry, pe_list);
+
+				DFS_DPRINTK(dfs, WLAN_DEBUG_DFS,
+					"%s : removing the the freq = %u from done list and adding to NOL list\n",
+					__func__,
+					precac_entry->vht80_freq);
+				TAILQ_INSERT_TAIL(&dfs->dfs_precac_nol_list,
+						precac_entry, pe_list);
+				OS_SET_TIMER(&precac_entry->precac_nol_timer,
+						dfs_get_nol_timeout(dfs)*1000);
+				break;
+			}
+		}
+	}
+	PRECAC_LIST_UNLOCK(dfs);
+
+	/* TODO xxx:- Need to lock the channel change */
+	/*
+	 * If radar Found on Primary no need to do restart VAP's channels since
+	 * channel change will happen after RANDOM channel selection anyway.
+	 */
+
+	if (dfs->dfs_precac_timer_running) {
+		/* Cancel the PreCAC timer */
+		qdf_timer_stop(&dfs->dfs_precac_timer);
+		dfs->dfs_precac_timer_running = 0;
+
+		/*
+		 * Change the channel
+		 * case 1:-  No  VHT80 channel for precac is available so bring
+		 * it back to VHT80
+		 * case 2:-  pick a new VHT80 channel for precac
+		 */
+		if (is_radar_found_on_secondary_seg) {
+			if (dfs_is_ap_cac_timer_running(dfs)) {
+				dfs->dfs_defer_precac_channel_change = 1;
+				DFS_DPRINTK(dfs, WLAN_DEBUG_DFS,
+					"%s : Primary CAC is running, defer the channel change\n",
+					__func__);
+			} else {
+				dfs_mlme_channel_change_by_precac(
+						dfs->dfs_pdev_obj);
+			}
+		}
+	}
+}
+
+bool dfs_is_precac_timer_running(struct wlan_dfs *dfs)
+{
+	return dfs->dfs_precac_timer_running ? true : false;
+}
+
+#define VHT80_IEEE_FREQ_OFFSET 6
+void dfs_find_precac_secondary_vht80_chan(struct wlan_dfs *dfs,
+		struct dfs_ieee80211_channel **chan)
+{
+	uint8_t first_primary_ic_ieee;
+
+	first_primary_ic_ieee =
+		dfs->dfs_precac_secondary_freq - VHT80_IEEE_FREQ_OFFSET;
+
+	dfs_mlme_find_dot11_channel(dfs->dfs_pdev_obj, first_primary_ic_ieee, 0,
+			IEEE80211_MODE_11AC_VHT80,
+			&((*chan)->ic_freq),
+			&((*chan)->ic_flags),
+			&((*chan)->ic_flagext),
+			&((*chan)->ic_ieee),
+			&((*chan)->ic_vhtop_ch_freq_seg1),
+			&((*chan)->ic_vhtop_ch_freq_seg2));
+}
+
+/**
+ * dfs_precac_timeout() - Precac timeout.
+ *
+ * Removes the channel from precac_required list and adds it to the
+ * precac_done_list. Triggers a precac channel change.
+ */
+static os_timer_func(dfs_precac_timeout)
+{
+	struct dfs_precac_entry *precac_entry, *tmp_precac_entry;
+	struct wlan_dfs *dfs = NULL;
+
+	OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
+	dfs->dfs_precac_timer_running = 0;
+
+	/*
+	 * Remove the HVT80 freq from the precac-required-list and add it to the
+	 * precac-done-list
+	 */
+
+	PRECAC_LIST_LOCK(dfs);
+	if (!TAILQ_EMPTY(&dfs->dfs_precac_required_list)) {
+		TAILQ_FOREACH_SAFE(precac_entry,
+				&dfs->dfs_precac_required_list,
+				pe_list,
+				tmp_precac_entry) {
+			if (dfs->dfs_precac_secondary_freq ==
+					precac_entry->vht80_freq) {
+				TAILQ_REMOVE(&dfs->dfs_precac_required_list,
+						precac_entry, pe_list);
+				DFS_DPRINTK(dfs, WLAN_DEBUG_DFS,
+					"%s : removing the the freq = %u from required list and adding to done list\n",
+					__func__,
+					precac_entry->vht80_freq);
+				TAILQ_INSERT_TAIL(&dfs->dfs_precac_done_list,
+						precac_entry, pe_list);
+				break;
+			}
+		}
+	}
+	PRECAC_LIST_UNLOCK(dfs);
+
+	DFS_DPRINTK(dfs, WLAN_DEBUG_DFS,
+		"%s : Pre-cac expired, Precac Secondary chan %u curr time %d\n",
+		__func__,
+		dfs->dfs_precac_secondary_freq,
+		(qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000));
+	/* Do vdev restart so that we can change the secondary VHT80 channel. */
+
+	/* TODO xxx : Need to lock the channel change */
+	dfs_mlme_channel_change_by_precac(dfs->dfs_pdev_obj);
+}
+
+/**
+ * dfs_precac_nol_timeout() - NOL timeout for precac channel.
+ *
+ * Removes the VHT80 channel from precac nol list and adds it to precac required
+ * list.
+ */
+static os_timer_func(dfs_precac_nol_timeout)
+{
+	struct dfs_precac_entry *precac_entry;
+	struct wlan_dfs *dfs = NULL;
+
+	OS_GET_TIMER_ARG(precac_entry, struct dfs_precac_entry *);
+	dfs = (struct wlan_dfs *)precac_entry->dfs;
+
+	PRECAC_LIST_LOCK(dfs);
+	if (!TAILQ_EMPTY(&dfs->dfs_precac_nol_list)) {
+		/* Move the channel from precac-NOL to precac-required-list */
+		TAILQ_REMOVE(&dfs->dfs_precac_nol_list, precac_entry, pe_list);
+		DFS_DPRINTK(dfs, WLAN_DEBUG_DFS,
+			"%s : removing the the freq = %u from PreCAC NOL-list and adding Precac-required list\n",
+			__func__, precac_entry->vht80_freq);
+		TAILQ_INSERT_TAIL(&dfs->dfs_precac_required_list, precac_entry,
+				pe_list);
+	}
+	PRECAC_LIST_UNLOCK(dfs);
+
+	/* TODO xxx : Need to lock the channel change */
+	/* Do a channel change */
+	dfs_mlme_channel_change_by_precac(dfs->dfs_pdev_obj);
+}
+
+void dfs_init_precac_list(struct wlan_dfs *dfs)
+{
+	u_int i;
+	uint8_t found;
+	struct dfs_precac_entry *tmp_precac_entry;
+	int nchans = 0;
+
+	/*
+	 * We need to prepare list of uniq VHT80 center frequencies. But at the
+	 * beginning we do not know how many uniq frequencies are present.
+	 * Therefore, we calculate the MAX size and allocate a temporary
+	 * list/array. However we fill the temporary array with uniq frequencies
+	 * and copy the uniq list of frequencies to* the final list with exact
+	 * size.
+	 */
+	TAILQ_INIT(&dfs->dfs_precac_required_list);
+	TAILQ_INIT(&dfs->dfs_precac_done_list);
+	TAILQ_INIT(&dfs->dfs_precac_nol_list);
+	dfs_mlme_get_ic_nchans(dfs->dfs_pdev_obj, &nchans);
+
+	PRECAC_LIST_LOCK(dfs);
+	/* Fill the  precac-required-list with unique elements */
+	for (i = 0; i < nchans; i++) {
+		struct dfs_ieee80211_channel *ichan = NULL, lc;
+
+		ichan = &lc;
+		dfs_mlme_get_ic_channels(dfs->dfs_pdev_obj,
+				&(ichan->ic_freq),
+				&(ichan->ic_flags),
+				&(ichan->ic_flagext),
+				&(ichan->ic_ieee),
+				&(ichan->ic_vhtop_ch_freq_seg1),
+				&(ichan->ic_vhtop_ch_freq_seg2),
+				i);
+
+		if (IEEE80211_IS_CHAN_11AC_VHT80(ichan) &&
+				IEEE80211_IS_CHAN_DFS(ichan)) {
+			found = 0;
+			TAILQ_FOREACH(tmp_precac_entry,
+					&dfs->dfs_precac_required_list,
+					pe_list) {
+				if (tmp_precac_entry->vht80_freq ==
+						ichan->ic_vhtop_ch_freq_seg1) {
+					found = 1;
+					break;
+				}
+			}
+			if (!found) {
+				struct dfs_precac_entry *precac_entry;
+
+				precac_entry = qdf_mem_malloc(
+					sizeof(*precac_entry));
+				precac_entry->vht80_freq =
+					ichan->ic_vhtop_ch_freq_seg1;
+				precac_entry->dfs = dfs;
+
+				/*
+				 * Initialize per entry timer. Shall be used
+				 * when the entry moves to precac_nol_list.
+				 */
+				qdf_timer_init(NULL,
+					&(precac_entry->precac_nol_timer),
+					dfs_precac_nol_timeout,
+					(void *) (precac_entry),
+					QDF_TIMER_TYPE_WAKE_APPS);
+				TAILQ_INSERT_TAIL(
+						&dfs->dfs_precac_required_list,
+						precac_entry, pe_list);
+			}
+		}
+	}
+	PRECAC_LIST_UNLOCK(dfs);
+
+	DFS_DPRINTK(dfs, WLAN_DEBUG_DFS,
+		"%s : Print the list of VHT80 frequencies from linked list\n",
+		__func__);
+	TAILQ_FOREACH(tmp_precac_entry,
+			&dfs->dfs_precac_required_list,
+			pe_list)
+		DFS_PRINTK("freq=%u\n", tmp_precac_entry->vht80_freq);
+}
+
+void dfs_deinit_precac_list(struct wlan_dfs *dfs)
+{
+	struct dfs_precac_entry *tmp_precac_entry, *precac_entry;
+
+	DFS_DPRINTK(dfs, WLAN_DEBUG_DFS,
+		"%s : Free the list of VHT80 frequencies from linked list(precac_required)\n",
+		__func__);
+	PRECAC_LIST_LOCK(dfs);
+	if (!TAILQ_EMPTY(&dfs->dfs_precac_required_list))
+		TAILQ_FOREACH_SAFE(precac_entry,
+				&dfs->dfs_precac_required_list,
+				pe_list, tmp_precac_entry) {
+			TAILQ_REMOVE(&dfs->dfs_precac_required_list,
+					precac_entry, pe_list);
+			qdf_mem_free(precac_entry);
+		}
+
+	DFS_DPRINTK(dfs, WLAN_DEBUG_DFS,
+		"%s : Free the list of VHT80 frequencies from linked list(precac_done)\n",
+		__func__);
+	if (!TAILQ_EMPTY(&dfs->dfs_precac_done_list))
+		TAILQ_FOREACH_SAFE(precac_entry,
+				&dfs->dfs_precac_done_list,
+				pe_list, tmp_precac_entry) {
+			TAILQ_REMOVE(&dfs->dfs_precac_required_list,
+					precac_entry, pe_list);
+			qdf_mem_free(precac_entry);
+		}
+
+	DFS_DPRINTK(dfs, WLAN_DEBUG_DFS,
+		"%s : Free the list of VHT80 frequencies from linked list(precac_nol)\n",
+		__func__);
+	if (!TAILQ_EMPTY(&dfs->dfs_precac_nol_list))
+		TAILQ_FOREACH_SAFE(precac_entry,
+				&dfs->dfs_precac_nol_list,
+				pe_list,
+				tmp_precac_entry) {
+			qdf_timer_stop(&precac_entry->precac_nol_timer);
+			TAILQ_REMOVE(&dfs->dfs_precac_required_list,
+					precac_entry, pe_list);
+			qdf_mem_free(precac_entry);
+		}
+	PRECAC_LIST_UNLOCK(dfs);
+
+}
+
+uint8_t dfs_get_freq_from_precac_required_list(struct wlan_dfs *dfs,
+		uint8_t exclude_ieee_freq)
+{
+	struct dfs_precac_entry *precac_entry;
+	uint8_t ieee_freq = 0;
+
+	DFS_DPRINTK(dfs, WLAN_DEBUG_DFS, "%s : exclude_ieee_freq = %u\n",
+		__func__, exclude_ieee_freq);
+
+	PRECAC_LIST_LOCK(dfs);
+	if (!TAILQ_EMPTY(&dfs->dfs_precac_required_list)) {
+		TAILQ_FOREACH(precac_entry, &dfs->dfs_precac_required_list,
+				pe_list) {
+			if (precac_entry->vht80_freq != exclude_ieee_freq) {
+				ieee_freq = precac_entry->vht80_freq;
+				break;
+			}
+		}
+	}
+	PRECAC_LIST_UNLOCK(dfs);
+	DFS_DPRINTK(dfs, WLAN_DEBUG_DFS, "%s : ieee_freq = %u\n",
+		__func__, ieee_freq);
+
+	return ieee_freq;
+}
+
+void dfs_cancel_precac_timer(struct wlan_dfs *dfs)
+{
+	qdf_timer_stop(&dfs->dfs_precac_timer);
+	dfs->dfs_precac_timer_running = 0;
+}
+
+void dfs_start_precac_timer(struct wlan_dfs *dfs, uint8_t precac_chan)
+{
+	struct dfs_ieee80211_channel *ichan, lc;
+	uint8_t first_primary_ic_ieee;
+	int primary_cac_timeout;
+	int secondary_cac_timeout;
+	int precac_timeout;
+
+#define EXTRA_TIME_IN_SEC 5
+	dfs->dfs_precac_timer_running = 1;
+
+	/*
+	 * Get the first primary ieee chan in the HT80 band and find the channel
+	 * pointer.
+	 */
+	first_primary_ic_ieee = precac_chan - VHT80_IEEE_FREQ_OFFSET;
+
+	primary_cac_timeout = dfs_mlme_get_cac_timeout(dfs->dfs_pdev_obj,
+			dfs->dfs_curchan->ic_freq,
+			dfs->dfs_curchan->ic_vhtop_ch_freq_seg2,
+			dfs->dfs_curchan->ic_flags);
+
+	ichan = &lc;
+	dfs_mlme_find_dot11_channel(dfs->dfs_pdev_obj, first_primary_ic_ieee, 0,
+			IEEE80211_MODE_11AC_VHT80,
+			&(ichan->ic_freq),
+			&(ichan->ic_flags),
+			&(ichan->ic_flagext),
+			&(ichan->ic_ieee),
+			&(ichan->ic_vhtop_ch_freq_seg1),
+			&(ichan->ic_vhtop_ch_freq_seg2));
+
+	secondary_cac_timeout = (dfs->dfs_precac_timeout_override != -1) ?
+		dfs->dfs_precac_timeout_override :
+		dfs_mlme_get_cac_timeout(dfs->dfs_pdev_obj,
+				ichan->ic_freq,
+				ichan->ic_vhtop_ch_freq_seg2,
+				ichan->ic_flags);
+
+	/*
+	 * EXTRA time is needed so that if CAC and PreCAC is running
+	 * simultaneously, PreCAC expiry function may be called before CAC
+	 * expiry and PreCAC expiry does a channel change (vdev_restart) the
+	 * restart response calls CAC_start function(ieee80211_dfs_cac_start)
+	 * which cancels any previous CAC timer and starts a new CAC again.
+	 * So CAC expiry does not happen and moreover a new CAC is started.
+	 * Therefore do not disturb the CAC by channel restart (vdev_restart).
+	 */
+	precac_timeout = QDF_MAX(primary_cac_timeout, secondary_cac_timeout) +
+		EXTRA_TIME_IN_SEC;
+	DFS_DPRINTK(dfs, WLAN_DEBUG_DFS,
+		"%s : precactimeout = %d\n",
+		__func__, (precac_timeout)*1000);
+	OS_SET_TIMER(&dfs->dfs_precac_timer, (precac_timeout) * 1000);
+}
+
+void dfs_print_precaclists(struct wlan_dfs *dfs)
+{
+	struct dfs_precac_entry *tmp_precac_entry;
+
+	if (dfs == NULL) {
+		DFS_DPRINTK(dfs, WLAN_DEBUG_DFS_NOL,
+			"%s: sc_dfs is NULL\n", __func__);
+		return;
+	}
+
+	PRECAC_LIST_LOCK(dfs);
+
+	/* Print the Pre-CAC required List */
+	DFS_PRINTK("%s : Pre-cac-required list of VHT80 frequencies\n",
+		__func__);
+	TAILQ_FOREACH(tmp_precac_entry,
+			&dfs->dfs_precac_required_list,
+			pe_list) {
+		DFS_PRINTK("%s : freq=%u\n", __func__,
+				tmp_precac_entry->vht80_freq);
+	}
+
+	/* Print the Pre-CAC done List */
+	DFS_PRINTK("%s : Pre-cac-done list of VHT80 frequencies\n", __func__);
+	TAILQ_FOREACH(tmp_precac_entry,
+			&dfs->dfs_precac_done_list,
+			pe_list) {
+		DFS_PRINTK("%s : freq=%u\n",
+			__func__, tmp_precac_entry->vht80_freq);
+	}
+
+	/* Print the Pre-CAC NOL List */
+	DFS_PRINTK("%s Pre-cac-NOL list of VHT80 frequencies\n", __func__);
+	TAILQ_FOREACH(tmp_precac_entry,
+			&dfs->dfs_precac_nol_list,
+			pe_list) {
+		DFS_PRINTK("%s : freq=%u\n", __func__,
+			tmp_precac_entry->vht80_freq);
+	}
+
+	PRECAC_LIST_UNLOCK(dfs);
+}
+
+void dfs_reset_precaclists(struct wlan_dfs *dfs)
+{
+	DFS_DPRINTK(dfs, WLAN_DEBUG_DFS,
+		"%s : Reset precaclist of VHT80 frequencies\n", __func__);
+	dfs_deinit_precac_list(dfs);
+	dfs_init_precac_list(dfs);
+}
+
+void dfs_reset_precac_lists(struct wlan_dfs *dfs)
+{
+	if (dfs == NULL) {
+		DFS_DPRINTK(dfs, WLAN_DEBUG_DFS_NOL,
+			"%s: sc_dfs is NULL\n", __func__);
+		return;
+	}
+	dfs_reset_precaclists(dfs);
+}
+
+void dfs_find_vht80_chan_for_precac(struct wlan_dfs *dfs,
+		uint32_t chan_mode,
+		uint8_t ch_freq_seg1,
+		uint32_t *cfreq1,
+		uint32_t *cfreq2,
+		uint32_t *phy_mode,
+		bool *dfs_set_cfreq2,
+		bool *set_agile)
+{
+	if (chan_mode == IEEE80211_MODE_11AC_VHT80) {
+		/*
+		 * If
+		 * 1) The chip is CASCADE
+		 * 2) The user phy_mode is VHT80 and
+		 * 3) The user has enabled Pre-CAC and
+		 * 4) The regdomain the ETSI
+		 * then find a center frequency for the secondary VHT80 and
+		 * Change the mode to VHT80_80 or VHT160
+		 */
+		uint8_t ieee_freq;
+
+		DFS_DPRINTK(dfs, WLAN_DEBUG_DFS,
+			"%s : precac_secondary_freq = %u precac_running = %u\n",
+			__func__,
+			dfs->dfs_precac_secondary_freq,
+			dfs->dfs_precac_timer_running);
+
+		if (dfs->dfs_precac_enable &&
+				(lmac_get_target_type(dfs->dfs_pdev_obj) ==
+				 TARGET_TYPE_QCA9984) &&
+				(lmac_get_dfsdomain(dfs->dfs_pdev_obj) ==
+				 DFS_ETSI_DOMAIN)) {
+			/*
+			 * If precac timer is running then do not change the
+			 * secondary channel use the old secondary VHT80
+			 * channel. If precac timer is not running then try to
+			 * find a new channel from precac-required-list.
+			 */
+			if (dfs->dfs_precac_timer_running) {
+				/*
+				 * Primary and secondary VHT80 cannot be the
+				 * same. Therefore exclude the primary
+				 * frequency while getting new channel from
+				 * precac-required-list.
+				 */
+				if (ch_freq_seg1 ==
+						dfs->dfs_precac_secondary_freq)
+					ieee_freq =
+					dfs_get_freq_from_precac_required_list(
+							dfs,
+							ch_freq_seg1);
+				else
+					ieee_freq =
+						dfs->dfs_precac_secondary_freq;
+			} else
+				ieee_freq =
+					dfs_get_freq_from_precac_required_list(
+							dfs, ch_freq_seg1);
+
+			if (ieee_freq) {
+				if (ieee_freq == (ch_freq_seg1 +
+						VHT160_IEEE_FREQ_DIFF)) {
+					/*
+					 * Override the HW channel mode to
+					 * VHT160
+					 */
+					uint8_t ieee_160_cfreq;
+
+					ieee_160_cfreq =
+						(ieee_freq + ch_freq_seg1)/2;
+					chan_mode = IEEE80211_MODE_11AC_VHT160;
+					*cfreq1 = dfs_mlme_ieee2mhz(
+							dfs->dfs_pdev_obj,
+							ch_freq_seg1,
+							IEEE80211_CHAN_5GHZ);
+					*cfreq2 = dfs_mlme_ieee2mhz(
+							dfs->dfs_pdev_obj,
+							ieee_160_cfreq,
+							IEEE80211_CHAN_5GHZ);
+				} else {
+					/*
+					 * Override the HW channel mode to
+					 * VHT80_80.
+					 */
+					chan_mode =
+						IEEE80211_MODE_11AC_VHT80_80;
+					*cfreq2 = dfs_mlme_ieee2mhz(
+							dfs->dfs_pdev_obj,
+							ieee_freq,
+							IEEE80211_CHAN_5GHZ);
+				}
+				*phy_mode = lmac_get_phymode_info(
+						dfs->dfs_pdev_obj, chan_mode);
+				*dfs_set_cfreq2 = true;
+
+				/*
+				 * Finally set the agile flag.
+				 * When we want a full calibration of both
+				 * primary VHT80 and secondary VHT80 the agile
+				 * flag is set to FALSE else set to TRUE. When
+				 * a channel is being set for the first time
+				 * this flag must be FALSE because first time
+				 * the entire channel must be calibrated. All
+				 * subsequent times the flag must be set to TRUE
+				 * if we are changing only the secondary VHT80.
+				 */
+				if (dfs->dfs_precac_primary_freq ==
+						ch_freq_seg1)
+					*set_agile = true;
+				else
+					*set_agile = false;
+
+				DFS_DPRINTK(dfs, WLAN_DEBUG_DFS,
+					"%s : cfreq1 = %u cfreq2 = %u ieee_freq = %u mode = %u set_agile = %d\n",
+					__func__,
+					*cfreq1,
+					*cfreq2,
+					ieee_freq,
+					chan_mode,
+					*set_agile);
+
+				dfs->dfs_precac_secondary_freq = ieee_freq;
+				dfs->dfs_precac_primary_freq = ch_freq_seg1;
+
+				/* Start the pre_cac_timer */
+				dfs_start_precac_timer(dfs,
+						dfs->dfs_precac_secondary_freq);
+			} /* End of if(ieee_freq) */
+		} /* End of if(dfs->dfs_precac_enable) */
+	}
+}
+
+void dfs_set_precac_enable(struct wlan_dfs *dfs, uint32_t value)
+{
+	dfs->dfs_precac_enable = value;
+}
+
+uint32_t dfs_get_precac_enable(struct wlan_dfs *dfs)
+{
+	return dfs->dfs_precac_enable;
+}