From 48ecda84bf763490b56de02cf27fcda15c956698 Mon Sep 17 00:00:00 2001 From: Shashikala Prabhu Date: Fri, 13 Apr 2018 01:13:30 +0530 Subject: [PATCH] qcacmn: Fix 4.9GHz cfg80211 issues Send correct channel list to Firmware. When cfg80211 is enabled, STA is scanning in a set of wrong channels. When scan callback happens from cfg80211 module the cfg80211 module gives us the channel numbers. There are some channel numbers which are same in both 5GHz and in 2.4Ghz bands. For example, channel number 1 maps to frequency 4942MHz in 5GHz band, but in 2.4GHz band channel number 1 maps to frequency 2412MHz. So cfg80211 may give us a wrong channel number. Since we have the exact frequency of the channel we should use that instead of the one given by cfg80211. The channel object given to the driver by cfg80211 during scan callback is the same as the one registered to cfg80211 by the driver. So we can use the channel frequency inside the channel object for scan which is not changed by the cfg80211 module. Use regdb function to convert channel number to frequency while receiving scan entries from FW. Use pdev band (5/2.4GHz) information to map to correct 2.4Ghz/5Ghz channel frequency. Half/Quarter rate flags in the scan_ctrl_flags are not set. Set Half/Quarter rate flags in scan_ctrl_flags. Change-Id: I9df8f0e90938f86f6987574f8259a5cf66b672aa CRs-Fixed: 2180273 --- os_if/linux/scan/inc/wlan_cfg80211_scan.h | 5 +- os_if/linux/scan/src/wlan_cfg80211_scan.c | 38 ++++---- umac/regulatory/core/src/reg_services.c | 91 ++++++++++++++++++- umac/regulatory/core/src/reg_services.h | 25 +++++ .../dispatcher/inc/wlan_reg_services_api.h | 2 + .../scan/dispatcher/inc/wlan_scan_utils_api.h | 7 ++ .../scan/dispatcher/src/wlan_scan_utils_api.c | 9 ++ 7 files changed, 152 insertions(+), 25 deletions(-) diff --git a/os_if/linux/scan/inc/wlan_cfg80211_scan.h b/os_if/linux/scan/inc/wlan_cfg80211_scan.h index ea203bd9553b..6a849cf2a8aa 100644 --- a/os_if/linux/scan/inc/wlan_cfg80211_scan.h +++ b/os_if/linux/scan/inc/wlan_cfg80211_scan.h @@ -119,11 +119,14 @@ struct scan_req { * struct scan_params - Scan params * @source: scan request source * @default_ie: default scan ie - * + * @half_rate: Half rate flag + * @quarter_rate: Quarter rate flag */ struct scan_params { uint8_t source; struct element_info default_ie; + bool half_rate; + bool quarter_rate; }; /** diff --git a/os_if/linux/scan/src/wlan_cfg80211_scan.c b/os_if/linux/scan/src/wlan_cfg80211_scan.c index 7de207c18fba..c7801d27bfac 100644 --- a/os_if/linux/scan/src/wlan_cfg80211_scan.c +++ b/os_if/linux/scan/src/wlan_cfg80211_scan.c @@ -37,6 +37,7 @@ #ifdef WLAN_POLICY_MGR_ENABLE #include #endif +#include static const struct nla_policy scan_policy[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1] = { @@ -1212,6 +1213,7 @@ int wlan_cfg80211_scan(struct wlan_objmgr_pdev *pdev, uint8_t i; int status; uint8_t num_chan = 0, channel; + uint32_t c_freq; struct wlan_objmgr_vdev *vdev; wlan_scan_requester req_id; struct pdev_osif_priv *osif_priv; @@ -1293,6 +1295,11 @@ int wlan_cfg80211_scan(struct wlan_objmgr_pdev *pdev, (wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_GO_MODE)) req->scan_req.scan_f_passive = false; + if (params->half_rate) + req->scan_req.scan_f_half_rate = true; + else if (params->quarter_rate) + req->scan_req.scan_f_quarter_rate = true; + if ((request->n_ssids == 1) && request->ssids && !qdf_mem_cmp(&request->ssids[0], "DIRECT-", 7)) is_p2p_scan = true; @@ -1332,7 +1339,8 @@ int wlan_cfg80211_scan(struct wlan_objmgr_pdev *pdev, for (i = 0; i < request->n_channels; i++) { channel = request->channels[i]->hw_value; - if (wlan_is_dsrc_channel(wlan_chan_to_freq(channel))) + c_freq = wlan_reg_chan_to_freq(pdev, channel); + if (wlan_is_dsrc_channel(c_freq)) continue; #ifdef WLAN_POLICY_MGR_ENABLE if (ap_or_go_present) { @@ -1354,9 +1362,8 @@ int wlan_cfg80211_scan(struct wlan_objmgr_pdev *pdev, } #endif len += snprintf(chl + len, 5, "%d ", channel); - req->scan_req.chan_list.chan[num_chan].freq = - wlan_chan_to_freq(channel); - band = util_scan_scm_chan_to_band(channel); + req->scan_req.chan_list.chan[num_chan].freq = c_freq; + band = util_scan_scm_freq_to_band(c_freq); if (band == WLAN_BAND_2_4_GHZ) req->scan_req.chan_list.chan[num_chan].phymode = SCAN_PHY_MODE_11G; @@ -1610,28 +1617,15 @@ int wlan_vendor_abort_scan(struct wlan_objmgr_pdev *pdev, } static inline struct ieee80211_channel * -wlan_get_ieee80211_channel(struct wiphy *wiphy, int chan_no) +wlan_get_ieee80211_channel(struct wiphy *wiphy, + struct wlan_objmgr_pdev *pdev, + int chan_no) { unsigned int freq; struct ieee80211_channel *chan; - if (WLAN_CHAN_IS_2GHZ(chan_no) && - (wiphy->bands[NL80211_BAND_2GHZ] != NULL)) { - freq = - ieee80211_channel_to_frequency(chan_no, - NL80211_BAND_2GHZ); - } else if (WLAN_CHAN_IS_5GHZ(chan_no) && - (wiphy->bands[NL80211_BAND_5GHZ] != NULL)) { - freq = - ieee80211_channel_to_frequency(chan_no, - NL80211_BAND_5GHZ); - } else { - cfg80211_err("Invalid chan_no %d", chan_no); - return NULL; - } - + freq = wlan_reg_chan_to_freq(pdev, chan_no); chan = ieee80211_get_channel(wiphy, freq); - if (!chan) cfg80211_err("chan is NULL, chan_no: %d freq: %d", chan_no, freq); @@ -1806,7 +1800,7 @@ void wlan_cfg80211_inform_bss_frame(struct wlan_objmgr_pdev *pdev, */ bss_data.rssi = scan_params->rssi_raw; - bss_data.chan = wlan_get_ieee80211_channel(wiphy, + bss_data.chan = wlan_get_ieee80211_channel(wiphy, pdev, scan_params->channel.chan_idx); if (!bss_data.chan) { qdf_mem_free(bss_data.mgmt); diff --git a/umac/regulatory/core/src/reg_services.c b/umac/regulatory/core/src/reg_services.c index 267e1bc78798..1f1d54b0037e 100644 --- a/umac/regulatory/core/src/reg_services.c +++ b/umac/regulatory/core/src/reg_services.c @@ -1759,8 +1759,17 @@ uint32_t reg_chan_to_freq(struct wlan_objmgr_pdev *pdev, chan_list = pdev_priv_obj->cur_chan_list; for (count = 0; count < NUM_CHANNELS; count++) - if (chan_list[count].chan_num == chan_num) - return chan_list[count].center_freq; + if (chan_list[count].chan_num == chan_num) { + if (reg_chan_in_range(chan_list, + pdev_priv_obj->range_2g_low, + pdev_priv_obj->range_2g_high, + pdev_priv_obj->range_5g_low, + pdev_priv_obj->range_5g_high, + count)) { + return chan_list[count].center_freq; + } + } + reg_err("invalid channel %d", chan_num); @@ -2283,6 +2292,84 @@ reg_modify_chan_list_for_freq_range(struct regulatory_channel *chan_list, } } +bool reg_chan_in_range(struct regulatory_channel *chan_list, + uint32_t low_freq_2g, + uint32_t high_freq_2g, + uint32_t low_freq_5g, + uint32_t high_freq_5g, + enum channel_enum ch_enum) +{ + uint32_t low_limit_2g = NUM_CHANNELS; + uint32_t high_limit_2g = NUM_CHANNELS; + uint32_t low_limit_5g = NUM_CHANNELS; + uint32_t high_limit_5g = NUM_CHANNELS; + bool chan_in_range; + enum channel_enum chan_enum; + uint16_t min_bw; + uint32_t center_freq; + + for (chan_enum = 0; chan_enum < NUM_CHANNELS; chan_enum++) { + min_bw = chan_list[chan_enum].min_bw; + center_freq = chan_list[chan_enum].center_freq; + + if ((center_freq - min_bw/2) >= low_freq_2g) { + low_limit_2g = chan_enum; + break; + } + } + + for (chan_enum = 0; chan_enum < NUM_CHANNELS; chan_enum++) { + min_bw = chan_list[chan_enum].min_bw; + center_freq = chan_list[chan_enum].center_freq; + + if ((center_freq - min_bw/2) >= low_freq_5g) { + low_limit_5g = chan_enum; + break; + } + } + + for (chan_enum = NUM_CHANNELS - 1; chan_enum >= 0; chan_enum--) { + min_bw = chan_list[chan_enum].min_bw; + center_freq = chan_list[chan_enum].center_freq; + + if (center_freq + min_bw/2 <= high_freq_2g) { + high_limit_2g = chan_enum; + break; + } + if (chan_enum == 0) + break; + } + + for (chan_enum = NUM_CHANNELS - 1; chan_enum >= 0; chan_enum--) { + min_bw = chan_list[chan_enum].min_bw; + center_freq = chan_list[chan_enum].center_freq; + + if (center_freq + min_bw/2 <= high_freq_5g) { + high_limit_5g = chan_enum; + break; + } + if (chan_enum == 0) + break; + } + + chan_in_range = false; + if ((low_limit_2g <= ch_enum) && + (high_limit_2g >= ch_enum) && + (low_limit_2g != NUM_CHANNELS) && + (high_limit_2g != NUM_CHANNELS)) + chan_in_range = true; + if ((low_limit_5g <= ch_enum) && + (high_limit_5g >= ch_enum) && + (low_limit_5g != NUM_CHANNELS) && + (high_limit_5g != NUM_CHANNELS)) + chan_in_range = true; + + if (chan_in_range) + return true; + else + return false; +} + static void reg_init_pdev_mas_chan_list(struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj, struct mas_chan_params diff --git a/umac/regulatory/core/src/reg_services.h b/umac/regulatory/core/src/reg_services.h index 41c1f4b47bfd..57344ad642db 100644 --- a/umac/regulatory/core/src/reg_services.h +++ b/umac/regulatory/core/src/reg_services.h @@ -47,6 +47,13 @@ ((chan_num >= REG_MIN_24GHZ_CH_NUM) && \ (chan_num <= REG_MAX_24GHZ_CH_NUM)) +#define REG_MIN_24GHZ_CH_FREQ channel_map[MIN_24GHZ_CHANNEL].center_freq +#define REG_MAX_24GHZ_CH_FREQ channel_map[MAX_24GHZ_CHANNEL].center_freq + +#define REG_IS_24GHZ_CH_FREQ(freq) \ + ((freq >= REG_MIN_24GHZ_CH_FREQ) && \ + (freq <= REG_MAX_24GHZ_CH_FREQ)) + #ifndef CONFIG_LEGACY_CHAN_ENUM #define REG_MIN_49GHZ_CH_FREQ channel_map[MIN_49GHZ_CHANNEL].center_freq #define REG_MAX_49GHZ_CH_FREQ channel_map[MAX_49GHZ_CHANNEL].center_freq @@ -499,4 +506,22 @@ QDF_STATUS reg_set_hal_reg_cap(struct wlan_objmgr_psoc *psoc, struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap, uint16_t phy_cnt); +/** + * reg_chan_in_range() - Check if the given channel is in pdev's channel range + * @chan_list: Pointer to regulatory channel list. + * @low_freq_2g: Low frequency 2G. + * @high_freq_2g: High frequency 2G. + * @low_freq_5g: Low frequency 5G. + * @high_freq_5g: High frequency 5G. + * @ch_enum: Channel enum. + * + * Return: true if ch_enum is with in pdev's channel range, else false. + */ +bool reg_chan_in_range(struct regulatory_channel *chan_list, + uint32_t low_freq_2g, + uint32_t high_freq_2g, + uint32_t low_freq_5g, + uint32_t high_freq_5g, + enum channel_enum ch_enum); + #endif diff --git a/umac/regulatory/dispatcher/inc/wlan_reg_services_api.h b/umac/regulatory/dispatcher/inc/wlan_reg_services_api.h index e5dcd3bd63ad..746385fea8db 100644 --- a/umac/regulatory/dispatcher/inc/wlan_reg_services_api.h +++ b/umac/regulatory/dispatcher/inc/wlan_reg_services_api.h @@ -41,6 +41,8 @@ #define WLAN_REG_IS_5GHZ_CH(chan) REG_IS_5GHZ_CH(chan) #define WLAN_REG_IS_11P_CH(chan) REG_IS_11P_CH(chan) +#define WLAN_REG_IS_24GHZ_CH_FREQ(freq) REG_IS_24GHZ_CH_FREQ(freq) + #ifndef CONFIG_LEGACY_CHAN_ENUM #define WLAN_REG_IS_49GHZ_FREQ(freq) REG_IS_49GHZ_FREQ(freq) #endif diff --git a/umac/scan/dispatcher/inc/wlan_scan_utils_api.h b/umac/scan/dispatcher/inc/wlan_scan_utils_api.h index aff016e069f9..040e525d3bdc 100644 --- a/umac/scan/dispatcher/inc/wlan_scan_utils_api.h +++ b/umac/scan/dispatcher/inc/wlan_scan_utils_api.h @@ -1444,4 +1444,11 @@ util_scan_entry_mbo_oce(struct scan_cache_entry *scan_entry) */ enum wlan_band util_scan_scm_chan_to_band(uint32_t chan); +/** + * util_scan_scm_freq_to_band() - API to get band from frequency + * @freq: Channel frequency + * + * Return: Band information as per frequency + */ +enum wlan_band util_scan_scm_freq_to_band(uint16_t freq); #endif diff --git a/umac/scan/dispatcher/src/wlan_scan_utils_api.c b/umac/scan/dispatcher/src/wlan_scan_utils_api.c index 716f04b51947..1eb298627e19 100644 --- a/umac/scan/dispatcher/src/wlan_scan_utils_api.c +++ b/umac/scan/dispatcher/src/wlan_scan_utils_api.c @@ -25,6 +25,7 @@ #include #include <../../core/src/wlan_scan_cache_db.h> #include <../../core/src/wlan_scan_main.h> +#include const char* util_scan_get_ev_type_name(enum scan_event_type type) @@ -108,6 +109,14 @@ enum wlan_band util_scan_scm_chan_to_band(uint32_t chan) return WLAN_BAND_5_GHZ; } +enum wlan_band util_scan_scm_freq_to_band(uint16_t freq) +{ + if (WLAN_REG_IS_24GHZ_CH_FREQ(freq)) + return WLAN_BAND_2_4_GHZ; + + return WLAN_BAND_5_GHZ; +} + bool util_is_scan_entry_match( struct scan_cache_entry *entry1, struct scan_cache_entry *entry2)