Merge "qca-wifi: Split dfs_zero_cac.c into multiple files"
This commit is contained in:

committed by
Gerrit - the friendly Code Review server

commit
9fc3cab1a6
257
umac/dfs/core/src/dfs_precac_forest.h
Normal file
257
umac/dfs/core/src/dfs_precac_forest.h
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020 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 the headers of Precac Tree structure feature.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DFS_PRECAC_FOREST_H_
|
||||
#define _DFS_PRECAC_FOREST_H_
|
||||
#include <dfs_zero_cac.h>
|
||||
#include <dfs.h>
|
||||
#include <wlan_lmac_if_def.h>
|
||||
#define N_OFFSETS 2
|
||||
|
||||
/**
|
||||
* struct dfs_channel_bw - Structure to store the information about precac
|
||||
* root's primary channel frequency, maximum bandwidth and the center frequency.
|
||||
*
|
||||
* @dfs_pri_ch_freq: Primary channel frequency of the root channel.
|
||||
* @dfs_center_ch_freq: Center frequency of the 20/40/80/160 channel.In case of
|
||||
* the 165MHz channel, it is 5730MHz.
|
||||
* @dfs_max_bw: Maximum bandwidth of the channel available in the
|
||||
* current channel list.
|
||||
*/
|
||||
struct dfs_channel_bw {
|
||||
uint16_t dfs_pri_ch_freq;
|
||||
uint16_t dfs_center_ch_freq;
|
||||
uint16_t dfs_max_bw;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct precac_tree_offset_for_different_bw - Bandwidth, tree depth and
|
||||
* channel offsets information to build the precac tree.
|
||||
* @bandwidth: Bandwidth of the the root node.
|
||||
* @tree_depth: Tree depth of the precac tree.
|
||||
* @initial_and_next_offsets: Offset to root node to find the initial and the
|
||||
* next channels of the node.
|
||||
*/
|
||||
struct precac_tree_offset_for_different_bw {
|
||||
int bandwidth;
|
||||
int tree_depth;
|
||||
int initial_and_next_offsets[TREE_DEPTH_MAX][N_OFFSETS];
|
||||
};
|
||||
|
||||
#define START_INDEX 0
|
||||
#define STEP_INDEX 1
|
||||
|
||||
|
||||
static const
|
||||
struct precac_tree_offset_for_different_bw offset20 = {DFS_CHWIDTH_20_VAL,
|
||||
TREE_DEPTH_20,
|
||||
{
|
||||
{0, NEXT_20_CHAN_FREQ_OFFSET}
|
||||
}
|
||||
};
|
||||
|
||||
static const
|
||||
struct precac_tree_offset_for_different_bw offset40 = {DFS_CHWIDTH_40_VAL,
|
||||
TREE_DEPTH_40,
|
||||
{
|
||||
{0, NEXT_40_CHAN_FREQ_OFFSET},
|
||||
{-10, NEXT_20_CHAN_FREQ_OFFSET}
|
||||
}
|
||||
};
|
||||
|
||||
static const
|
||||
struct precac_tree_offset_for_different_bw offset80 = {DFS_CHWIDTH_80_VAL,
|
||||
TREE_DEPTH_80,
|
||||
{
|
||||
{0, NEXT_80_CHAN_FREQ_OFFSET},
|
||||
{-20, NEXT_40_CHAN_FREQ_OFFSET},
|
||||
{-30, NEXT_20_CHAN_FREQ_OFFSET}
|
||||
}
|
||||
};
|
||||
|
||||
static const
|
||||
struct precac_tree_offset_for_different_bw offset160 = {DFS_CHWIDTH_160_VAL,
|
||||
TREE_DEPTH_160,
|
||||
{
|
||||
{INITIAL_160_CHAN_FREQ_OFFSET, NEXT_160_CHAN_FREQ_OFFSET},
|
||||
{INITIAL_80_CHAN_FREQ_OFFSET, NEXT_80_CHAN_FREQ_OFFSET},
|
||||
{INITIAL_40_CHAN_FREQ_OFFSET, NEXT_40_CHAN_FREQ_OFFSET},
|
||||
{INITIAL_20_CHAN_FREQ_OFFSET, NEXT_20_CHAN_FREQ_OFFSET}
|
||||
}
|
||||
};
|
||||
|
||||
static const
|
||||
struct precac_tree_offset_for_different_bw default_offset = {0, 0};
|
||||
|
||||
/* Given a bandwidth, find the number of subchannels in that bandwidth */
|
||||
#define N_SUBCHS_FOR_BANDWIDTH(_bw) ((_bw) / MIN_DFS_SUBCHAN_BW)
|
||||
|
||||
#define DFS_160MHZ_SECSEG_CHAN_OFFSET 40
|
||||
|
||||
#define VHT80_FREQ_OFFSET 30
|
||||
/* For any 160MHz channel, a frequency offset of 70MHz would have been enough
|
||||
* to include the right edge and left edge channels. But, the restricted 80P80
|
||||
* or the 165MHz channel is also assumed to have a 160MHz root ie channel 146,
|
||||
* so an offset of 75MHz is chosen.
|
||||
*/
|
||||
#define VHT160_FREQ_OFFSET 75
|
||||
|
||||
#define IS_WITHIN_RANGE(_A, _B, _C) \
|
||||
(((_A) >= ((_B)-(_C))) && ((_A) <= ((_B)+(_C))))
|
||||
|
||||
#define IS_WITHIN_RANGE_STRICT(_A, _B, _C) \
|
||||
(((_A) > ((_B)-(_C))) && ((_A) < ((_B)+(_C))))
|
||||
|
||||
#define MAX_PREFIX_CHAR 28
|
||||
|
||||
/**
|
||||
* dfs_configure_deschan_for_precac() - API to prioritize user configured
|
||||
* channel for preCAC.
|
||||
*
|
||||
* @dfs: Pointer to DFS of wlan_dfs structure.
|
||||
* Return: frequency of type qdf_freq_t if configured, else 0.
|
||||
*/
|
||||
qdf_freq_t dfs_configure_deschan_for_precac(struct wlan_dfs *dfs);
|
||||
|
||||
/**
|
||||
* dfs_is_pcac_required_for_freq() - Find if given frequency is preCAC required.
|
||||
* @node: Pointer to the preCAC tree Node in which the frequency is present.
|
||||
* @freq: Frequency to be checked.
|
||||
*
|
||||
* Return: False if the frequency is not fully CAC done or in NOL, else true.
|
||||
*/
|
||||
bool dfs_is_pcac_required_for_freq(struct precac_tree_node *node,
|
||||
uint16_t freq);
|
||||
|
||||
/**
|
||||
* dfs_find_subchannels_for_center_freq() - API to find the subchannels given
|
||||
* the center frequencies and ch_width.
|
||||
* @pri_center_freq: It is the center of 20/40/80/160Mhz band and for 80+80Mhz
|
||||
* it is the center of the first 80Mhz band.
|
||||
* @sec_center_freq: It is used only for 80+80Mhz and denotes the center
|
||||
* of the second 80Mhz band.
|
||||
* @ch_width: Channel width.
|
||||
* @channels: List of subchannels.
|
||||
*
|
||||
* Return: Number of subchannels.
|
||||
*/
|
||||
uint8_t dfs_find_subchannels_for_center_freq(qdf_freq_t pri_center_freq,
|
||||
qdf_freq_t sec_center_freq,
|
||||
enum phy_ch_width ch_width,
|
||||
qdf_freq_t *channels);
|
||||
|
||||
/**
|
||||
* dfs_find_precac_state_of_node() - Find the preCAC state of the given channel.
|
||||
* @channel: Channel whose preCAC state is to be found.
|
||||
* @precac_entry: PreCAC entry where the channel exists.
|
||||
*
|
||||
* Return, enum value of type precac_chan_state.
|
||||
*/
|
||||
enum precac_chan_state
|
||||
dfs_find_precac_state_of_node(qdf_freq_t channel,
|
||||
struct dfs_precac_entry *precac_entry);
|
||||
|
||||
/* dfs_mark_adfs_chan_as_cac_done()- Mark the ADFS CAC completed channel as
|
||||
* CAC done in the precac tree.
|
||||
* @dfs: Pointer to struct wlan_dfs.
|
||||
*/
|
||||
void dfs_mark_adfs_chan_as_cac_done(struct wlan_dfs *dfs);
|
||||
|
||||
/* dfs_descend_precac_tree_for_freq() - Descend into the precac BSTree based on
|
||||
* the channel provided. If the channel is less than
|
||||
* given node's channel, descend left, else right.
|
||||
* @node: Precac BSTree node.
|
||||
* @chan_freq: Channel freq whose node is to be found.
|
||||
*
|
||||
* Return: the next precac_tree_node (left child or right child of
|
||||
* current node).
|
||||
*/
|
||||
|
||||
struct precac_tree_node *
|
||||
dfs_descend_precac_tree_for_freq(struct precac_tree_node *node,
|
||||
uint16_t chan_freq);
|
||||
|
||||
/**
|
||||
* dfs_unmark_rcac_done() - Unmark the CAC done channels from the RCAC list.
|
||||
* @dfs: Pointer to wlan_dfs object.
|
||||
*/
|
||||
#ifdef QCA_SUPPORT_ADFS_RCAC
|
||||
void dfs_unmark_rcac_done(struct wlan_dfs *dfs);
|
||||
#else
|
||||
static inline
|
||||
void dfs_unmark_rcac_done(struct wlan_dfs *dfs)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* dfs_is_precac_completed_count_non_zero() - API to find if the preCAC
|
||||
* completed channels count is zero/non_zero.
|
||||
* @dfs: Pointer to DFS object.
|
||||
*
|
||||
* Return true, if there exists atleast one node/subchannel in the preCAC list
|
||||
* that is CAC done, else return false.
|
||||
*/
|
||||
bool dfs_is_precac_completed_count_non_zero(struct wlan_dfs *dfs);
|
||||
|
||||
/*
|
||||
* dfs_fill_adfs_chan_params() - Fill the ADFS FW params.
|
||||
* @dfs: Pointer to wlan_dfs.
|
||||
* @adfs_param: Pointer to struct dfs_agile_cac_params.
|
||||
* @ch_freq: Frequency in MHZ to be programmed to the agile detector.
|
||||
*/
|
||||
void dfs_fill_adfs_chan_params(struct wlan_dfs *dfs,
|
||||
struct dfs_agile_cac_params *adfs_param);
|
||||
|
||||
/* dfs_agile_precac_cleanup() - Reset parameters of wlan_dfs.
|
||||
*
|
||||
* @dfs: Pointer to struct wlan_dfs.
|
||||
*/
|
||||
void dfs_agile_precac_cleanup(struct wlan_dfs *dfs);
|
||||
|
||||
#ifdef WLAN_DFS_PRECAC_AUTO_CHAN_SUPPORT
|
||||
/**
|
||||
* dfs_precac_check_home_chan_change() - Change the home channel
|
||||
* after precac is done.
|
||||
*
|
||||
* @dfs: Pointer to dfs handler.
|
||||
*
|
||||
* If precac is done on the home channel, then return true, else false.
|
||||
*
|
||||
* Return: true if precac done on home channel, else false.
|
||||
*/
|
||||
bool dfs_precac_check_home_chan_change(struct wlan_dfs *dfs);
|
||||
#else
|
||||
static inline bool dfs_precac_check_home_chan_change(struct wlan_dfs *dfs)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#endif /* _DFS_PRECAC_FOREST_H_ */
|
952
umac/dfs/core/src/misc/dfs_agile_sm.c
Normal file
952
umac/dfs/core/src/misc/dfs_agile_sm.c
Normal file
@@ -0,0 +1,952 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020 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 Agile State machine functions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../dfs_precac_forest.h"
|
||||
#include "wlan_reg_services_api.h"
|
||||
|
||||
#ifdef QCA_SUPPORT_AGILE_DFS
|
||||
/* dfs_start_agile_engine() - Prepare ADFS params and program the agile
|
||||
* engine sending agile config cmd to FW.
|
||||
* @dfs: Pointer to struct wlan_dfs.
|
||||
*/
|
||||
void dfs_start_agile_engine(struct wlan_dfs *dfs)
|
||||
{
|
||||
struct dfs_agile_cac_params adfs_param;
|
||||
struct wlan_lmac_if_dfs_tx_ops *dfs_tx_ops;
|
||||
struct dfs_soc_priv_obj *dfs_soc_obj = dfs->dfs_soc_obj;
|
||||
|
||||
/* Fill the RCAC ADFS params and send it to FW.
|
||||
* FW does not use RCAC timeout values for RCAC feature.
|
||||
* FW runs an infinite timer.
|
||||
*/
|
||||
dfs_fill_adfs_chan_params(dfs, &adfs_param);
|
||||
adfs_param.min_precac_timeout = MIN_RCAC_DURATION;
|
||||
adfs_param.max_precac_timeout = MAX_RCAC_DURATION;
|
||||
adfs_param.ocac_mode = QUICK_RCAC_MODE;
|
||||
|
||||
qdf_info("%s : %d RCAC channel request sent for pdev: %pK ch_freq: %d",
|
||||
__func__, __LINE__, dfs->dfs_pdev_obj,
|
||||
dfs->dfs_agile_precac_freq_mhz);
|
||||
|
||||
dfs_tx_ops = wlan_psoc_get_dfs_txops(dfs_soc_obj->psoc);
|
||||
|
||||
if (dfs_tx_ops && dfs_tx_ops->dfs_agile_ch_cfg_cmd)
|
||||
dfs_tx_ops->dfs_agile_ch_cfg_cmd(dfs->dfs_pdev_obj,
|
||||
&adfs_param);
|
||||
else
|
||||
dfs_err(NULL, WLAN_DEBUG_DFS_ALWAYS,
|
||||
"dfs_tx_ops=%pK", dfs_tx_ops);
|
||||
}
|
||||
|
||||
/**
|
||||
* --------------------- ROLLING CAC STATE MACHINE ----------------------
|
||||
*
|
||||
* Rolling CAC is a feature where in, a separate hardware (Agile detector)
|
||||
* will be brought up in a channel that is not the current operating channel
|
||||
* and will continue to monitor the channel non-stop, until the next
|
||||
* channel change or radar in this RCAC channel.
|
||||
*
|
||||
* Now if the Rolling CAC channel was radar free for a minimum duration
|
||||
* (1 min.) and the device is now switching to this channel, no CAC is required.
|
||||
*
|
||||
* I.e. let's say the current operating channel is 64 HT80 and we are starting
|
||||
* the agile detector in 100 HT80. After a minute of being up in 100 HT80, we
|
||||
* switch the radio to 100 HT80. This operating channel change will not
|
||||
* require CAC now since the channel was radar free for the last 1 minute,
|
||||
* as determined by the agile detector.
|
||||
*
|
||||
* Introduction of a rolling CAC state machine:
|
||||
*
|
||||
* To acheive the rolling CAC feature using the agile detector, a trivial
|
||||
* state machine is implemented, as represented below:
|
||||
*
|
||||
* _________________
|
||||
* | |
|
||||
* |------------>| INIT |<-----------|
|
||||
* | |_________________| |
|
||||
* | | |
|
||||
* | | |
|
||||
* | [EV_RCAC_STOP] | [EV_RCAC_START] | [EV_RCAC_STOP]
|
||||
* | [EV_ADFS_RADAR] | | [EV_ADFS_RADAR]
|
||||
* | | |
|
||||
* | | |
|
||||
* ________|________ | ________|________
|
||||
* | | |----------->| |
|
||||
* | COMPLETE | | RUNNING |
|
||||
* |_________________|<-------------------------|_________________|
|
||||
* [EV_RCAC_DONE]
|
||||
*
|
||||
*
|
||||
*
|
||||
* Legend:
|
||||
* _________________
|
||||
* | |
|
||||
* 1. | RCAC STATES |
|
||||
* |_________________|
|
||||
*
|
||||
* 2. [RCAC_EVENTS]
|
||||
*
|
||||
*
|
||||
* Event triggers and handlers description:
|
||||
*
|
||||
* EV_RCAC_START:
|
||||
* Posted from vdev response and is handled by all three states.
|
||||
* 1. INIT handler:
|
||||
* a. Check if RCAC is already running,
|
||||
* - If yes, do not transition.
|
||||
* - If no, go to step b.
|
||||
* b. Check if a new RCAC channel can be found,
|
||||
* - If no, do not transition.
|
||||
* - If yes, transition to RUNNING.
|
||||
*
|
||||
* EV_RCAC_STOP:
|
||||
* Posted from last vap down or config disable, handled by RUNNING
|
||||
* and COMPLETE.
|
||||
* 1. RUNNING handler:
|
||||
* a. Stop the HOST RCAC timer.
|
||||
* b. Send wmi_adfs_abort_cmd to FW and transition to INIT.
|
||||
* 2. COMPLETE handler:
|
||||
* a. Send wmi_adfs_abort_cmd to FW and transition to INIT.
|
||||
*
|
||||
* EV_ADFS_RADAR:
|
||||
* Posted from radar detection and is handled in RUNNING and COMPLETE.
|
||||
* 1. RUNNING handler (same as EV_RCAC_START):
|
||||
* a. Check if RCAC was running for this pdev,
|
||||
* - If yes, transition to INIT and post EV_RCAC_START event.
|
||||
* - If no, ignore.
|
||||
* 2. COMPLETE handler (same as EV_RCAC_START):
|
||||
* a. Check if RCAC was running for this pdev,
|
||||
* - If yes, transition to INIT and post EV_RCAC_START event.
|
||||
* - If no, ignore.
|
||||
*
|
||||
* Note: EV_ADFS_RADAR works same as EV_RCAC_START event right now, but
|
||||
* will change in future, where, based on user preference, either
|
||||
* a new RCAC channel will be picked (requiring the transition to
|
||||
* INIT like present), or RCAC will be restarted on the same channel.
|
||||
*
|
||||
* EV_RCAC_DONE:
|
||||
* Posted from host RCAC timer completion and is handled in RUNNING.
|
||||
* 1. RUNNING handler:
|
||||
* a. mark RCAC done and transition to COMPLETE.
|
||||
*
|
||||
* Epilogue:
|
||||
* Rolling CAC state machine is for the entire psoc and since the
|
||||
* agile detector can run for one pdev at a time, sharing of resource is
|
||||
* required.
|
||||
* In case of ETSI preCAC, sharing was done in a round robin fashion where
|
||||
* each pdev runs ADFS for it's channels alternatively. However, in RCAC, the
|
||||
* CAC period is not defined is continuous till the next channel change.
|
||||
*
|
||||
* Hence ADFS detector is shared as follows:
|
||||
* 1. First come first serve: the pdev that is brought up first, i.e, for
|
||||
* the first vdev response, an RCAC_START is posted and this pdev will
|
||||
* hold the agile detector and run RCAC till it is stopped.
|
||||
* 2. Stopping the RCAC can be either by disabling user config "rcac_en 0"
|
||||
* or by bringing down all vaps, or if no channel is available.
|
||||
* 3. Once RCAC is stopped for a pdev, it can be started in the other pdev
|
||||
* by restarting it's vap (i.e. a vdev response).
|
||||
*
|
||||
* A working sequence of RCAC is as follows:
|
||||
* - Consider that the channel configured during bring up is 52HT80.
|
||||
* 1. The First VAP's vdev_start_resp posts an event EV_RCAC_START to the
|
||||
* RCAC state machine.
|
||||
* 2. The RCAC state machine which is in INIT state (default) receives the
|
||||
* event, picks a channel to do rolling CAC on, e.g. channel 100HT80.
|
||||
* The SM is then transitioned to RUNNING state.
|
||||
* 3. In the entry of RUNNING state, a host timer is started and agile
|
||||
* cfg cmd to FW is sent.
|
||||
* 4. When the HOST timer expires, it posts the EV_RCAC_DONE event to
|
||||
* the state machine.
|
||||
* 5. EV_RCAC_DONE event received in RUNNING state, transitions the SM
|
||||
* to COMPLETE.
|
||||
* 6. In the entry of COMPLETE, the RCAC channel is marked as CAC done
|
||||
* in the precac tree.
|
||||
* 7. If radar is detected on primary channel, the new channel is the
|
||||
* RCAC channel (100HT80) which does not require CAC if the preCAC
|
||||
* tree is marked as CAC done.
|
||||
* Before sending vdev_start, an EV_RCAC_STOP is posted
|
||||
* which moves the SM to INIT state clearing all the params and
|
||||
* bringing down the agile detector.
|
||||
* (CAC decisions are taken before).
|
||||
* 8. After vdev_resp, another EV_RCAC_START is sent to restart the
|
||||
* RCAC SM with a new RCAC channel if available.
|
||||
*
|
||||
* A future enhancement will be triggering RCAC_START at user level.
|
||||
*/
|
||||
|
||||
/**
|
||||
* dfs_agile_set_curr_state() - API to set the current state of Agile SM.
|
||||
* @dfs_soc_obj: Pointer to DFS soc private object.
|
||||
* @state: value of current state.
|
||||
*
|
||||
* Return: void.
|
||||
*/
|
||||
static void dfs_agile_set_curr_state(struct dfs_soc_priv_obj *dfs_soc_obj,
|
||||
enum dfs_agile_sm_state state)
|
||||
{
|
||||
if (state < DFS_AGILE_S_MAX) {
|
||||
dfs_soc_obj->dfs_agile_sm_cur_state = state;
|
||||
} else {
|
||||
dfs_err(NULL, WLAN_DEBUG_DFS_ALWAYS,
|
||||
"DFS RCAC state (%d) is invalid", state);
|
||||
QDF_BUG(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dfs_agile_get_curr_state() - API to get current state of Agile SM.
|
||||
* @dfs_soc_obj: Pointer to DFS soc private object.
|
||||
*
|
||||
* Return: current state enum of type, dfs_rcac_sm_state.
|
||||
*/
|
||||
static enum dfs_agile_sm_state
|
||||
dfs_agile_get_curr_state(struct dfs_soc_priv_obj *dfs_soc_obj)
|
||||
{
|
||||
return dfs_soc_obj->dfs_agile_sm_cur_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* dfs_rcac_sm_transition_to() - Wrapper API to transition the Agile SM state.
|
||||
* @dfs_soc_obj: Pointer to dfs soc private object that hold the SM handle.
|
||||
* @state: State to which the SM is transitioning to.
|
||||
*
|
||||
* Return: void.
|
||||
*/
|
||||
static void dfs_agile_sm_transition_to(struct dfs_soc_priv_obj *dfs_soc_obj,
|
||||
enum dfs_agile_sm_state state)
|
||||
{
|
||||
wlan_sm_transition_to(dfs_soc_obj->dfs_agile_sm_hdl, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* dfs_agile_sm_deliver_event() - API to post events to Agile SM.
|
||||
* @dfs_soc_obj: Pointer to dfs soc private object.
|
||||
* @event: Event to be posted to the RCAC SM.
|
||||
* @event_data_len: Length of event data.
|
||||
* @event_data: Pointer to event data.
|
||||
*
|
||||
* Return: QDF_STATUS_SUCCESS on handling the event, else failure.
|
||||
*
|
||||
* Note: This version of event posting API is not under lock and hence
|
||||
* should only be called for posting events within the SM and not be
|
||||
* under a dispatcher API without a lock.
|
||||
*/
|
||||
static
|
||||
QDF_STATUS dfs_agile_sm_deliver_event(struct dfs_soc_priv_obj *dfs_soc_obj,
|
||||
enum dfs_agile_sm_evt event,
|
||||
uint16_t event_data_len,
|
||||
void *event_data)
|
||||
{
|
||||
return wlan_sm_dispatch(dfs_soc_obj->dfs_agile_sm_hdl,
|
||||
event,
|
||||
event_data_len,
|
||||
event_data);
|
||||
}
|
||||
|
||||
#ifdef QCA_SUPPORT_ADFS_RCAC
|
||||
/* dfs_start_agile_rcac_timer() - Start host agile RCAC timer.
|
||||
*
|
||||
* @dfs: Pointer to struct wlan_dfs.
|
||||
*/
|
||||
void dfs_start_agile_rcac_timer(struct wlan_dfs *dfs)
|
||||
{
|
||||
struct dfs_soc_priv_obj *dfs_soc_obj = dfs->dfs_soc_obj;
|
||||
uint32_t rcac_timeout = MIN_RCAC_DURATION;
|
||||
|
||||
dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
|
||||
"Host RCAC timeout = %d ms", rcac_timeout);
|
||||
|
||||
qdf_timer_mod(&dfs_soc_obj->dfs_rcac_timer,
|
||||
rcac_timeout);
|
||||
}
|
||||
|
||||
|
||||
/* dfs_stop_agile_rcac_timer() - Cancel the RCAC timer.
|
||||
*
|
||||
* @dfs: Pointer to struct wlan_dfs.
|
||||
*/
|
||||
void dfs_stop_agile_rcac_timer(struct wlan_dfs *dfs)
|
||||
{
|
||||
struct dfs_soc_priv_obj *dfs_soc_obj;
|
||||
|
||||
dfs_soc_obj = dfs->dfs_soc_obj;
|
||||
qdf_timer_sync_cancel(&dfs_soc_obj->dfs_rcac_timer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* dfs_abort_agile_rcac() - Send abort Agile RCAC to F/W.
|
||||
* @dfs: Pointer to struct wlan_dfs.
|
||||
*/
|
||||
static void dfs_abort_agile_rcac(struct wlan_dfs *dfs)
|
||||
{
|
||||
|
||||
struct wlan_objmgr_psoc *psoc;
|
||||
struct wlan_lmac_if_dfs_tx_ops *dfs_tx_ops;
|
||||
|
||||
dfs_stop_agile_rcac_timer(dfs);
|
||||
psoc = wlan_pdev_get_psoc(dfs->dfs_pdev_obj);
|
||||
dfs_tx_ops = wlan_psoc_get_dfs_txops(psoc);
|
||||
if (dfs_tx_ops && dfs_tx_ops->dfs_ocac_abort_cmd)
|
||||
dfs_tx_ops->dfs_ocac_abort_cmd(dfs->dfs_pdev_obj);
|
||||
|
||||
qdf_mem_zero(&dfs->dfs_rcac_param, sizeof(struct dfs_rcac_params));
|
||||
dfs->dfs_agile_precac_freq_mhz = 0;
|
||||
dfs->dfs_precac_chwidth = CH_WIDTH_INVALID;
|
||||
dfs->dfs_soc_obj->cur_agile_dfs_index = DFS_PSOC_NO_IDX;
|
||||
}
|
||||
#else
|
||||
static inline void dfs_abort_agile_rcac(struct wlan_dfs *dfs)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/* dfs_abort_agile_precac() - Reset parameters of wlan_dfs and send abort
|
||||
* to F/W.
|
||||
* @dfs: Pointer to struct wlan_dfs.
|
||||
*/
|
||||
static void dfs_abort_agile_precac(struct wlan_dfs *dfs)
|
||||
{
|
||||
struct wlan_objmgr_psoc *psoc;
|
||||
struct wlan_lmac_if_dfs_tx_ops *dfs_tx_ops;
|
||||
|
||||
psoc = wlan_pdev_get_psoc(dfs->dfs_pdev_obj);
|
||||
dfs_tx_ops = wlan_psoc_get_dfs_txops(psoc);
|
||||
|
||||
dfs_agile_precac_cleanup(dfs);
|
||||
/*Send the abort to F/W as well */
|
||||
if (dfs_tx_ops && dfs_tx_ops->dfs_ocac_abort_cmd)
|
||||
dfs_tx_ops->dfs_ocac_abort_cmd(dfs->dfs_pdev_obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* dfs_agile_state_init_entry() - Entry API for INIT state
|
||||
* @ctx: DFS SoC private object
|
||||
*
|
||||
* API to perform operations on moving to INIT state
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
static void dfs_agile_state_init_entry(void *ctx)
|
||||
{
|
||||
struct dfs_soc_priv_obj *dfs_soc = (struct dfs_soc_priv_obj *)ctx;
|
||||
|
||||
dfs_agile_set_curr_state(dfs_soc, DFS_AGILE_S_INIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* dfs_agile_state_init_exit() - Exit API for INIT state
|
||||
* @ctx: DFS SoC private object
|
||||
*
|
||||
* API to perform operations on moving out of INIT state
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
static void dfs_agile_state_init_exit(void *ctx)
|
||||
{
|
||||
/* NO OPS */
|
||||
}
|
||||
|
||||
/**
|
||||
* dfs_init_agile_start_evt_handler() - Init state start event handler.
|
||||
* @dfs: Instance of wlan_dfs structure.
|
||||
* @dfs_soc: DFS SoC private object
|
||||
*
|
||||
* Return : True if PreCAC/RCAC chan is found.
|
||||
*/
|
||||
static bool dfs_init_agile_start_evt_handler(struct wlan_dfs *dfs,
|
||||
struct dfs_soc_priv_obj *dfs_soc)
|
||||
{
|
||||
bool is_chan_found = false;
|
||||
|
||||
/*For RCAC */
|
||||
if (dfs_is_agile_rcac_enabled(dfs)) {
|
||||
/* Check if feature is enabled for this DFS and if RCAC channel
|
||||
* is valid, if those are true, send appropriate WMIs to FW
|
||||
* and only then transition to the state as follows.
|
||||
*/
|
||||
dfs_prepare_agile_rcac_channel(dfs, &is_chan_found);
|
||||
}
|
||||
/*For PreCAC */
|
||||
else if (dfs_is_agile_precac_enabled(dfs)) {
|
||||
dfs_soc->dfs_priv[dfs->dfs_psoc_idx].agile_precac_active
|
||||
= true;
|
||||
if (!dfs_soc->precac_state_started &&
|
||||
!dfs_soc->dfs_precac_timer_running) {
|
||||
dfs_soc->precac_state_started = true;
|
||||
dfs_prepare_agile_precac_chan(dfs, &is_chan_found);
|
||||
}
|
||||
}
|
||||
|
||||
return is_chan_found;
|
||||
}
|
||||
|
||||
/**
|
||||
* dfs_agile_state_init_event() - INIT State event handler
|
||||
* @ctx: DFS SoC private object
|
||||
* @event: Event posted to the SM.
|
||||
* @event_data_len: Length of event data.
|
||||
* @event_data: Pointer to event data.
|
||||
*
|
||||
* API to handle events in INIT state
|
||||
*
|
||||
* Return: TRUE: on handling event
|
||||
* FALSE: on ignoring the event
|
||||
*/
|
||||
static bool dfs_agile_state_init_event(void *ctx,
|
||||
uint16_t event,
|
||||
uint16_t event_data_len,
|
||||
void *event_data)
|
||||
{
|
||||
struct dfs_soc_priv_obj *dfs_soc = (struct dfs_soc_priv_obj *)ctx;
|
||||
bool status;
|
||||
struct wlan_dfs *dfs;
|
||||
bool is_chan_found;
|
||||
|
||||
if (!event_data)
|
||||
return false;
|
||||
|
||||
dfs = (struct wlan_dfs *)event_data;
|
||||
|
||||
switch (event) {
|
||||
case DFS_AGILE_SM_EV_AGILE_START:
|
||||
|
||||
if (dfs_soc->cur_agile_dfs_index != DFS_PSOC_NO_IDX)
|
||||
return true;
|
||||
|
||||
is_chan_found = dfs_init_agile_start_evt_handler(dfs,
|
||||
dfs_soc);
|
||||
if (is_chan_found) {
|
||||
dfs_soc->cur_agile_dfs_index = dfs->dfs_psoc_idx;
|
||||
dfs_agile_sm_transition_to(dfs_soc,
|
||||
DFS_AGILE_S_RUNNING);
|
||||
} else {
|
||||
/*
|
||||
* This happens when there is no preCAC chan
|
||||
* in any of the radios
|
||||
*/
|
||||
dfs_agile_precac_cleanup(dfs);
|
||||
/* Cleanup and wait */
|
||||
}
|
||||
|
||||
status = true;
|
||||
break;
|
||||
default:
|
||||
status = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* dfs_agile_state_running_entry() - Entry API for running state
|
||||
* @ctx: DFS SoC private object
|
||||
*
|
||||
* API to perform operations on moving to running state
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
static void dfs_agile_state_running_entry(void *ctx)
|
||||
{
|
||||
struct dfs_soc_priv_obj *dfs_soc = (struct dfs_soc_priv_obj *)ctx;
|
||||
struct wlan_dfs *dfs =
|
||||
dfs_soc->dfs_priv[dfs_soc->cur_agile_dfs_index].dfs;
|
||||
|
||||
dfs_agile_set_curr_state(dfs_soc, DFS_AGILE_S_RUNNING);
|
||||
|
||||
/* RCAC */
|
||||
if (dfs_is_agile_rcac_enabled(dfs)) {
|
||||
dfs_start_agile_rcac_timer(dfs);
|
||||
dfs_start_agile_engine(dfs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dfs_agile_state_running_exit() - Exit API for RUNNING state
|
||||
* @ctx: DFS SoC private object
|
||||
*
|
||||
* API to perform operations on moving out of RUNNING state
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
static void dfs_agile_state_running_exit(void *ctx)
|
||||
{
|
||||
/* NO OPS */
|
||||
}
|
||||
|
||||
/**
|
||||
* dfs_agile_state_running_event() - RUNNING State event handler
|
||||
* @ctx: DFS SoC private object
|
||||
* @event: Event posted to the SM.
|
||||
* @event_data_len: Length of event data.
|
||||
* @event_data: Pointer to event data.
|
||||
*
|
||||
* API to handle events in RUNNING state
|
||||
*
|
||||
* Return: TRUE: on handling event
|
||||
* FALSE: on ignoring the event
|
||||
*/
|
||||
static bool dfs_agile_state_running_event(void *ctx,
|
||||
uint16_t event,
|
||||
uint16_t event_data_len,
|
||||
void *event_data)
|
||||
{
|
||||
struct dfs_soc_priv_obj *dfs_soc = (struct dfs_soc_priv_obj *)ctx;
|
||||
bool status;
|
||||
struct wlan_dfs *dfs;
|
||||
bool is_cac_done_on_des_chan;
|
||||
|
||||
if (!event_data)
|
||||
return false;
|
||||
|
||||
dfs = (struct wlan_dfs *)event_data;
|
||||
|
||||
if (dfs->dfs_psoc_idx != dfs_soc->cur_agile_dfs_index)
|
||||
return false;
|
||||
|
||||
switch (event) {
|
||||
case DFS_AGILE_SM_EV_ADFS_RADAR:
|
||||
/* After radar is found on the Agile channel we need to find
|
||||
* a new channel and then start Agile CAC on that.
|
||||
* On receiving the "DFS_AGILE_SM_EV_ADFS_RADAR_FOUND" if
|
||||
* we change the state from [RUNNING] -> [RUNNING] then
|
||||
* [RUNNING] should handle case in which a channel is not found
|
||||
* and bring the state machine back to INIT.
|
||||
* Instead we move the state to INIT and post the event
|
||||
* "DFS_AGILE_SM_EV_AGILE_START" so INIT handles the case of
|
||||
* channel not found and stay in that state.
|
||||
* Abort the existing RCAC and restart from INIT state.
|
||||
*/
|
||||
if (dfs_is_agile_rcac_enabled(dfs))
|
||||
dfs_abort_agile_rcac(dfs);
|
||||
else if (dfs_is_agile_precac_enabled(dfs))
|
||||
dfs_abort_agile_precac(dfs);
|
||||
|
||||
dfs_agile_sm_transition_to(dfs_soc, DFS_AGILE_S_INIT);
|
||||
dfs_agile_sm_deliver_event(dfs_soc,
|
||||
DFS_AGILE_SM_EV_AGILE_START,
|
||||
event_data_len,
|
||||
event_data);
|
||||
|
||||
status = true;
|
||||
break;
|
||||
case DFS_AGILE_SM_EV_AGILE_STOP:
|
||||
if (dfs_is_agile_rcac_enabled(dfs))
|
||||
dfs_abort_agile_rcac(dfs);
|
||||
else if (dfs_is_agile_precac_enabled(dfs))
|
||||
dfs_abort_agile_precac(dfs);
|
||||
|
||||
dfs_agile_sm_transition_to(dfs_soc, DFS_AGILE_S_INIT);
|
||||
status = true;
|
||||
break;
|
||||
case DFS_AGILE_SM_EV_AGILE_DONE:
|
||||
if (dfs_is_agile_precac_enabled(dfs)) {
|
||||
if (dfs_soc->ocac_status == OCAC_SUCCESS) {
|
||||
dfs_soc->ocac_status = OCAC_RESET;
|
||||
dfs_mark_adfs_chan_as_cac_done(dfs);
|
||||
}
|
||||
dfs_agile_sm_transition_to(dfs_soc, DFS_AGILE_S_INIT);
|
||||
dfs_agile_precac_cleanup(dfs);
|
||||
is_cac_done_on_des_chan =
|
||||
dfs_precac_check_home_chan_change(dfs);
|
||||
if (!is_cac_done_on_des_chan) {
|
||||
dfs_agile_sm_deliver_event(dfs_soc,
|
||||
DFS_AGILE_SM_EV_AGILE_START,
|
||||
event_data_len,
|
||||
event_data);
|
||||
}
|
||||
} else if (dfs_is_agile_rcac_enabled(dfs)) {
|
||||
dfs_agile_sm_transition_to(dfs_soc,
|
||||
DFS_AGILE_S_COMPLETE);
|
||||
}
|
||||
status = true;
|
||||
break;
|
||||
default:
|
||||
status = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* dfs_agile_state_complete_entry() - Entry API for complete state
|
||||
* @ctx: DFS SoC private object
|
||||
*
|
||||
* API to perform operations on moving to complete state
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
static void dfs_agile_state_complete_entry(void *ctx)
|
||||
{
|
||||
struct dfs_soc_priv_obj *dfs_soc_obj = (struct dfs_soc_priv_obj *)ctx;
|
||||
struct wlan_dfs *dfs;
|
||||
|
||||
dfs_agile_set_curr_state(dfs_soc_obj, DFS_AGILE_S_COMPLETE);
|
||||
|
||||
if (!(dfs_soc_obj->cur_agile_dfs_index < WLAN_UMAC_MAX_PDEVS))
|
||||
return;
|
||||
|
||||
dfs = dfs_soc_obj->dfs_priv[dfs_soc_obj->cur_agile_dfs_index].dfs;
|
||||
|
||||
/* Mark the RCAC channel as CAC done. */
|
||||
dfs_mark_adfs_chan_as_cac_done(dfs);
|
||||
}
|
||||
|
||||
/**
|
||||
* dfs_agile_state_complete_exit() - Exit API for complete state
|
||||
* @ctx: DFS SoC private object
|
||||
*
|
||||
* API to perform operations on moving out of complete state
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
static void dfs_agile_state_complete_exit(void *ctx)
|
||||
{
|
||||
/* NO OPs. */
|
||||
}
|
||||
|
||||
/**
|
||||
* dfs_agile_state_complete_event() - COMPLETE State event handler
|
||||
* @ctx: DFS SoC private object
|
||||
* @event: Event posted to the SM.
|
||||
* @event_data_len: Length of event data.
|
||||
* @event_data: Pointer to event data.
|
||||
*
|
||||
* API to handle events in COMPLETE state
|
||||
*
|
||||
* Return: TRUE: on handling event
|
||||
* FALSE: on ignoring the event
|
||||
*/
|
||||
static bool dfs_agile_state_complete_event(void *ctx,
|
||||
uint16_t event,
|
||||
uint16_t event_data_len,
|
||||
void *event_data)
|
||||
{
|
||||
struct dfs_soc_priv_obj *dfs_soc = (struct dfs_soc_priv_obj *)ctx;
|
||||
bool status;
|
||||
struct wlan_dfs *dfs;
|
||||
|
||||
if (!event_data)
|
||||
return false;
|
||||
|
||||
dfs = (struct wlan_dfs *)event_data;
|
||||
|
||||
if (dfs->dfs_psoc_idx != dfs_soc->cur_agile_dfs_index)
|
||||
return false;
|
||||
|
||||
switch (event) {
|
||||
case DFS_AGILE_SM_EV_ADFS_RADAR:
|
||||
/* Reset the RCAC done state for this RCAC chan of this dfs.
|
||||
* Unmark the channels for RCAC done before calling abort API as
|
||||
* the abort API invalidates the cur_agile_dfs_index.
|
||||
*/
|
||||
dfs_unmark_rcac_done(dfs);
|
||||
/* Abort the existing RCAC and restart from INIT state. */
|
||||
dfs_abort_agile_rcac(dfs);
|
||||
dfs_agile_sm_transition_to(dfs_soc, DFS_AGILE_S_INIT);
|
||||
dfs_agile_sm_deliver_event(dfs_soc,
|
||||
DFS_AGILE_SM_EV_AGILE_START,
|
||||
event_data_len,
|
||||
event_data);
|
||||
status = true;
|
||||
break;
|
||||
case DFS_AGILE_SM_EV_AGILE_STOP:
|
||||
/* Reset the RCAC done state for this RCAC chan of this dfs.
|
||||
* Unmark the channels for RCAC done before calling abort API as
|
||||
* the abort API invalidates the cur_agile_dfs_index.
|
||||
*/
|
||||
dfs_unmark_rcac_done(dfs);
|
||||
dfs_abort_agile_rcac(dfs);
|
||||
dfs_agile_sm_transition_to(dfs_soc, DFS_AGILE_S_INIT);
|
||||
status = true;
|
||||
break;
|
||||
default:
|
||||
status = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct wlan_sm_state_info dfs_agile_sm_info[] = {
|
||||
{
|
||||
(uint8_t)DFS_AGILE_S_INIT,
|
||||
(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
|
||||
(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
|
||||
false,
|
||||
"INIT",
|
||||
dfs_agile_state_init_entry,
|
||||
dfs_agile_state_init_exit,
|
||||
dfs_agile_state_init_event
|
||||
},
|
||||
{
|
||||
(uint8_t)DFS_AGILE_S_RUNNING,
|
||||
(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
|
||||
(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
|
||||
false,
|
||||
"RUNNING",
|
||||
dfs_agile_state_running_entry,
|
||||
dfs_agile_state_running_exit,
|
||||
dfs_agile_state_running_event
|
||||
},
|
||||
{
|
||||
(uint8_t)DFS_AGILE_S_COMPLETE,
|
||||
(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
|
||||
(uint8_t)WLAN_SM_ENGINE_STATE_NONE,
|
||||
false,
|
||||
"COMPLETE",
|
||||
dfs_agile_state_complete_entry,
|
||||
dfs_agile_state_complete_exit,
|
||||
dfs_agile_state_complete_event
|
||||
},
|
||||
};
|
||||
|
||||
static const char *dfs_agile_sm_event_names[] = {
|
||||
"EV_AGILE_START",
|
||||
"EV_AGILE_STOP",
|
||||
"EV_AGILE_DONE",
|
||||
"EV_ADFS_RADAR_FOUND",
|
||||
};
|
||||
|
||||
/**
|
||||
* dfs_agile_sm_print_state() - API to log the current state.
|
||||
* @dfs_soc_obj: Pointer to dfs soc private object.
|
||||
*
|
||||
* Return: void.
|
||||
*/
|
||||
static void dfs_agile_sm_print_state(struct dfs_soc_priv_obj *dfs_soc_obj)
|
||||
{
|
||||
enum dfs_agile_sm_state state;
|
||||
|
||||
state = dfs_agile_get_curr_state(dfs_soc_obj);
|
||||
if (!(state < DFS_AGILE_S_MAX))
|
||||
return;
|
||||
|
||||
dfs_debug(NULL, WLAN_DEBUG_DFS_AGILE, "->[%s] %s",
|
||||
dfs_soc_obj->dfs_agile_sm_hdl->name,
|
||||
dfs_agile_sm_info[state].name);
|
||||
}
|
||||
|
||||
/**
|
||||
* dfs_agile_sm_print_state_event() - API to log the current state and event
|
||||
* received.
|
||||
* @dfs_soc_obj: Pointer to dfs soc private object.
|
||||
* @event: Event posted to RCAC SM.
|
||||
*
|
||||
* Return: void.
|
||||
*/
|
||||
static void dfs_agile_sm_print_state_event(struct dfs_soc_priv_obj *dfs_soc_obj,
|
||||
enum dfs_agile_sm_evt event)
|
||||
{
|
||||
enum dfs_agile_sm_state state;
|
||||
|
||||
state = dfs_agile_get_curr_state(dfs_soc_obj);
|
||||
if (!(state < DFS_AGILE_S_MAX))
|
||||
return;
|
||||
|
||||
dfs_debug(NULL, WLAN_DEBUG_DFS_AGILE, "[%s]%s, %s",
|
||||
dfs_soc_obj->dfs_agile_sm_hdl->name,
|
||||
dfs_agile_sm_info[state].name,
|
||||
dfs_agile_sm_event_names[event]);
|
||||
}
|
||||
|
||||
QDF_STATUS dfs_agile_sm_deliver_evt(struct dfs_soc_priv_obj *dfs_soc_obj,
|
||||
enum dfs_agile_sm_evt event,
|
||||
uint16_t event_data_len,
|
||||
void *event_data)
|
||||
{
|
||||
enum dfs_agile_sm_state old_state, new_state;
|
||||
QDF_STATUS status;
|
||||
|
||||
DFS_AGILE_SM_SPIN_LOCK(dfs_soc_obj);
|
||||
old_state = dfs_agile_get_curr_state(dfs_soc_obj);
|
||||
|
||||
/* Print current state and event received */
|
||||
dfs_agile_sm_print_state_event(dfs_soc_obj, event);
|
||||
|
||||
status = dfs_agile_sm_deliver_event(dfs_soc_obj, event,
|
||||
event_data_len, event_data);
|
||||
|
||||
new_state = dfs_agile_get_curr_state(dfs_soc_obj);
|
||||
|
||||
/* Print new state after event if transition happens */
|
||||
if (old_state != new_state)
|
||||
dfs_agile_sm_print_state(dfs_soc_obj);
|
||||
DFS_AGILE_SM_SPIN_UNLOCK(dfs_soc_obj);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
QDF_STATUS dfs_agile_sm_create(struct dfs_soc_priv_obj *dfs_soc_obj)
|
||||
{
|
||||
struct wlan_sm *sm;
|
||||
|
||||
sm = wlan_sm_create("DFS_AGILE", dfs_soc_obj,
|
||||
DFS_AGILE_S_INIT,
|
||||
dfs_agile_sm_info,
|
||||
QDF_ARRAY_SIZE(dfs_agile_sm_info),
|
||||
dfs_agile_sm_event_names,
|
||||
QDF_ARRAY_SIZE(dfs_agile_sm_event_names));
|
||||
if (!sm) {
|
||||
qdf_err("DFS AGILE SM allocation failed");
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
}
|
||||
dfs_soc_obj->dfs_agile_sm_hdl = sm;
|
||||
|
||||
qdf_spinlock_create(&dfs_soc_obj->dfs_agile_sm_lock);
|
||||
|
||||
/* Initialize the RCAC DFS index to default (no index). */
|
||||
dfs_soc_obj->cur_agile_dfs_index = DFS_PSOC_NO_IDX;
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
QDF_STATUS dfs_agile_sm_destroy(struct dfs_soc_priv_obj *dfs_soc_obj)
|
||||
{
|
||||
wlan_sm_delete(dfs_soc_obj->dfs_agile_sm_hdl);
|
||||
qdf_spinlock_destroy(&dfs_soc_obj->dfs_agile_sm_lock);
|
||||
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef QCA_SUPPORT_ADFS_RCAC
|
||||
QDF_STATUS dfs_set_rcac_enable(struct wlan_dfs *dfs, bool rcac_en)
|
||||
{
|
||||
if (rcac_en == dfs->dfs_agile_rcac_ucfg) {
|
||||
dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
|
||||
"Rolling CAC: %d is already configured", rcac_en);
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
dfs->dfs_agile_rcac_ucfg = rcac_en;
|
||||
|
||||
/* RCAC config is changed. Reset the preCAC tree. */
|
||||
dfs_reset_precac_lists(dfs);
|
||||
|
||||
if (!rcac_en) {
|
||||
dfs_agile_sm_deliver_evt(dfs->dfs_soc_obj,
|
||||
DFS_AGILE_SM_EV_AGILE_STOP,
|
||||
0,
|
||||
(void *)dfs);
|
||||
}
|
||||
dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "rolling cac is %d", rcac_en);
|
||||
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
QDF_STATUS dfs_get_rcac_enable(struct wlan_dfs *dfs, bool *rcacen)
|
||||
{
|
||||
*rcacen = dfs->dfs_agile_rcac_ucfg;
|
||||
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
QDF_STATUS dfs_set_rcac_freq(struct wlan_dfs *dfs, qdf_freq_t rcac_freq)
|
||||
{
|
||||
if (wlan_reg_is_5ghz_ch_freq(rcac_freq))
|
||||
dfs->dfs_agile_rcac_freq_ucfg = rcac_freq;
|
||||
else
|
||||
dfs->dfs_agile_rcac_freq_ucfg = 0;
|
||||
|
||||
dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "rolling cac freq %d",
|
||||
dfs->dfs_agile_rcac_freq_ucfg);
|
||||
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
QDF_STATUS dfs_get_rcac_freq(struct wlan_dfs *dfs, qdf_freq_t *rcac_freq)
|
||||
{
|
||||
*rcac_freq = dfs->dfs_agile_rcac_freq_ucfg;
|
||||
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rolling CAC Timer timeout function. Following actions are done
|
||||
* on timer expiry:
|
||||
* Timer running flag is cleared.
|
||||
* If the rolling CAC state is completed, the RCAC freq and its sub-channels
|
||||
* are marked as 'CAC Done' in the preCAC tree.
|
||||
*/
|
||||
static os_timer_func(dfs_rcac_timeout)
|
||||
{
|
||||
struct wlan_dfs *dfs;
|
||||
struct dfs_soc_priv_obj *dfs_soc_obj;
|
||||
|
||||
OS_GET_TIMER_ARG(dfs_soc_obj, struct dfs_soc_priv_obj *);
|
||||
|
||||
dfs = dfs_soc_obj->dfs_priv[dfs_soc_obj->cur_agile_dfs_index].dfs;
|
||||
|
||||
dfs_agile_sm_deliver_evt(dfs_soc_obj,
|
||||
DFS_AGILE_SM_EV_AGILE_DONE,
|
||||
0,
|
||||
(void *)dfs);
|
||||
}
|
||||
|
||||
void dfs_rcac_timer_init(struct dfs_soc_priv_obj *dfs_soc_obj)
|
||||
{
|
||||
qdf_timer_init(NULL, &dfs_soc_obj->dfs_rcac_timer,
|
||||
dfs_rcac_timeout,
|
||||
(void *)dfs_soc_obj,
|
||||
QDF_TIMER_TYPE_WAKE_APPS);
|
||||
}
|
||||
|
||||
void dfs_rcac_timer_deinit(struct dfs_soc_priv_obj *dfs_soc_obj)
|
||||
{
|
||||
qdf_timer_free(&dfs_soc_obj->dfs_rcac_timer);
|
||||
}
|
||||
|
||||
/* dfs_prepare_agile_rcac_channel() - Find a valid Rolling CAC channel if
|
||||
* available.
|
||||
*
|
||||
* @dfs: Pointer to struct wlan_dfs.
|
||||
* @is_rcac_chan_available: Flag to indicate if a valid RCAC channel is
|
||||
* available.
|
||||
*/
|
||||
void dfs_prepare_agile_rcac_channel(struct wlan_dfs *dfs,
|
||||
bool *is_rcac_chan_available)
|
||||
{
|
||||
qdf_freq_t rcac_ch_freq = 0;
|
||||
|
||||
/* Find out a valid rcac_ch_freq */
|
||||
dfs_set_agilecac_chan_for_freq(dfs, &rcac_ch_freq, 0, 0);
|
||||
|
||||
/* If RCAC channel is available, the caller will start the timer and
|
||||
* send RCAC config to FW. If channel not available, the caller takes
|
||||
* care of sending RCAC abort and moving SM to INIT, resetting the RCAC
|
||||
* variables.
|
||||
*/
|
||||
*is_rcac_chan_available = rcac_ch_freq ? true : false;
|
||||
dfs_debug(dfs, WLAN_DEBUG_DFS_AGILE, "Chosen rcac channel: %d",
|
||||
rcac_ch_freq);
|
||||
}
|
||||
#endif
|
||||
#endif
|
1871
umac/dfs/core/src/misc/dfs_precac_list.c
Normal file
1871
umac/dfs/core/src/misc/dfs_precac_list.c
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user