Browse Source

qcacld-3.0: Update HDD VDEV mapping on link switch

Once link switch set MAC address response is received,
HDD is notified. Update the active bitmap in adapter and
move VDEV information from existing link to new link.
No need to call VDEV attach/detach as part of set MAC addr
due to link switch and also call DP callback to update
DP link mac address.

Save the new link info mapping on VDEV map address update,
use the mapping on dynamic MAC address update to restore to
proper link info, so that new connection will start correct
with VDEV-MAC address mapping.

Change-Id: I625c74d9cf42a4a78f23dcc419b4151717c203ae
CRs-Fixed: 3557829
Vinod Kumar Pirla 1 year ago
parent
commit
5a3f3cca79
3 changed files with 295 additions and 19 deletions
  1. 55 0
      core/hdd/inc/wlan_hdd_main.h
  2. 159 13
      core/hdd/src/wlan_hdd_main.c
  3. 81 6
      core/hdd/src/wlan_hdd_mlo.c

+ 55 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -1153,6 +1153,7 @@ struct wlan_hdd_tx_power {
  * @mac_addr: Current MAC Address for the adapter
  * @mld_addr: MLD address for adapter
  * @event_flags: a bitmap of hdd_adapter_flags
+ * @curr_link_info_map: Current mapping of link info in adapter array
  * @active_links: a bitmap of active links in @link_info array
  * @num_links_on_create: No of active links set on initial hdd_open_adapter().
  * @is_ll_stats_req_pending: atomic variable to check active stats req
@@ -1282,6 +1283,7 @@ struct hdd_adapter {
 	struct qdf_mac_addr mld_addr;
 #endif
 	unsigned long event_flags;
+	uint8_t curr_link_info_map[WLAN_MAX_ML_BSS_LINKS];
 	unsigned long active_links;
 	uint8_t num_links_on_create;
 
@@ -2758,6 +2760,24 @@ hdd_adapter_get_next_active_link_info(struct hdd_adapter *adapter,
 struct wlan_hdd_link_info *
 wlan_hdd_get_link_info_from_objmgr(struct wlan_objmgr_vdev *vdev);
 
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \
+	defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV)
+/**
+ * hdd_adapter_disable_all_links() - Reset the links on stop adapter.
+ * @adapter: HDD adapter
+ *
+ * Resets the MAC address in each link info and resets the link info
+ * mapping in adapter array.
+ *
+ * Return: void
+ */
+void hdd_adapter_disable_all_links(struct hdd_adapter *adapter);
+#else
+static inline void hdd_adapter_disable_all_links(struct hdd_adapter *adapter)
+{
+}
+#endif
+
 struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx,
 				     uint8_t session_type,
 				     const char *name, tSirMacAddr mac_addr,
@@ -5241,6 +5261,41 @@ QDF_STATUS hdd_stop_adapter_ext(struct hdd_context *hdd_ctx,
  */
 void hdd_check_for_net_dev_ref_leak(struct hdd_adapter *adapter);
 
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV)
+
+/**
+ * hdd_link_switch_vdev_mac_addr_update() - API to update OSIF/HDD on VDEV
+ * mac addr update due to link switch.
+ * @ieee_old_link_id: Current  IEEE link ID of VDEV prior to link switch
+ * @ieee_new_link_id: New IEEE link ID of VDEV post link switch
+ * @vdev_id: VDEV undergoing link switch.
+ *
+ * Check if both @ieee_old_link_id and @ieee_new_link_id are part of adapter
+ * corresponding to @vdev_id. Then take necessary actions to support link switch
+ * MAC update and update DP to change link MAC address to new link's address.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+hdd_link_switch_vdev_mac_addr_update(int32_t ieee_old_link_id,
+				     int32_t ieee_new_link_id, uint8_t vdev_id);
+
+/**
+ * hdd_get_link_info_by_ieee_link_id() - Find link info pointer matching with
+ * IEEE link ID.
+ * @adapter: HDD adapter
+ * @link_id: IEEE link ID to search for.
+ *
+ * Search the station ctx connection info for matching link ID in @adapter and
+ * return the link info pointer on match. The IEEE link ID is updated in station
+ * context during MLO connection and reset on disconnection.
+ *
+ * Return: link info pointer
+ */
+struct wlan_hdd_link_info *
+hdd_get_link_info_by_ieee_link_id(struct hdd_adapter *adapter, int32_t link_id);
+#endif
+
 #ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE
 /**
  * hdd_dynamic_mac_address_set(): API to set MAC address, when interface

+ 159 - 13
core/hdd/src/wlan_hdd_main.c

@@ -5835,6 +5835,144 @@ hdd_is_dynamic_set_mac_addr_supported(struct hdd_context *hdd_ctx)
 }
 #endif
 
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV)
+static QDF_STATUS
+hdd_adapter_update_links_on_link_switch(struct wlan_hdd_link_info *cur_link_info,
+					struct wlan_hdd_link_info *new_link_info)
+{
+	unsigned long link_flags;
+	struct wlan_objmgr_vdev *vdev;
+	int cur_link_idx, new_link_idx;
+	uint8_t cur_old_pos, cur_new_pos;
+	struct vdev_osif_priv *vdev_priv;
+	struct hdd_adapter *adapter = cur_link_info->adapter;
+
+	/* Update the new position of current and new link info
+	 * in the link info array.
+	 */
+	cur_link_idx = hdd_adapter_get_index_of_link_info(cur_link_info);
+	new_link_idx = hdd_adapter_get_index_of_link_info(new_link_info);
+
+	cur_old_pos = adapter->curr_link_info_map[cur_link_idx];
+	cur_new_pos = adapter->curr_link_info_map[new_link_idx];
+
+	adapter->curr_link_info_map[new_link_idx] = cur_old_pos;
+	adapter->curr_link_info_map[cur_link_idx] = cur_new_pos;
+
+	/* Move VDEV from current link info to new link info */
+	qdf_atomic_clear_bit(cur_link_idx, &adapter->active_links);
+	qdf_spin_lock_bh(&cur_link_info->vdev_lock);
+	vdev = cur_link_info->vdev;
+	cur_link_info->vdev = NULL;
+	cur_link_info->vdev_id = WLAN_INVALID_VDEV_ID;
+	qdf_spin_unlock_bh(&cur_link_info->vdev_lock);
+
+	qdf_spin_lock_bh(&new_link_info->vdev_lock);
+	new_link_info->vdev = vdev;
+	new_link_info->vdev_id = wlan_vdev_get_id(vdev);
+	qdf_spin_unlock_bh(&new_link_info->vdev_lock);
+	qdf_atomic_set_bit(new_link_idx, &adapter->active_links);
+
+	/* Move the link flags between current and new link info */
+	link_flags = new_link_info->link_flags;
+	new_link_info->link_flags = cur_link_info->link_flags;
+	cur_link_info->link_flags = link_flags;
+
+	/* Update VDEV-OSIF priv pointer to new link info */
+	vdev_priv = wlan_vdev_get_ospriv(new_link_info->vdev);
+	vdev_priv->legacy_osif_priv = new_link_info;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+struct wlan_hdd_link_info *
+hdd_get_link_info_by_ieee_link_id(struct hdd_adapter *adapter, int32_t link_id)
+{
+	struct wlan_hdd_link_info *link_info;
+	struct hdd_station_ctx *sta_ctx;
+
+	if (!adapter || link_id == WLAN_INVALID_LINK_ID) {
+		hdd_err("NULL adapter or invalid link ID");
+		return NULL;
+	}
+
+	hdd_adapter_for_each_link_info(adapter, link_info) {
+		sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
+		if (sta_ctx->conn_info.ieee_link_id == link_id)
+			return link_info;
+	}
+
+	return NULL;
+}
+
+QDF_STATUS
+hdd_link_switch_vdev_mac_addr_update(int32_t ieee_old_link_id,
+				     int32_t ieee_new_link_id, uint8_t vdev_id)
+{
+	QDF_STATUS status = QDF_STATUS_E_INVAL;
+	struct hdd_context *hdd_ctx;
+	struct hdd_adapter *adapter;
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_hdd_link_info *cur_link_info, *new_link_info;
+	struct hdd_station_ctx *sta_ctx;
+
+	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+	if (!hdd_ctx) {
+		hdd_err("HDD ctx NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	cur_link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
+	if (!cur_link_info) {
+		hdd_err("VDEV %d not found", vdev_id);
+		return status;
+	}
+
+	vdev = hdd_objmgr_get_vdev_by_user(cur_link_info, WLAN_OSIF_ID);
+	if (!vdev) {
+		hdd_err("Invalid VDEV %d", vdev_id);
+		return status;
+	}
+
+	sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(cur_link_info);
+	if (sta_ctx->conn_info.ieee_link_id != ieee_old_link_id) {
+		hdd_err("Link id %d mismatch", sta_ctx->conn_info.ieee_link_id);
+		goto release_ref;
+	}
+
+	adapter = cur_link_info->adapter;
+	new_link_info = hdd_get_link_info_by_ieee_link_id(adapter,
+							  ieee_new_link_id);
+	if (!new_link_info) {
+		hdd_err("Link id %d not found", ieee_new_link_id);
+		goto release_ref;
+	}
+
+	status = ucfg_dp_update_link_mac_addr(vdev, &new_link_info->link_addr,
+					      true);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("DP link MAC update failed");
+		goto release_ref;
+	}
+
+	status = hdd_adapter_update_links_on_link_switch(cur_link_info,
+							 new_link_info);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("Failed to update adapter link info");
+		goto release_ref;
+	}
+
+	hdd_adapter_update_mlo_mgr_mac_addr(adapter);
+	sme_vdev_set_data_tx_callback(vdev);
+	ucfg_pmo_del_wow_pattern(vdev);
+	ucfg_pmo_register_wow_default_patterns(vdev);
+
+release_ref:
+	hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
+	return status;
+}
+#endif
+
 /**
  * __hdd_set_mac_address() - set the user specified mac address
  * @dev:	Pointer to the net device.
@@ -7639,8 +7777,7 @@ static void hdd_sta_destroy_ctx_all(struct hdd_context *hdd_ctx)
 	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
 					   NET_DEV_HOLD_STA_DESTROY_CTX_ALL) {
 		if (adapter->device_mode == QDF_STA_MODE) {
-			hdd_adapter_for_each_active_link_info(adapter,
-							      link_info) {
+			hdd_adapter_for_each_link_info(adapter, link_info) {
 				hdd_cleanup_conn_info(link_info);
 			}
 		}
@@ -7672,8 +7809,10 @@ static inline void hdd_adapter_destroy_vdev_info(struct hdd_adapter *adapter)
 {
 	struct wlan_hdd_link_info *link_info;
 
-	hdd_adapter_for_each_link_info(adapter, link_info)
+	hdd_adapter_for_each_link_info(adapter, link_info) {
+		qdf_event_destroy(&link_info->acs_complete_event);
 		qdf_spinlock_destroy(&link_info->vdev_lock);
+	}
 }
 
 static void hdd_cleanup_adapter(struct hdd_context *hdd_ctx,
@@ -8271,17 +8410,21 @@ wlan_hdd_set_ml_cap_for_sap_intf(struct hdd_adapter_create_param *create_params,
 
 #if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \
 	defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV)
-static void hdd_adapter_disable_all_links(struct hdd_adapter *adapter)
+void hdd_adapter_disable_all_links(struct hdd_adapter *adapter)
 {
+	uint8_t idx_pos;
 	struct wlan_hdd_link_info *link_info;
 
-	hdd_adapter_for_each_link_info(adapter, link_info)
+	hdd_adapter_for_each_link_info(adapter, link_info) {
 		qdf_zero_macaddr(&link_info->link_addr);
-}
-#else
-static inline void
-hdd_adapter_disable_all_links(struct hdd_adapter *adapter)
-{
+		idx_pos = hdd_adapter_get_index_of_link_info(link_info);
+		adapter->curr_link_info_map[idx_pos] = idx_pos;
+	}
+	adapter->deflink = &adapter->link_info[WLAN_HDD_DEFLINK_IDX];
+	if (adapter->device_mode == QDF_STA_MODE)
+		adapter->active_links = (1 << adapter->num_links_on_create) - 1;
+	else
+		adapter->active_links = 0x1;
 }
 #endif
 
@@ -8307,6 +8450,7 @@ static void hdd_adapter_enable_links(struct hdd_adapter *adapter,
 
 static void hdd_adapter_init_link_info(struct hdd_adapter *adapter)
 {
+	uint8_t idx_pos;
 	struct wlan_hdd_link_info *link_info;
 
 	/* Initialize each member in link info array to default values */
@@ -8315,6 +8459,10 @@ static void hdd_adapter_init_link_info(struct hdd_adapter *adapter)
 		link_info->vdev_id = WLAN_UMAC_VDEV_ID_MAX;
 		qdf_spinlock_create(&link_info->vdev_lock);
 		init_completion(&link_info->vdev_destroy_event);
+		qdf_event_create(&link_info->acs_complete_event);
+
+		idx_pos = hdd_adapter_get_index_of_link_info(link_info);
+		adapter->curr_link_info_map[idx_pos] = idx_pos;
 	}
 }
 
@@ -8565,7 +8713,6 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx,
 		  hdd_stop_sap_due_to_invalid_channel);
 	qdf_list_create(&adapter->blocked_scan_request_q, WLAN_MAX_SCAN_COUNT);
 	qdf_mutex_create(&adapter->blocked_scan_request_q_lock);
-	qdf_event_create(&adapter->deflink->acs_complete_event);
 	qdf_spinlock_create(&adapter->mc_list_lock);
 	qdf_event_create(&adapter->peer_cleanup_done);
 	hdd_sta_info_init(&adapter->sta_info_list);
@@ -8625,13 +8772,12 @@ static void __hdd_close_adapter(struct hdd_context *hdd_ctx,
 
 	qdf_copy_macaddr(&adapter_mac, &adapter->mac_addr);
 	if (adapter->device_mode == QDF_STA_MODE) {
-		hdd_adapter_for_each_active_link_info(adapter, link_info)
+		hdd_adapter_for_each_link_info(adapter, link_info)
 			hdd_cleanup_conn_info(link_info);
 	}
 	qdf_list_destroy(&adapter->blocked_scan_request_q);
 	qdf_mutex_destroy(&adapter->blocked_scan_request_q_lock);
 	policy_mgr_clear_concurrency_mode(hdd_ctx->psoc, adapter->device_mode);
-	qdf_event_destroy(&adapter->deflink->acs_complete_event);
 	qdf_event_destroy(&adapter->peer_cleanup_done);
 	hdd_adapter_feature_update_work_deinit(adapter);
 	hdd_cleanup_adapter(hdd_ctx, adapter, rtnl_held);

+ 81 - 6
core/hdd/src/wlan_hdd_mlo.c

@@ -30,6 +30,7 @@
 #include "wlan_psoc_mlme_ucfg_api.h"
 #include "wlan_osif_request_manager.h"
 #include "wlan_hdd_object_manager.h"
+#include <wlan_osif_priv.h>
 
 /*max time in ms, caller may wait for link state request get serviced */
 #define WLAN_WAIT_TIME_LINK_STATE 800
@@ -253,6 +254,7 @@ void hdd_adapter_set_ml_adapter(struct hdd_adapter *adapter)
 
 static struct mlo_osif_ext_ops mlo_osif_ops = {
 	.mlo_mgr_osif_update_bss_info = hdd_cm_save_connected_links_info,
+	.mlo_mgr_osif_update_mac_addr = hdd_link_switch_vdev_mac_addr_update,
 };
 
 QDF_STATUS hdd_mlo_mgr_register_osif_ops(void)
@@ -328,10 +330,80 @@ QDF_STATUS hdd_derive_link_address_from_mld(struct qdf_mac_addr *mld_addr,
 
 #ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE
 #ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV
+static void hdd_adapter_restore_link_vdev_map(struct hdd_adapter *adapter)
+{
+	int i;
+	unsigned long link_flags;
+	uint8_t vdev_id, cur_link_idx, temp_link_idx;
+	struct vdev_osif_priv *osif_priv;
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_hdd_link_info *temp_link_info, *link_info;
+
+	hdd_adapter_for_each_link_info(adapter, link_info) {
+		cur_link_idx = hdd_adapter_get_index_of_link_info(link_info);
+		/* If the current index matches the current pos in mapping
+		 * then the link info is in same position
+		 */
+		if (adapter->curr_link_info_map[cur_link_idx] == cur_link_idx)
+			continue;
+
+		/* Find the index where current link info is moved to perform
+		 * VDEV info swap.
+		 */
+		for (i = cur_link_idx + 1; i < WLAN_MAX_ML_BSS_LINKS; i++) {
+			if (adapter->curr_link_info_map[i] == cur_link_idx) {
+				temp_link_idx = i;
+				break;
+			}
+		}
+
+		if (i == WLAN_MAX_ML_BSS_LINKS)
+			continue;
+
+		temp_link_info = &adapter->link_info[temp_link_idx];
+
+		/* Move VDEV info from current link info */
+		qdf_spin_lock_bh(&temp_link_info->vdev_lock);
+		vdev = temp_link_info->vdev;
+		vdev_id = temp_link_info->vdev_id;
+		temp_link_info->vdev = link_info->vdev;
+		temp_link_info->vdev_id = link_info->vdev_id;
+		qdf_spin_unlock_bh(&temp_link_info->vdev_lock);
+
+		/* Fill current link info's actual VDEV info */
+		qdf_spin_lock_bh(&link_info->vdev_lock);
+		link_info->vdev = vdev;
+		link_info->vdev_id = vdev_id;
+		qdf_spin_unlock_bh(&link_info->vdev_lock);
+
+		/* Swap link flags */
+		link_flags = temp_link_info->link_flags;
+		temp_link_info->link_flags = link_info->link_flags;
+		link_info->link_flags = link_flags;
+
+		/* Update VDEV-OSIF priv pointer to new link info. */
+		if (!vdev)
+			continue;
+
+		osif_priv = wlan_vdev_get_ospriv(vdev);
+		if (!osif_priv)
+			continue;
+		osif_priv->legacy_osif_priv = link_info;
+
+		/* Update the mapping, current link info's mapping will be
+		 * set to be proper.
+		 */
+		adapter->curr_link_info_map[temp_link_idx] =
+				adapter->curr_link_info_map[cur_link_idx];
+		adapter->curr_link_info_map[cur_link_idx] = cur_link_idx;
+	}
+	hdd_adapter_disable_all_links(adapter);
+}
+
 int hdd_update_vdev_mac_address(struct hdd_adapter *adapter,
 				struct qdf_mac_addr mac_addr)
 {
-	int i = 0, ret = 0;
+	int idx, i, ret = 0;
 	bool eht_capab, update_self_peer;
 	QDF_STATUS status;
 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
@@ -358,9 +430,12 @@ int hdd_update_vdev_mac_address(struct hdd_adapter *adapter,
 	if (QDF_IS_STATUS_ERROR(status))
 		return qdf_status_to_os_return(status);
 
+	hdd_adapter_restore_link_vdev_map(adapter);
+
+	i = 0;
 	hdd_adapter_for_each_active_link_info(adapter, link_info) {
-		addr_list[i] = &link_addrs[i].bytes[0];
-		i++;
+		idx = hdd_adapter_get_index_of_link_info(link_info);
+		addr_list[i++] = &link_addrs[idx].bytes[0];
 	}
 
 	status = sme_check_for_duplicate_session(hdd_ctx->mac_handle,
@@ -372,16 +447,16 @@ int hdd_update_vdev_mac_address(struct hdd_adapter *adapter,
 	hdd_adapter_for_each_link_info(adapter, link_info)
 		qdf_copy_macaddr(&link_info->link_addr, &link_addrs[i++]);
 
-	i = 0;
 	hdd_adapter_for_each_active_link_info(adapter, link_info) {
+		idx = hdd_adapter_get_index_of_link_info(link_info);
 		update_self_peer =
 			(link_info == adapter->deflink) ? true : false;
-		ret = hdd_dynamic_mac_address_set(link_info, link_addrs[i],
+		ret = hdd_dynamic_mac_address_set(link_info, link_addrs[idx],
 						  mac_addr, update_self_peer);
 		if (ret)
 			return ret;
 
-		qdf_copy_macaddr(&link_info->link_addr, &link_addrs[i++]);
+		qdf_copy_macaddr(&link_info->link_addr, &link_addrs[idx]);
 	}
 
 	hdd_adapter_update_mlo_mgr_mac_addr(adapter);