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

1
Kbuild
View File

@@ -2839,6 +2839,7 @@ cppflags-$(CONFIG_WLAN_CFR_ENABLE) += -DWLAN_CFR_ENABLE
cppflags-$(CONFIG_WLAN_ENH_CFR_ENABLE) += -DWLAN_ENH_CFR_ENABLE
cppflags-$(CONFIG_WLAN_CFR_ENABLE) += -DCFR_USE_FIXED_FOLDER
cppflags-$(CONFIG_WLAN_FEATURE_MEDIUM_ASSESS) += -DWLAN_FEATURE_MEDIUM_ASSESS
cppflags-$(CONFIG_FEATURE_RADAR_HISTORY) += -DFEATURE_RADAR_HISTORY
cppflags-$(CONFIG_DIRECT_BUF_RX_ENABLE) += -DDIRECT_BUF_RX_ENABLE
cppflags-$(CONFIG_WMI_DBR_SUPPORT) += -DWMI_DBR_SUPPORT
ifneq ($(CONFIG_CNSS_QCA6750), y)

View File

@@ -1083,6 +1083,7 @@ CONFIG_FW_THERMAL_THROTTLE := y
CONFIG_WLAN_FEATURE_BIG_DATA_STATS := y
CONFIG_WLAN_FEATURE_IGMP_OFFLOAD := y
CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST := y
CONFIG_FEATURE_RADAR_HISTORY := y
ifeq (y,$(findstring y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM) $(CONFIG_ICNSS) $(CONFIG_ICNSS_MODULE) $(CONFIG_ICNSS2_HELIUM)))
CONFIG_WLAN_FEATURE_BMI := n

View File

@@ -16177,6 +16177,168 @@ static int wlan_hdd_cfg80211_extscan_get_valid_channels(
return errno;
}
#ifdef FEATURE_RADAR_HISTORY
static uint32_t get_radar_history_evt_len(uint32_t count)
{
uint32_t data_len = NLMSG_HDRLEN;
data_len +=
/* nested attribute hdr QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_ENTRIES */
nla_total_size(count *
(nla_total_size(
/* channel frequency */
nla_total_size(sizeof(uint32_t)) +
/* timestamp */
nla_total_size(sizeof(uint64_t)) +
/* radar detected flag */
nla_total_size(0))));
return data_len;
}
/**
* __wlan_hdd_cfg80211_radar_history () - Get radar history
* @wiphy: Pointer to wireless phy
* @wdev: Pointer to wireless device
* @data: Pointer to data
* @data_len: Data length
*
* Return: 0 on success, negative errno on failure
*/
static int
__wlan_hdd_cfg80211_get_radar_history(struct wiphy *wiphy,
struct wireless_dev
*wdev, const void *data,
int data_len)
{
struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
QDF_STATUS status;
struct sk_buff *reply_skb = NULL;
int ret, len;
struct dfs_radar_history *radar_history = NULL;
uint32_t hist_count = 0;
int idx;
struct nlattr *ch_array, *ch_element;
if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
hdd_err("Command not allowed in FTM mode");
return -EPERM;
}
ret = wlan_hdd_validate_context(hdd_ctx);
if (ret)
return -EINVAL;
status = wlansap_query_radar_history(hdd_ctx->mac_handle,
&radar_history, &hist_count);
if (!QDF_IS_STATUS_SUCCESS(status))
return -EINVAL;
len = get_radar_history_evt_len(hist_count);
reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len);
if (!reply_skb) {
ret = -ENOMEM;
goto err;
}
ch_array = nla_nest_start(
reply_skb, QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_ENTRIES);
if (!ch_array) {
ret = -ENOMEM;
goto err;
}
for (idx = 0; idx < hist_count; idx++) {
ch_element = nla_nest_start(reply_skb, idx);
if (!ch_element) {
ret = -ENOMEM;
goto err;
}
if (nla_put_u32(reply_skb,
QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_FREQ,
radar_history[idx].ch_freq)) {
ret = -ENOMEM;
goto err;
}
if (wlan_cfg80211_nla_put_u64(
reply_skb,
QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_TIMESTAMP,
radar_history[idx].time)) {
ret = -ENOMEM;
goto err;
}
if (radar_history[idx].radar_found &&
nla_put_flag(
reply_skb,
QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_DETECTED)) {
ret = -ENOMEM;
goto err;
}
nla_nest_end(reply_skb, ch_element);
}
nla_nest_end(reply_skb, ch_array);
qdf_mem_free(radar_history);
ret = cfg80211_vendor_cmd_reply(reply_skb);
hdd_debug("get radar history count %d, ret %d", hist_count, ret);
return ret;
err:
qdf_mem_free(radar_history);
if (reply_skb)
kfree_skb(reply_skb);
hdd_debug("get radar history error %d", ret);
return ret;
}
/**
* wlan_hdd_cfg80211_get_radar_history() - get radar history
* @wiphy: wiphy pointer
* @wdev: pointer to struct wireless_dev
* @data: pointer to incoming NL vendor data
* @data_len: length of @data
*
* Return: 0 on success; error number otherwise.
*/
static int wlan_hdd_cfg80211_get_radar_history(struct wiphy *wiphy,
struct wireless_dev *wdev,
const void *data,
int data_len)
{
int errno;
struct osif_vdev_sync *vdev_sync;
errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
if (errno)
return errno;
errno = __wlan_hdd_cfg80211_get_radar_history(wiphy, wdev,
data, data_len);
osif_vdev_sync_op_stop(vdev_sync);
return errno;
}
#define FEATURE_RADAR_HISTORY_VENDOR_COMMANDS \
{ \
.info.vendor_id = QCA_NL80211_VENDOR_ID, \
.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_RADAR_HISTORY, \
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | \
WIPHY_VENDOR_CMD_NEED_NETDEV | \
WIPHY_VENDOR_CMD_NEED_RUNNING, \
.doit = wlan_hdd_cfg80211_get_radar_history, \
vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) \
},
#else
#define FEATURE_RADAR_HISTORY_VENDOR_COMMANDS
#endif
const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = {
{
.info.vendor_id = QCA_NL80211_VENDOR_ID,
@@ -16634,6 +16796,7 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = {
FEATURE_WMM_COMMANDS
FEATURE_GPIO_CFG_VENDOR_COMMANDS
FEATURE_MEDIUM_ASSESS_VENDOR_COMMANDS
FEATURE_RADAR_HISTORY_VENDOR_COMMANDS
};
struct hdd_context *hdd_cfg80211_wiphy_alloc(void)

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