From f1d581361d059d0eef23a2684b596449b6fdde63 Mon Sep 17 00:00:00 2001 From: Alok Kumar Date: Mon, 19 Aug 2019 18:02:40 +0530 Subject: [PATCH] qcacld-3.0: Open a mon thread for packet capture mode Create a mon thread to process the packets for pktcapture mode only if packet capture mode is enabled. Change-Id: I64e3687d08acd0d27019ed9e11b5b92b13fcd878 CRs-Fixed: 2528545 --- core/cds/inc/cds_sched.h | 246 ++++++++++++++++- core/cds/src/cds_api.c | 6 + core/cds/src/cds_sched.c | 496 +++++++++++++++++++++++++++++++++- core/hdd/inc/wlan_hdd_main.h | 4 + core/hdd/inc/wlan_hdd_power.h | 32 ++- core/hdd/src/wlan_hdd_power.c | 58 +++- 6 files changed, 837 insertions(+), 5 deletions(-) diff --git a/core/cds/inc/cds_sched.h b/core/cds/inc/cds_sched.h index 0c3d160d1199..8bb33f742322 100644 --- a/core/cds/inc/cds_sched.h +++ b/core/cds/inc/cds_sched.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-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 @@ -77,6 +77,88 @@ struct cds_ol_rx_pkt { }; +#ifdef WLAN_FEATURE_PKT_CAPTURE +/* + * Maximum number of cds messages to be allocated for + * OL MON thread. + */ +#define CDS_MAX_OL_MON_PKT 4000 + +struct cds_sched_mon_context { + /* MON thread lock */ + spinlock_t ol_mon_thread_lock; + + /* OL MON thread handle */ + struct task_struct *ol_mon_thread; + + /* Handle of Event for MON thread to signal startup */ + struct completion ol_mon_start_event; + + /* Completion object to suspend OL MON thread */ + struct completion ol_suspend_mon_event; + + /* Completion objext to resume OL MON thread */ + struct completion ol_resume_mon_event; + + /* Completion object for OL MON thread shutdown */ + struct completion ol_mon_shutdown; + + /* Waitq for OL MON thread */ + wait_queue_head_t ol_mon_wait_queue; + + unsigned long ol_mon_event_flag; + + /* MON buffer queue */ + struct list_head ol_mon_thread_queue; + + /* Spinlock to synchronize between tasklet and thread */ + spinlock_t ol_mon_queue_lock; + + /* MON queue length */ + unsigned int ol_mon_queue_len; + + /* Lock to synchronize free buffer queue access */ + spinlock_t cds_ol_mon_pkt_freeq_lock; + + /* Free message queue for OL MON processing */ + struct list_head cds_ol_mon_pkt_freeq; + + /* MON thread affinity cpu */ + unsigned long mon_thread_cpu; + +}; + +#endif /* WLAN_FEATURE_PKT_CAPTURE */ +typedef void (*cds_ol_mon_thread_cb)( + void *context, void *monpkt, + uint8_t vdev_id, uint8_t tid, + uint8_t status, bool pkt_format); + +/* + * CDS message wrapper for mon data from TXRX + */ +struct cds_ol_mon_pkt { + struct list_head list; + void *context; + + /* mon skb */ + void *monpkt; + + /* vdev id to which this packet is destined */ + uint8_t vdev_id; + + uint8_t tid; + + /* Tx packet status */ + uint8_t status; + + /* 0 = 802.3 format , 1 = 802.11 format */ + bool pkt_format; + + /* Call back to further send this packet to txrx layer */ + cds_ol_mon_thread_cb callback; +}; + /* ** CDS Scheduler context ** The scheduler context contains the following: @@ -140,6 +222,10 @@ typedef struct _cds_sched_context { bool rx_affinity_required; uint8_t conf_rx_thread_ul_affinity; #endif + +#ifdef WLAN_FEATURE_PKT_CAPTURE + struct cds_sched_mon_context sched_mon_ctx; +#endif /* WLAN_FEATURE_PKT_CAPTURE */ } cds_sched_context, *p_cds_sched_context; /** @@ -551,4 +637,162 @@ void cds_shutdown_notifier_call(void); */ void cds_resume_rx_thread(void); +#ifdef WLAN_FEATURE_PKT_CAPTURE +/** + * cds_resume_mon_thread() - resume mon thread by completing its resume event + * + * Resume MON thread by completing RX thread resume event + * + * Return: None + */ +void cds_resume_mon_thread(void); + +/** + * cds_drop_monpkt() - API to drop pending mon packets + * @pschedcontext: Pointer to the global CDS Sched Context + * + * This api drops all the pending packets in the queue. + * + * Return: none + */ +void cds_drop_monpkt(p_cds_sched_context pschedcontext); + +/** + * cds_indicate_monpkt() - API to Indicate rx data packet + * @pschedcontext: pointer to CDS Sched Context + * @pkt: CDS OL MON pkt pointer containing to mon data message buffer + * + * Return: none + */ +void cds_indicate_monpkt(p_cds_sched_context pschedcontext, + struct cds_ol_mon_pkt *pkt); + +/** + * cds_wakeup_mon_thread() - wakeup mon thread + * @Arg: Pointer to the global CDS Sched Context + * + * This api wake up cds_ol_mon_thread() to process pkt + * + * Return: none + */ +void cds_wakeup_mon_thread(p_cds_sched_context pschedcontext); + +/** + * cds_close_mon_thread() - close the Tlshim MON thread + * + * This api closes the Tlshim MON thread: + * + * Return: qdf status + */ +QDF_STATUS cds_close_mon_thread(void); + +/** + * cds_open_mon_thread() - open the Tlshim MON thread + * @pSchedContext: Pointer to the global CDS Sched Context + * + * This api opens the Tlshim MON thread: + * + * Return: qdf status + */ +QDF_STATUS cds_open_mon_thread(p_cds_sched_context pschedcontext); + +/** + * cds_alloc_mon_thread() - alloc resources for MON thread + * @pSchedContext: Pointer to the global CDS Sched Context + * + * This api alloc resources for MON thread: + * + * Return: qdf status + */ +QDF_STATUS cds_alloc_mon_thread(p_cds_sched_context pschedcontext); + +/** + * cds_alloc_ol_mon_pkt() - API to return next available cds message + * @pSchedContext: Pointer to the global CDS Sched Context + * + * This api returns next available cds message buffer used for mon data + * processing + * + * Return: Pointer to cds message buffer + */ +struct cds_ol_mon_pkt *cds_alloc_ol_mon_pkt(p_cds_sched_context pschedcontext); + +/** + * cds_free_ol_mon_pkt() - api to release cds message to the freeq + * This api returns the cds message used for mon data to the free queue + * @pSchedContext: Pointer to the global CDS Sched Context + * @pkt: CDS message buffer to be returned to free queue. + * + * Return: none + */ +void cds_free_ol_mon_pkt(p_cds_sched_context pschedcontext, + struct cds_ol_mon_pkt *pkt); + +/** + * cds_free_ol_mon_pkt_freeq() - free cds buffer free queue + * @pSchedContext - pointer to the global CDS Sched Context + * + * This API does mem free of the buffers available in free cds buffer + * queue which is used for mon Data processing. + * + * Return: none + */ +void cds_free_ol_mon_pkt_freeq(p_cds_sched_context pschedcontext); +#else +static inline +void cds_resume_mon_thread(void) +{ +} + +static inline +void cds_drop_monpkt(p_cds_sched_context pschedcontext) +{ +} + +static inline +void cds_indicate_monpkt(p_cds_sched_context pschedcontext, + struct cds_ol_mon_pkt *pkt) +{ +} + +static inline +void cds_wakeup_mon_thread(p_cds_sched_context pschedcontext) +{ +} + +static inline +QDF_STATUS cds_close_mon_thread(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS cds_open_mon_thread(p_cds_sched_context pschedcontext) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS cds_alloc_mon_thread(p_cds_sched_context pschedcontext) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +struct cds_ol_mon_pkt *cds_alloc_ol_mon_pkt(p_cds_sched_context pschedcontext) +{ + return NULL; +} + +static inline +void cds_free_ol_mon_pkt(p_cds_sched_context pschedcontext, + struct cds_ol_mon_pkt *pkt) +{ +} + +static inline +void cds_free_ol_mon_pkt_freeq(p_cds_sched_context pschedcontext) +{ +} +#endif /* WLAN_FEATURE_PKT_CAPTURE */ #endif /* #ifndef __CDS_SCHED_H */ diff --git a/core/cds/src/cds_api.c b/core/cds/src/cds_api.c index 97aeefbad11b..056854112330 100644 --- a/core/cds/src/cds_api.c +++ b/core/cds/src/cds_api.c @@ -1134,6 +1134,12 @@ QDF_STATUS cds_post_disable(void) return QDF_STATUS_E_INVAL; } + qdf_status = cds_close_mon_thread(); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("Failed to close MON thread!"); + return QDF_STATUS_E_INVAL; + } + cdp_pdev_pre_detach(cds_get_context(QDF_MODULE_ID_SOC), OL_TXRX_PDEV_ID, 1); diff --git a/core/cds/src/cds_sched.c b/core/cds/src/cds_sched.c index 4994e1f292bb..b141f0e04e0c 100644 --- a/core/cds/src/cds_sched.c +++ b/core/cds/src/cds_sched.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2014-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 @@ -56,6 +56,17 @@ enum notifier_state { } notifier_state; static p_cds_sched_context gp_cds_sched_context; + +#ifdef WLAN_FEATURE_PKT_CAPTURE +static int cds_ol_mon_thread(void *arg); +static QDF_STATUS cds_alloc_ol_mon_pkt_freeq(p_cds_sched_context pschedcontext); +static inline +int cds_set_mon_cpus_allowed_ptr(struct task_struct *task, unsigned long cpu) +{ + return set_cpus_allowed_ptr(task, cpumask_of(cpu)); +} +#endif /* WLAN_FEATURE_PKT_CAPTURE */ + #ifdef QCA_CONFIG_SMP static int cds_ol_rx_thread(void *arg); static uint32_t affine_cpu; @@ -507,6 +518,10 @@ QDF_STATUS cds_sched_open(void *p_cds_context, pSchedContext->high_throughput_required = false; pSchedContext->rx_affinity_required = false; #endif + + if (QDF_STATUS_SUCCESS != cds_alloc_mon_thread(pSchedContext)) + goto mon_freeqalloc_failure; + gp_cds_sched_context = pSchedContext; #ifdef QCA_CONFIG_SMP @@ -524,14 +539,29 @@ QDF_STATUS cds_sched_open(void *p_cds_context, wait_for_completion_interruptible(&pSchedContext->ol_rx_start_event); cds_debug("CDS OL Rx Thread has started"); #endif + + if (QDF_STATUS_SUCCESS != cds_open_mon_thread(pSchedContext)) + goto OL_MON_THREAD_START_FAILURE; + /* We're good now: Let's get the ball rolling!!! */ cds_debug("CDS Scheduler successfully Opened"); return QDF_STATUS_SUCCESS; +OL_MON_THREAD_START_FAILURE: +#ifdef QCA_CONFIG_SMP + /* Try and force the Main thread controller to exit */ + set_bit(RX_SHUTDOWN_EVENT, &pSchedContext->ol_rx_event_flag); + set_bit(RX_POST_EVENT, &pSchedContext->ol_rx_event_flag); + wake_up_interruptible(&pSchedContext->ol_rx_wait_queue); + /* Wait for RX Thread to exit */ + wait_for_completion(&pSchedContext->ol_rx_shutdown); +#endif + #ifdef QCA_CONFIG_SMP OL_RX_THREAD_START_FAILURE: #endif - + cds_free_ol_mon_pkt_freeq(gp_cds_sched_context); +mon_freeqalloc_failure: #ifdef QCA_CONFIG_SMP qdf_cpuhp_unregister(&pSchedContext->cpuhp_event_handle); cds_free_ol_rx_pkt_freeq(gp_cds_sched_context); @@ -887,6 +917,9 @@ QDF_STATUS cds_sched_close(void) } cds_close_rx_thread(); + + cds_close_mon_thread(); + gp_cds_sched_context = NULL; return QDF_STATUS_SUCCESS; } /* cds_sched_close() */ @@ -1040,3 +1073,462 @@ int cds_get_gfp_flags(void) return flags; } +#ifdef WLAN_FEATURE_PKT_CAPTURE +/** + * cds_free_ol_mon_pkt_freeq() - free cds buffer free queue + * @pSchedContext - pointer to the global CDS Sched Context + * + * This API does mem free of the buffers available in free cds buffer + * queue which is used for mon Data processing. + * + * Return: none + */ +void cds_free_ol_mon_pkt_freeq(p_cds_sched_context pschedcontext) +{ + struct cds_ol_mon_pkt *pkt; + + if (!cds_is_pktcapture_enabled()) + return; + + spin_lock_bh(&pschedcontext->sched_mon_ctx.cds_ol_mon_pkt_freeq_lock); + while (!list_empty(&pschedcontext-> + sched_mon_ctx.cds_ol_mon_pkt_freeq)) { + pkt = list_entry((&pschedcontext-> + sched_mon_ctx.cds_ol_mon_pkt_freeq)->next, + typeof(*pkt), list); + list_del(&pkt->list); + spin_unlock_bh(&pschedcontext-> + sched_mon_ctx.cds_ol_mon_pkt_freeq_lock); + qdf_mem_free(pkt); + spin_lock_bh(&pschedcontext-> + sched_mon_ctx.cds_ol_mon_pkt_freeq_lock); + } + spin_unlock_bh(&pschedcontext->sched_mon_ctx.cds_ol_mon_pkt_freeq_lock); +} + +/** + * cds_alloc_ol_mon_pkt_freeq() - Function to allocate free buffer queue + * @pSchedContext - pointer to the global CDS Sched Context + * + * This API allocates CDS_MAX_OL_MON_PKT number of cds message buffers + * which are used for mon data processing. + * + * Return: status of memory allocation + */ +static QDF_STATUS cds_alloc_ol_mon_pkt_freeq(p_cds_sched_context pschedcontext) +{ + struct cds_ol_mon_pkt *pkt, *tmp; + int i; + + for (i = 0; i < CDS_MAX_OL_MON_PKT; i++) { + pkt = qdf_mem_malloc(sizeof(*pkt)); + if (!pkt) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s Vos packet allocation for ol mon thread failed", + __func__); + goto free; + } + spin_lock_bh(&pschedcontext-> + sched_mon_ctx.cds_ol_mon_pkt_freeq_lock); + list_add_tail(&pkt->list, &pschedcontext-> + sched_mon_ctx.cds_ol_mon_pkt_freeq); + spin_unlock_bh(&pschedcontext-> + sched_mon_ctx.cds_ol_mon_pkt_freeq_lock); + } + + return QDF_STATUS_SUCCESS; + +free: + spin_lock_bh(&pschedcontext->sched_mon_ctx.cds_ol_mon_pkt_freeq_lock); + list_for_each_entry_safe(pkt, tmp, + &pschedcontext-> + sched_mon_ctx.cds_ol_mon_pkt_freeq, + list) { + list_del(&pkt->list); + spin_unlock_bh(&pschedcontext-> + sched_mon_ctx.cds_ol_mon_pkt_freeq_lock); + qdf_mem_free(pkt); + spin_lock_bh(&pschedcontext-> + sched_mon_ctx.cds_ol_mon_pkt_freeq_lock); + } + spin_unlock_bh(&pschedcontext->sched_mon_ctx.cds_ol_mon_pkt_freeq_lock); + return QDF_STATUS_E_NOMEM; +} + +/** + * cds_free_ol_mon_pkt() - api to release cds message to the freeq + * This api returns the cds message used for mon data to the free queue + * @pSchedContext: Pointer to the global CDS Sched Context + * @pkt: CDS message buffer to be returned to free queue. + * + * Return: none + */ +void +cds_free_ol_mon_pkt(p_cds_sched_context pschedcontext, + struct cds_ol_mon_pkt *pkt) +{ + memset(pkt, 0, sizeof(*pkt)); + spin_lock_bh(&pschedcontext->sched_mon_ctx.cds_ol_mon_pkt_freeq_lock); + list_add_tail(&pkt->list, + &pschedcontext->sched_mon_ctx.cds_ol_mon_pkt_freeq); + spin_unlock_bh(&pschedcontext->sched_mon_ctx.cds_ol_mon_pkt_freeq_lock); +} + +/** + * cds_alloc_ol_mon_pkt() - API to return next available cds message + * @pSchedContext: Pointer to the global CDS Sched Context + * + * This api returns next available cds message buffer used for mon data + * processing + * + * Return: Pointer to cds message buffer + */ +struct cds_ol_mon_pkt *cds_alloc_ol_mon_pkt(p_cds_sched_context pschedcontext) +{ + struct cds_ol_mon_pkt *pkt; + + spin_lock_bh(&pschedcontext->sched_mon_ctx.cds_ol_mon_pkt_freeq_lock); + if (list_empty(&pschedcontext->sched_mon_ctx.cds_ol_mon_pkt_freeq)) { + spin_unlock_bh(&pschedcontext-> + sched_mon_ctx.cds_ol_mon_pkt_freeq_lock); + return NULL; + } + pkt = list_first_entry(&pschedcontext-> + sched_mon_ctx.cds_ol_mon_pkt_freeq, + struct cds_ol_mon_pkt, list); + list_del(&pkt->list); + spin_unlock_bh(&pschedcontext->sched_mon_ctx.cds_ol_mon_pkt_freeq_lock); + return pkt; +} + +/** + * cds_indicate_monpkt() - indicate mon data packet + * @Arg: Pointer to the global CDS Sched Context + * @pkt: CDS data message buffer + * + * This api enqueues the mon packet into ol_mon_thread_queue and notifies + * cds_ol_mon_thread() + * + * Return: none + */ +void +cds_indicate_monpkt(p_cds_sched_context pschedcontext, + struct cds_ol_mon_pkt *pkt) +{ + spin_lock_bh(&pschedcontext->sched_mon_ctx.ol_mon_queue_lock); + list_add_tail(&pkt->list, &pschedcontext-> + sched_mon_ctx.ol_mon_thread_queue); + spin_unlock_bh(&pschedcontext->sched_mon_ctx.ol_mon_queue_lock); + set_bit(RX_POST_EVENT, &pschedcontext->sched_mon_ctx.ol_mon_event_flag); + wake_up_interruptible(&pschedcontext->sched_mon_ctx.ol_mon_wait_queue); +} + +/** + * cds_wakeup_mon_thread() - wakeup mon thread + * @Arg: Pointer to the global CDS Sched Context + * + * This api wake up cds_ol_mon_thread() to process pkt + * + * Return: none + */ +void +cds_wakeup_mon_thread(p_cds_sched_context pschedcontext) +{ + set_bit(RX_POST_EVENT, &pschedcontext->sched_mon_ctx.ol_mon_event_flag); + wake_up_interruptible(&pschedcontext->sched_mon_ctx.ol_mon_wait_queue); +} + +/** + * cds_close_mon_thread() - close the Tlshim Rx thread + * + * This api closes the Tlshim Rx thread: + * + * Return: qdf status + */ +QDF_STATUS cds_close_mon_thread(void) +{ + if (!cds_is_pktcapture_enabled()) + return QDF_STATUS_SUCCESS; + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: invoked", __func__); + + if (!gp_cds_sched_context) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: gp_cds_sched_context == NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (!gp_cds_sched_context->sched_mon_ctx.ol_mon_thread) + return QDF_STATUS_SUCCESS; + + /* Shut down Tlshim Rx thread */ + set_bit(RX_SHUTDOWN_EVENT, + &gp_cds_sched_context->sched_mon_ctx.ol_mon_event_flag); + set_bit(RX_POST_EVENT, + &gp_cds_sched_context->sched_mon_ctx.ol_mon_event_flag); + wake_up_interruptible(&gp_cds_sched_context-> + sched_mon_ctx.ol_mon_wait_queue); + wait_for_completion(&gp_cds_sched_context-> + sched_mon_ctx.ol_mon_shutdown); + gp_cds_sched_context->sched_mon_ctx.ol_mon_thread = NULL; + cds_drop_monpkt(gp_cds_sched_context); + cds_free_ol_mon_pkt_freeq(gp_cds_sched_context); + + return QDF_STATUS_SUCCESS; +} /* cds_close_mon_thread */ + +/** + * cds_open_mon_thread() - open the Tlshim Rx thread + * + * This api open the Tlshim Rx thread: + * + * Return: qdf status + */ +QDF_STATUS cds_open_mon_thread(p_cds_sched_context pschedcontext) +{ + if (!cds_is_pktcapture_enabled()) + return QDF_STATUS_SUCCESS; + + pschedcontext->sched_mon_ctx.ol_mon_thread = kthread_create( + cds_ol_mon_thread, + pschedcontext, + "cds_ol_mon_thread"); + if (IS_ERR(pschedcontext->sched_mon_ctx.ol_mon_thread)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Could not Create CDS OL MON Thread", + __func__); + return QDF_STATUS_E_FAILURE; + } + wake_up_process(pschedcontext->sched_mon_ctx.ol_mon_thread); + cds_debug("CDS OL MON thread Created"); + + wait_for_completion_interruptible( + &pschedcontext->sched_mon_ctx.ol_mon_start_event); + cds_debug("CDS OL MON Thread has started"); + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_drop_monpkt() - api to drop pending mon packets for a sta + * @pschedcontext: Pointer to the global CDS Sched Context + * + * This api drops all queued packets for a station. + * + * Return: none + */ +void cds_drop_monpkt(p_cds_sched_context pschedcontext) +{ + struct list_head local_list; + struct cds_ol_mon_pkt *pkt, *tmp; + qdf_nbuf_t buf, next_buf; + + INIT_LIST_HEAD(&local_list); + spin_lock_bh(&pschedcontext->sched_mon_ctx.ol_mon_queue_lock); + if (list_empty(&pschedcontext->sched_mon_ctx.ol_mon_thread_queue)) { + spin_unlock_bh(&pschedcontext->sched_mon_ctx.ol_mon_queue_lock); + return; + } + list_for_each_entry_safe(pkt, tmp, + &pschedcontext-> + sched_mon_ctx.ol_mon_thread_queue, + list) + list_move_tail(&pkt->list, &local_list); + + spin_unlock_bh(&pschedcontext->sched_mon_ctx.ol_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; + } + cds_free_ol_mon_pkt(pschedcontext, pkt); + } +} + +/** + * cds_mon_from_queue() - function to process pending mon packets + * @pschedcontext: Pointer to the global CDS Sched 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 cds_mon_from_queue(p_cds_sched_context pschedcontext) +{ + struct cds_ol_mon_pkt *pkt; + uint8_t vdev_id; + uint8_t tid; + + spin_lock_bh(&pschedcontext->sched_mon_ctx.ol_mon_queue_lock); + while (!list_empty(&pschedcontext->sched_mon_ctx.ol_mon_thread_queue)) { + pkt = list_first_entry(&pschedcontext-> + sched_mon_ctx.ol_mon_thread_queue, + struct cds_ol_mon_pkt, list); + list_del(&pkt->list); + spin_unlock_bh(&pschedcontext->sched_mon_ctx.ol_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); + cds_free_ol_mon_pkt(pschedcontext, pkt); + spin_lock_bh(&pschedcontext->sched_mon_ctx.ol_mon_queue_lock); + } + spin_unlock_bh(&pschedcontext->sched_mon_ctx.ol_mon_queue_lock); +} + +/** + * cds_ol_mon_thread() - cds main tlshim mon thread + * @Arg: pointer to the global CDS Sched Context + * + * This api is the thread handler for mon Data packet processing. + * + * Return: thread exit code + */ +static int cds_ol_mon_thread(void *arg) +{ + p_cds_sched_context pschedcontext = (p_cds_sched_context)arg; + unsigned long pref_cpu = 0; + bool shutdown = false; + int status, i; + + if (!arg) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Bad Args passed", __func__); + return 0; + } + + 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; + } + + cds_set_mon_cpus_allowed_ptr(current, pref_cpu); + + complete(&pschedcontext->sched_mon_ctx.ol_mon_start_event); + + while (!shutdown) { + status = + wait_event_interruptible( + pschedcontext->sched_mon_ctx.ol_mon_wait_queue, + test_bit(RX_POST_EVENT, + &pschedcontext-> + sched_mon_ctx.ol_mon_event_flag) || + test_bit(RX_SUSPEND_EVENT, + &pschedcontext-> + sched_mon_ctx.ol_mon_event_flag)); + if (status == -ERESTARTSYS) + break; + + clear_bit(RX_POST_EVENT, + &pschedcontext->sched_mon_ctx.ol_mon_event_flag); + while (true) { + if (test_bit(RX_SHUTDOWN_EVENT, + &pschedcontext-> + sched_mon_ctx.ol_mon_event_flag)) { + clear_bit(RX_SHUTDOWN_EVENT, + &pschedcontext-> + sched_mon_ctx.ol_mon_event_flag); + if (test_bit( + RX_SUSPEND_EVENT, + &pschedcontext-> + sched_mon_ctx.ol_mon_event_flag)) { + clear_bit( + RX_SUSPEND_EVENT, + &pschedcontext-> + sched_mon_ctx.ol_mon_event_flag); + complete + (&pschedcontext-> + sched_mon_ctx.ol_suspend_mon_event); + } + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_INFO, + "%s: Shutting down OL MON Thread", + __func__); + shutdown = true; + break; + } + cds_mon_from_queue(pschedcontext); + + if (test_bit(RX_SUSPEND_EVENT, + &pschedcontext-> + sched_mon_ctx.ol_mon_event_flag)) { + clear_bit(RX_SUSPEND_EVENT, + &pschedcontext-> + sched_mon_ctx.ol_mon_event_flag); + spin_lock(&pschedcontext-> + sched_mon_ctx.ol_mon_thread_lock); + INIT_COMPLETION + (pschedcontext-> + sched_mon_ctx.ol_resume_mon_event); + complete(&pschedcontext-> + sched_mon_ctx.ol_suspend_mon_event); + spin_unlock(&pschedcontext-> + sched_mon_ctx.ol_mon_thread_lock); + wait_for_completion_interruptible + (&pschedcontext-> + sched_mon_ctx.ol_resume_mon_event); + } + break; + } + } + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG, + "%s: Exiting CDS OL mon thread", __func__); + complete_and_exit(&pschedcontext->sched_mon_ctx.ol_mon_shutdown, 0); + + return 0; +} + +void cds_resume_mon_thread(void) +{ + p_cds_sched_context cds_sched_context; + + cds_sched_context = get_cds_sched_ctxt(); + if (!cds_sched_context) { + cds_err("cds_sched_context is NULL"); + return; + } + + complete(&cds_sched_context->sched_mon_ctx.ol_resume_mon_event); +} + +QDF_STATUS +cds_alloc_mon_thread(p_cds_sched_context pschedcontext) +{ + if (!cds_is_pktcapture_enabled()) + return QDF_STATUS_SUCCESS; + + spin_lock_init(&pschedcontext->sched_mon_ctx.ol_mon_thread_lock); + init_waitqueue_head(&pschedcontext->sched_mon_ctx.ol_mon_wait_queue); + init_completion(&pschedcontext->sched_mon_ctx.ol_mon_start_event); + init_completion(&pschedcontext->sched_mon_ctx.ol_suspend_mon_event); + init_completion(&pschedcontext->sched_mon_ctx.ol_resume_mon_event); + init_completion(&pschedcontext->sched_mon_ctx.ol_mon_shutdown); + pschedcontext->sched_mon_ctx.ol_mon_event_flag = 0; + spin_lock_init(&pschedcontext->sched_mon_ctx.ol_mon_queue_lock); + spin_lock_init(&pschedcontext->sched_mon_ctx.cds_ol_mon_pkt_freeq_lock); + INIT_LIST_HEAD(&pschedcontext->sched_mon_ctx.ol_mon_thread_queue); + spin_lock_bh(&pschedcontext->sched_mon_ctx.cds_ol_mon_pkt_freeq_lock); + INIT_LIST_HEAD(&pschedcontext->sched_mon_ctx.cds_ol_mon_pkt_freeq); + spin_unlock_bh(&pschedcontext->sched_mon_ctx.cds_ol_mon_pkt_freeq_lock); + + return cds_alloc_ol_mon_pkt_freeq(pschedcontext); +} +#endif /* WLAN_FEATURE_PKT_CAPTURE */ diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index a004ef19e3b6..0eb9b82046f4 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -1622,6 +1622,10 @@ struct hdd_context { bool is_scheduler_suspended; +#ifdef WLAN_FEATURE_PKT_CAPTURE + bool is_ol_mon_thread_suspended; +#endif + #ifdef QCA_CONFIG_SMP bool is_ol_rx_thread_suspended; #endif diff --git a/core/hdd/inc/wlan_hdd_power.h b/core/hdd/inc/wlan_hdd_power.h index 0ff09176b964..13459d786895 100644 --- a/core/hdd/inc/wlan_hdd_power.h +++ b/core/hdd/inc/wlan_hdd_power.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2012, 2014-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 @@ -534,6 +534,36 @@ hdd_wlan_fake_apps_suspend(struct wiphy *wiphy, struct net_device *dev, } #endif /* WLAN_SUSPEND_RESUME_TEST */ +#ifdef WLAN_FEATURE_PKT_CAPTURE +/** + * wlan_hdd_mon_thread_resume() - Resume MON thread + * @hdd_ctx: HDD context + * + * Check if MON thread is suspended, and resume if yes. + * + * Return: None + */ +void wlan_hdd_mon_thread_resume(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_mon_thread_suspend() - Suspend MON thread + * @hdd_ctx: HDD context + * + * To suspend MON thread + * + * Return: 0 for success + */ +int wlan_hdd_mon_thread_suspend(struct hdd_context *hdd_ctx); + +#else +static inline void wlan_hdd_mon_thread_resume(struct hdd_context *hdd_ctx) {} +static inline int wlan_hdd_mon_thread_suspend(struct hdd_context *hdd_ctx) +{ + return 0; +} + +#endif /* WLAN_FEATURE_PKT_CAPTURE */ + #ifdef QCA_CONFIG_SMP /** * wlan_hdd_rx_thread_resume() - Resume RX thread diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c index 533cec358329..054d290e6bee 100644 --- a/core/hdd/src/wlan_hdd_power.c +++ b/core/hdd/src/wlan_hdd_power.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-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 @@ -123,6 +123,46 @@ void hdd_wlan_offload_event(uint8_t type, uint8_t state) } #endif +#ifdef WLAN_FEATURE_PKT_CAPTURE + +/* timeout in msec to wait for RX_THREAD to suspend */ +#define HDD_MONTHREAD_SUSPEND_TIMEOUT 200 + +void wlan_hdd_mon_thread_resume(struct hdd_context *hdd_ctx) +{ + if (hdd_ctx->is_ol_mon_thread_suspended) { + cds_resume_mon_thread(); + hdd_ctx->is_ol_mon_thread_suspended = false; + } +} + +int wlan_hdd_mon_thread_suspend(struct hdd_context *hdd_ctx) +{ + p_cds_sched_context cds_sched_context = get_cds_sched_ctxt(); + int rc; + + if (!cds_sched_context) + return -EINVAL; + + set_bit(RX_SUSPEND_EVENT, + &cds_sched_context->sched_mon_ctx.ol_mon_event_flag); + wake_up_interruptible(&cds_sched_context-> + sched_mon_ctx.ol_mon_wait_queue); + rc = wait_for_completion_timeout( + &cds_sched_context->sched_mon_ctx.ol_suspend_mon_event, + msecs_to_jiffies(HDD_MONTHREAD_SUSPEND_TIMEOUT)); + if (!rc) { + clear_bit(RX_SUSPEND_EVENT, + &cds_sched_context->sched_mon_ctx.ol_mon_event_flag); + hdd_err("Failed to stop tl_shim mon thread"); + return -EINVAL; + } + hdd_ctx->is_ol_mon_thread_suspended = true; + + return 0; +} +#endif + #ifdef QCA_CONFIG_SMP /* timeout in msec to wait for RX_THREAD to suspend */ @@ -1313,6 +1353,9 @@ QDF_STATUS hdd_wlan_shutdown(void) dp_txrx_resume(cds_get_context(QDF_MODULE_ID_SOC)); + if (cds_is_pktcapture_enabled()) + wlan_hdd_mon_thread_resume(hdd_ctx); + /* * After SSR, FW clear its txrx stats. In host, * as adapter is intact so those counts are still @@ -1718,6 +1761,9 @@ static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy) if (hdd_ctx->enable_dp_rx_threads) dp_txrx_resume(cds_get_context(QDF_MODULE_ID_SOC)); + if (cds_is_pktcapture_enabled()) + wlan_hdd_mon_thread_resume(hdd_ctx); + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, TRACE_CODE_HDD_CFG80211_RESUME_WLAN, NO_SESSION, hdd_ctx->is_wiphy_suspended); @@ -1914,6 +1960,11 @@ static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy, if (hdd_ctx->enable_dp_rx_threads) dp_txrx_suspend(cds_get_context(QDF_MODULE_ID_SOC)); + if (cds_is_pktcapture_enabled()) { + if (wlan_hdd_mon_thread_suspend(hdd_ctx)) + goto resume_ol_mon; + } + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN, NO_SESSION, hdd_ctx->is_wiphy_suspended); @@ -1934,6 +1985,11 @@ resume_dp_thread: if (hdd_ctx->enable_dp_rx_threads) dp_txrx_resume(cds_get_context(QDF_MODULE_ID_SOC)); +resume_ol_mon: + /* Resume tlshim MON thread */ + if (cds_is_pktcapture_enabled()) + wlan_hdd_mon_thread_resume(hdd_ctx); + resume_ol_rx: /* Resume tlshim Rx thread */ wlan_hdd_rx_thread_resume(hdd_ctx);