Browse Source

qcacmn: Add support for ETSI pre-CAC cleared list

In ETSI domain, after CAC, channel is added to ETSI CAC cleared list,
so that next time it can skip CAC if channel is already present in this
list. If radar found, remove channel(s) from this list indicating that
when channel(s) is/are selected in future, the CAC needs to be re-done.

Change-Id: If6b31ecda2ab159188e7724bce7d1c2d8375fa3c
CRs-Fixed: 2143266
Shaakir Mohamed 6 years ago
parent
commit
a0895b9989

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

@@ -1059,6 +1059,11 @@ struct wlan_dfs {
 	TAILQ_HEAD(, dfs_precac_entry) dfs_precac_done_list;
 	TAILQ_HEAD(, dfs_precac_entry) dfs_precac_nol_list;
 
+#ifdef QCA_SUPPORT_ETSI_PRECAC_DFS
+	TAILQ_HEAD(, dfs_etsi_precac_entry) dfs_etsiprecac_required_list;
+	TAILQ_HEAD(, dfs_etsi_precac_entry) dfs_etsiprecac_done_list;
+#endif
+
 	struct dfs_channel *dfs_curchan;
 	struct wlan_objmgr_pdev *dfs_pdev_obj;
 	bool           dfs_is_offload_enabled;

+ 238 - 0
umac/dfs/core/src/dfs_etsi_precac.h

@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2016-2018 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 ETSI Pre-CAC DFS APIs.
+ */
+
+#ifndef _DFS_ETSI_PRECAC_H_
+#define _DFS_ETSI_PRECAC_H_
+
+#include "dfs.h"
+
+#define VHT160_IEEE_FREQ_DIFF 16
+
+/**
+ * struct dfs_etsi_precac_entry - PreCAC entry for ETSI domain
+ * @pe_list:           ETSI PreCAC entry.
+ * @freq:              primary freq.
+ * @etsi_caclst_ticks  start tick, OS speicfic.
+ * @dfs:               Pointer to wlan_dfs structure.
+ */
+struct dfs_etsi_precac_entry {
+	TAILQ_ENTRY(dfs_etsi_precac_entry) pe_list;
+	uint16_t          freq;
+	unsigned long     etsi_caclst_ticks;
+	struct wlan_dfs   *dfs;
+};
+
+/**
+ * dfs_print_etsi_precaclists() - Print etsi precac list.
+ * @dfs: Pointer to wlan_dfs structure.
+ */
+#if defined(QCA_SUPPORT_ETSI_PRECAC_DFS)
+void dfs_print_etsi_precaclists(struct wlan_dfs *dfs);
+#else
+static inline void dfs_print_etsi_precaclists(struct wlan_dfs *dfs)
+{
+}
+#endif
+
+/**
+ * dfs_reset_etsi_precac_lists() - Resets the ETSI precac lists.
+ * @dfs: Pointer to wlan_dfs structure.
+ */
+#if defined(QCA_SUPPORT_ETSI_PRECAC_DFS)
+void dfs_reset_etsi_precac_lists(struct wlan_dfs *dfs);
+#else
+static inline void dfs_reset_etsi_precac_lists(struct wlan_dfs *dfs)
+{
+}
+#endif
+
+/**
+ * dfs_reset_etsiprecaclists()- Clears and initializes etsi_precac_required_list
+ *                                etsi_precac_done_list.
+ *
+ * @dfs: Pointer to wlan_dfs structure.
+ */
+#if defined(QCA_SUPPORT_ETSI_PRECAC_DFS)
+void dfs_reset_etsiprecaclists(struct wlan_dfs *dfs);
+#else
+static inline void dfs_reset_etsiprecaclists(struct wlan_dfs *dfs)
+{
+}
+#endif
+
+/**
+ * dfs_deinit_etsi_precac_list() - Clears the etsi precac list.
+ * @dfs: Pointer to wlan_dfs dtructure.
+ */
+#if defined(QCA_SUPPORT_ETSI_PRECAC_DFS)
+void dfs_deinit_etsi_precac_list(struct wlan_dfs *dfs);
+#else
+static inline void dfs_deinit_etsi_precac_list(struct wlan_dfs *dfs)
+{
+}
+#endif
+
+/**
+ * dfs_etsi_precac_attach() - Initialize ETSI precac variables.
+ * @dfs: Pointer to DFS structure.
+ */
+#if defined(QCA_SUPPORT_ETSI_PRECAC_DFS)
+void dfs_etsi_precac_attach(struct wlan_dfs *dfs);
+#else
+static inline void dfs_etsi_precac_attach(struct wlan_dfs *dfs)
+{
+}
+#endif
+
+/**
+ * dfs_etsi_precac_detach() - Free etsi_precac memory.
+ * @dfs: Pointer to wlan_dfs dtructure.
+ */
+#if defined(QCA_SUPPORT_ETSI_PRECAC_DFS)
+void dfs_etsi_precac_detach(struct wlan_dfs *dfs);
+#else
+static inline void dfs_etsi_precac_detach(struct wlan_dfs *dfs)
+{
+}
+#endif
+
+/**
+ * dfs_init_etsiprecac_list() - Init ETSI precac list.
+ * @dfs: Pointer to wlan_dfs dtructure.
+ */
+#if defined(QCA_SUPPORT_ETSI_PRECAC_DFS)
+void dfs_init_etsi_precac_list(struct wlan_dfs *dfs);
+#else
+static inline void dfs_init_etsi_precac_list(struct wlan_dfs *dfs)
+{
+}
+#endif
+
+/**
+ * dfs_is_subchan_in_etsi_precac_done_list() - Is HT20 sub channel
+ *                                             in etsi precac done list.
+ * @dfs: Pointer to wlan_dfs structure.
+ * @channel: HT20 sub channel
+ *
+ * Return: If subchannel present in precac done list return 1.
+ *         Otherwise return 0
+ */
+#if defined(QCA_SUPPORT_ETSI_PRECAC_DFS)
+int dfs_is_subchan_in_etsi_precac_done_list(struct wlan_dfs *dfs,
+					    uint8_t channel);
+#else
+static inline int dfs_is_subchan_in_etsi_precac_done_list(struct wlan_dfs *dfs)
+{
+	return 0;
+}
+#endif
+/**
+ * dfs_is_etsi_precac_done() - Is precac done.
+ * @dfs: Pointer to wlan_dfs structure.
+ *
+ * Return: If precac already done in channel, return 1. Otherwise return 0.
+ */
+#if defined(QCA_SUPPORT_ETSI_PRECAC_DFS)
+bool dfs_is_etsi_precac_done(struct wlan_dfs *dfs);
+#else
+static inline bool dfs_is_etsi_precac_done(struct wlan_dfs *dfs)
+{
+	return false;
+}
+#endif
+
+/**
+ * dfs_mark_etsi_precac_dfs() - Mark the precac channel as radar for ETSI.
+ * @dfs: Pointer to wlan_dfs structure.
+ * @channels: List of HT20 primary channels
+ * @num_channels: Number of HT20 primary channels
+ */
+#if defined(QCA_SUPPORT_ETSI_PRECAC_DFS)
+void dfs_mark_etsi_precac_dfs(struct wlan_dfs *dfs,
+			      uint8_t *channels, uint8_t num_channels);
+#else
+static inline void dfs_mark_etsi_precac_dfs(struct wlan_dfs *dfs,
+					    uint8_t *channels,
+					    uint8_t num_channels)
+{
+}
+#endif
+
+/**
+ * dfs_add_chan_to_etsi_done_list() - Add subchannel to ETSI CAC done list,
+ *                                       if present in ETSI CAC required list
+ * @dfs: Pointer to wlan_dfs structure.
+ * @channel: HT20 primary channel
+ *
+ * Return: If channel added to ETSI CAC done list, return 1. Otherwise return 0.
+ */
+#if defined(QCA_SUPPORT_ETSI_PRECAC_DFS)
+int dfs_add_chan_to_etsi_done_list(struct wlan_dfs *dfs, uint8_t channel);
+#else
+static inline int dfs_add_chan_to_etsi_done_list(struct wlan_dfs *dfs,
+						 uint8_t channel)
+{
+	return 0;
+}
+#endif
+
+/**
+ * dfs_add_to_etsi_precac_done_list() - Add channel to ETSI CAC done list
+ * @curchan: Pointer to dfs_channel structure.
+ *
+ */
+#if defined(QCA_SUPPORT_ETSI_PRECAC_DFS)
+void dfs_add_to_etsi_precac_done_list(struct wlan_dfs *dfs);
+#else
+static inline void dfs_add_to_etsi_precac_done_list(struct wlan_dfs *dfs)
+{
+}
+#endif
+
+/**
+ * dfs_get_bonding_channels_without_seg_info() - Get bonding channels in curchan
+ * @curchan: Pointer to dfs_channel structure.
+ * @channels: channel array holding list of bonded channels.
+ *
+ * Return: number of sub channels in the current channel.
+ */
+#ifdef QCA_SUPPORT_ETSI_PRECAC_DFS
+uint8_t dfs_get_bonding_channels_without_seg_info(struct dfs_channel *curchan,
+						  uint8_t *channels);
+#else
+static inline uint8_t
+dfs_get_bonding_channels_without_seg_info(struct dfs_channel *curchan,
+					  uint8_t *channels)
+{
+	return 0;
+}
+#endif
+
+#endif /* _DFS_ETSI_PRECAC_H_ */

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

@@ -30,6 +30,7 @@
 #include "../dfs_filter_init.h"
 #include "../dfs_full_offload.h"
 #include "wlan_dfs_utils_api.h"
+#include "../dfs_etsi_precac.h"
 
 /**
  * dfs_testtimer_task() - Sends CSA in the current channel.
@@ -117,6 +118,7 @@ int dfs_attach(struct wlan_dfs *dfs)
 	}
 	dfs_cac_attach(dfs);
 	dfs_zero_cac_attach(dfs);
+	dfs_etsi_precac_attach(dfs);
 	dfs_nol_attach(dfs);
 
 	/*
@@ -153,6 +155,7 @@ void dfs_detach(struct wlan_dfs *dfs)
 {
 	if (!dfs->dfs_is_offload_enabled)
 		dfs_main_detach(dfs);
+	dfs_etsi_precac_detach(dfs);
 	dfs_zero_cac_detach(dfs);
 	dfs_nol_detach(dfs);
 }
@@ -472,9 +475,11 @@ int dfs_control(struct wlan_dfs *dfs,
 		break;
 	case DFS_SHOW_PRECAC_LISTS:
 		dfs_print_precaclists(dfs);
+		dfs_print_etsi_precaclists(dfs);
 		break;
 	case DFS_RESET_PRECAC_LISTS:
 		dfs_reset_precac_lists(dfs);
+		dfs_reset_etsi_precac_lists(dfs);
 		break;
 	case DFS_SECOND_SEGMENT_BANGRADAR:
 		if (dfs->dfs_is_offload_enabled) {

+ 6 - 0
umac/dfs/core/src/misc/dfs_cac.c

@@ -30,6 +30,7 @@
 
 #include "../dfs_channel.h"
 #include "../dfs_zero_cac.h"
+#include "../dfs_etsi_precac.h"
 #include "wlan_dfs_utils_api.h"
 #include "wlan_dfs_mlme_api.h"
 #include "../dfs_internal.h"
@@ -106,6 +107,11 @@ static os_timer_func(dfs_cac_timeout)
 	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "cac expired, chan %d curr time %d",
 		dfs->dfs_curchan->dfs_ch_freq,
 		(qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000));
+
+	/* Once CAC is done, add channel to ETSI precacdone list*/
+	if (utils_get_dfsdomain(dfs->dfs_pdev_obj) == DFS_ETSI_DOMAIN)
+		dfs_add_to_etsi_precac_done_list(dfs);
+
 	/*
 	 * When radar is detected during a CAC we are woken up prematurely to
 	 * switch to a new channel. Check the channel to decide how to act.

+ 396 - 0
umac/dfs/core/src/misc/dfs_etsi_precac.c

@@ -0,0 +1,396 @@
+/*
+ * Copyright (c) 2016-2018 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 ETSI CAC DFS functions.
+ * Summary: In ETSI domain, after CAC, channel is added to ETSI CAC cleared
+ * list, so that next time it can skip CAC if channel already present in this
+ * list. If radar found, remove channel from this list indicating to redo
+ * CAC,when channel is selected in future.
+ */
+
+#include "../dfs_etsi_precac.h"
+#include "wlan_dfs_lmac_api.h"
+#include "wlan_dfs_mlme_api.h"
+#include "wlan_dfs_utils_api.h"
+#include "../dfs_internal.h"
+#include "../dfs_process_radar_found_ind.h"
+
+#define ETSI_CAC_TIME_OUT_MS 86400000
+int dfs_is_subchan_in_etsi_precac_done_list(struct wlan_dfs *dfs,
+					    uint8_t channel)
+{
+	struct dfs_etsi_precac_entry *precac_entry = NULL;
+	struct dfs_etsi_precac_entry *tmp_precac_entry = NULL;
+	uint8_t found = 0;
+	uint32_t diff_ms;
+
+	if (utils_is_dfs_ch(dfs->dfs_pdev_obj, channel)) {
+		/*For each channel in the list here do the below operation*/
+		PRECAC_LIST_LOCK(dfs);
+		if (TAILQ_EMPTY(&dfs->dfs_etsiprecac_done_list)) {
+			PRECAC_LIST_UNLOCK(dfs);
+			return 0;
+		}
+
+		TAILQ_FOREACH_SAFE(precac_entry, &dfs->dfs_etsiprecac_done_list,
+				   pe_list, tmp_precac_entry) {
+			diff_ms = qdf_system_ticks_to_msecs(qdf_system_ticks() -
+					precac_entry->etsi_caclst_ticks);
+			if (channel == precac_entry->freq &&
+			    diff_ms < ETSI_CAC_TIME_OUT_MS) {
+				found = 1;
+				break;
+			}
+		}
+		PRECAC_LIST_UNLOCK(dfs);
+		if (found)
+			return 1;
+	} else {
+		return 1;
+	}
+
+	return 0;
+}
+
+bool dfs_is_etsi_precac_done(struct wlan_dfs *dfs)
+{
+	bool ret_val = 1;
+	uint8_t channels[NUM_CHANNELS_160MHZ];
+	uint8_t nchannels = 0;
+	int i;
+
+	nchannels = dfs_get_bonding_channels_without_seg_info(dfs->dfs_curchan,
+							      channels);
+
+	for (i = 0; i < nchannels; i++) {
+		if (dfs_is_subchan_in_etsi_precac_done_list(dfs, channels[i])) {
+			continue;
+		} else {
+			ret_val = 0;
+			break;
+		}
+	}
+
+	dfs_debug(dfs, WLAN_DEBUG_DFS, "ret_val = %d", ret_val);
+
+	return ret_val;
+}
+
+void dfs_mark_etsi_precac_dfs(struct wlan_dfs *dfs, uint8_t *channels,
+			      uint8_t num_channels)
+{
+	struct dfs_etsi_precac_entry *precac_entry = NULL;
+	struct dfs_etsi_precac_entry *tmp_precac_entry = NULL;
+	int i = 0;
+
+	if (num_channels > NUM_CHANNELS_160MHZ) {
+		dfs_err(dfs, WLAN_DEBUG_DFS,
+			"Invalid num channels: %d", num_channels);
+		return;
+	}
+
+	PRECAC_LIST_LOCK(dfs);
+	for (i = 0; i < num_channels; i++) {
+		TAILQ_FOREACH_SAFE(precac_entry, &dfs->dfs_etsiprecac_done_list,
+				   pe_list, tmp_precac_entry) {
+			if (channels[i] != precac_entry->freq)
+				continue;
+
+		TAILQ_REMOVE(&dfs->dfs_etsiprecac_done_list,
+			     precac_entry, pe_list);
+		TAILQ_INSERT_TAIL(&dfs->dfs_etsiprecac_required_list,
+				  precac_entry, pe_list);
+		}
+	}
+	PRECAC_LIST_UNLOCK(dfs);
+}
+
+void dfs_init_etsi_precac_list(struct wlan_dfs *dfs)
+{
+	u_int i;
+	uint8_t found;
+	struct dfs_etsi_precac_entry *tmp_precac_entry;
+	int nchans = 0;
+
+	/*
+	 * We need to prepare list of unique VHT20 center frequencies.
+	 * But at the beginning we do not know how many unique frequencies
+	 * are present. Therefore, we calculate the MAX size and allocate
+	 * a temporary list/array. However we fill the temporary array with
+	 * unique frequencies and copy the unique list of frequencies to
+	 * the final list with exact size.
+	 */
+	TAILQ_INIT(&dfs->dfs_etsiprecac_done_list);
+	TAILQ_INIT(&dfs->dfs_etsiprecac_required_list);
+
+	dfs_mlme_get_dfs_ch_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_channel *ichan = NULL, lc;
+
+		ichan = &lc;
+		dfs_mlme_get_dfs_ch_channels(dfs->dfs_pdev_obj,
+					     &ichan->dfs_ch_freq,
+					     &ichan->dfs_ch_flags,
+					     &ichan->dfs_ch_flagext,
+					     &ichan->dfs_ch_ieee,
+					     &ichan->dfs_ch_vhtop_ch_freq_seg1,
+					     &ichan->dfs_ch_vhtop_ch_freq_seg2,
+					     i);
+
+		if (!WLAN_IS_CHAN_DFS(ichan))
+			continue;
+
+		found = 0;
+		TAILQ_FOREACH(tmp_precac_entry,
+			      &dfs->dfs_etsiprecac_required_list,
+			      pe_list) {
+			if (tmp_precac_entry->freq ==
+			   ichan->dfs_ch_vhtop_ch_freq_seg1) {
+				found = 1;
+				break;
+			}
+		}
+		if (!found) {
+			struct dfs_etsi_precac_entry *etsi_precac_entry;
+
+			etsi_precac_entry = qdf_mem_malloc(
+					sizeof(*etsi_precac_entry));
+			if (!etsi_precac_entry) {
+				dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
+					"etsi precac entry alloc fail");
+				continue;
+			}
+			etsi_precac_entry->freq =
+				ichan->dfs_ch_vhtop_ch_freq_seg1;
+			etsi_precac_entry->dfs = dfs;
+			TAILQ_INSERT_TAIL(&dfs->dfs_etsiprecac_required_list,
+					  etsi_precac_entry, pe_list);
+		}
+	}
+	PRECAC_LIST_UNLOCK(dfs);
+
+	dfs_debug(dfs, WLAN_DEBUG_DFS,
+		  "Print the list of VHT20 frequencies from linked list");
+	TAILQ_FOREACH(tmp_precac_entry,
+		      &dfs->dfs_etsiprecac_required_list,
+			pe_list)
+	dfs_info(dfs, WLAN_DEBUG_DFS, "freq=%u",
+		 tmp_precac_entry->freq);
+}
+
+void dfs_deinit_etsi_precac_list(struct wlan_dfs *dfs)
+{
+	struct dfs_etsi_precac_entry *tmp_precac_entry, *precac_entry;
+
+	dfs_debug(dfs, WLAN_DEBUG_DFS,
+		  "Free list of HT20/VHT20 freq from etsiprecac_required list");
+	PRECAC_LIST_LOCK(dfs);
+
+	if (!TAILQ_EMPTY(&dfs->dfs_etsiprecac_required_list))
+		TAILQ_FOREACH_SAFE(precac_entry,
+				   &dfs->dfs_etsiprecac_required_list,
+				pe_list,
+				tmp_precac_entry) {
+			TAILQ_REMOVE(&dfs->dfs_etsiprecac_required_list,
+				     precac_entry, pe_list);
+			qdf_mem_free(precac_entry);
+		}
+
+	dfs_debug(dfs, WLAN_DEBUG_DFS,
+		  "Free list of HT20/VHT20 freq from etsipcac_done list");
+
+	if (!TAILQ_EMPTY(&dfs->dfs_etsiprecac_done_list))
+		TAILQ_FOREACH_SAFE(precac_entry,
+				   &dfs->dfs_etsiprecac_done_list,
+				pe_list,
+				tmp_precac_entry) {
+			TAILQ_REMOVE(&dfs->dfs_etsiprecac_done_list,
+				     precac_entry, pe_list);
+			qdf_mem_free(precac_entry);
+		}
+
+	PRECAC_LIST_UNLOCK(dfs);
+}
+
+void dfs_etsi_precac_attach(struct wlan_dfs *dfs)
+{
+}
+
+void dfs_etsi_precac_detach(struct wlan_dfs *dfs)
+{
+	dfs_deinit_etsi_precac_list(dfs);
+}
+
+void dfs_print_etsi_precaclists(struct wlan_dfs *dfs)
+{
+	struct dfs_etsi_precac_entry *tmp_precac_entry;
+
+	if (!dfs) {
+		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
+		return;
+	}
+
+	PRECAC_LIST_LOCK(dfs);
+	/* Print the ETSI Pre-CAC required List */
+	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
+		 "Pre-cac-required list of VHT20 frequencies");
+	TAILQ_FOREACH(tmp_precac_entry,
+		      &dfs->dfs_etsiprecac_required_list,
+			pe_list) {
+		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
+			 "freq=%u ",
+				tmp_precac_entry->freq);
+	}
+
+	/* Print the ETSI Pre-CAC done List */
+	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
+		 "Pre-cac-done list of VHT20 frequencies");
+	TAILQ_FOREACH(tmp_precac_entry,
+		      &dfs->dfs_etsiprecac_done_list,
+			pe_list) {
+		unsigned long time_added =
+			qdf_system_ticks_to_msecs(
+					tmp_precac_entry->etsi_caclst_ticks);
+
+		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
+			 "freq=%u added at (msec): %lu",
+				tmp_precac_entry->freq,
+				time_added);
+	}
+	PRECAC_LIST_UNLOCK(dfs);
+}
+
+void dfs_reset_etsiprecaclists(struct wlan_dfs *dfs)
+{
+	dfs_debug(dfs, WLAN_DEBUG_DFS,
+		  "Reset precaclist of VHT80 frequencies");
+	dfs_deinit_etsi_precac_list(dfs);
+	dfs_init_etsi_precac_list(dfs);
+}
+
+void dfs_reset_etsi_precac_lists(struct wlan_dfs *dfs)
+{
+	if (!dfs) {
+		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
+		return;
+	}
+	dfs_reset_etsiprecaclists(dfs);
+}
+
+int dfs_add_chan_to_etsi_done_list(struct wlan_dfs *dfs, uint8_t channel)
+{
+	struct dfs_etsi_precac_entry *precac_entry, *tmp_precac_entry;
+
+	PRECAC_LIST_LOCK(dfs);
+	TAILQ_FOREACH_SAFE(precac_entry,
+			   &dfs->dfs_etsiprecac_required_list,
+			   pe_list, tmp_precac_entry) {
+		if (channel == precac_entry->freq) {
+			TAILQ_REMOVE(&dfs->dfs_etsiprecac_required_list,
+				     precac_entry, pe_list);
+			TAILQ_INSERT_TAIL(&dfs->dfs_etsiprecac_done_list,
+					  precac_entry,
+					  pe_list);
+			precac_entry->etsi_caclst_ticks = qdf_system_ticks();
+			PRECAC_LIST_UNLOCK(dfs);
+			return 1;
+		}
+	}
+	PRECAC_LIST_UNLOCK(dfs);
+
+	return 0;
+}
+
+void dfs_add_to_etsi_precac_done_list(struct wlan_dfs *dfs)
+{
+	uint8_t channels[NUM_CHANNELS_160MHZ];
+	uint8_t nchannels = 0;
+	int i = 0;
+
+	nchannels = dfs_get_bonding_channels_without_seg_info(dfs->dfs_curchan,
+							      channels);
+	for (i = 0; i < nchannels; i++) {
+		if (!utils_is_dfs_ch(dfs->dfs_pdev_obj, channels[i]))
+			continue;
+
+		if (TAILQ_EMPTY(&dfs->dfs_etsiprecac_required_list))
+			break;
+
+		dfs_add_chan_to_etsi_done_list(dfs, channels[i]);
+	}
+}
+
+uint8_t dfs_get_bonding_channels_without_seg_info(struct dfs_channel *curchan,
+						  uint8_t *channels)
+{
+	uint8_t center_chan;
+	uint8_t nchannels = 0;
+
+	center_chan = curchan->dfs_ch_vhtop_ch_freq_seg1;
+
+	if (WLAN_IS_CHAN_MODE_20(curchan)) {
+		nchannels = 1;
+		channels[0] = center_chan;
+	} else if (WLAN_IS_CHAN_MODE_40(curchan)) {
+		nchannels = 2;
+		channels[0] = center_chan - DFS_5GHZ_NEXT_CHAN_OFFSET;
+		channels[1] = center_chan + DFS_5GHZ_NEXT_CHAN_OFFSET;
+	} else if (WLAN_IS_CHAN_MODE_80(curchan)) {
+		nchannels = 4;
+		channels[0] = center_chan - DFS_5GHZ_2ND_CHAN_OFFSET;
+		channels[1] = center_chan - DFS_5GHZ_NEXT_CHAN_OFFSET;
+		channels[2] = center_chan + DFS_5GHZ_NEXT_CHAN_OFFSET;
+		channels[3] = center_chan + DFS_5GHZ_2ND_CHAN_OFFSET;
+	} else if (WLAN_IS_CHAN_MODE_80_80(curchan)) {
+		nchannels = 8;
+		channels[0] = center_chan - DFS_5GHZ_2ND_CHAN_OFFSET;
+		channels[1] = center_chan - DFS_5GHZ_NEXT_CHAN_OFFSET;
+		channels[2] = center_chan + DFS_5GHZ_NEXT_CHAN_OFFSET;
+		channels[3] = center_chan + DFS_5GHZ_2ND_CHAN_OFFSET;
+		center_chan = curchan->dfs_ch_vhtop_ch_freq_seg2;
+		channels[4] = center_chan - DFS_5GHZ_2ND_CHAN_OFFSET;
+		channels[5] = center_chan - DFS_5GHZ_NEXT_CHAN_OFFSET;
+		channels[6] = center_chan + DFS_5GHZ_NEXT_CHAN_OFFSET;
+		channels[7] = center_chan + DFS_5GHZ_2ND_CHAN_OFFSET;
+	} else if (WLAN_IS_CHAN_MODE_160(curchan)) {
+		nchannels = 8;
+		center_chan = curchan->dfs_ch_vhtop_ch_freq_seg2;
+		channels[0] = center_chan - DFS_5GHZ_4TH_CHAN_OFFSET;
+		channels[1] = center_chan - DFS_5GHZ_3RD_CHAN_OFFSET;
+		channels[2] = center_chan - DFS_5GHZ_2ND_CHAN_OFFSET;
+		channels[3] = center_chan - DFS_5GHZ_NEXT_CHAN_OFFSET;
+		channels[4] = center_chan + DFS_5GHZ_NEXT_CHAN_OFFSET;
+		channels[5] = center_chan + DFS_5GHZ_2ND_CHAN_OFFSET;
+		channels[6] = center_chan + DFS_5GHZ_3RD_CHAN_OFFSET;
+		channels[7] = center_chan + DFS_5GHZ_4TH_CHAN_OFFSET;
+	}
+
+	return nchannels;
+}

+ 12 - 10
umac/dfs/core/src/misc/dfs_process_radar_found_ind.c

@@ -23,11 +23,12 @@
 
 #include "../dfs.h"
 #include "../dfs_zero_cac.h"
+#include "../dfs_etsi_precac.h"
 #include "../dfs_process_radar_found_ind.h"
 #include <wlan_reg_services_api.h>
 #include <wlan_dfs_utils_api.h>
 #include "wlan_dfs_mlme_api.h"
-
+#include "../dfs_internal.h"
 /**
  * TODO: The code is not according to the following description needs
  * modification and correction. Code always adds left and right channels to
@@ -157,7 +158,8 @@ static QDF_STATUS dfs_radar_add_channel_list_to_nol(struct wlan_dfs *dfs,
 				(uint16_t)utils_dfs_chan_to_freq(channels[i]),
 				dfs->wlan_dfs_nol_timeout);
 		nollist[num_ch++] = last_chan;
-		dfs_info(dfs, WLAN_DEBUG_DFS, "ch=%d Added to NOL", last_chan);
+		dfs_info(dfs, WLAN_DEBUG_DFS_NOL, "ch=%d Added to NOL",
+			 last_chan);
 	}
 
 	if (!num_ch) {
@@ -358,14 +360,6 @@ static uint8_t dfs_find_radar_affected_subchans(struct wlan_dfs *dfs,
 	return i;
 }
 
-/**
- * dfs_get_bonding_channels() - Get bonding channels.
- * @curchan: Pointer to dfs_channels to know width and primary channel.
- * @segment_id: Segment id, useful for 80+80/160 MHz operating band.
- * @channels: Pointer to save radar affected channels.
- *
- * Return: Number of channels.
- */
 uint8_t dfs_get_bonding_channels(struct dfs_channel *curchan,
 				 uint32_t segment_id,
 				 uint8_t *channels)
@@ -520,6 +514,14 @@ QDF_STATUS dfs_process_radar_ind(struct wlan_dfs *dfs,
 	if (dfs->dfs_precac_enable)
 		dfs_mark_precac_dfs(dfs, dfs->is_radar_found_on_secondary_seg);
 
+	if (utils_get_dfsdomain(dfs->dfs_pdev_obj) == DFS_ETSI_DOMAIN) {
+		/* Remove chan from ETSI Pre-CAC Cleared List*/
+		dfs_info(dfs, WLAN_DEBUG_DFS_NOL,
+			 "%s : %d remove channel from ETSI PreCAC List\n",
+			 __func__, __LINE__);
+		dfs_mark_etsi_precac_dfs(dfs, channels, num_channels);
+	}
+
 	if (!dfs->dfs_is_offload_enabled &&
 	    dfs->is_radar_found_on_secondary_seg) {
 		dfs_second_segment_radar_disable(dfs);

+ 39 - 0
umac/dfs/dispatcher/inc/wlan_dfs_utils_api.h

@@ -107,6 +107,26 @@ QDF_STATUS utils_dfs_reset(struct wlan_objmgr_pdev *pdev);
  */
 QDF_STATUS utils_dfs_reset_precaclists(struct wlan_objmgr_pdev *pdev);
 
+/**
+ * utils_dfs_reset_etsi_precaclists() - Clears and initializes etsi
+ *                                      precac_required_list,
+ *                                      etsi precac_done_list and
+ *                                      etsi precac_nol_list.
+ * @pdev: Pointer to DFS pdev object.
+ *
+ * Wrapper function for dfs_reset_etsiprecaclists(). This function called from
+ * outside of DFS component.
+ */
+#ifdef QCA_SUPPORT_ETSI_PRECAC_DFS
+QDF_STATUS utils_dfs_reset_etsi_precaclists(struct wlan_objmgr_pdev *pdev);
+#else
+static inline QDF_STATUS utils_dfs_reset_etsi_precaclists(
+		struct wlan_objmgr_pdev *pdev)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 /**
  * utils_dfs_cancel_precac_timer() - Cancel the precac timer.
  * @pdev: Pointer to DFS pdev object.
@@ -126,6 +146,25 @@ QDF_STATUS utils_dfs_cancel_precac_timer(struct wlan_objmgr_pdev *pdev);
 QDF_STATUS utils_dfs_is_precac_done(struct wlan_objmgr_pdev *pdev,
 		bool *is_precac_done);
 
+/**
+ * utils_dfs_is_esti_precac_done() - Is ETSI precac done.
+ * @pdev: Pointer to DFS pdev object.
+ *
+ * wrapper function for dfs_is_etsi_precac_done(). This
+ * function called from outside of dfs component.
+ */
+#ifdef QCA_SUPPORT_ETSI_PRECAC_DFS
+QDF_STATUS utils_dfs_is_etsi_precac_done(struct wlan_objmgr_pdev *pdev,
+					 bool *is_etsi_precac_done);
+#else
+static inline QDF_STATUS utils_dfs_is_etsi_precac_done(
+		struct wlan_objmgr_pdev *pdev,
+		bool *is_etsi_precac_done)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 /**
  * utils_dfs_cancel_cac_timer() - Cancels the CAC timer.
  * @pdev: Pointer to DFS pdev object.

+ 37 - 0
umac/dfs/dispatcher/src/wlan_dfs_utils_api.c

@@ -24,6 +24,7 @@
 #include "wlan_dfs_utils_api.h"
 #include "../../core/src/dfs.h"
 #include "../../core/src/dfs_zero_cac.h"
+#include "../../core/src/dfs_etsi_precac.h"
 #include <wlan_reg_services_api.h>
 #include "../../core/src/dfs_random_chan_sel.h"
 #ifdef QCA_DFS_USE_POLICY_MANAGER
@@ -50,6 +51,7 @@ QDF_STATUS utils_dfs_reset(struct wlan_objmgr_pdev *pdev)
 	dfs_reset(dfs);
 	dfs_nol_update(dfs);
 	dfs_reset_precaclists(dfs);
+	dfs_reset_etsiprecaclists(dfs);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -84,6 +86,23 @@ QDF_STATUS utils_dfs_reset_precaclists(struct wlan_objmgr_pdev *pdev)
 }
 qdf_export_symbol(utils_dfs_reset_precaclists);
 
+#ifdef QCA_SUPPORT_ETSI_PRECAC_DFS
+QDF_STATUS utils_dfs_reset_etsi_precaclists(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_dfs *dfs;
+
+	dfs = global_dfs_to_mlme.pdev_get_comp_private_obj(pdev);
+	if (!dfs)
+		return  QDF_STATUS_E_FAILURE;
+
+	dfs_reset_etsiprecaclists(dfs);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+qdf_export_symbol(utils_dfs_reset_etsi_precaclists);
+#endif
+
 QDF_STATUS utils_dfs_cancel_precac_timer(struct wlan_objmgr_pdev *pdev)
 {
 	struct wlan_dfs *dfs;
@@ -113,6 +132,24 @@ QDF_STATUS utils_dfs_is_precac_done(struct wlan_objmgr_pdev *pdev,
 }
 qdf_export_symbol(utils_dfs_is_precac_done);
 
+#ifdef QCA_SUPPORT_ETSI_PRECAC_DFS
+QDF_STATUS utils_dfs_is_etsi_precac_done(struct wlan_objmgr_pdev *pdev,
+					 bool *is_etsi_precac_done)
+{
+	struct wlan_dfs *dfs;
+
+	dfs = global_dfs_to_mlme.pdev_get_comp_private_obj(pdev);
+	if (!dfs)
+		return  QDF_STATUS_E_FAILURE;
+
+	*is_etsi_precac_done = dfs_is_etsi_precac_done(dfs);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+qdf_export_symbol(utils_dfs_is_etsi_precac_done);
+#endif
+
 QDF_STATUS utils_dfs_cancel_cac_timer(struct wlan_objmgr_pdev *pdev)
 {
 	struct wlan_dfs *dfs;