qcacmn: Add unregister API for direct buf ring

Add Unregister API to de-register and free resources in direct buf
module. Existing logic of freeing all resources as part of pdev destroy
does not take care of soc_start and soc_stop scenarios. Add this API to
enable modules to de-register as part of soc_stop and register during
start.

CRs-Fixed: 2385313
Change-Id: Ibe6f6bc5f4bd2acc5a9fe71eee09c151853073bc
diff --git a/spectral/dispatcher/inc/wlan_spectral_tgt_api.h b/spectral/dispatcher/inc/wlan_spectral_tgt_api.h
index 8eac4cb..ba3b33e 100644
--- a/spectral/dispatcher/inc/wlan_spectral_tgt_api.h
+++ b/spectral/dispatcher/inc/wlan_spectral_tgt_api.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
@@ -232,7 +232,7 @@
 			    void *payload);
 
 /**
- * tgt_spectral_register_to_dbr() - Register to direct dma
+ * tgt_spectral_register_to_dbr() - Register to direct DMA
  * @pdev: Pointer to pdev object
  *
  * Return: QDF_STATUS
@@ -241,6 +241,15 @@
 tgt_spectral_register_to_dbr(struct wlan_objmgr_pdev *pdev);
 
 /**
+ * tgt_spectral_unregister_to_dbr() - Register to direct DMA
+ * @pdev: Pointer to pdev object
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+tgt_spectral_unregister_to_dbr(struct wlan_objmgr_pdev *pdev);
+
+/**
  * tgt_spectral_get_target_type() - Get target type
  * @psoc: Pointer to psoc object
  *
diff --git a/spectral/dispatcher/inc/wlan_spectral_utils_api.h b/spectral/dispatcher/inc/wlan_spectral_utils_api.h
index 5878b9a..a673426 100644
--- a/spectral/dispatcher/inc/wlan_spectral_utils_api.h
+++ b/spectral/dispatcher/inc/wlan_spectral_utils_api.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
@@ -154,6 +154,29 @@
  */
 QDF_STATUS spectral_pdev_open(struct wlan_objmgr_pdev *pdev);
 
+/**
+ * spectral_register_dbr() - register Spectral event handler with DDMA
+ * @pdev:  pointer to pdev object
+ *
+ * API to register event handler with Direct DMA
+ *
+ * Return: QDF_STATUS_SUCCESS upon successful registration,
+ *         QDF_STATUS_E_FAILURE upon failure
+ */
+
+QDF_STATUS spectral_register_dbr(struct wlan_objmgr_pdev *pdev);
+
+/**
+ * spectral_unregister_dbr() - unregister Spectral event handler with DDMA
+ * @pdev:  pointer to pdev object
+ *
+ * API to unregister event handler with Direct DMA
+ *
+ * Return: QDF_STATUS_SUCCESS upon successful unregistration,
+ *         QDF_STATUS_E_FAILURE upon failure
+ */
+QDF_STATUS spectral_unregister_dbr(struct wlan_objmgr_pdev *pdev);
+
 #ifdef DIRECT_BUF_RX_ENABLE
 /**
  * spectral_dbr_event_handler() - Spectral dbr event handler
diff --git a/spectral/dispatcher/src/wlan_spectral_tgt_api.c b/spectral/dispatcher/src/wlan_spectral_tgt_api.c
index bd32528..e0e6399 100644
--- a/spectral/dispatcher/src/wlan_spectral_tgt_api.c
+++ b/spectral/dispatcher/src/wlan_spectral_tgt_api.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011,2017-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011,2017-2019 The Linux Foundation. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
@@ -296,10 +296,33 @@
 
 	return QDF_STATUS_SUCCESS;
 }
+
+QDF_STATUS
+tgt_spectral_unregister_to_dbr(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_lmac_if_direct_buf_rx_tx_ops *dbr_tx_ops = NULL;
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	dbr_tx_ops = &psoc->soc_cb.tx_ops.dbr_tx_ops;
+
+	if (tgt_spectral_get_target_type(psoc) == TARGET_TYPE_QCA8074)
+		if (dbr_tx_ops->direct_buf_rx_module_unregister)
+			return dbr_tx_ops->direct_buf_rx_module_unregister
+				(pdev, 0);
+
+	return QDF_STATUS_E_FAILURE;
+}
 #else
 QDF_STATUS
 tgt_spectral_register_to_dbr(struct wlan_objmgr_pdev *pdev)
 {
 	return QDF_STATUS_SUCCESS;
 }
+
+QDF_STATUS
+tgt_spectral_unregister_to_dbr(struct wlan_objmgr_pdev *pdev)
+{
+	return QDF_STATUS_SUCCESS;
+}
 #endif
diff --git a/spectral/dispatcher/src/wlan_spectral_utils_api.c b/spectral/dispatcher/src/wlan_spectral_utils_api.c
index b9d8997..71db87b 100644
--- a/spectral/dispatcher/src/wlan_spectral_utils_api.c
+++ b/spectral/dispatcher/src/wlan_spectral_utils_api.c
@@ -239,3 +239,21 @@
 	status = tgt_spectral_register_to_dbr(pdev);
 	return QDF_STATUS_SUCCESS;
 }
+
+QDF_STATUS spectral_register_dbr(struct wlan_objmgr_pdev *pdev)
+{
+	return tgt_spectral_register_to_dbr(pdev);
+}
+
+qdf_export_symbol(spectral_register_dbr);
+
+QDF_STATUS spectral_unregister_dbr(struct wlan_objmgr_pdev *pdev)
+{
+	QDF_STATUS status;
+
+	status = tgt_spectral_unregister_to_dbr(pdev);
+
+	return status;
+}
+
+qdf_export_symbol(spectral_unregister_dbr);
diff --git a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_api.c b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_api.c
index 03001de..1361c0a 100644
--- a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_api.c
+++ b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_api.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019 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
@@ -166,6 +166,8 @@
 {
 	tx_ops->dbr_tx_ops.direct_buf_rx_module_register =
 				target_if_direct_buf_rx_module_register;
+	tx_ops->dbr_tx_ops.direct_buf_rx_module_unregister =
+				target_if_direct_buf_rx_module_unregister;
 	tx_ops->dbr_tx_ops.direct_buf_rx_register_events =
 				target_if_direct_buf_rx_register_events;
 	tx_ops->dbr_tx_ops.direct_buf_rx_unregister_events =
diff --git a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c
index 730b563..4d4c88f 100644
--- a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c
+++ b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019 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
@@ -728,6 +728,48 @@
 	return status;
 }
 
+QDF_STATUS target_if_direct_buf_rx_module_unregister(
+			struct wlan_objmgr_pdev *pdev, uint8_t mod_id)
+{
+	QDF_STATUS status;
+	struct direct_buf_rx_pdev_obj *dbr_pdev_obj;
+
+	if (!pdev) {
+		direct_buf_rx_err("pdev context passed is null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (mod_id >= DBR_MODULE_MAX) {
+		direct_buf_rx_err("Invalid module id");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	dbr_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj
+			(pdev,
+			 WLAN_TARGET_IF_COMP_DIRECT_BUF_RX);
+
+	if (!dbr_pdev_obj) {
+		direct_buf_rx_err("dir buf rx object is null");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	direct_buf_rx_info("Dbr pdev obj %pK", dbr_pdev_obj);
+
+	if (!dbr_pdev_obj->dbr_mod_param) {
+		direct_buf_rx_err("dbr_pdev_obj->dbr_mod_param is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (mod_id >= dbr_pdev_obj->num_modules) {
+		direct_buf_rx_err("Module %d not supported in target", mod_id);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = target_if_deinit_dbr_ring(pdev, dbr_pdev_obj, mod_id);
+
+	return status;
+}
+
 static void *target_if_dbr_vaddr_lookup(
 			struct direct_buf_rx_module_param *mod_param,
 			qdf_dma_addr_t paddr, uint32_t cookie)
@@ -989,7 +1031,8 @@
 	dbr_buf_pool = mod_param->dbr_buf_pool;
 	direct_buf_rx_info("dbr buf pool %pK", dbr_buf_pool);
 	target_if_dbr_deinit_ring(pdev, mod_param);
-	qdf_mem_free(dbr_buf_pool);
+	if (mod_param->dbr_buf_pool)
+		qdf_mem_free(dbr_buf_pool);
 	mod_param->dbr_buf_pool = NULL;
 
 	return QDF_STATUS_SUCCESS;
@@ -1011,9 +1054,11 @@
 	direct_buf_rx_info("mod_param %pK", mod_param);
 	direct_buf_rx_info("dbr_ring_cap %pK", mod_param->dbr_ring_cap);
 	target_if_dbr_deinit_srng(pdev, mod_param);
-	qdf_mem_free(mod_param->dbr_ring_cap);
+	if (mod_param->dbr_ring_cap)
+		qdf_mem_free(mod_param->dbr_ring_cap);
 	mod_param->dbr_ring_cap = NULL;
-	qdf_mem_free(mod_param->dbr_ring_cfg);
+	if (mod_param->dbr_ring_cfg)
+		qdf_mem_free(mod_param->dbr_ring_cfg);
 	mod_param->dbr_ring_cfg = NULL;
 
 	return QDF_STATUS_SUCCESS;
diff --git a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.h b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.h
index d06a968..cfbaeca 100644
--- a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.h
+++ b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019 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
@@ -232,4 +232,14 @@
 			int (*dbr_rsp_handler)(struct wlan_objmgr_pdev *pdev,
 				struct direct_buf_rx_data *dbr_data));
 
+/**
+ * target_if_direct_buf_rx_module_unregister() - Function to unregister to
+ *                                               direct buffer rx module
+ * @pdev: pointer to pdev object
+ * @mod_id: module id indicating the module using direct buffer rx framework
+ *
+ * Return: QDF status of operation
+ */
+QDF_STATUS target_if_direct_buf_rx_module_unregister(
+			struct wlan_objmgr_pdev *pdev, uint8_t mod_id);
 #endif /* _TARGET_IF_DIRECT_BUF_RX_MAIN_H_ */
diff --git a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h
index eee0853..5a44259 100644
--- a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h
+++ b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h
@@ -443,6 +443,8 @@
  * struct wlan_lmac_if_direct_buf_rx_tx_ops - structire of direct buf rx txops
  * @direct_buf_rx_module_register: Registration API callback for modules
  *                                 to register with direct buf rx framework
+ * @direct_buf_rx_module_unregister: Unregistration API to clean up module
+ *                                   specific resources in DBR
  * @direct_buf_rx_register_events: Registration of WMI events for direct
  *                                 buffer rx framework
  * @direct_buf_rx_unregister_events: Unregistraton of WMI events for direct
@@ -454,6 +456,8 @@
 			struct wlan_objmgr_pdev *pdev, uint8_t mod_id,
 			int (*dbr_rsp_handler)(struct wlan_objmgr_pdev *pdev,
 				struct direct_buf_rx_data *dbr_data));
+	QDF_STATUS (*direct_buf_rx_module_unregister)(
+			struct wlan_objmgr_pdev *pdev, uint8_t mod_id);
 	QDF_STATUS (*direct_buf_rx_register_events)(
 			struct wlan_objmgr_psoc *psoc);
 	QDF_STATUS (*direct_buf_rx_unregister_events)(