qcacmn: Populate RNR info during scan req

Populate RNR info during scan req instead of beacon
add/delete to avoid loop while holding scan db spin lock.
With loop spin lock can take more than 5ms, which can results
in asserts.

Change-Id: I4ba346b8dcbaf7da844f97195dbdd3003bdb234b
CRs-Fixed: 2640889
This commit is contained in:
Abhishek Singh 2020-03-12 22:53:37 +05:30 • committed by nshrivas
commit 5cf1392709
5 changed files with 203 additions and 122 deletions

View file

@ -53,26 +53,42 @@
#include <wlan_objmgr_vdev_obj.h>
#include <wlan_dfs_utils_api.h>
/* 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)
struct channel_list_db *scm_get_rnr_channel_db(struct wlan_objmgr_psoc *psoc)
{
struct wlan_scan_obj *scan_obj = NULL;
scan_obj = wlan_psoc_get_scan_obj(psoc);
if (!scan_obj)
return NULL;
return &scan_obj->rnr_channel_db;
}
struct meta_rnr_channel *scm_get_chan_meta(struct wlan_objmgr_psoc *psoc,
uint32_t chan_freq)
{
int i;
struct channel_list_db *rnr_channel_db;
if (!chan_freq || !wlan_reg_is_6ghz_chan_freq(chan_freq))
if (!psoc || !chan_freq || !wlan_reg_is_6ghz_chan_freq(chan_freq))
return NULL;
rnr_channel_db = scm_get_rnr_channel_db(psoc);
if (!rnr_channel_db)
return NULL;
for (i = 0; i <= NUM_6GHZ_CHANNELS; i++)
if (rnr_channel_db.channel[i].chan_freq == chan_freq)
return &rnr_channel_db.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)
static void scm_add_rnr_channel_db(struct wlan_objmgr_psoc *psoc,
struct scan_cache_entry *entry)
{
uint32_t chan_freq;
uint8_t is_6g_bss, i;
@ -89,7 +105,7 @@ static void scm_add_rnr_channel_db(struct scan_cache_entry *entry)
scm_debug("BSS freq %d BSSID: %pM", chan_freq, entry->bssid.bytes);
if (is_6g_bss) {
channel = scm_get_chan_meta(chan_freq);
channel = scm_get_chan_meta(psoc, chan_freq);
if (!channel) {
scm_debug("Failed to get chan Meta freq %d", chan_freq);
return;
@ -113,7 +129,7 @@ static void scm_add_rnr_channel_db(struct scan_cache_entry *entry)
chan_freq = wlan_reg_chan_opclass_to_freq(rnr_bss->channel_number,
rnr_bss->operating_class,
false);
channel = scm_get_chan_meta(chan_freq);
channel = scm_get_chan_meta(psoc, chan_freq);
if (!channel) {
scm_debug("Failed to get chan Meta freq %d", chan_freq);
continue;
@ -141,96 +157,6 @@ static void scm_add_rnr_channel_db(struct scan_cache_entry *entry)
&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("BSS freq %d BSSID: %pM", chan_freq, entry->bssid.bytes);
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);
continue;
}
cur_node = NULL;
qdf_list_peek_front(&channel->rnr_list, &cur_node);
/* Free the Node */
while (cur_node) {
next_node = NULL;
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);
channel->bss_beacon_probe_count--;
break;
} 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);
channel->bss_beacon_probe_count--;
break;
}
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
/**
@ -363,7 +289,6 @@ 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);
}
@ -397,7 +322,6 @@ 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++;
}
@ -1635,19 +1559,23 @@ QDF_STATUS scm_channel_list_db_init(struct wlan_objmgr_psoc *psoc)
{
uint32_t i, j;
uint32_t min_freq, max_freq;
struct channel_list_db *rnr_channel_db;
min_freq = wlan_reg_min_6ghz_chan_freq();
max_freq = wlan_reg_max_6ghz_chan_freq();
scm_info("min_freq %d max_freq %d", min_freq, max_freq);
i = min_freq;
qdf_mem_zero(&rnr_channel_db, sizeof(struct channel_list_db));
rnr_channel_db = scm_get_rnr_channel_db(psoc);
if (!rnr_channel_db)
return QDF_STATUS_E_INVAL;
for (j = 0; j < NUM_6GHZ_CHANNELS; j++) {
if (i >= min_freq && i <= max_freq)
rnr_channel_db.channel[j].chan_freq = i;
rnr_channel_db->channel[j].chan_freq = i;
i += 20;
/* init list for all to avoid uninitialized list */
qdf_list_create(&rnr_channel_db.channel[j].rnr_list,
qdf_list_create(&rnr_channel_db->channel[j].rnr_list,
WLAN_MAX_RNR_COUNT);
}
return QDF_STATUS_SUCCESS;
@ -1659,9 +1587,14 @@ QDF_STATUS scm_channel_list_db_deinit(struct wlan_objmgr_psoc *psoc)
qdf_list_node_t *cur_node, *next_node;
struct meta_rnr_channel *channel;
struct scan_rnr_node *rnr_node;
struct channel_list_db *rnr_channel_db;
rnr_channel_db = scm_get_rnr_channel_db(psoc);
if (!rnr_channel_db)
return QDF_STATUS_E_INVAL;
for (i = 0; i < NUM_6GHZ_CHANNELS; i++) {
channel = &rnr_channel_db.channel[i];
channel = &rnr_channel_db->channel[i];
channel->chan_freq = 0;
channel->beacon_probe_last_time_found = 0;
channel->bss_beacon_probe_count = 0;
@ -1686,15 +1619,78 @@ QDF_STATUS scm_channel_list_db_deinit(struct wlan_objmgr_psoc *psoc)
return QDF_STATUS_SUCCESS;
}
#else
QDF_STATUS scm_channel_list_db_init(struct wlan_objmgr_psoc *psoc)
QDF_STATUS scm_rnr_db_flush(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;
struct channel_list_db *rnr_channel_db;
rnr_channel_db = scm_get_rnr_channel_db(psoc);
if (!rnr_channel_db)
return QDF_STATUS_E_INVAL;
for (i = 0; i < NUM_6GHZ_CHANNELS; i++) {
channel = &rnr_channel_db->channel[i];
cur_node = NULL;
qdf_list_peek_front(&channel->rnr_list, &cur_node);
while (cur_node) {
next_node = NULL;
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;
}
/* Reset beacon info */
channel->beacon_probe_last_time_found = 0;
channel->bss_beacon_probe_count = 0;
}
return QDF_STATUS_SUCCESS;
}
QDF_STATUS scm_channel_list_db_deinit(struct wlan_objmgr_psoc *psoc)
void scm_update_rnr_from_scan_cache(struct wlan_objmgr_pdev *pdev)
{
return QDF_STATUS_SUCCESS;
uint8_t i;
struct scan_dbs *scan_db;
struct scan_cache_node *cur_node;
struct scan_cache_node *next_node = NULL;
struct wlan_objmgr_psoc *psoc;
struct scan_cache_entry *entry;
psoc = wlan_pdev_get_psoc(pdev);
if (!psoc) {
scm_err("psoc is NULL");
return;
}
scan_db = wlan_pdev_get_scan_db(psoc, pdev);
if (!scan_db) {
scm_err("scan_db is NULL");
return;
}
for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
cur_node = scm_get_next_node(scan_db,
&scan_db->scan_hash_tbl[i], NULL);
while (cur_node) {
entry = cur_node->entry;
scm_add_rnr_channel_db(psoc, entry);
next_node =
scm_get_next_node(scan_db,
&scan_db->scan_hash_tbl[i],
cur_node);
cur_node = next_node;
next_node = NULL;
}
}
}
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@ -199,6 +199,26 @@ QDF_STATUS scm_db_init(struct wlan_objmgr_psoc *psoc);
*/
QDF_STATUS scm_db_deinit(struct wlan_objmgr_psoc *psoc);
#ifdef FEATURE_6G_SCAN_CHAN_SORT_ALGO
/**
* scm_get_rnr_channel_db() - API to get rnr db
* @psoc: psoc
*
* Return: rnr db
*/
struct channel_list_db *scm_get_rnr_channel_db(struct wlan_objmgr_psoc *psoc);
/**
* scm_get_chan_meta() - API to return channel meta
* @psoc: psoc
* @freq: channel frequency
*
* Return: channel meta information
*/
struct meta_rnr_channel *scm_get_chan_meta(struct wlan_objmgr_psoc *psoc,
uint32_t chan_freq);
/**
* scm_channel_list_db_init() - API to init scan list priority list db
* @psoc: psoc
@ -216,12 +236,33 @@ QDF_STATUS scm_channel_list_db_init(struct wlan_objmgr_psoc *psoc);
QDF_STATUS scm_channel_list_db_deinit(struct wlan_objmgr_psoc *psoc);
/**
* scm_get_chan_meta() - API to return channel meta
* @freq: channel frequency
* scm_rnr_db_flush() - API to flush rnr entries
* @psoc: psoc
*
* Return: channel meta information
* Return: QDF_STATUS
*/
struct meta_rnr_channel *scm_get_chan_meta(uint32_t freq);
QDF_STATUS scm_rnr_db_flush(struct wlan_objmgr_psoc *psoc);
/**
* scm_update_rnr_from_scan_cache() - API to update rnr info from scan cache
* @pdev: pdev
*
* Return: void
*/
void scm_update_rnr_from_scan_cache(struct wlan_objmgr_pdev *pdev);
#else
static inline QDF_STATUS scm_channel_list_db_init(struct wlan_objmgr_psoc *psoc)
{
return QDF_STATUS_SUCCESS;
}
static inline
QDF_STATUS scm_channel_list_db_deinit(struct wlan_objmgr_psoc *psoc)
{
return QDF_STATUS_SUCCESS;
}
#endif
/**
* scm_validate_scoring_config() - validate score config

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@ -90,6 +90,9 @@
#define SCAN_P2P_SCAN_MAX_BURST_DURATION (240)
#define SCAN_GO_BURST_SCAN_MAX_NUM_OFFCHANNELS (6)
/* MAX RNR entries per channel*/
#define WLAN_MAX_RNR_COUNT 15
/**
* struct probe_time_dwell_time - probe time, dwell time map
* @dwell_time: dwell time
@ -495,6 +498,7 @@ struct scan_cb {
* @drop_bcn_on_chan_mismatch: drop bcn if channel mismatch
* @scan_start_request_buff: buffer used to pass
* scan config to event handlers
* @rnr_channel_db: RNR channel list database
*/
struct wlan_scan_obj {
uint32_t scan_disabled;
@ -519,6 +523,9 @@ struct wlan_scan_obj {
bool disable_timeout;
bool drop_bcn_on_chan_mismatch;
struct scan_start_request scan_start_request_buff;
#ifdef FEATURE_6G_SCAN_CHAN_SORT_ALGO
struct channel_list_db rnr_channel_db;
#endif
};
/**

View file

@ -942,6 +942,7 @@ static void scm_sort_6ghz_channel_list(struct wlan_objmgr_vdev *vdev,
struct chan_info temp_list[MAX_6GHZ_CHANNEL];
struct rnr_chan_weight *rnr_chan_info, *temp;
uint32_t weight;
struct wlan_objmgr_psoc *psoc;
rnr_chan_info = qdf_mem_malloc(sizeof(rnr_chan_info) * MAX_6GHZ_CHANNEL);
if (!rnr_chan_info)
@ -960,9 +961,15 @@ static void scm_sort_6ghz_channel_list(struct wlan_objmgr_vdev *vdev,
return;
}
psoc = wlan_vdev_get_psoc(vdev);
if (!psoc) {
scm_err("Psoc is NULL");
return;
}
/* compute the weightage */
for (i = 0, j = 0; i < tmp_list_count; i++) {
channel = scm_get_chan_meta(temp_list[i].freq);
channel = scm_get_chan_meta(psoc, temp_list[i].freq);
if (!channel)
continue;
weight = channel->bss_beacon_probe_count * BCN_PROBE_WEIGHTAGE +
@ -1001,7 +1008,8 @@ static void scm_sort_6ghz_channel_list(struct wlan_objmgr_vdev *vdev,
qdf_mem_free(rnr_chan_info);
}
static void scm_update_rnr_info(struct scan_start_request *req)
static void scm_update_rnr_info(struct wlan_objmgr_psoc *psoc,
struct scan_start_request *req)
{
uint8_t i, num_bssid = 0, num_ssid = 0;
uint8_t total_count = MAX_HINTS_PER_SCAN_REQ;
@ -1019,7 +1027,7 @@ static void scm_update_rnr_info(struct scan_start_request *req)
for (i = 0; i < chan_list->num_chan; i++) {
freq = chan_list->chan[i].freq;
chan = scm_get_chan_meta(freq);
chan = scm_get_chan_meta(psoc, freq);
if (!chan) {
scm_debug("Failed to get meta, freq %d", freq);
continue;
@ -1057,13 +1065,38 @@ static void scm_update_rnr_info(struct scan_start_request *req)
}
}
}
static void scm_add_rnr_info(struct wlan_objmgr_pdev *pdev,
struct scan_start_request *req)
{
struct wlan_objmgr_psoc *psoc;
struct channel_list_db *rnr_db;
psoc = wlan_pdev_get_psoc(pdev);
if (!psoc)
return;
rnr_db = scm_get_rnr_channel_db(psoc);
if (!rnr_db)
return;
rnr_db->scan_count++;
if (rnr_db->scan_count >= RNR_UPDATE_SCAN_CNT_THRESHOLD) {
rnr_db->scan_count = 0;
scm_rnr_db_flush(psoc);
scm_update_rnr_from_scan_cache(pdev);
}
scm_update_rnr_info(psoc, req);
}
#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)
static void scm_add_rnr_info(struct wlan_objmgr_pdev *pdev,
struct scan_start_request *req)
{
}
#endif
@ -1283,8 +1316,9 @@ scm_scan_req_update_params(struct wlan_objmgr_vdev *vdev,
else if (!req->scan_req.chan_list.num_chan)
ucfg_scan_init_chanlist_params(req, 0, NULL, NULL);
if (scan_obj->scan_def.scan_mode_6g != SCAN_MODE_6G_NO_CHANNEL)
scm_add_rnr_info(pdev, req);
scm_update_channel_list(req, scan_obj);
scm_update_rnr_info(req);
}
static inline void scm_print_scan_req_info(struct scan_req_params *req)

View file

@ -1479,12 +1479,15 @@ struct meta_rnr_channel {
qdf_list_t rnr_list;
};
#define RNR_UPDATE_SCAN_CNT_THRESHOLD 2
/**
* channel_list_db - Database for channel information
* @channel: channel meta information
* @scan_count: scan count since the db was updated
*/
struct channel_list_db {
struct meta_rnr_channel channel[NUM_6GHZ_CHANNELS];
uint8_t scan_count;
};
/**