Эх сурвалжийг харах

qcacmn: Add support for 6GHz scan priority algorithm

Add support for 6Ghz scan channel list priority algorithm.

Change-Id: I63b0ddf384c4bd62a6a25feb7dfe4f80b5f85fbe
CRs-Fixed: 2564949
Sandeep Puligilla 5 жил өмнө
parent
commit
d763fee333

+ 229 - 2
umac/scan/core/src/wlan_scan_cache_db.c

@@ -53,6 +53,174 @@
 #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)
+{
+	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)
 {

+ 24 - 0
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

+ 136 - 0
umac/scan/core/src/wlan_scan_manager.c

@@ -36,6 +36,18 @@
 #include <wlan_dfs_utils_api.h>
 #include <wlan_scan_cfg.h>
 
+/* 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,

+ 56 - 1
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

+ 2 - 0
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;
 }