Merge "qca-wifi: Split dfs_zero_cac.c into multiple files"

Esse commit está contido em:
Linux Build Service Account
2020-12-02 21:08:41 -08:00
commit de Gerrit - the friendly Code Review server
4 arquivos alterados com 3233 adições e 3059 exclusões

Ver arquivo

@@ -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_ */

Ver arquivo

@@ -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

Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff

Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff