From 3ad4f9d78b5c74b1247e4fe7c9c0cb3a34a46e9c Mon Sep 17 00:00:00 2001 From: Liangwei Dong Date: Thu, 3 Jun 2021 16:25:37 +0800 Subject: [PATCH] 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 --- Kbuild | 1 + configs/default_defconfig | 1 + core/hdd/src/wlan_hdd_cfg80211.c | 163 ++++++++++++++++++++ core/sap/inc/sap_api.h | 47 ++++++ core/sap/src/sap_fsm.c | 246 +++++++++++++++++++++++++++++++ core/sap/src/sap_internal.h | 4 +- 6 files changed, 461 insertions(+), 1 deletion(-) diff --git a/Kbuild b/Kbuild index ad086656cc..74777ce9f4 100644 --- a/Kbuild +++ b/Kbuild @@ -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) diff --git a/configs/default_defconfig b/configs/default_defconfig index 22307eb35d..0900ce7268 100644 --- a/configs/default_defconfig +++ b/configs/default_defconfig @@ -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 diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index b8862a69fa..a75c07669d 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -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) diff --git a/core/sap/inc/sap_api.h b/core/sap/inc/sap_api.h index 95bf3c7aef..d640bb560d 100644 --- a/core/sap/inc/sap_api.h +++ b/core/sap/inc/sap_api.h @@ -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 diff --git a/core/sap/src/sap_fsm.c b/core/sap/src/sap_fsm.c index 5affc0ffbb..1115fc081c 100644 --- a/core/sap/src/sap_fsm.c +++ b/core/sap/src/sap_fsm.c @@ -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; diff --git a/core/sap/src/sap_internal.h b/core/sap/src/sap_internal.h index 04087a4d8f..b722dfbd4c 100644 --- a/core/sap/src/sap_internal.h +++ b/core/sap/src/sap_internal.h @@ -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