Ver Fonte

qcacmn: Remove all commands related to vdev when it is destroyed

If serialization module has queued some commands for particular vdev
and if that vdev gets destroyed without informing serialization
module then upon those command timeout, serialization try to point
vdev pointer which is invalid. This situation create a crash.

If serialization module has some commands pending or active for vdev
which is being destroyed then remove those commands as part of vdev
destroyed notification.

CRs-Fixed: 2099063
Change-Id: I8df9900d83bea758ca5c50cbe0edf31e06f83a4c
Krunal Soni há 7 anos atrás
pai
commit
be546459fa

+ 66 - 9
umac/cmn_services/serialization/inc/wlan_serialization_legacy_api.h

@@ -145,25 +145,82 @@ uint32_t wlan_serialization_get_pending_list_count(
 		uint8_t is_cmd_from_pending_scan_queue);
 
 /**
- * wlan_serialization_purge_cmd_list() - Purge given list
+ * wlan_serialization_legacy_init_callback() - Initialize the legacy callbacks
+ *
+ * This API will be called only from legacy modules to initialize the
+ * purge command callbacks
+ *
+ * Return: none
+ */
+void wlan_serialization_legacy_init_callback(void);
+
+/**
+ * wlan_serialization_purge_cmd_list_by_vdev_id() - Purge given list
  * @psoc: pointer to soc
- * @vdev_id: pointer to vdev_id variable
+ * @vdev_id: vdev_id variable
  * @purge_scan_active_queue: whether to purge active scan queue
  * @purge_scan_pending_queue: whether to purge pending scan queue
  * @purge_nonscan_active_queue: whether to purge active nonscan queue
  * @purge_nonscan_pending_queue: whether to purge pending nonscan queue
  * @purge_all_queues: whether to purge all queues.
  *
- * This API will purge queue based given flags and vdev_id. If vdev_id
- * is null then it will purge the queues per pdev. If vdev_id is given then
+ * This API will purge queue based given flags and vdev_id. If vdev
+ * is invalid then it will return immediately. If correct vdev_id is given then
  * it will purge the queues per vdev.
  *
+ * Example:
+ * 1) If you want to purge scan active queue for particular vdev then
+ *    provide correct vdev_id value and purge_scan_active_queue flag set to
+ *    TRUE and rest of the flags set to false.
+ * 2) If you want to purge all queues for particular vdev then provide
+ *    correct vdev_id value and set purge_all_queues flag set to TRUE and rest
+ *    of the flags set to false.
+ * 3) If you want to purge active scan and active non-scan queues to be flushed
+ *    then set purge_scan_active_queue and purge_nonscan_active_queue flags to
+ *    be set TRUE and rest of the flags to be FALSE
+ *
+ * Return: none
+ */
+void wlan_serialization_purge_cmd_list_by_vdev_id(struct wlan_objmgr_psoc *psoc,
+		uint8_t vdev_id,
+		bool purge_scan_active_queue,
+		bool purge_scan_pending_queue,
+		bool purge_nonscan_active_queue,
+		bool purge_nonscan_pending_queue,
+		bool purge_all_queues);
+/**
+ * wlan_serialization_purge_cmd_list() - Purge given list
+ * @psoc: pointer to soc
+ * @vdev: pointer to vdev object
+ * @purge_scan_active_queue: whether to purge active scan queue
+ * @purge_scan_pending_queue: whether to purge pending scan queue
+ * @purge_nonscan_active_queue: whether to purge active nonscan queue
+ * @purge_nonscan_pending_queue: whether to purge pending nonscan queue
+ * @purge_all_queues: whether to purge all queues.
+ *
+ * This API will purge queue based given flags and vdev object. If vdev
+ * is null then it will purge the queues per pdev by default.
+ * If vdev is given then it will purge the queues per vdev.
+ *
+ * Example:
+ * 1) If you want to purge scan active queue for particular vdev then
+ *    provide correct vdev object and purge_scan_active_queue flag set to
+ *    TRUE and rest of the flags set to false.
+ * 2) If you want to purge all queues for particular vdev then provide
+ *    correct vdev object value & set purge_all_queues flag set to TRUE and rest
+ *    of the flags set to false.
+ * 3) If you want to purge active scan and active non-scan queues to be flushed
+ *    for pdev then set purge_scan_active_queue and purge_nonscan_active_queue
+ *    flags to be set TRUE and rest of the flags to be FALSE with vdev object
+ *    passed as NULL.
+ *
  * Return: none
  */
 void wlan_serialization_purge_cmd_list(struct wlan_objmgr_psoc *psoc,
-		uint8_t *vdev_id, uint8_t purge_scan_active_queue,
-		uint8_t purge_scan_pending_queue,
-		uint8_t purge_nonscan_active_queue,
-		uint8_t purge_nonscan_pending_queue,
-		uint8_t purge_all_queues);
+		struct wlan_objmgr_vdev *vdev,
+		bool purge_scan_active_queue,
+		bool purge_scan_pending_queue,
+		bool purge_nonscan_active_queue,
+		bool purge_nonscan_pending_queue,
+		bool purge_all_queues);
 #endif

+ 38 - 20
umac/cmn_services/serialization/src/wlan_serialization_legacy_api.c

@@ -27,6 +27,8 @@
 #include "wlan_serialization_utils_i.h"
 #include "wlan_objmgr_vdev_obj.h"
 
+extern struct serialization_legacy_callback ser_legacy_cb;
+
 static struct wlan_objmgr_pdev *wlan_serialization_get_first_pdev(
 			struct wlan_objmgr_psoc *psoc)
 {
@@ -372,17 +374,46 @@ release_vdev_ref:
 	return cmd;
 }
 
+void wlan_serialization_legacy_init_callback(void)
+{
+	ser_legacy_cb.serialization_purge_cmd_list =
+			wlan_serialization_purge_cmd_list;
+}
+
+void wlan_serialization_purge_cmd_list_by_vdev_id(struct wlan_objmgr_psoc *psoc,
+			uint8_t vdev_id, bool purge_scan_active_queue,
+			bool purge_scan_pending_queue,
+			bool purge_nonscan_active_queue,
+			bool purge_nonscan_pending_queue,
+			bool purge_all_queues)
+{
+	struct wlan_objmgr_vdev *vdev;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+			WLAN_SERIALIZATION_ID);
+	if (!vdev) {
+		serialization_err("Invalid vdev");
+		return;
+	}
+	wlan_serialization_purge_cmd_list(psoc, vdev, purge_scan_active_queue,
+				purge_scan_pending_queue,
+				purge_nonscan_active_queue,
+				purge_nonscan_pending_queue,
+				purge_all_queues);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_SERIALIZATION_ID);
+}
+
 void wlan_serialization_purge_cmd_list(struct wlan_objmgr_psoc *psoc,
-		uint8_t *vdev_id, uint8_t purge_scan_active_queue,
-		uint8_t purge_scan_pending_queue,
-		uint8_t purge_nonscan_active_queue,
-		uint8_t purge_nonscan_pending_queue,
-		uint8_t purge_all_queues)
+		struct wlan_objmgr_vdev *vdev,
+		bool purge_scan_active_queue,
+		bool purge_scan_pending_queue,
+		bool purge_nonscan_active_queue,
+		bool purge_nonscan_pending_queue,
+		bool purge_all_queues)
 {
 	struct wlan_serialization_timer *ser_timer;
 	struct wlan_serialization_psoc_priv_obj *psoc_ser_obj;
 	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
-	struct wlan_objmgr_vdev *vdev = NULL;
 	struct wlan_objmgr_pdev *pdev = NULL;
 	uint32_t i = 0;
 
@@ -400,18 +431,10 @@ void wlan_serialization_purge_cmd_list(struct wlan_objmgr_psoc *psoc,
 		serialization_err("Invalid psoc_ser_obj");
 		return;
 	}
-	if (vdev_id) {
-		vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, *vdev_id,
-				WLAN_SERIALIZATION_ID);
-		if (!vdev) {
-			serialization_err("Invalid vdev");
-			return;
-		}
-	}
 	pdev = wlan_serialization_get_first_pdev(psoc);
 	if (!pdev) {
 		serialization_err("Invalid pdev");
-		goto release_vdev_ref;
+		return;
 	}
 	for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) {
 		ser_timer = &psoc_ser_obj->timers[i];
@@ -464,11 +487,6 @@ void wlan_serialization_purge_cmd_list(struct wlan_objmgr_psoc *psoc,
 			pdev, vdev, NULL, false);
 	}
 	wlan_objmgr_pdev_release_ref(pdev, WLAN_SERIALIZATION_ID);
-release_vdev_ref:
-	/* vdev could be NULL if vdev_id passed is NULL */
-	if (vdev)
-		wlan_objmgr_vdev_release_ref(vdev, WLAN_SERIALIZATION_ID);
 
 	return;
 }
-

+ 135 - 5
umac/cmn_services/serialization/src/wlan_serialization_main.c

@@ -31,6 +31,8 @@
 #include "wlan_serialization_rules_i.h"
 #include "wlan_serialization_utils_i.h"
 
+struct serialization_legacy_callback ser_legacy_cb;
+
 QDF_STATUS wlan_serialization_psoc_close(struct wlan_objmgr_psoc *psoc)
 {
 	QDF_STATUS status;
@@ -78,7 +80,19 @@ QDF_STATUS wlan_serialization_psoc_open(struct wlan_objmgr_psoc *psoc)
 	return QDF_STATUS_SUCCESS;
 }
 
-QDF_STATUS wlan_serialization_psoc_obj_create_notification(
+/**
+ * wlan_serialization_psoc_obj_create_notification() - PSOC obj create callback
+ * @psoc: PSOC object
+ * @arg_list: Variable argument list
+ *
+ * This callback is registered with object manager during initialization and
+ * when obj manager gets its turn to create the object, it would notify each
+ * component with the corresponding callback registered to inform the
+ * completion of the creation of the respective object.
+ *
+ * Return: QDF Status
+ */
+static QDF_STATUS wlan_serialization_psoc_obj_create_notification(
 		struct wlan_objmgr_psoc *psoc, void *arg_list)
 {
 	struct wlan_serialization_psoc_priv_obj *soc_ser_obj;
@@ -161,7 +175,20 @@ wlan_serialization_create_cmd_pool(struct wlan_objmgr_pdev *pdev,
 	return QDF_STATUS_SUCCESS;
 }
 
-QDF_STATUS wlan_serialization_pdev_obj_create_notification(
+
+/**
+ * wlan_serialization_pdev_obj_create_notification() - PDEV obj create callback
+ * @pdev: PDEV object
+ * @arg_list: Variable argument list
+ *
+ * This callback is registered with object manager during initialization and
+ * when obj manager gets its turn to create the object, it would notify each
+ * component with the corresponding callback registered to inform the
+ * completion of the creation of the respective object.
+ *
+ * Return: QDF Status
+ */
+static QDF_STATUS wlan_serialization_pdev_obj_create_notification(
 		struct wlan_objmgr_pdev *pdev, void *arg_list)
 {
 	struct wlan_serialization_pdev_priv_obj *ser_pdev_obj;
@@ -199,7 +226,19 @@ QDF_STATUS wlan_serialization_pdev_obj_create_notification(
 	return status;
 }
 
-QDF_STATUS wlan_serialization_psoc_obj_destroy_notification(
+/**
+ * wlan_serialization_psoc_obj_destroy_notification() - PSOC obj delete callback
+ * @psoc: PSOC object
+ * @arg_list: Variable argument list
+ *
+ * This callback is registered with object manager during initialization and
+ * when obj manager gets its turn to delete the object, it would notify each
+ * component with the corresponding callback registered to inform the
+ * completion of the deletion of the respective object.
+ *
+ * Return: QDF Status
+ */
+static QDF_STATUS wlan_serialization_psoc_obj_destroy_notification(
 		struct wlan_objmgr_psoc *psoc, void *arg_list)
 {
 	QDF_STATUS status;
@@ -221,7 +260,19 @@ QDF_STATUS wlan_serialization_psoc_obj_destroy_notification(
 	return status;
 }
 
-QDF_STATUS wlan_serialization_pdev_obj_destroy_notification(
+/**
+ * wlan_serialization_pdev_obj_destroy_notification() - PDEV obj delete callback
+ * @pdev: PDEV object
+ * @arg_list: Variable argument list
+ *
+ * This callback is registered with object manager during initialization and
+ * when obj manager gets its turn to delete the object, it would notify each
+ * component with the corresponding callback registered to inform the
+ * completion of the deletion of the respective object.
+ *
+ * Return: QDF Status
+ */
+static QDF_STATUS wlan_serialization_pdev_obj_destroy_notification(
 		struct wlan_objmgr_pdev *pdev, void *arg_list)
 {
 	QDF_STATUS status;
@@ -245,6 +296,52 @@ QDF_STATUS wlan_serialization_pdev_obj_destroy_notification(
 	return status;
 }
 
+/**
+ * wlan_serialization_vdev_obj_create_notification() - VDEV obj create callback
+ * @vdev: VDEV object
+ * @arg_list: Variable argument list
+ *
+ * This callback is registered with object manager during initialization and
+ * when obj manager gets its turn to create the object, it would notify each
+ * component with the corresponding callback registered to inform the
+ * completion of the creation of the respective object.
+ *
+ * Return: QDF Status
+ */
+static QDF_STATUS wlan_serialization_vdev_obj_create_notification(
+		struct wlan_objmgr_vdev *vdev, void *arg_list)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * wlan_serialization_vdev_obj_destroy_notification() - vdev obj delete callback
+ * @vdev: VDEV object
+ * @arg_list: Variable argument list
+ *
+ * This callback is registered with object manager during initialization and
+ * when obj manager gets its turn to delete the object, it would notify each
+ * component with the corresponding callback registered to inform the
+ * completion of the deletion of the respective object.
+ *
+ * Return: QDF Status
+ */
+static QDF_STATUS wlan_serialization_vdev_obj_destroy_notification(
+		struct wlan_objmgr_vdev *vdev, void *arg_list)
+{
+	uint8_t vdev_id = wlan_vdev_get_id(vdev);
+
+	if (!ser_legacy_cb.serialization_purge_cmd_list)
+		return QDF_STATUS_SUCCESS;
+
+	serialization_debug("for vdev_id[%d] vdev[%p] flush all cmds",
+			  vdev_id, vdev);
+	ser_legacy_cb.serialization_purge_cmd_list(wlan_vdev_get_psoc(vdev),
+			vdev, false, false, false, false, true);
+
+	return QDF_STATUS_SUCCESS;
+}
+
 QDF_STATUS wlan_serialization_init(void)
 {
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
@@ -281,15 +378,43 @@ QDF_STATUS wlan_serialization_init(void)
 		goto err_pdev_delete;
 	}
 
+	status = wlan_objmgr_register_vdev_create_handler(
+			WLAN_UMAC_COMP_SERIALIZATION,
+			wlan_serialization_vdev_obj_create_notification, NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		serialization_err("Failed to reg vdev ser obj create handler");
+		goto err_vdev_create;
+	}
+
+	status = wlan_objmgr_register_vdev_destroy_handler(
+			WLAN_UMAC_COMP_SERIALIZATION,
+			wlan_serialization_vdev_obj_destroy_notification, NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		serialization_err("Failed to reg vdev ser obj delete handler");
+		goto err_vdev_delete;
+	}
 	serialization_info("serialization handlers registered with obj mgr");
+	/*
+	 * Initialize the structure so all callbacks are registered
+	 * initially as NULL.
+	 */
+	qdf_mem_zero(&ser_legacy_cb, sizeof(ser_legacy_cb));
 
 	return QDF_STATUS_SUCCESS;
 
+err_vdev_delete:
+	wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_SERIALIZATION,
+			wlan_serialization_vdev_obj_create_notification, NULL);
+err_vdev_create:
+	wlan_objmgr_unregister_pdev_destroy_handler(
+			WLAN_UMAC_COMP_SERIALIZATION,
+			wlan_serialization_pdev_obj_destroy_notification, NULL);
 err_pdev_delete:
 	wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_SERIALIZATION,
 			wlan_serialization_pdev_obj_create_notification, NULL);
 err_pdev_create:
-	wlan_objmgr_unregister_psoc_destroy_handler(WLAN_UMAC_COMP_SERIALIZATION,
+	wlan_objmgr_unregister_psoc_destroy_handler(
+			WLAN_UMAC_COMP_SERIALIZATION,
 			wlan_serialization_psoc_obj_destroy_notification, NULL);
 err_psoc_delete:
 	wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_SERIALIZATION,
@@ -344,6 +469,11 @@ QDF_STATUS wlan_serialization_deinit(void)
 	}
 
 	serialization_alert("deregistered callbacks with obj mgr successfully");
+	/*
+	 * Initialize the structure so all callbacks are registered
+	 * initially as NULL.
+	 */
+	qdf_mem_zero(&ser_legacy_cb, sizeof(ser_legacy_cb));
 
 	return ret_status;
 }

+ 9 - 55
umac/cmn_services/serialization/src/wlan_serialization_main_i.h

@@ -51,63 +51,17 @@
 	serialization_logfl(QDF_TRACE_LEVEL_DEBUG, format, ## args)
 
 /**
- * wlan_serialization_psoc_obj_create_notification() - PSOC obj create callback
- * @psoc: PSOC object
- * @arg_list: Variable argument list
+ * struct serialization_legacy_callback - to handle legacy serialization cb
  *
- * This callback is registered with object manager during initialization and
- * when obj manager gets its turn to create the object, it would notify each
- * component with the corresponding callback registered to inform the
- * completion of the creation of the respective object.
+ * @serialization_purge_cmd_list: function ptr to be filled by serialization
+ *				  module
  *
- * Return: QDF Status
+ * Some of the legacy modules wants to call API to purge the commands in
+ * order to handle backward compatibility.
  */
-QDF_STATUS wlan_serialization_psoc_obj_create_notification(
-		struct wlan_objmgr_psoc *psoc, void *arg_list);
-
-/**
- * wlan_serialization_psoc_obj_destroy_notification() - PSOC obj delete callback
- * @psoc: PSOC object
- * @arg_list: Variable argument list
- *
- * This callback is registered with object manager during initialization and
- * when obj manager gets its turn to delete the object, it would notify each
- * component with the corresponding callback registered to inform the
- * completion of the deletion of the respective object.
- *
- * Return: QDF Status
- */
-QDF_STATUS  wlan_serialization_psoc_obj_destroy_notification(
-		struct wlan_objmgr_psoc *psoc, void *arg_list);
-
-/**
- * wlan_serialization_pdev_obj_create_notification() - PDEV obj create callback
- * @psoc: PDEV object
- * @arg_list: Variable argument list
- *
- * This callback is registered with object manager during initialization and
- * when obj manager gets its turn to create the object, it would notify each
- * component with the corresponding callback registered to inform the
- * completion of the creation of the respective object.
- *
- * Return: QDF Status
- */
-QDF_STATUS wlan_serialization_pdev_obj_create_notification(
-		struct wlan_objmgr_pdev *pdev, void *arg_list);
-
-/**
- * wlan_serialization_pdev_obj_destroy_notification() - PSOC obj delete callback
- * @pdev: PDEV object
- * @arg_list: Variable argument list
- *
- * This callback is registered with object manager during initialization and
- * when obj manager gets its turn to delete the object, it would notify each
- * component with the corresponding callback registered to inform the
- * completion of the deletion of the respective object.
- *
- * Return: QDF Status
- */
-QDF_STATUS wlan_serialization_pdev_obj_destroy_notification(
-		struct wlan_objmgr_pdev *pdev, void *arg_list);
+struct serialization_legacy_callback {
+	void (*serialization_purge_cmd_list) (struct wlan_objmgr_psoc *,
+		struct wlan_objmgr_vdev *, bool, bool, bool, bool, bool);
+};
 
 #endif

+ 2 - 2
umac/cmn_services/serialization/src/wlan_serialization_utils.c

@@ -155,11 +155,11 @@ static void wlan_serialization_generic_timer_callback(void *arg)
 		return;
 	}
 
-	serialization_err("active command timeout for cmd_id[%d]", cmd->cmd_id);
+	serialization_err("active cmd timeout for cmd_type[%d] vdev[%p]",
+			  cmd->cmd_type, cmd->vdev);
 	if (cmd->cmd_cb)
 		cmd->cmd_cb(cmd, WLAN_SER_CB_ACTIVE_CMD_TIMEOUT);
 
-	serialization_err("active command timeout for cmd_id[%d]", cmd->cmd_id);
 	if (cmd->cmd_type >= WLAN_SER_CMD_NONSCAN)
 		QDF_BUG(0);
 	/*