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
diff --git a/umac/cmn_services/serialization/src/wlan_serialization_main.c b/umac/cmn_services/serialization/src/wlan_serialization_main.c
index 1873b29..9d8f4c8 100644
--- a/umac/cmn_services/serialization/src/wlan_serialization_main.c
+++ b/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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 		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 @@
 	}
 
 	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;
 }