Просмотр исходного кода

qcacld-3.0: Create mon thread for packet capture

Create mon thread to process the packets for
packet capture.

Change-Id: I0c83b17273f140970b4feea49cd42da4c540046b
CRs-Fixed: 2618657
Vulupala Shashank Reddy 5 лет назад
Родитель
Сommit
aa481cc459

+ 1 - 0
Kbuild

@@ -1048,6 +1048,7 @@ PKT_CAPTURE_INC := -I$(WLAN_ROOT)/$(PKT_CAPTURE_DIR)/core/inc \
 
 ifeq ($(CONFIG_WLAN_FEATURE_PKT_CAPTURE), y)
 PKT_CAPTURE_OBJS := $(PKT_CAPTURE_DIR)/core/src/wlan_pkt_capture_main.o \
+		$(PKT_CAPTURE_DIR)/core/src/wlan_pkt_capture_mon_thread.o \
 		$(PKT_CAPTURE_DIR)/dispatcher/src/wlan_pkt_capture_ucfg_api.o
 endif
 

+ 208 - 0
components/pkt_capture/core/inc/wlan_pkt_capture_mon_thread.h

@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2020 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
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: Declare APIs which shall be used for monitor thread access.
+ */
+
+#ifndef _WLAN_PKT_CAPTURE_MON_THREAD_H_
+#define _WLAN_PKT_CAPTURE_MON_THREAD_H_
+
+#include "wlan_pkt_capture_main.h"
+
+#define PKT_CAPTURE_RX_POST_EVENT 0x01
+#define PKT_CAPTURE_RX_SUSPEND_EVENT 0x02
+#define PKT_CAPTURE_RX_SHUTDOWN_EVENT 0x04
+
+/*
+ * Maximum number of packets to be allocated for
+ * Packet Capture Monitor thread.
+ */
+#define MAX_MON_PKT_SIZE 4000
+
+/* timeout in msec to wait for mon thread to suspend */
+#define PKT_CAPTURE_SUSPEND_TIMEOUT 200
+
+typedef void (*pkt_capture_mon_thread_cb)(void *context, void *monpkt,
+					  uint8_t vdev_id, uint8_t tid,
+					  uint8_t status, bool pkt_format);
+
+/*
+ * struct pkt_capture_mon_pkt - mon packet wrapper for mon data from TXRX
+ * @list: List for storing mon packets
+ * @context: Callback context
+ * @monpkt: Mon skb
+ * @vdev_id: Vdev id to which this packet is destined
+ * @tid: Tid of mon packet
+ * @status: Tx packet status
+ * @pkt_format: Mon packet format, 0 = 802.3 format , 1 = 802.11 format
+ * @callback: Mon callback
+ */
+struct pkt_capture_mon_pkt {
+	struct list_head list;
+	void *context;
+	void *monpkt;
+	uint8_t vdev_id;
+	uint8_t tid;
+	uint8_t status;
+	bool pkt_format;
+	pkt_capture_mon_thread_cb callback;
+};
+
+/**
+ * struct pkt_capture_mon_context - packet capture mon thread context
+ * @mon_thread_lock: MON thread lock
+ * @mon_thread: MON thread handle
+ * @mon_start_event: Handle of Event for MON thread to signal startup
+ * @suspend_mon_event: Completion to suspend packet capture MON thread
+ * @resume_mon_event: Completion to resume packet capture MON thread
+ * @mon_shutdown: Completion for packet capture MON thread shutdown
+ * @mon_wait_queue: Waitq for packet capture MON thread
+ * @mon_event_flag: Mon event flag
+ * @mon_thread_queue: MON buffer queue
+ * @mon_queue_lock: Spinlock to synchronize between tasklet and thread
+ * @mon_pkt_freeq_lock: Lock to synchronize free buffer queue access
+ * @mon_pkt_freeq: Free message queue for packet capture MON processing
+ * @is_mon_thread_suspended: flag to check mon thread suspended or not
+ */
+struct pkt_capture_mon_context {
+	/* MON thread lock */
+	spinlock_t mon_thread_lock;
+	struct task_struct *mon_thread;
+	struct completion mon_start_event;
+	struct completion suspend_mon_event;
+	struct completion resume_mon_event;
+	struct completion mon_shutdown;
+	wait_queue_head_t mon_wait_queue;
+	unsigned long mon_event_flag;
+	struct list_head mon_thread_queue;
+
+	/* Spinlock to synchronize between tasklet and thread */
+	spinlock_t mon_queue_lock;
+
+	/* Lock to synchronize free buffer queue access */
+	spinlock_t mon_pkt_freeq_lock;
+
+	struct list_head mon_pkt_freeq;
+	bool is_mon_thread_suspended;
+};
+
+/**
+ * pkt_capture_suspend_mon_thread() - suspend packet capture mon thread
+ * vdev: pointer to vdev object manager
+ *
+ * Return: 0 on success, -EINVAL on failure
+ */
+int pkt_capture_suspend_mon_thread(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * pkt_capture_resume_mon_thread() - resume packet capture mon thread
+ * vdev: pointer to vdev object manager
+ *
+ * Resume packet capture MON thread by completing RX thread resume event.
+ *
+ * Return: None
+ */
+void pkt_capture_resume_mon_thread(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * pkt_capture_drop_monpkt() - API to drop pending mon packets
+ * mon_ctx: pointer to packet capture mon context
+ *
+ * This api drops all the pending packets in the queue.
+ *
+ * Return: None
+ */
+void pkt_capture_drop_monpkt(struct pkt_capture_mon_context *mon_ctx);
+
+/**
+ * pkt_capture_indicate_monpkt() - API to Indicate rx data packet
+ * @vdev: pointer to vdev object manager
+ * @pkt: MON pkt pointer containing to mon data message buffer
+ *
+ * Return: None
+ */
+void pkt_capture_indicate_monpkt(struct wlan_objmgr_vdev *vdev,
+				 struct pkt_capture_mon_pkt *pkt);
+
+/**
+ * pkt_capture_wakeup_mon_thread() - wakeup packet capture mon thread
+ * @vdev: pointer to vdev object
+ *
+ * This api wake up pkt_capture_mon_thread() to process pkt.
+ *
+ * Return: None
+ */
+void pkt_capture_wakeup_mon_thread(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * pkt_capture_close_mon_thread() - close packet capture MON thread
+ * @mon_ctx: pointer to packet capture mon context
+ *
+ * This api closes packet capture MON thread.
+ *
+ * Return: None
+ */
+void pkt_capture_close_mon_thread(struct pkt_capture_mon_context *mon_ctx);
+
+/**
+ * pkt_capture_open_mon_thread() - open packet capture MON thread
+ * @mon_ctx: pointer to packet capture mon context
+ *
+ * This api opens the packet capture MON thread.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+pkt_capture_open_mon_thread(struct pkt_capture_mon_context *mon_ctx);
+
+/**
+ * pkt_capture_alloc_mon_thread() - alloc resources for
+ * packet capture MON thread
+ * @mon_ctx: pointer to packet capture mon context
+ *
+ * This api alloc resources for packet capture MON thread.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+pkt_capture_alloc_mon_thread(struct pkt_capture_mon_context *mon_ctx);
+
+/**
+ * pkt_capture_alloc_mon_pkt() - API to return next available mon packet
+ * @vdev: pointer to vdev object manager
+ *
+ * This api returns next available mon packet buffer used for mon data
+ * processing.
+ *
+ * Return: Pointer to pkt_capture_mon_pkt
+ */
+struct pkt_capture_mon_pkt *
+pkt_capture_alloc_mon_pkt(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * pkt_capture_free_mon_pkt_freeq() - free mon packet free queue
+ * @mon_ctx: pointer to packet capture mon context
+ *
+ * This API does mem free of the buffers available in free mon packet
+ * queue which is used for mon Data processing.
+ *
+ * Return: None
+ */
+void pkt_capture_free_mon_pkt_freeq(struct pkt_capture_mon_context *mon_ctx);
+#endif /* _WLAN_PKT_CAPTURE_MON_THREAD_H_ */

+ 3 - 0
components/pkt_capture/core/inc/wlan_pkt_capture_priv.h

@@ -29,6 +29,7 @@
 
 #include "wlan_pkt_capture_objmgr.h"
 #include "wlan_pkt_capture_public_structs.h"
+#include "wlan_pkt_capture_mon_thread.h"
 
 /**
  * struct pkt_capture_cfg - packet capture cfg to store ini values
@@ -41,9 +42,11 @@ struct pkt_capture_cfg {
 /**
  * struct pkt_capture_vdev_priv - Private object to be stored in vdev
  * @vdev: pointer to vdev object
+ * @pkt_capture_mon_ctx: pointer to packet capture mon context
  */
 struct pkt_capture_vdev_priv {
 	struct wlan_objmgr_vdev *vdev;
+	struct pkt_capture_mon_context *mon_ctx;
 };
 
 /**

+ 69 - 0
components/pkt_capture/core/src/wlan_pkt_capture_main.c

@@ -23,6 +23,7 @@
 
 #include "wlan_pkt_capture_main.h"
 #include "cfg_ucfg_api.h"
+#include "wlan_pkt_capture_mon_thread.h"
 
 enum pkt_capture_mode pkt_capture_get_mode(struct wlan_objmgr_psoc *psoc)
 {
@@ -42,6 +43,44 @@ enum pkt_capture_mode pkt_capture_get_mode(struct wlan_objmgr_psoc *psoc)
 	return psoc_priv->cfg_param.pkt_capture_mode;
 }
 
+/**
+ * pkt_capture_mon_context_create() - Create packet capture mon context
+ * @vdev_priv: pointer to packet capture vdev priv obj
+ *
+ * This function allocates memory for packet capture mon context
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+pkt_capture_mon_context_create(struct pkt_capture_vdev_priv *vdev_priv)
+{
+	struct pkt_capture_mon_context *mon_context;
+
+	mon_context = qdf_mem_malloc(sizeof(*mon_context));
+	if (!mon_context) {
+		pkt_capture_err("MON context create failed");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	vdev_priv->mon_ctx = mon_context;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * pkt_capture_mon_context_destroy() - Destroy packet capture mon context
+ * @vdev_priv: pointer to packet capture vdev priv obj
+ *
+ * Free packet capture mon context
+ *
+ * Return: None
+ */
+static void
+pkt_capture_mon_context_destroy(struct pkt_capture_vdev_priv *vdev_priv)
+{
+	qdf_mem_free(vdev_priv->mon_ctx);
+}
+
 /**
  * pkt_capture_cfg_init() - Initialize packet capture cfg ini params
  * @psoc_priv: psoc private object
@@ -62,6 +101,7 @@ pkt_capture_cfg_init(struct pkt_psoc_priv *psoc_priv)
 QDF_STATUS
 pkt_capture_vdev_create_notification(struct wlan_objmgr_vdev *vdev, void *arg)
 {
+	struct pkt_capture_mon_context *mon_ctx;
 	struct pkt_capture_vdev_priv *vdev_priv;
 	QDF_STATUS status;
 
@@ -79,8 +119,35 @@ pkt_capture_vdev_create_notification(struct wlan_objmgr_vdev *vdev, void *arg)
 	}
 
 	vdev_priv->vdev = vdev;
+
+	status = pkt_capture_mon_context_create(vdev_priv);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		pkt_capture_err("Failed to create mon context");
+		goto detach_vdev_priv;
+	}
+	mon_ctx = vdev_priv->mon_ctx;
+
+	status = pkt_capture_alloc_mon_thread(mon_ctx);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		pkt_capture_err("Failed to alloc mon thread");
+		goto destroy_mon_context;
+	}
+
+	status = pkt_capture_open_mon_thread(mon_ctx);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		pkt_capture_err("Failed to open mon thread");
+		goto open_mon_thread_fail;
+	}
 	return status;
 
+open_mon_thread_fail:
+	pkt_capture_free_mon_pkt_freeq(mon_ctx);
+destroy_mon_context:
+	pkt_capture_mon_context_destroy(vdev_priv);
+detach_vdev_priv:
+	wlan_objmgr_vdev_component_obj_detach(vdev,
+					      WLAN_UMAC_COMP_PKT_CAPTURE,
+					      vdev_priv);
 free_vdev_priv:
 	qdf_mem_free(vdev_priv);
 	return status;
@@ -105,6 +172,8 @@ pkt_capture_vdev_destroy_notification(struct wlan_objmgr_vdev *vdev, void *arg)
 	if (QDF_IS_STATUS_ERROR(status))
 		pkt_capture_err("Failed to detach vdev component obj");
 
+	pkt_capture_close_mon_thread(vdev_priv->mon_ctx);
+	pkt_capture_mon_context_destroy(vdev_priv);
 	qdf_mem_free(vdev_priv);
 	return status;
 }

+ 460 - 0
components/pkt_capture/core/src/wlan_pkt_capture_mon_thread.c

@@ -0,0 +1,460 @@
+/*
+ * Copyright (c) 2020 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
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: Define internal APIs related to the packet capture component
+ */
+
+#include "wlan_pkt_capture_priv.h"
+#include <linux/kthread.h>
+
+void pkt_capture_free_mon_pkt_freeq(struct pkt_capture_mon_context *mon_ctx)
+{
+	struct pkt_capture_mon_pkt *pkt;
+
+	spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock);
+	while (!list_empty(&mon_ctx->mon_pkt_freeq)) {
+		pkt = list_entry((&mon_ctx->mon_pkt_freeq)->next,
+				 typeof(*pkt), list);
+		list_del(&pkt->list);
+		spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock);
+		qdf_mem_free(pkt);
+		spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock);
+	}
+	spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock);
+}
+
+/**
+ * pkt_capture_alloc_mon_pkt_freeq() - Function to allocate free buffer queue
+ * @mon_ctx: pointer to packet capture mon context
+ *
+ * This API allocates MAX_MON_PKT_SIZE number of mon packets
+ * which are used for mon data processing.
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+pkt_capture_alloc_mon_pkt_freeq(struct pkt_capture_mon_context *mon_ctx)
+{
+	struct pkt_capture_mon_pkt *pkt, *tmp;
+	int i;
+
+	for (i = 0; i < MAX_MON_PKT_SIZE; i++) {
+		pkt = qdf_mem_malloc(sizeof(*pkt));
+		if (!pkt) {
+			pkt_capture_err("mon packet freeq allocation fail");
+			goto free;
+		}
+		spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock);
+		list_add_tail(&pkt->list,
+			      &mon_ctx->mon_pkt_freeq);
+		spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock);
+	}
+
+	return QDF_STATUS_SUCCESS;
+free:
+	spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock);
+	list_for_each_entry_safe(pkt, tmp,
+				 &mon_ctx->mon_pkt_freeq,
+				 list) {
+		list_del(&pkt->list);
+		spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock);
+		qdf_mem_free(pkt);
+		spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock);
+	}
+	spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock);
+
+	return QDF_STATUS_E_NOMEM;
+}
+
+/**
+ * pkt_capture_free_mon_pkt() - api to release mon packet to the freeq
+ * @mon_ctx: Pointer to packet capture mon context
+ * @pkt: MON packet buffer to be returned to free queue.
+ *
+ * This api returns the mon packet used for mon data to the free queue
+ *
+ * Return: None
+ */
+static void
+pkt_capture_free_mon_pkt(struct pkt_capture_mon_context *mon_ctx,
+			 struct pkt_capture_mon_pkt *pkt)
+{
+	memset(pkt, 0, sizeof(*pkt));
+	spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock);
+	list_add_tail(&pkt->list, &mon_ctx->mon_pkt_freeq);
+	spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock);
+}
+
+struct pkt_capture_mon_pkt *
+pkt_capture_alloc_mon_pkt(struct wlan_objmgr_vdev *vdev)
+{
+	struct pkt_capture_vdev_priv *vdev_priv;
+	struct pkt_capture_mon_context *mon_ctx;
+	struct pkt_capture_mon_pkt *pkt;
+
+	if (!vdev) {
+		pkt_capture_err("vdev is NULL");
+		return NULL;
+	}
+
+	vdev_priv = pkt_capture_vdev_get_priv(vdev);
+	if (!vdev_priv) {
+		pkt_capture_err("packet capture vdev priv is NULL");
+		return NULL;
+	}
+
+	mon_ctx = vdev_priv->mon_ctx;
+	if (!mon_ctx) {
+		pkt_capture_err("packet capture mon context is NULL");
+		return NULL;
+	}
+
+	spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock);
+	if (list_empty(&mon_ctx->mon_pkt_freeq)) {
+		spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock);
+		return NULL;
+	}
+
+	pkt = list_first_entry(&mon_ctx->mon_pkt_freeq,
+			       struct pkt_capture_mon_pkt, list);
+	list_del(&pkt->list);
+	spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock);
+
+	return pkt;
+}
+
+void pkt_capture_indicate_monpkt(struct wlan_objmgr_vdev *vdev,
+				 struct pkt_capture_mon_pkt *pkt)
+{
+	struct pkt_capture_vdev_priv *vdev_priv;
+	struct pkt_capture_mon_context *mon_ctx;
+
+	if (!vdev) {
+		pkt_capture_err("vdev is NULL");
+		return;
+	}
+
+	vdev_priv = pkt_capture_vdev_get_priv(vdev);
+	if (!vdev_priv) {
+		pkt_capture_err("packet capture vdev priv is NULL");
+		return;
+	}
+	mon_ctx = vdev_priv->mon_ctx;
+
+	spin_lock_bh(&mon_ctx->mon_queue_lock);
+	list_add_tail(&pkt->list, &mon_ctx->mon_thread_queue);
+	spin_unlock_bh(&mon_ctx->mon_queue_lock);
+	set_bit(PKT_CAPTURE_RX_POST_EVENT, &mon_ctx->mon_event_flag);
+	wake_up_interruptible(&mon_ctx->mon_wait_queue);
+}
+
+void pkt_capture_wakeup_mon_thread(struct wlan_objmgr_vdev *vdev)
+{
+	struct pkt_capture_vdev_priv *vdev_priv;
+	struct pkt_capture_mon_context *mon_ctx;
+
+	if (!vdev) {
+		pkt_capture_err("vdev is NULL");
+		return;
+	}
+
+	vdev_priv = pkt_capture_vdev_get_priv(vdev);
+	if (!vdev_priv) {
+		pkt_capture_err("packet capture vdev priv is NULL");
+		return;
+	}
+	mon_ctx = vdev_priv->mon_ctx;
+
+	set_bit(PKT_CAPTURE_RX_POST_EVENT, &mon_ctx->mon_event_flag);
+	wake_up_interruptible(&mon_ctx->mon_wait_queue);
+}
+
+/**
+ * pkt_capture_process_from_queue() - function to process pending mon packets
+ * @mon_ctx: Pointer to packet capture mon context
+ *
+ * This api traverses the pending buffer list and calling the callback.
+ * This callback would essentially send the packet to HDD.
+ *
+ * Return: None
+ */
+static void
+pkt_capture_process_from_queue(struct pkt_capture_mon_context *mon_ctx)
+{
+	struct pkt_capture_mon_pkt *pkt;
+	uint8_t vdev_id;
+	uint8_t tid;
+
+	spin_lock_bh(&mon_ctx->mon_queue_lock);
+	while (!list_empty(&mon_ctx->mon_thread_queue)) {
+		pkt = list_first_entry(&mon_ctx->mon_thread_queue,
+				       struct pkt_capture_mon_pkt, list);
+		list_del(&pkt->list);
+		spin_unlock_bh(&mon_ctx->mon_queue_lock);
+		vdev_id = pkt->vdev_id;
+		tid = pkt->tid;
+		pkt->callback(pkt->context, pkt->monpkt, vdev_id,
+			      tid, pkt->status, pkt->pkt_format);
+		pkt_capture_free_mon_pkt(mon_ctx, pkt);
+		spin_lock_bh(&mon_ctx->mon_queue_lock);
+	}
+	spin_unlock_bh(&mon_ctx->mon_queue_lock);
+}
+
+/**
+ * pkt_capture_mon_thread() - packet capture mon thread
+ * @arg: Pointer to vdev object manager
+ *
+ * This api is the thread handler for mon Data packet processing.
+ *
+ * Return: thread exit code
+ */
+static int pkt_capture_mon_thread(void *arg)
+{
+	struct pkt_capture_mon_context *mon_ctx;
+	unsigned long pref_cpu = 0;
+	bool shutdown = false;
+	int status, i;
+
+	if (!arg) {
+		pkt_capture_err("Bad Args passed to mon thread");
+		return 0;
+	}
+	mon_ctx = (struct pkt_capture_mon_context *)arg;
+	set_user_nice(current, -1);
+#ifdef MSM_PLATFORM
+	set_wake_up_idle(true);
+#endif
+
+	/**
+	 * Find the available cpu core other than cpu 0 and
+	 * bind the thread
+	 */
+	for_each_online_cpu(i) {
+		if (i == 0)
+			continue;
+		pref_cpu = i;
+			break;
+	}
+
+	set_cpus_allowed_ptr(current, cpumask_of(pref_cpu));
+
+	complete(&mon_ctx->mon_start_event);
+
+	while (!shutdown) {
+		status =
+		wait_event_interruptible(mon_ctx->mon_wait_queue,
+					 test_bit(PKT_CAPTURE_RX_POST_EVENT,
+						  &mon_ctx->mon_event_flag) ||
+					 test_bit(PKT_CAPTURE_RX_SUSPEND_EVENT,
+						  &mon_ctx->mon_event_flag));
+		if (status == -ERESTARTSYS)
+			break;
+
+		clear_bit(PKT_CAPTURE_RX_POST_EVENT,
+			  &mon_ctx->mon_event_flag);
+		while (true) {
+			if (test_bit(PKT_CAPTURE_RX_SHUTDOWN_EVENT,
+				     &mon_ctx->mon_event_flag)) {
+				clear_bit(PKT_CAPTURE_RX_SHUTDOWN_EVENT,
+					  &mon_ctx->mon_event_flag);
+				if (test_bit(
+					PKT_CAPTURE_RX_SUSPEND_EVENT,
+					&mon_ctx->mon_event_flag)) {
+					clear_bit(PKT_CAPTURE_RX_SUSPEND_EVENT,
+						  &mon_ctx->mon_event_flag);
+					complete(&mon_ctx->suspend_mon_event);
+				}
+				pkt_capture_info("Shutting down pktcap thread");
+				shutdown = true;
+				break;
+			}
+			pkt_capture_process_from_queue(mon_ctx);
+
+			if (test_bit(PKT_CAPTURE_RX_SUSPEND_EVENT,
+				     &mon_ctx->mon_event_flag)) {
+				clear_bit(PKT_CAPTURE_RX_SUSPEND_EVENT,
+					  &mon_ctx->mon_event_flag);
+				spin_lock(&mon_ctx->mon_thread_lock);
+				INIT_COMPLETION(mon_ctx->resume_mon_event);
+				complete(&mon_ctx->suspend_mon_event);
+				spin_unlock(&mon_ctx->mon_thread_lock);
+				wait_for_completion_interruptible
+					(&mon_ctx->resume_mon_event);
+			}
+			break;
+		}
+	}
+	pkt_capture_debug("Exiting packet capture mon thread");
+	complete_and_exit(&mon_ctx->mon_shutdown, 0);
+
+	return 0;
+}
+
+void pkt_capture_close_mon_thread(struct pkt_capture_mon_context *mon_ctx)
+{
+	if (!mon_ctx->mon_thread)
+		return;
+
+	/* Shut down Tlshim Rx thread */
+	set_bit(PKT_CAPTURE_RX_SHUTDOWN_EVENT,
+		&mon_ctx->mon_event_flag);
+	set_bit(PKT_CAPTURE_RX_POST_EVENT,
+		&mon_ctx->mon_event_flag);
+	wake_up_interruptible(&mon_ctx->mon_wait_queue);
+	wait_for_completion(&mon_ctx->mon_shutdown);
+	mon_ctx->mon_thread = NULL;
+	pkt_capture_drop_monpkt(mon_ctx);
+	pkt_capture_free_mon_pkt_freeq(mon_ctx);
+}
+
+QDF_STATUS
+pkt_capture_open_mon_thread(struct pkt_capture_mon_context *mon_ctx)
+{
+	mon_ctx->mon_thread = kthread_create(pkt_capture_mon_thread,
+					     mon_ctx,
+					     "pkt_capture_mon_thread");
+
+	if (IS_ERR(mon_ctx->mon_thread)) {
+		pkt_capture_fatal("Could not Create packet capture mon thread");
+		return QDF_STATUS_E_FAILURE;
+	}
+	wake_up_process(mon_ctx->mon_thread);
+	pkt_capture_debug("packet capture MON thread Created");
+
+	wait_for_completion_interruptible(&mon_ctx->mon_start_event);
+	pkt_capture_debug("packet capture MON Thread has started");
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void pkt_capture_drop_monpkt(struct pkt_capture_mon_context *mon_ctx)
+{
+	struct pkt_capture_mon_pkt *pkt, *tmp;
+	struct list_head local_list;
+	qdf_nbuf_t buf, next_buf;
+
+	INIT_LIST_HEAD(&local_list);
+	spin_lock_bh(&mon_ctx->mon_queue_lock);
+	if (list_empty(&mon_ctx->mon_thread_queue)) {
+		spin_unlock_bh(&mon_ctx->mon_queue_lock);
+		return;
+	}
+	list_for_each_entry_safe(pkt, tmp,
+				 &mon_ctx->mon_thread_queue,
+				 list)
+		list_move_tail(&pkt->list, &local_list);
+
+	spin_unlock_bh(&mon_ctx->mon_queue_lock);
+
+	list_for_each_entry_safe(pkt, tmp, &local_list, list) {
+		list_del(&pkt->list);
+		buf = pkt->monpkt;
+		while (buf) {
+			next_buf = qdf_nbuf_queue_next(buf);
+			qdf_nbuf_free(buf);
+			buf = next_buf;
+		}
+		pkt_capture_free_mon_pkt(mon_ctx, pkt);
+	}
+}
+
+int pkt_capture_suspend_mon_thread(struct wlan_objmgr_vdev *vdev)
+{
+	struct pkt_capture_vdev_priv *vdev_priv;
+	struct pkt_capture_mon_context *mon_ctx;
+	int rc;
+
+	if (!vdev) {
+		pkt_capture_err("vdev is NULL");
+		return -EINVAL;
+	}
+
+	vdev_priv = pkt_capture_vdev_get_priv(vdev);
+	if (!vdev_priv) {
+		pkt_capture_err("packet capture vdev priv is NULL");
+		return -EINVAL;
+	}
+	mon_ctx = vdev_priv->mon_ctx;
+	if (!mon_ctx) {
+		pkt_capture_err("packet capture mon context is NULL");
+		return -EINVAL;
+	}
+
+	set_bit(PKT_CAPTURE_RX_SUSPEND_EVENT,
+		&mon_ctx->mon_event_flag);
+	wake_up_interruptible(&mon_ctx->mon_wait_queue);
+	rc = wait_for_completion_timeout(
+			&mon_ctx->suspend_mon_event,
+			msecs_to_jiffies(PKT_CAPTURE_SUSPEND_TIMEOUT));
+	if (!rc) {
+		clear_bit(PKT_CAPTURE_RX_SUSPEND_EVENT,
+			  &mon_ctx->mon_event_flag);
+		pkt_capture_err("Failed to suspend packet capture mon thread");
+		return -EINVAL;
+	}
+	mon_ctx->is_mon_thread_suspended = true;
+
+	return 0;
+}
+
+void pkt_capture_resume_mon_thread(struct wlan_objmgr_vdev *vdev)
+{
+	struct pkt_capture_vdev_priv *vdev_priv;
+	struct pkt_capture_mon_context *mon_ctx;
+
+	if (!vdev) {
+		pkt_capture_err("vdev is NULL");
+		return;
+	}
+
+	vdev_priv = pkt_capture_vdev_get_priv(vdev);
+	if (!vdev_priv) {
+		pkt_capture_err("packet capture vdev priv is NULL");
+		return;
+	}
+	mon_ctx = vdev_priv->mon_ctx;
+	if (!mon_ctx) {
+		pkt_capture_err("packet capture mon context is NULL");
+		return;
+	}
+
+	if (mon_ctx->is_mon_thread_suspended)
+		complete(&mon_ctx->resume_mon_event);
+}
+
+QDF_STATUS
+pkt_capture_alloc_mon_thread(struct pkt_capture_mon_context *mon_ctx)
+{
+	spin_lock_init(&mon_ctx->mon_thread_lock);
+	init_waitqueue_head(&mon_ctx->mon_wait_queue);
+	init_completion(&mon_ctx->mon_start_event);
+	init_completion(&mon_ctx->suspend_mon_event);
+	init_completion(&mon_ctx->resume_mon_event);
+	init_completion(&mon_ctx->mon_shutdown);
+	mon_ctx->mon_event_flag = 0;
+	spin_lock_init(&mon_ctx->mon_queue_lock);
+	spin_lock_init(&mon_ctx->mon_pkt_freeq_lock);
+	INIT_LIST_HEAD(&mon_ctx->mon_thread_queue);
+	spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock);
+	INIT_LIST_HEAD(&mon_ctx->mon_pkt_freeq);
+	spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock);
+
+	return pkt_capture_alloc_mon_pkt_freeq(mon_ctx);
+}

+ 31 - 1
components/pkt_capture/dispatcher/inc/wlan_pkt_capture_ucfg_api.h

@@ -54,7 +54,26 @@ void ucfg_pkt_capture_deinit(void);
  *
  * Return: enum pkt_capture_mode
  */
-enum pkt_capture_mode ucfg_pkt_capture_get_mode(struct wlan_objmgr_psoc *psoc);
+enum pkt_capture_mode
+ucfg_pkt_capture_get_mode(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * ucfg_pkt_capture_suspend_mon_thread() - suspend packet capture mon thread
+ * vdev: pointer to vdev object manager
+ *
+ * Return: 0 on success, -EINVAL on failure
+ */
+int ucfg_pkt_capture_suspend_mon_thread(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_pkt_capture_resume_mon_thread() - resume packet capture mon thread
+ * vdev: pointer to vdev object manager
+ *
+ * Resume packet capture MON thread by completing RX thread resume event
+ *
+ * Return: None
+ */
+void ucfg_pkt_capture_resume_mon_thread(struct wlan_objmgr_vdev *vdev);
 #else
 static inline
 QDF_STATUS ucfg_pkt_capture_init(void)
@@ -72,5 +91,16 @@ enum pkt_capture_mode ucfg_pkt_capture_get_mode(struct wlan_objmgr_psoc *psoc)
 {
 	return PACKET_CAPTURE_MODE_DISABLE;
 }
+
+static inline
+void ucfg_pkt_capture_resume_mon_thread(struct wlan_objmgr_vdev *vdev)
+{
+}
+
+static inline
+int ucfg_pkt_capture_suspend_mon_thread(struct wlan_objmgr_vdev *vdev)
+{
+	return 0;
+}
 #endif /* WLAN_FEATURE_PKT_CAPTURE */
 #endif /* _WLAN_PKT_CAPTURE_UCFG_API_H_ */

+ 11 - 0
components/pkt_capture/dispatcher/src/wlan_pkt_capture_ucfg_api.c

@@ -23,6 +23,7 @@
 #include "wlan_pkt_capture_objmgr.h"
 #include "wlan_pkt_capture_main.h"
 #include "wlan_pkt_capture_ucfg_api.h"
+#include "wlan_pkt_capture_mon_thread.h"
 
 enum pkt_capture_mode ucfg_pkt_capture_get_mode(struct wlan_objmgr_psoc *psoc)
 {
@@ -114,3 +115,13 @@ void ucfg_pkt_capture_deinit(void)
 	if (QDF_IS_STATUS_ERROR(status))
 		pkt_capture_err("Failed to unregister psoc create handler");
 }
+
+int ucfg_pkt_capture_suspend_mon_thread(struct wlan_objmgr_vdev *vdev)
+{
+	return pkt_capture_suspend_mon_thread(vdev);
+}
+
+void ucfg_pkt_capture_resume_mon_thread(struct wlan_objmgr_vdev *vdev)
+{
+	pkt_capture_resume_mon_thread(vdev);
+}