Forráskód Böngészése

qcacld-3.0: add checks for deinit in ipa_register_ready_cb

Since stop_modules can happen in parallel due to idle shutdown,
add additional checks whether the IPA deinit happened already
or in-progress, in ipa_register_ready_cb.

Change-Id: Icc1973be3e90d4231addcebab55e621d19c5789c
CRs-Fixed: 2903419
Vevek Venkatesan 4 éve
szülő
commit
42c0970be1

+ 13 - 1
components/ipa/core/inc/wlan_ipa_main.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -93,6 +93,18 @@ ipa_pdev_get_priv_obj(struct wlan_objmgr_pdev *pdev)
 	return pdev_obj;
 }
 
+/**
+ * ipa_priv_obj_get_pdev() - API to get pdev from IPA object
+ * @ipa_obj: IPA object
+ *
+ * Return: pdev object
+ */
+static inline struct wlan_objmgr_pdev *
+ipa_priv_obj_get_pdev(struct wlan_ipa_priv *ipa_obj)
+{
+	return ipa_obj->pdev;
+}
+
 /**
  * ipa_is_hw_support() - Is IPA HW support?
  *

+ 1 - 0
components/ipa/core/inc/wlan_ipa_priv.h

@@ -684,6 +684,7 @@ struct wlan_ipa_priv {
 	qdf_mc_timer_t rt_debug_fill_timer;
 	qdf_mutex_t rt_debug_lock;
 	qdf_mutex_t ipa_lock;
+	qdf_mutex_t init_deinit_lock;
 
 	uint8_t vdev_to_iface[WLAN_IPA_MAX_SESSION];
 	bool vdev_offload_enabled[WLAN_IPA_MAX_SESSION];

+ 18 - 9
components/ipa/core/src/wlan_ipa_main.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -573,24 +573,33 @@ bool ipa_is_tx_pending(struct wlan_objmgr_pdev *pdev)
 QDF_STATUS ipa_uc_ol_deinit(struct wlan_objmgr_pdev *pdev)
 {
 	struct wlan_ipa_priv *ipa_obj;
+	QDF_STATUS status;
+
+	ipa_obj = ipa_pdev_get_priv_obj(pdev);
+	if (!ipa_obj) {
+		ipa_err("IPA object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	qdf_mutex_acquire(&ipa_obj->init_deinit_lock);
 
 	if (!ipa_config_is_enabled()) {
 		ipa_debug("ipa is disabled");
-		return QDF_STATUS_SUCCESS;
+		status = QDF_STATUS_SUCCESS;
+		goto out;
 	}
 
 	if (!ipa_cb_is_ready()) {
 		ipa_debug("ipa is not ready");
-		return QDF_STATUS_SUCCESS;
+		status = QDF_STATUS_SUCCESS;
+		goto out;
 	}
 
-	ipa_obj = ipa_pdev_get_priv_obj(pdev);
-	if (!ipa_obj) {
-		ipa_err("IPA object is NULL");
-		return QDF_STATUS_E_FAILURE;
-	}
+	status = wlan_ipa_uc_ol_deinit(ipa_obj);
 
-	return wlan_ipa_uc_ol_deinit(ipa_obj);
+out:
+	qdf_mutex_release(&ipa_obj->init_deinit_lock);
+	return status;
 }
 
 QDF_STATUS ipa_send_mcc_scc_msg(struct wlan_objmgr_pdev *pdev,

+ 40 - 13
components/ipa/dispatcher/src/wlan_ipa_obj_mgmt_api.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, 2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018, 2020-2021 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -24,6 +24,7 @@
 #include "wlan_objmgr_global_obj.h"
 #include "target_if_ipa.h"
 #include "wlan_ipa_ucfg_api.h"
+#include "qdf_platform.h"
 
 static bool g_ipa_is_ready;
 bool ipa_cb_is_ready(void)
@@ -70,6 +71,7 @@ ipa_pdev_obj_destroy_notification(struct wlan_objmgr_pdev *pdev,
 		ipa_err("Failed to detatch ipa pdev object");
 
 	ipa_obj_cleanup(ipa_obj);
+	qdf_mutex_destroy(&ipa_obj->init_deinit_lock);
 	qdf_mem_free(ipa_obj);
 	ipa_disable_register_cb();
 
@@ -101,6 +103,7 @@ ipa_pdev_obj_create_notification(struct wlan_objmgr_pdev *pdev,
 	if (!ipa_obj)
 		return QDF_STATUS_E_NOMEM;
 
+	qdf_mutex_create(&ipa_obj->init_deinit_lock);
 	status = wlan_objmgr_pdev_component_obj_attach(pdev,
 						       WLAN_UMAC_COMP_IPA,
 						       (void *)ipa_obj,
@@ -123,31 +126,45 @@ ipa_pdev_obj_create_notification(struct wlan_objmgr_pdev *pdev,
 static void ipa_register_ready_cb(void *user_data)
 {
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
-	struct wlan_objmgr_pdev *pdev = (struct wlan_objmgr_pdev *)
-		user_data;
+	struct wlan_ipa_priv *ipa_obj = (struct wlan_ipa_priv *)user_data;
+	struct wlan_objmgr_pdev *pdev;
 	struct wlan_objmgr_psoc *psoc;
 	qdf_device_t qdf_dev;
-	struct wlan_ipa_priv *ipa_obj;
 
 	if (!ipa_config_is_enabled()) {
 		ipa_info("IPA config is disabled");
 		return;
 	}
-	if (!pdev) {
-		ipa_err("Pdev obj mgr is NULL");
+	if (!ipa_obj) {
+		ipa_err("IPA object is NULL");
+		return;
+	}
+
+	/* Validate driver state to determine ipa_obj is valid or not */
+	if (qdf_is_driver_state_module_stop()) {
+		ipa_err("Driver modules stop in-progress or done");
 		return;
 	}
+
+	qdf_mutex_acquire(&ipa_obj->init_deinit_lock);
+	/*
+	 * Meanwhile acquiring lock, driver stop modules can happen in parallel,
+	 * validate driver state once again to proceed with IPA init.
+	 */
+	if (qdf_is_driver_state_module_stop()) {
+		ipa_err("Driver modules stop in-progress/done, releasing lock");
+		goto out;
+	}
+	pdev = ipa_priv_obj_get_pdev(ipa_obj);
 	psoc = wlan_pdev_get_psoc(pdev);
 	qdf_dev = wlan_psoc_get_qdf_dev(psoc);
-
 	if (!qdf_dev) {
 		ipa_err("QDF device context is NULL");
-		return;
+		goto out;
 	}
 
 	g_ipa_is_ready = true;
 	ipa_info("IPA ready callback invoked: ipa_register_ready_cb");
-	ipa_obj = ipa_pdev_get_priv_obj(pdev);
 	status = ipa_obj_setup(ipa_obj);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		ipa_err("Failed to setup ipa component");
@@ -155,28 +172,38 @@ static void ipa_register_ready_cb(void *user_data)
 						      WLAN_UMAC_COMP_IPA,
 						      ipa_obj);
 		qdf_mem_free(ipa_obj);
-		return;
+		goto out;
 	}
 	if (ucfg_ipa_uc_ol_init(pdev, qdf_dev)) {
 		ipa_err("IPA ucfg_ipa_uc_ol_init failed");
-		return;
+		goto out;
 	}
+
+out:
+	qdf_mutex_release(&ipa_obj->init_deinit_lock);
 }
 
 QDF_STATUS ipa_register_is_ipa_ready(struct wlan_objmgr_pdev *pdev)
 {
 	int ret;
+	struct wlan_ipa_priv *ipa_obj;
 
 	if (!ipa_config_is_enabled()) {
 		ipa_info("IPA config is disabled");
 		return QDF_STATUS_SUCCESS;
 	}
 
+	ipa_obj = ipa_pdev_get_priv_obj(pdev);
+	if (!ipa_obj) {
+		ipa_err("IPA object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
 	ret = qdf_ipa_register_ipa_ready_cb(ipa_register_ready_cb,
-					    (void *)pdev);
+					    (void *)ipa_obj);
 	if (ret == -EEXIST) {
 		ipa_info("IPA is ready, invoke callback");
-		ipa_register_ready_cb((void *)pdev);
+		ipa_register_ready_cb((void *)ipa_obj);
 	} else if (ret) {
 		ipa_err("Failed to check IPA readiness %d", ret);
 		return QDF_STATUS_E_FAILURE;