qcacmn: Free serial cmd before its timer when rmmod

Rmmod process:
wlan_hdd_pld_remove --> hdd_stop_adapter --> hdd_vdev_destroy
--> WLAN_SER_CMD_DEL_STA_SESSION (25) cmd queued --> PLD_FW_DOWN
(will complete wait event as part of qdf_complete_wait_events)
--> hdd_wlan_stop_modules --> cds_disable -->
dispatcher_psoc_disable --> wlan_serialization_psoc_disable -->
wlan_serialization_timer_destroy --> umac_stop --> csr_stop -->
wlan_ser_cancel_non_scan_cmd -> check if timer is present but th
 timer are already destroyed, so assert.

Move wlan_serialization_purge_cmd_list into converged API file to
be shared by MCC and WIN.

Change-Id: Iad557e4a05d682c257be0c39049c52950e5eb530
CRs-Fixed: 2451058
diff --git a/umac/cmn_services/serialization/inc/wlan_serialization_api.h b/umac/cmn_services/serialization/inc/wlan_serialization_api.h
index a22337c..a7e19d0 100644
--- a/umac/cmn_services/serialization/inc/wlan_serialization_api.h
+++ b/umac/cmn_services/serialization/inc/wlan_serialization_api.h
@@ -604,4 +604,20 @@
 wlan_ser_validate_umac_cmd(struct wlan_objmgr_vdev *vdev,
 			   enum wlan_serialization_cmd_type cmd_type,
 			   wlan_ser_umac_cmd_cb umac_cmd_cb);
+
+/**
+ * wlan_serialization_purge_all_pdev_cmd() - purge all command for given pdev
+ * @pdev: objmgr pdev pointer
+ *
+ * Return: void
+ */
+void wlan_serialization_purge_all_pdev_cmd(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * wlan_serialization_purge_all_cmd() - purge all command for psoc
+ * @psoc: objmgr psoc pointer
+ *
+ * Return: void
+ */
+void wlan_serialization_purge_all_cmd(struct wlan_objmgr_psoc *psoc);
 #endif
diff --git a/umac/cmn_services/serialization/src/wlan_serialization_api.c b/umac/cmn_services/serialization/src/wlan_serialization_api.c
index de9ae64..bebc087 100644
--- a/umac/cmn_services/serialization/src/wlan_serialization_api.c
+++ b/umac/cmn_services/serialization/src/wlan_serialization_api.c
@@ -781,3 +781,44 @@
 
 	return status;
 }
+
+void wlan_serialization_purge_all_pdev_cmd(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_ser_pdev_obj *ser_pdev_obj;
+
+	if (!pdev) {
+		ser_err("NULL pdev");
+		return;
+	}
+
+	ser_pdev_obj = wlan_serialization_get_pdev_obj(pdev);
+	if (!ser_pdev_obj) {
+		ser_err("invalid ser_pdev_obj");
+		return;
+	}
+
+	wlan_ser_cancel_scan_cmd(ser_pdev_obj, pdev, NULL, NULL,
+				 WLAN_SER_CMD_SCAN, false);
+	wlan_ser_cancel_scan_cmd(ser_pdev_obj, pdev, NULL, NULL,
+				 WLAN_SER_CMD_SCAN, true);
+	wlan_ser_cancel_non_scan_cmd(ser_pdev_obj, pdev, NULL, NULL,
+				     WLAN_SER_CMD_NONSCAN, false);
+	wlan_ser_cancel_non_scan_cmd(ser_pdev_obj, pdev, NULL, NULL,
+				     WLAN_SER_CMD_NONSCAN, true);
+}
+
+static inline
+void wlan_ser_purge_pdev_cmd_cb(struct wlan_objmgr_psoc *psoc,
+				void *object, void *arg)
+{
+	struct wlan_objmgr_pdev *pdev = (struct wlan_objmgr_pdev *)object;
+
+	wlan_serialization_purge_all_pdev_cmd(pdev);
+}
+
+void wlan_serialization_purge_all_cmd(struct wlan_objmgr_psoc *psoc)
+{
+	wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
+				     wlan_ser_purge_pdev_cmd_cb, NULL, 1,
+				     WLAN_SERIALIZATION_ID);
+}
diff --git a/umac/cmn_services/serialization/src/wlan_serialization_main.c b/umac/cmn_services/serialization/src/wlan_serialization_main.c
index dbb7fb3..f663a8d 100644
--- a/umac/cmn_services/serialization/src/wlan_serialization_main.c
+++ b/umac/cmn_services/serialization/src/wlan_serialization_main.c
@@ -41,6 +41,12 @@
 		ser_err("invalid ser_soc_obj");
 		goto error;
 	}
+
+	/*
+	 * purge all serialization command if there are any pending to make
+	 * sure memory and vdev ref are freed.
+	 */
+	wlan_serialization_purge_all_cmd(psoc);
 	/* clean up all timers before exiting */
 	status = wlan_serialization_cleanup_all_timers(ser_soc_obj);
 	if (status != QDF_STATUS_SUCCESS)