mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-13 08:07:32 -04:00
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
This commit is contained in:
parent
08748c89fb
commit
189e80817f
2 changed files with 1142 additions and 0 deletions
254
umac/dfs/core/src/dfs_zero_cac.h
Normal file
254
umac/dfs/core/src/dfs_zero_cac.h
Normal file
|
|
@ -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
umac/dfs/core/src/misc/dfs_zero_cac.c
Normal file
888
umac/dfs/core/src/misc/dfs_zero_cac.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
Loading…
Reference in a new issue