diff --git a/umac/scan/core/src/wlan_scan_cache_db.c b/umac/scan/core/src/wlan_scan_cache_db.c index 2d470f646c57..8e36b2a53764 100644 --- a/umac/scan/core/src/wlan_scan_cache_db.c +++ b/umac/scan/core/src/wlan_scan_cache_db.c @@ -53,6 +53,174 @@ #include #include +/* MAX RNR entries per channel*/ +#define WLAN_MAX_RNR_COUNT 15 +struct channel_list_db rnr_channel_db; + +#ifdef FEATURE_6G_SCAN_CHAN_SORT_ALGO +struct meta_rnr_channel *scm_get_chan_meta(uint32_t chan_freq) +{ + int i; + + for (i = 0; i <= MAX_6GHZ_CHANNEL; i++) + if (rnr_channel_db.channel[i].chan_freq == chan_freq) + return &rnr_channel_db.channel[i]; + + return NULL; +} + +static void scm_add_rnr_channel_db(struct scan_cache_entry *entry) +{ + uint32_t chan_freq; + uint8_t is_6g_bss, i; + struct meta_rnr_channel *channel; + struct rnr_bss_info *rnr_bss; + struct scan_rnr_node *rnr_node; + + chan_freq = entry->channel.chan_freq; + is_6g_bss = wlan_reg_is_6ghz_chan_freq(chan_freq); + + /* Return if the BSS is not 6G and RNR IE is not present */ + if (!(is_6g_bss || entry->ie_list.rnrie)) + return; + + scm_debug("scan entry channel freq %d", chan_freq); + if (is_6g_bss) { + channel = scm_get_chan_meta(chan_freq); + if (channel) { + scm_debug("Failed to get chan Meta freq %d", chan_freq); + return; + } + channel->bss_beacon_probe_count++; + channel->beacon_probe_last_time_found = entry->scan_entry_time; + } + + /* + * If scan entry got RNR IE then loop through all + * entries and increase the BSS count in respective channels + */ + if (!entry->ie_list.rnrie) + return; + + for (i = 0; i < MAX_RNR_BSS; i++) { + rnr_bss = &entry->rnr.bss_info[i]; + channel->bss_beacon_probe_count++; + /* Don't add RNR entry if list is full */ + if (qdf_list_size(&channel->rnr_list) >= WLAN_MAX_RNR_COUNT) + continue; + /* Skip if entry is not valid */ + if (!rnr_bss->channel_number) + continue; + rnr_node = qdf_mem_malloc(sizeof(struct scan_rnr_node)); + if (!rnr_node) + return; + chan_freq = wlan_reg_chan_opclass_to_freq(rnr_bss->channel_number, + rnr_bss->operating_class, + false); + channel = scm_get_chan_meta(chan_freq); + if (!channel) { + scm_debug("Failed to get chan Meta freq %d", chan_freq); + qdf_mem_free(rnr_node); + return; + } + rnr_node->entry.timestamp = entry->scan_entry_time; + if (!qdf_is_macaddr_zero(&rnr_bss->bssid)) + qdf_mem_copy(&rnr_node->entry.bssid, + &rnr_bss->bssid, + QDF_MAC_ADDR_SIZE); + if (rnr_bss->short_ssid) + rnr_node->entry.short_ssid = rnr_bss->short_ssid; + qdf_list_insert_back(&channel->rnr_list, + &rnr_node->node); + } +} + +static void scm_del_rnr_channel_db(struct scan_cache_entry *entry) +{ + uint32_t chan_freq; + uint8_t is_6g_bss, i; + struct meta_rnr_channel *channel; + struct rnr_bss_info *rnr_bss; + struct scan_rnr_node *rnr_node; + qdf_list_node_t *cur_node, *next_node; + + chan_freq = entry->channel.chan_freq; + is_6g_bss = wlan_reg_is_6ghz_chan_freq(chan_freq); + + /* Return if the BSS is not 6G and RNR IE is not present*/ + if (!(is_6g_bss || entry->ie_list.rnrie)) + return; + + scm_debug("channel freq of scan entry %d", chan_freq); + if (is_6g_bss) { + channel = scm_get_chan_meta(chan_freq); + if (!channel) { + scm_debug("Failed to get chan Meta freq %d", chan_freq); + return; + } + channel->bss_beacon_probe_count--; + } + /* + * If scan entry got RNR IE then loop through all + * entries and decrease the BSS count in respective channels + */ + if (!entry->ie_list.rnrie) + return; + + for (i = 0; i < MAX_RNR_BSS; i++) { + rnr_bss = &entry->rnr.bss_info[i]; + /* Skip if entry is not valid */ + if (!rnr_bss->channel_number) + continue; + chan_freq = wlan_reg_chan_opclass_to_freq(rnr_bss->channel_number, + rnr_bss->operating_class, + false); + channel = scm_get_chan_meta(chan_freq); + if (!channel) { + scm_debug("Failed to get chan Meta freq %d", + chan_freq); + return; + } + channel->bss_beacon_probe_count--; + qdf_list_peek_front(&channel->rnr_list, &cur_node); + /* Free the Node */ + while (cur_node) { + qdf_list_peek_next(&channel->rnr_list, cur_node, + &next_node); + rnr_node = qdf_container_of(cur_node, + struct scan_rnr_node, + node); + if (qdf_is_macaddr_equal(&rnr_node->entry.bssid, + &rnr_bss->bssid)) { + qdf_list_remove_node(&channel->rnr_list, + &rnr_node->node); + qdf_mem_free(rnr_node); + } else if (rnr_node->entry.short_ssid == + rnr_bss->short_ssid) { + qdf_list_remove_node(&channel->rnr_list, + &rnr_node->node); + qdf_mem_free(rnr_node); + } + cur_node = next_node; + next_node = NULL; + } + } +} +#else +struct meta_rnr_channel *scm_get_chan_meta(uint32_t channel_freq) +{ + return NULL; +} + +static void scm_add_rnr_channel_db(struct scan_cache_entry *entry) +{ +} + +static void scm_del_rnr_channel_db(struct scan_cache_entry *entry) +{ +} +#endif + /** * scm_del_scan_node() - API to remove scan node from the list * @list: hash list @@ -183,7 +351,7 @@ static void scm_scan_entry_del(struct scan_dbs *scan_db, return; } scan_node->cookie = 0; - + scm_del_rnr_channel_db(scan_node->entry); scm_scan_entry_put_ref(scan_db, scan_node, false); } @@ -217,6 +385,7 @@ static void scm_add_scan_node(struct scan_dbs *scan_db, qdf_list_insert_before(&scan_db->scan_hash_tbl[hash_idx], &scan_node->node, &dup_node->node); + scm_add_rnr_channel_db(scan_node->entry); scan_db->num_entries++; } @@ -1414,7 +1583,6 @@ QDF_STATUS scm_db_init(struct wlan_objmgr_psoc *psoc) qdf_list_create(&scan_db->scan_hash_tbl[j], MAX_SCAN_CACHE_SIZE); } - return QDF_STATUS_SUCCESS; } @@ -1445,6 +1613,65 @@ QDF_STATUS scm_db_deinit(struct wlan_objmgr_psoc *psoc) return QDF_STATUS_SUCCESS; } +#ifdef FEATURE_6G_SCAN_CHAN_SORT_ALGO +QDF_STATUS scm_channel_list_db_init(struct wlan_objmgr_psoc *psoc) +{ + uint8_t i, j = 0; + uint32_t min_freq, max_freq; + + min_freq = wlan_reg_min_6ghz_chan_freq(); + max_freq = wlan_reg_max_6ghz_chan_freq(); + + scm_debug("min_freq %d max_freq %d", min_freq, max_freq); + for (i = min_freq; i <= max_freq; i += 20, j++) { + rnr_channel_db.channel[j].chan_freq = i; + qdf_list_create(&rnr_channel_db.channel[j].rnr_list, + WLAN_MAX_RNR_COUNT); + scm_debug("freq %d", i); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS scm_channel_list_db_deinit(struct wlan_objmgr_psoc *psoc) +{ + int i; + qdf_list_node_t *cur_node, *next_node; + struct meta_rnr_channel *channel; + struct scan_rnr_node *rnr_node; + + for (i = 0; i <= MAX_6GHZ_CHANNEL; i++) { + channel = &rnr_channel_db.channel[i]; + channel->chan_freq = 0; + qdf_list_peek_front(&channel->rnr_list, &cur_node); + while (cur_node) { + qdf_list_peek_next(&channel->rnr_list, cur_node, + &next_node); + rnr_node = qdf_container_of(cur_node, + struct scan_rnr_node, + node); + qdf_list_remove_node(&channel->rnr_list, + &rnr_node->node); + qdf_mem_free(rnr_node); + cur_node = next_node; + next_node = NULL; + } + } + + return QDF_STATUS_SUCCESS; +} +#else +QDF_STATUS scm_channel_list_db_init(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS scm_channel_list_db_deinit(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} +#endif + QDF_STATUS scm_update_scan_mlme_info(struct wlan_objmgr_pdev *pdev, struct scan_cache_entry *entry) { diff --git a/umac/scan/core/src/wlan_scan_cache_db.h b/umac/scan/core/src/wlan_scan_cache_db.h index 7d4e65821713..5de55d55ee87 100644 --- a/umac/scan/core/src/wlan_scan_cache_db.h +++ b/umac/scan/core/src/wlan_scan_cache_db.h @@ -199,6 +199,30 @@ QDF_STATUS scm_db_init(struct wlan_objmgr_psoc *psoc); */ QDF_STATUS scm_db_deinit(struct wlan_objmgr_psoc *psoc); +/** + * scm_channel_list_db_init() - API to init scan list priority list db + * @psoc: psoc + * + * Return: QDF_STATUS + */ +QDF_STATUS scm_channel_list_db_init(struct wlan_objmgr_psoc *psoc); + +/** + * scm_channel_list_db_deinit() - API to deinit scan list priority list db + * @psoc: psoc + * + * Return: QDF_STATUS + */ +QDF_STATUS scm_channel_list_db_deinit(struct wlan_objmgr_psoc *psoc); + +/** + * scm_get_chan_meta() - API to return channel meta + * @freq: channel frequency + * + * Return: channel meta information + */ +struct meta_rnr_channel *scm_get_chan_meta(uint32_t freq); + /** * scm_validate_scoring_config() - validate score config * @score_cfg: config to be validated diff --git a/umac/scan/core/src/wlan_scan_manager.c b/umac/scan/core/src/wlan_scan_manager.c index d890c6d99bef..e179aa21a4e4 100644 --- a/umac/scan/core/src/wlan_scan_manager.c +++ b/umac/scan/core/src/wlan_scan_manager.c @@ -36,6 +36,18 @@ #include #include +/* Beacon/probe weightage multiplier */ +#define BCN_PROBE_WEIGHTAGE 5 + +/* Saved profile weightage multiplier */ +#define SAVED_PROFILE_WEIGHTAGE 10 + +/* maximum number of 6ghz hints can be sent per scan request */ +#define MAX_HINTS_PER_SCAN_REQ 15 + +/* maximum number of hints can be sent per 6ghz channel */ +#define MAX_HINTS_PER_CHANNEL 4 + QDF_STATUS scm_scan_free_scan_request_mem(struct scan_start_request *req) { @@ -899,6 +911,128 @@ scm_update_6ghz_channel_list(struct wlan_objmgr_vdev *vdev, } #endif +#ifdef FEATURE_6G_SCAN_CHAN_SORT_ALGO +static void scm_sort_6ghz_channel_list(struct wlan_objmgr_vdev *vdev, + struct chan_list *chan_list) +{ + uint8_t i, j = 0, min, tmp_list_count; + struct meta_rnr_channel *channel; + struct chan_info temp_list[MAX_6GHZ_CHANNEL]; + struct rnr_chan_weight *rnr_chan_info, *temp; + uint32_t weight; + + rnr_chan_info = qdf_mem_malloc(sizeof(rnr_chan_info) * MAX_6GHZ_CHANNEL); + if (!rnr_chan_info) + return; + + for (i = 0; i < chan_list->num_chan; i++) { + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_list->chan[i].freq)) + temp_list[j++].freq = chan_list->chan[i].freq; + } + tmp_list_count = j; + scm_debug("Total 6ghz channels %d", tmp_list_count); + + /* No Need to sort if the 6ghz channels are less than one */ + if (tmp_list_count < 1) { + qdf_mem_free(rnr_chan_info); + return; + } + + /* compute the weightage */ + for (i = 0; i < tmp_list_count; i++) { + channel = scm_get_chan_meta(temp_list[i].freq); + weight = channel->bss_beacon_probe_count * BCN_PROBE_WEIGHTAGE + + channel->saved_profile_count * SAVED_PROFILE_WEIGHTAGE; + rnr_chan_info[i].weight = weight; + rnr_chan_info[i].chan_freq = temp_list[i].freq; + } + + /* Sort the channel using selection sort */ + for (i = 0; i < tmp_list_count - 1; i++) { + min = i; + for (j = i + 1; j < tmp_list_count; j++) { + if (rnr_chan_info[j].weight < + rnr_chan_info[min].weight) { + min = j; + } + } + if (min != i) { + qdf_mem_copy(&temp, &rnr_chan_info[min], + sizeof(*rnr_chan_info)); + qdf_mem_copy(&rnr_chan_info[min], &rnr_chan_info[i], + sizeof(*rnr_chan_info)); + qdf_mem_copy(&rnr_chan_info[i], &temp, + sizeof(*rnr_chan_info)); + } + } + + /* update the 6g list based on the weightage */ + for (i = 0, j = 0; + (i < NUM_CHANNELS && j < NUM_6GHZ_CHANNELS); i++) { + if (wlan_reg_is_6ghz_chan_freq(chan_list->chan[i].freq)) + chan_list->chan[i].freq = rnr_chan_info[j++].chan_freq; + } + qdf_mem_free(rnr_chan_info); +} + +static void scm_update_rnr_info(struct scan_start_request *req) +{ + uint8_t i, num_bssid = 0, num_ssid = 0; + uint8_t total_count = MAX_HINTS_PER_SCAN_REQ; + uint32_t freq; + struct meta_rnr_channel *chan; + qdf_list_node_t *cur_node, *next_node; + struct scan_rnr_node *rnr_node; + struct chan_list *chan_list; + + if (!req) + return; + + chan_list = &req->scan_req.chan_list; + for (i = 0; i < chan_list->num_chan; i++) { + freq = chan_list->chan[i].freq; + if (!wlan_reg_is_6ghz_chan_freq(freq)) + continue; + + chan = scm_get_chan_meta(freq); + if (qdf_list_empty(&chan->rnr_list)) + continue; + + qdf_list_peek_front(&chan->rnr_list, &cur_node); + while (cur_node && total_count) { + qdf_list_peek_next(&chan->rnr_list, cur_node, + &next_node); + rnr_node = qdf_container_of(cur_node, + struct scan_rnr_node, + node); + if (!qdf_is_macaddr_zero(&rnr_node->entry.bssid)) { + qdf_mem_copy(&req->scan_req.hint_bssid[num_bssid++].bssid, + &rnr_node->entry.bssid, + QDF_MAC_ADDR_SIZE); + req->scan_req.num_hint_bssid++; + total_count--; + } else if (rnr_node->entry.short_ssid) { + req->scan_req.hint_s_ssid[num_ssid++].short_ssid = + rnr_node->entry.short_ssid; + req->scan_req.num_hint_s_ssid++; + total_count--; + } + cur_node = next_node; + next_node = NULL; + } + } +} +#else +static void scm_sort_6ghz_channel_list(struct wlan_objmgr_vdev *vdev, + struct chan_list *chan_list) +{ +} + +static void scm_update_rnr_info(struct scan_start_request *req) +{ +} +#endif + /** * scm_update_channel_list() - update scan req params depending on dfs inis * and initial scan request. @@ -975,6 +1109,7 @@ scm_update_channel_list(struct scan_start_request *req, req->scan_req.chan_list.num_chan = num_scan_channels; scm_update_6ghz_channel_list(req->vdev, &req->scan_req.chan_list, scan_obj); + scm_sort_6ghz_channel_list(req->vdev, &req->scan_req.chan_list); scm_scan_chlist_concurrency_modify(req->vdev, req); } @@ -1105,6 +1240,7 @@ scm_scan_req_update_params(struct wlan_objmgr_vdev *vdev, ucfg_scan_init_chanlist_params(req, 0, NULL, NULL); scm_update_channel_list(req, scan_obj); + scm_update_rnr_info(req); scm_debug("dwell time: active %d, passive %d, repeat_probe_time %d n_probes %d flags_ext %x, wide_bw_scan: %d priority: %d", req->scan_req.dwell_time_active, req->scan_req.dwell_time_passive, diff --git a/umac/scan/dispatcher/inc/wlan_scan_public_structs.h b/umac/scan/dispatcher/inc/wlan_scan_public_structs.h index dda691c2cdf7..ac321e3c6c12 100644 --- a/umac/scan/dispatcher/inc/wlan_scan_public_structs.h +++ b/umac/scan/dispatcher/inc/wlan_scan_public_structs.h @@ -35,7 +35,7 @@ typedef uint32_t wlan_scan_id; #define WLAN_SCAN_MAX_HINT_S_SSID 10 #define WLAN_SCAN_MAX_HINT_BSSID 10 -#define MAX_RNR_BSS 5 +#define MAX_RNR_BSS 5 #define WLAN_SCAN_MAX_NUM_SSID 16 #define WLAN_SCAN_MAX_NUM_BSSID 4 @@ -1470,4 +1470,59 @@ enum ext_cap_bit_field { OBSS_NARROW_BW_RU_IN_ULOFDMA_TOLERENT_SUPPORT = 79, }; +/** + * scan_rnr_info - RNR information + * @timestamp: time stamp of beacon/probe + * @short_ssid: Short SSID + * @bssid: BSSID + */ +struct scan_rnr_info { + qdf_time_t timestamp; + uint32_t short_ssid; + struct qdf_mac_addr bssid; +}; + +/** + * struct scan_rnr_node - Scan RNR entry node + * @node: node pointers + * @entry: scan RNR entry pointer + */ +struct scan_rnr_node { + qdf_list_node_t node; + struct scan_rnr_info entry; +}; + +/** + * meta_rnr_channel - Channel information for scan priority algorithm + * @chan_freq: channel frequency + * @bss_beacon_probe_count: Beacon and probe request count + * @saved_profile_count: Saved profile count + * @beacon_probe_last_time_found: Timestamp of beacon/probe observed + * @rnr_list: RNR list to store RNR IE information + */ +struct meta_rnr_channel { + uint32_t chan_freq; + uint32_t bss_beacon_probe_count; + uint32_t saved_profile_count; + qdf_time_t beacon_probe_last_time_found; + qdf_list_t rnr_list; +}; + +/** + * channel_list_db - Database for channel information + * @channel: channel meta information + */ +struct channel_list_db { + struct meta_rnr_channel channel[NUM_6GHZ_CHANNELS]; +}; + +/** + * rnr_chan_weight - RNR channel weightage + * @chan_freq: channel frequency + * @weight: weightage of the channel + */ +struct rnr_chan_weight { + uint32_t chan_freq; + uint32_t weight; +}; #endif diff --git a/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c b/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c index 29efcb3d2803..c977082bb953 100644 --- a/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c +++ b/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c @@ -1643,6 +1643,7 @@ ucfg_scan_psoc_open(struct wlan_objmgr_psoc *psoc) qdf_spinlock_create(&scan_obj->lock); ucfg_scan_register_pmo_handler(); scm_db_init(psoc); + scm_channel_list_db_init(psoc); return QDF_STATUS_SUCCESS; } @@ -1666,6 +1667,7 @@ ucfg_scan_psoc_close(struct wlan_objmgr_psoc *psoc) ucfg_scan_unregister_pmo_handler(); qdf_spinlock_destroy(&scan_obj->lock); wlan_scan_global_deinit(psoc); + scm_channel_list_db_deinit(psoc); return QDF_STATUS_SUCCESS; }