Jelajahi Sumber

qcacld-3.0: Add dp_link data structure

Currently dp_intf is create on adapter level,
but corresponds to vdev. ML connection can have
multiple links for same adapter.

Hence introduce a new data structure dp_link,
which corresponds to the vdev, whereas dp_intf
now corresponds only to adapter/netdev.

Change-Id: Ia2bba89f425b64b4e404f6866a54fe0f6e05ad6d
CRs-Fixed: 3518894
Rakesh Pillai 2 tahun lalu
induk
melakukan
21052cf452

+ 77 - 0
components/dp/core/inc/wlan_dp_main.h

@@ -144,6 +144,83 @@ dp_get_intf_by_macaddr(struct wlan_dp_psoc_context *dp_ctx,
 struct wlan_dp_intf*
 dp_get_intf_by_netdev(struct wlan_dp_psoc_context *dp_ctx, qdf_netdev_t dev);
 
+/**
+ * dp_get_front_link_no_lock() - Get the first link from the dp links list
+ * This API does not use any lock in it's implementation. It is the caller's
+ * directive to ensure concurrency safety.
+ * @dp_intf: DP interface handle
+ * @out_link: double pointer to pass the next link
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+dp_get_front_link_no_lock(struct wlan_dp_intf *dp_intf,
+			  struct wlan_dp_link **out_link);
+
+/**
+ * dp_get_next_link_no_lock() - Get the next link from the link list
+ * This API does not use any lock in it's implementation. It is the caller's
+ * directive to ensure concurrency safety.
+ * @dp_intf: DP interface handle
+ * @cur_link: pointer to the currentlink
+ * @out_link: double pointer to pass the nextlink
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+dp_get_next_link_no_lock(struct wlan_dp_intf *dp_intf,
+			 struct wlan_dp_link *cur_link,
+			 struct wlan_dp_link **out_link);
+
+/**
+ * __dp_take_ref_and_fetch_front_link_safe - Helper macro to lock, fetch
+ * front and next link, take ref and unlock.
+ * @dp_intf: DP interface handle
+ * @dp_link: an dp_link pointer to use as a cursor
+ * @dp_link_next: dp_link pointer to nextlink
+ */
+#define __dp_take_ref_and_fetch_front_link_safe(dp_intf, dp_link, \
+						dp_link_next) \
+	qdf_spin_lock_bh(&(dp_intf)->dp_link_list_lock), \
+	dp_get_front_link_no_lock(dp_intf, &(dp_link)), \
+	dp_get_next_link_no_lock(dp_intf, dp_link, &(dp_link_next)), \
+	qdf_spin_unlock_bh(&(dp_intf)->dp_link_list_lock)
+
+/**
+ * __dp_take_ref_and_fetch_next_link_safe - Helper macro to lock, fetch next
+ * interface, take ref and unlock.
+ * @dp_intf: DP interface handle
+ * @dp_link: dp_link pointer to use as a cursor
+ * @dp_link_next: dp_link pointer to next link
+ */
+#define __dp_take_ref_and_fetch_next_link_safe(dp_intf, dp_link, \
+					       dp_link_next) \
+	qdf_spin_lock_bh(&(dp_intf)->dp_link_list_lock), \
+	dp_link = dp_link_next, \
+	dp_get_next_link_no_lock(dp_intf, dp_link, &(dp_link_next)), \
+	qdf_spin_unlock_bh(&(dp_intf)->dp_link_list_lock)
+
+/**
+ * __dp_is_link_valid - Helper macro to return true/false for valid interface.
+ * @_dp_link: an dp_link pointer to use as a cursor
+ */
+#define __dp_is_link_valid(_dp_link) !!(_dp_link)
+
+/**
+ * dp_for_each_link_held_safe - Interface iterator called
+ *                                      in a delete safe manner
+ * @dp_intf: DP interface handle
+ * @dp_link: an dp_link pointer to use as a cursor
+ * @dp_link_next: dp_link pointer to the next interface
+ *
+ */
+#define dp_for_each_link_held_safe(dp_intf, dp_link, dp_link_next) \
+	for (__dp_take_ref_and_fetch_front_link_safe(dp_intf, dp_link, \
+						     dp_link_next); \
+	     __dp_is_link_valid(dp_link); \
+	     __dp_take_ref_and_fetch_next_link_safe(dp_intf, dp_link, \
+						    dp_link_next))
+
 /* MAX iteration count to wait for dp packet process to complete */
 #define DP_TASK_MAX_WAIT_CNT  100
 /* Milli seconds to wait when packet is getting processed */

+ 22 - 0
components/dp/core/inc/wlan_dp_priv.h

@@ -613,6 +613,10 @@ struct dp_rx_fst {
  * @qdf_sta_eap_frm_done_event: EAP frame event management
  * @traffic_end_ind: store traffic end indication info
  * @direct_link_config: direct link configuration parameters
+ * @num_links: Number of links for this DP interface
+ * @def_link: Pointer to default link (usually used for TX operation)
+ * @dp_link_list_lock: Lock to protect dp_link_list operatiosn
+ * @dp_link_list: List of dp_links for this DP interface
  */
 struct wlan_dp_intf {
 	struct wlan_dp_psoc_context *dp_ctx;
@@ -674,6 +678,24 @@ struct wlan_dp_intf {
 #ifdef FEATURE_DIRECT_LINK
 	struct direct_link_info direct_link_config;
 #endif
+	uint8_t num_links;
+	struct wlan_dp_link *def_link;
+	qdf_spinlock_t dp_link_list_lock;
+	qdf_list_t dp_link_list;
+};
+
+/**
+ * struct wlan_dp_link - DP link (corresponds to objmgr vdev)
+ * @node: list node for membership in the DP links list
+ * @link_id: ID for this DP link (Same as vdev_id)
+ * @mac_addr: mac address of this link
+ * @dp_intf: Parent DP interface for this DP link
+ */
+struct wlan_dp_link {
+	qdf_list_node_t node;
+	uint8_t link_id;
+	struct qdf_mac_addr mac_addr;
+	struct wlan_dp_intf *dp_intf;
 };
 
 /**

+ 137 - 39
components/dp/core/src/wlan_dp_main.c

@@ -216,6 +216,48 @@ int is_dp_intf_valid(struct wlan_dp_intf *dp_intf)
 	return validate_interface_id(dp_intf->intf_id);
 }
 
+QDF_STATUS dp_get_front_link_no_lock(struct wlan_dp_intf *dp_intf,
+				     struct wlan_dp_link **out_link)
+{
+	QDF_STATUS status;
+	qdf_list_node_t *node;
+
+	*out_link = NULL;
+
+	status = qdf_list_peek_front(&dp_intf->dp_link_list, &node);
+
+	if (QDF_IS_STATUS_ERROR(status))
+		return status;
+
+	*out_link = qdf_container_of(node, struct wlan_dp_link, node);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS dp_get_next_link_no_lock(struct wlan_dp_intf *dp_intf,
+				    struct wlan_dp_link *cur_link,
+				    struct wlan_dp_link **out_link)
+{
+	QDF_STATUS status;
+	qdf_list_node_t *node;
+
+	if (!cur_link)
+		return QDF_STATUS_E_INVAL;
+
+	*out_link = NULL;
+
+	status = qdf_list_peek_next(&dp_intf->dp_link_list,
+				    &cur_link->node,
+				    &node);
+
+	if (QDF_IS_STATUS_ERROR(status))
+		return status;
+
+	*out_link = qdf_container_of(node, struct wlan_dp_link, node);
+
+	return status;
+}
+
 static QDF_STATUS
 dp_intf_wait_for_task_complete(struct wlan_dp_intf *dp_intf)
 {
@@ -919,11 +961,13 @@ dp_vdev_obj_create_notification(struct wlan_objmgr_vdev *vdev, void *arg)
 	struct wlan_objmgr_psoc *psoc;
 	struct wlan_dp_psoc_context *dp_ctx;
 	struct wlan_dp_intf *dp_intf;
+	struct wlan_dp_link *dp_link;
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 	struct qdf_mac_addr *mac_addr;
 	qdf_netdev_t dev;
 
-	dp_info("DP VDEV OBJ create notification");
+	dp_info("DP VDEV OBJ create notification, vdev_id %d",
+		wlan_vdev_get_id(vdev));
 
 	psoc = wlan_vdev_get_psoc(vdev);
 	if (!psoc) {
@@ -949,36 +993,62 @@ dp_vdev_obj_create_notification(struct wlan_objmgr_vdev *vdev, void *arg)
 		return QDF_STATUS_E_INVAL;
 	}
 
-	dp_intf->device_mode = wlan_vdev_mlme_get_opmode(vdev);
+	dp_link = qdf_mem_malloc(sizeof(*dp_link));
+	if (!dp_link) {
+		dp_err("DP link(" QDF_MAC_ADDR_FMT ") memory alloc failed",
+		       QDF_MAC_ADDR_REF(mac_addr->bytes));
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	/* Update Parent interface details */
+	dp_link->dp_intf = dp_intf;
+	qdf_spin_lock_bh(&dp_intf->dp_link_list_lock);
+	qdf_list_insert_front(&dp_intf->dp_link_list, &dp_link->node);
+	dp_intf->num_links++;
+	qdf_spin_unlock_bh(&dp_intf->dp_link_list_lock);
+
+	qdf_copy_macaddr(&dp_link->mac_addr, mac_addr);
+
 	qdf_spin_lock_bh(&dp_intf->vdev_lock);
+	dp_link->link_id = vdev->vdev_objmgr.vdev_id;
 	dp_intf->intf_id = vdev->vdev_objmgr.vdev_id;
 	dp_intf->vdev = vdev;
 	qdf_spin_unlock_bh(&dp_intf->vdev_lock);
-	qdf_atomic_init(&dp_intf->num_active_task);
-
-	if (dp_intf->device_mode == QDF_SAP_MODE ||
-	    dp_intf->device_mode == QDF_P2P_GO_MODE) {
-		dp_intf->sap_tx_block_mask = DP_TX_FN_CLR | DP_TX_SAP_STOP;
-
-		status = qdf_event_create(&dp_intf->qdf_sta_eap_frm_done_event);
-		if (!QDF_IS_STATUS_SUCCESS(status)) {
-			dp_err("eap frm done event init failed!!");
-			return status;
-		}
-		qdf_mem_zero(&dp_intf->stats, sizeof(qdf_net_dev_stats));
-	}
 
 	status = wlan_objmgr_vdev_component_obj_attach(vdev,
 						       WLAN_COMP_DP,
-						       (void *)dp_intf,
+						       (void *)dp_link,
 						       QDF_STATUS_SUCCESS);
 	if (QDF_IS_STATUS_ERROR(status)) {
-		dp_err("Failed to attach dp_intf with vdev");
+		dp_err("Failed to attach dp_link with vdev");
 		return status;
 	}
 
-	dp_nud_ignore_tracking(dp_intf, false);
-	dp_mic_enable_work(dp_intf);
+	if (dp_intf->num_links == 1) {
+		/*
+		 * Interface level operations to be done only
+		 * when the first link is created
+		 */
+		dp_intf->def_link = dp_link;
+		dp_intf->device_mode = wlan_vdev_mlme_get_opmode(vdev);
+		qdf_atomic_init(&dp_intf->num_active_task);
+		dp_nud_ignore_tracking(dp_intf, false);
+		dp_mic_enable_work(dp_intf);
+
+		if (dp_intf->device_mode == QDF_SAP_MODE ||
+		    dp_intf->device_mode == QDF_P2P_GO_MODE) {
+			dp_intf->sap_tx_block_mask = DP_TX_FN_CLR |
+						     DP_TX_SAP_STOP;
+
+			status = qdf_event_create(&dp_intf->qdf_sta_eap_frm_done_event);
+			if (!QDF_IS_STATUS_SUCCESS(status)) {
+				dp_err("eap frm done event init failed!!");
+				return status;
+			}
+			qdf_mem_zero(&dp_intf->stats,
+				     sizeof(qdf_net_dev_stats));
+		}
+	}
 
 	return status;
 }
@@ -988,48 +1058,76 @@ dp_vdev_obj_destroy_notification(struct wlan_objmgr_vdev *vdev, void *arg)
 
 {
 	struct wlan_dp_intf *dp_intf;
+	struct wlan_dp_link *dp_link;
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
 
-	dp_info("DP VDEV OBJ destroy notification");
+	dp_info("DP VDEV OBJ destroy notification, vdev_id %d",
+		wlan_vdev_get_id(vdev));
 
 	dp_intf = dp_get_vdev_priv_obj(vdev);
-	if (!dp_intf) {
-		dp_err("Failed to get DP interface obj");
+	/*
+	 * TODO - Remove the below line after proto-type of
+	 * dp_get_vdev_priv_obj is changed
+	 */
+	dp_link = (struct wlan_dp_link *)dp_intf;
+	if (!dp_link) {
+		dp_err("Failed to get DP link obj");
 		return QDF_STATUS_E_INVAL;
 	}
 
-	dp_nud_ignore_tracking(dp_intf, true);
-	dp_nud_reset_tracking(dp_intf);
-	dp_nud_flush_work(dp_intf);
-	dp_mic_flush_work(dp_intf);
+	dp_intf = dp_link->dp_intf;
 
+	qdf_spin_lock_bh(&dp_intf->dp_link_list_lock);
+	qdf_list_remove_node(&dp_intf->dp_link_list, &dp_link->node);
+	dp_intf->num_links--;
+	qdf_spin_unlock_bh(&dp_intf->dp_link_list_lock);
+
+	if (dp_intf->num_links == 0) {
+		/*
+		 * Interface level operations are stopped when last
+		 * link is deleted
+		 */
+		dp_nud_ignore_tracking(dp_intf, true);
+		dp_nud_reset_tracking(dp_intf);
+		dp_nud_flush_work(dp_intf);
+		dp_mic_flush_work(dp_intf);
+		qdf_mem_zero(&dp_intf->conn_info,
+			     sizeof(struct wlan_dp_conn_info));
+
+		if (dp_intf->device_mode == QDF_SAP_MODE ||
+		    dp_intf->device_mode == QDF_P2P_GO_MODE) {
+			status = qdf_event_destroy(&dp_intf->qdf_sta_eap_frm_done_event);
+			if (!QDF_IS_STATUS_SUCCESS(status)) {
+				dp_err("eap frm done event destroy failed!!");
+				return status;
+			}
+			dp_intf->txrx_ops.tx.tx = NULL;
+			dp_intf->sap_tx_block_mask |= DP_TX_FN_CLR;
+		}
+	}
+
+	/*
+	 * Change this to link level, since during link switch,
+	 * it might not go to 0
+	 */
 	status = dp_intf_wait_for_task_complete(dp_intf);
 	if (QDF_IS_STATUS_ERROR(status))
 		return status;
 
-	if (dp_intf->device_mode == QDF_SAP_MODE ||
-	    dp_intf->device_mode == QDF_P2P_GO_MODE) {
-		status = qdf_event_destroy(&dp_intf->qdf_sta_eap_frm_done_event);
-		if (!QDF_IS_STATUS_SUCCESS(status)) {
-			dp_err("eap frm done event destroy failed!!");
-			return status;
-		}
-		dp_intf->txrx_ops.tx.tx = NULL;
-		dp_intf->sap_tx_block_mask |= DP_TX_FN_CLR;
-	}
-	qdf_mem_zero(&dp_intf->conn_info, sizeof(struct wlan_dp_conn_info));
 	dp_intf->intf_id = WLAN_UMAC_VDEV_ID_MAX;
 	qdf_spin_lock_bh(&dp_intf->vdev_lock);
 	dp_intf->vdev = NULL;
 	qdf_spin_unlock_bh(&dp_intf->vdev_lock);
+
 	status = wlan_objmgr_vdev_component_obj_detach(vdev,
 						       WLAN_COMP_DP,
-						       (void *)dp_intf);
+						       (void *)dp_link);
 	if (QDF_IS_STATUS_ERROR(status)) {
-		dp_err("Failed to detach dp_intf with vdev");
+		dp_err("Failed to detach dp_link with vdev");
 		return status;
 	}
 
+	qdf_mem_free(dp_link);
 	return status;
 }
 

+ 7 - 0
components/dp/dispatcher/src/wlan_dp_ucfg_api.c

@@ -120,6 +120,7 @@ ucfg_dp_create_intf(struct wlan_objmgr_psoc *psoc,
 		return QDF_STATUS_E_FAILURE;
 	}
 
+	dp_intf->def_link = NULL;
 	dp_intf->dp_ctx = dp_ctx;
 	dp_intf->dev = ndev;
 	dp_intf->intf_id = WLAN_UMAC_VDEV_ID_MAX;
@@ -130,6 +131,9 @@ ucfg_dp_create_intf(struct wlan_objmgr_psoc *psoc,
 	qdf_list_insert_front(&dp_ctx->intf_list, &dp_intf->node);
 	qdf_spin_unlock_bh(&dp_ctx->intf_list_lock);
 
+	qdf_spinlock_create(&dp_intf->dp_link_list_lock);
+	qdf_list_create(&dp_intf->dp_link_list, 0);
+
 	dp_periodic_sta_stats_init(dp_intf);
 	dp_periodic_sta_stats_mutex_create(dp_intf);
 	dp_nud_init_tracking(dp_intf);
@@ -167,6 +171,9 @@ ucfg_dp_destroy_intf(struct wlan_objmgr_psoc *psoc,
 	dp_mic_deinit_work(dp_intf);
 	qdf_spinlock_destroy(&dp_intf->vdev_lock);
 
+	qdf_spinlock_destroy(&dp_intf->dp_link_list_lock);
+	qdf_list_destroy(&dp_intf->dp_link_list);
+
 	qdf_spin_lock_bh(&dp_ctx->intf_list_lock);
 	qdf_list_remove_node(&dp_ctx->intf_list, &dp_intf->node);
 	qdf_spin_unlock_bh(&dp_ctx->intf_list_lock);