qcacld-3.0: Handle DFS channel radar history get vendor command

Add support for QCA_NL80211_VENDOR_SUBCMD_GET_RADAR_HISTORY vendor
command. This command will return the current NOL list in driver
and the last Radar detection result in previous SAP active state
(includes CAC state).

Change-Id: I719630c39b89c1813ca05c4356dce627d72d82e2
CRs-Fixed: 2966501
This commit is contained in:
Liangwei Dong
2021-06-03 16:25:37 +08:00
committed by Madan Koyyalamudi
parent ed537c76da
commit 3ad4f9d78b
6 changed files with 461 additions and 1 deletions

View File

@@ -615,6 +615,35 @@ typedef struct sSapDfsInfo {
uint16_t reduced_beacon_interval;
} tSapDfsInfo;
/* MAX number of CAC channels to be recorded */
#define MAX_NUM_OF_CAC_HISTORY 8
/**
* struct prev_cac_result - previous cac result
* @ap_start_time: ap start timestamp
* @ap_end_time: ap stop or cac end timestamp
* @cac_complete: cac complete without found radar event
* @cac_ch_param: ap channel parameters
*/
struct prev_cac_result {
uint64_t ap_start_time;
uint64_t ap_end_time;
bool cac_complete;
struct ch_params cac_ch_param;
};
/**
* struct dfs_radar_history - radar found history element
* @time: timestamp in us from system boot
* @radar_found: radar found or not
* @ch_freq: channel frequency in Mhz
*/
struct dfs_radar_history {
uint64_t time;
bool radar_found;
uint16_t ch_freq;
};
#ifdef DCS_INTERFERENCE_DETECTION
/**
* struct sap_dcs_info - record sap dcs information.
@@ -1546,6 +1575,24 @@ uint32_t wlansap_get_safe_channel_from_pcl_for_sap(struct sap_context *sap_ctx);
qdf_freq_t wlansap_get_chan_band_restrict(struct sap_context *sap_ctx,
enum sap_csa_reason_code *csa_reason);
#ifdef FEATURE_RADAR_HISTORY
/**
* wlansap_query_radar_history() - get radar history info
* @mac_handle: mac context
* @radar_history: radar history buffer to be returned
* @count: total history count
*
* The API will return the dfs nol list(Radar found history) and
* CAC history (no Radar found).
*
* Return - QDF_STATUS
*/
QDF_STATUS
wlansap_query_radar_history(mac_handle_t mac_handle,
struct dfs_radar_history **radar_history,
uint32_t *count);
#endif
#ifdef DCS_INTERFERENCE_DETECTION
/**
* wlansap_dcs_set_vdev_wlan_interference_mitigation() - set wlan

View File

@@ -1402,6 +1402,245 @@ static bool sap_save_owe_pending_assoc_ind(struct sap_context *sap_ctx,
return true;
}
#ifdef FEATURE_RADAR_HISTORY
/* Last cac result */
static struct prev_cac_result prev_cac_history;
/**
* sap_update_cac_history() - record SAP Radar found result in last
* "active" or CAC period
* @mac_ctx: mac context
* @sap_ctx: sap context
* @event_id: sap event
*
* The function is to save the dfs channel information
* If SAP has been "active" or "CAC" on DFS channel for 60s and
* no found radar event.
*
* Return: void
*/
static void
sap_update_cac_history(struct mac_context *mac_ctx,
struct sap_context *sap_ctx,
eSapHddEvent event_id)
{
struct prev_cac_result *cac_result = &sap_ctx->cac_result;
switch (event_id) {
case eSAP_START_BSS_EVENT:
case eSAP_CHANNEL_CHANGE_RESP:
case eSAP_DFS_CAC_START:
if (sap_operating_on_dfs(mac_ctx, sap_ctx)) {
qdf_mem_zero(cac_result,
sizeof(struct prev_cac_result));
if (!sap_ctx->ch_params.mhz_freq_seg0) {
sap_debug("invalid seq0");
return;
}
cac_result->ap_start_time =
qdf_get_monotonic_boottime();
cac_result->cac_ch_param = sap_ctx->ch_params;
sap_debug("ap start(CAC) (%d, %d) bw %d",
cac_result->cac_ch_param.mhz_freq_seg0,
cac_result->cac_ch_param.mhz_freq_seg1,
cac_result->cac_ch_param.ch_width);
}
break;
case eSAP_DFS_RADAR_DETECT:
qdf_mem_zero(cac_result,
sizeof(struct prev_cac_result));
break;
case eSAP_DFS_CAC_END:
case eSAP_STOP_BSS_EVENT:
if (cac_result->ap_start_time) {
uint64_t diff_ms;
cac_result->ap_end_time =
qdf_get_monotonic_boottime();
diff_ms = qdf_do_div(cac_result->ap_end_time -
cac_result->ap_start_time, 1000);
if (diff_ms < DEFAULT_CAC_TIMEOUT - 5000) {
if (event_id == eSAP_STOP_BSS_EVENT)
qdf_mem_zero(
cac_result,
sizeof(struct prev_cac_result));
sap_debug("ap cac dur %llu ms", diff_ms);
break;
}
cac_result->cac_complete = true;
qdf_mem_copy(&prev_cac_history, cac_result,
sizeof(struct prev_cac_result));
sap_debug("ap cac saved %llu ms %llu (%d, %d) bw %d",
diff_ms,
cac_result->ap_end_time,
cac_result->cac_ch_param.mhz_freq_seg0,
cac_result->cac_ch_param.mhz_freq_seg1,
cac_result->cac_ch_param.ch_width);
if (event_id == eSAP_STOP_BSS_EVENT)
qdf_mem_zero(cac_result,
sizeof(struct prev_cac_result));
}
break;
default:
break;
}
}
/**
* find_ch_freq_in_radar_hist() - check channel frequency existing
* in radar history buffer
* @radar_result: radar history buffer
* @count: radar history element number
* @ch_freq: channel frequency
*
* Return: bool
*/
static
bool find_ch_freq_in_radar_hist(struct dfs_radar_history *radar_result,
uint32_t count, uint16_t ch_freq)
{
while (count) {
if (radar_result->ch_freq == ch_freq)
return true;
radar_result++;
count--;
}
return false;
}
/**
* sap_append_cac_history() - Add CAC history to list
* @radar_result: radar history buffer
* @idx: current radar history element number
* @max_elems: max elements nummber of radar history buffer.
*
* This function is to add the CAC history to radar history list.
*
* Return: void
*/
static
void sap_append_cac_history(struct mac_context *mac_ctx,
struct dfs_radar_history *radar_result,
uint32_t *idx, uint32_t max_elems)
{
struct prev_cac_result *cac_result = &prev_cac_history;
struct ch_params ch_param = cac_result->cac_ch_param;
uint32_t count = *idx;
if (!cac_result->cac_complete || !cac_result->ap_end_time) {
sap_debug("cac hist empty");
return;
}
if (ch_param.ch_width <= CH_WIDTH_20MHZ) {
if (wlan_reg_is_dfs_for_freq(mac_ctx->pdev,
ch_param.mhz_freq_seg0) &&
!find_ch_freq_in_radar_hist(radar_result, count,
ch_param.mhz_freq_seg0) &&
*idx < max_elems) {
radar_result[*idx].ch_freq = ch_param.mhz_freq_seg0;
radar_result[*idx].time = cac_result->ap_end_time;
radar_result[*idx].radar_found = false;
sap_debug("radar hist[%d] freq %d time %llu no radar",
*idx, ch_param.mhz_freq_seg0,
cac_result->ap_end_time);
(*idx)++;
}
} else {
uint16_t chan_cfreq;
enum channel_state state;
const struct bonded_channel_freq *bonded_chan_ptr = NULL;
state = wlan_reg_get_5g_bonded_channel_and_state_for_freq
(mac_ctx->pdev, ch_param.mhz_freq_seg0,
ch_param.ch_width, &bonded_chan_ptr);
if (!bonded_chan_ptr || state == CHANNEL_STATE_INVALID) {
sap_debug("invalid freq %d", ch_param.mhz_freq_seg0);
return;
}
chan_cfreq = bonded_chan_ptr->start_freq;
while (chan_cfreq <= bonded_chan_ptr->end_freq) {
state = wlan_reg_get_channel_state_for_freq(
mac_ctx->pdev, chan_cfreq);
if (state == CHANNEL_STATE_INVALID) {
sap_debug("invalid ch freq %d",
chan_cfreq);
chan_cfreq = chan_cfreq + 20;
continue;
}
if (wlan_reg_is_dfs_for_freq(mac_ctx->pdev,
chan_cfreq) &&
!find_ch_freq_in_radar_hist(radar_result, count,
chan_cfreq) &&
*idx < max_elems) {
radar_result[*idx].ch_freq = chan_cfreq;
radar_result[*idx].time =
cac_result->ap_end_time;
radar_result[*idx].radar_found = false;
sap_debug("radar hist[%d] freq %d time %llu no radar",
*idx, chan_cfreq,
cac_result->ap_end_time);
(*idx)++;
}
chan_cfreq = chan_cfreq + 20;
}
}
}
QDF_STATUS
wlansap_query_radar_history(mac_handle_t mac_handle,
struct dfs_radar_history **radar_history,
uint32_t *count)
{
struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle);
struct dfsreq_nolinfo *nol_info;
uint32_t i;
uint32_t hist_count;
struct dfs_radar_history *radar_result;
nol_info = qdf_mem_malloc(sizeof(struct dfsreq_nolinfo));
if (!nol_info)
return QDF_STATUS_E_NOMEM;
ucfg_dfs_getnol(mac_ctx->pdev, nol_info);
hist_count = nol_info->dfs_ch_nchans + MAX_NUM_OF_CAC_HISTORY;
radar_result = qdf_mem_malloc(sizeof(struct dfs_radar_history) *
hist_count);
if (!radar_result) {
qdf_mem_free(nol_info);
return QDF_STATUS_E_NOMEM;
}
for (i = 0; i < nol_info->dfs_ch_nchans && i < DFS_CHAN_MAX; i++) {
radar_result[i].ch_freq = nol_info->dfs_nol[i].nol_freq;
radar_result[i].time = nol_info->dfs_nol[i].nol_start_us;
radar_result[i].radar_found = true;
sap_debug("radar hist[%d] freq %d time %llu radar",
i, nol_info->dfs_nol[i].nol_freq,
nol_info->dfs_nol[i].nol_start_us);
}
sap_append_cac_history(mac_ctx, radar_result, &i, hist_count);
sap_debug("hist count %d cur %llu", i, qdf_get_monotonic_boottime());
*radar_history = radar_result;
*count = i;
qdf_mem_free(nol_info);
return QDF_STATUS_SUCCESS;
}
#else
static inline void
sap_update_cac_history(struct mac_context *mac_ctx,
struct sap_context *sap_ctx,
eSapHddEvent event_id)
{
}
#endif
/**
* sap_signal_hdd_event() - send event notification
* @sap_ctx: Sap Context
@@ -1506,6 +1745,9 @@ QDF_STATUS sap_signal_hdd_event(struct sap_context *sap_ctx,
bss_complete->operating_chan_freq = sap_ctx->chan_freq;
bss_complete->ch_width = sap_ctx->ch_params.ch_width;
if (QDF_IS_STATUS_SUCCESS(bss_complete->status))
sap_update_cac_history(mac_ctx, sap_ctx,
sap_hddevent);
break;
case eSAP_DFS_CAC_START:
case eSAP_DFS_CAC_INTERRUPTED:
@@ -1517,6 +1759,8 @@ QDF_STATUS sap_signal_hdd_event(struct sap_context *sap_ctx,
sap_ap_event->sapHddEventCode = sap_hddevent;
sap_ap_event->sapevt.sapStopBssCompleteEvent.status =
(eSapStatus) context;
sap_update_cac_history(mac_ctx, sap_ctx,
sap_hddevent);
break;
case eSAP_ACS_SCAN_SUCCESS_EVENT:
sap_handle_acs_scan_event(sap_ctx, sap_ap_event,
@@ -1820,6 +2064,8 @@ QDF_STATUS sap_signal_hdd_event(struct sap_context *sap_ctx,
sap_ctx->csr_roamProfile.ch_params.mhz_freq_seg0;
acs_selected->vht_seg1_center_ch_freq =
sap_ctx->csr_roamProfile.ch_params.mhz_freq_seg1;
sap_update_cac_history(mac_ctx, sap_ctx,
sap_hddevent);
sap_debug("SAP event callback event = %s",
"eSAP_CHANNEL_CHANGE_RESP");
break;

View File

@@ -193,7 +193,9 @@ struct sap_context {
bool isCacEndNotified;
bool isCacStartNotified;
bool is_sap_ready_for_chnl_chng;
#ifdef FEATURE_RADAR_HISTORY
struct prev_cac_result cac_result;
#endif
#ifdef FEATURE_AP_MCC_CH_AVOIDANCE
/*
* In a setup having two MDM both operating in AP+AP MCC scenario