blob: a09163453d877646affe6d85ef5d3eebe2ff6af0 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Rajeev Kumardbc886e2016-01-19 12:56:04 -08002 * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * File: cds_sched.c
30 *
31 * DOC: CDS Scheduler Implementation
32 */
33
34 /* Include Files */
35#include <cds_mq.h>
36#include <cds_api.h>
37#include <ani_global.h>
38#include <sir_types.h>
Anurag Chouhan6d760662016-02-20 16:05:43 +053039#include <qdf_types.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080040#include <lim_api.h>
41#include <sme_api.h>
42#include <wlan_qct_sys.h>
43#include "cds_sched.h"
44#include <wlan_hdd_power.h>
45#include "wma_types.h"
46#include <linux/spinlock.h>
47#include <linux/kthread.h>
48#include <linux/cpu.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080049/* Preprocessor Definitions and Constants */
50#define CDS_SCHED_THREAD_HEART_BEAT INFINITE
51/* Milli seconds to delay SSR thread when an Entry point is Active */
52#define SSR_WAIT_SLEEP_TIME 200
53/* MAX iteration count to wait for Entry point to exit before
54 * we proceed with SSR in WD Thread
55 */
56#define MAX_SSR_WAIT_ITERATIONS 200
57#define MAX_SSR_PROTECT_LOG (16)
58
59static atomic_t ssr_protect_entry_count;
60
61/**
62 * struct ssr_protect - sub system restart(ssr) protection tracking table
63 * @func: Function which needs ssr protection
64 * @free: Flag to tell whether entry is free in table or not
65 * @pid: Process id which needs ssr protection
66 */
67struct ssr_protect {
68 const char *func;
69 bool free;
70 uint32_t pid;
71};
72
73static spinlock_t ssr_protect_lock;
74static struct ssr_protect ssr_protect_log[MAX_SSR_PROTECT_LOG];
75
76static p_cds_sched_context gp_cds_sched_context;
77
78static int cds_mc_thread(void *Arg);
79#ifdef QCA_CONFIG_SMP
80static int cds_ol_rx_thread(void *arg);
81static unsigned long affine_cpu;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +053082static QDF_STATUS cds_alloc_ol_rx_pkt_freeq(p_cds_sched_context pSchedContext);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080083#endif
84
85#ifdef QCA_CONFIG_SMP
86#define CDS_CORE_PER_CLUSTER (4)
87static int cds_set_cpus_allowed_ptr(struct task_struct *task, unsigned long cpu)
88{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080089 return set_cpus_allowed_ptr(task, cpumask_of(cpu));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080090}
91
92/**
93 * cds_cpu_hotplug_notify() - hot plug notify
94 * @block: Pointer to block
95 * @state: State
96 * @hcpu: Pointer to hotplug cpu
97 *
98 * Return: NOTIFY_OK
99 */
100static int
101cds_cpu_hotplug_notify(struct notifier_block *block,
102 unsigned long state, void *hcpu)
103{
104 unsigned long cpu = (unsigned long)hcpu;
105 unsigned long pref_cpu = 0;
106 p_cds_sched_context pSchedContext = get_cds_sched_ctxt();
107 int i;
108 unsigned int multi_cluster;
109 unsigned int num_cpus;
110
111 if ((NULL == pSchedContext) || (NULL == pSchedContext->ol_rx_thread))
112 return NOTIFY_OK;
113
Rajeev Kumarfec3dbe2016-01-19 15:23:52 -0800114 if (cds_is_load_or_unload_in_progress())
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800115 return NOTIFY_OK;
116
117 num_cpus = num_possible_cpus();
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530118 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800119 "%s: RX CORE %d, STATE %d, NUM CPUS %d",
120 __func__, (int)affine_cpu, (int)state, num_cpus);
121 multi_cluster = (num_cpus > CDS_CORE_PER_CLUSTER) ? 1 : 0;
122
123 switch (state) {
124 case CPU_ONLINE:
125 if ((!multi_cluster) && (affine_cpu != 0))
126 return NOTIFY_OK;
127
128 for_each_online_cpu(i) {
129 if (i == 0)
130 continue;
131 pref_cpu = i;
132 if (!multi_cluster)
133 break;
134 }
135 break;
136 case CPU_DEAD:
137 if (cpu != affine_cpu)
138 return NOTIFY_OK;
139
140 affine_cpu = 0;
141 for_each_online_cpu(i) {
142 if (i == 0)
143 continue;
144 pref_cpu = i;
145 if (!multi_cluster)
146 break;
147 }
148 }
149
150 if (pref_cpu == 0)
151 return NOTIFY_OK;
152
153 if (!cds_set_cpus_allowed_ptr(pSchedContext->ol_rx_thread, pref_cpu))
154 affine_cpu = pref_cpu;
155
156 return NOTIFY_OK;
157}
158
159static struct notifier_block cds_cpu_hotplug_notifier = {
160 .notifier_call = cds_cpu_hotplug_notify,
161};
162#endif
163
164/**
165 * cds_sched_open() - initialize the CDS Scheduler
166 * @p_cds_context: Pointer to the global CDS Context
167 * @pSchedContext: Pointer to a previously allocated buffer big
168 * enough to hold a scheduler context.
169 * @SchedCtxSize: CDS scheduler context size
170 *
171 * This function initializes the CDS Scheduler
172 * Upon successful initialization:
173 * - All the message queues are initialized
174 * - The Main Controller thread is created and ready to receive and
175 * dispatch messages.
176 *
177 *
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530178 * Return: QDF status
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800179 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530180QDF_STATUS cds_sched_open(void *p_cds_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800181 p_cds_sched_context pSchedContext,
182 uint32_t SchedCtxSize)
183{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530184 QDF_STATUS vStatus = QDF_STATUS_SUCCESS;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530185 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800186 "%s: Opening the CDS Scheduler", __func__);
187 /* Sanity checks */
188 if ((p_cds_context == NULL) || (pSchedContext == NULL)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530189 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800190 "%s: Null params being passed", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530191 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800192 }
193 if (sizeof(cds_sched_context) != SchedCtxSize) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530194 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800195 "%s: Incorrect CDS Sched Context size passed",
196 __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530197 return QDF_STATUS_E_INVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800198 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530199 qdf_mem_zero(pSchedContext, sizeof(cds_sched_context));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800200 pSchedContext->pVContext = p_cds_context;
201 vStatus = cds_sched_init_mqs(pSchedContext);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530202 if (!QDF_IS_STATUS_SUCCESS(vStatus)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530203 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800204 "%s: Failed to initialize CDS Scheduler MQs",
205 __func__);
206 return vStatus;
207 }
208 /* Initialize the helper events and event queues */
209 init_completion(&pSchedContext->McStartEvent);
210 init_completion(&pSchedContext->McShutdown);
211 init_completion(&pSchedContext->ResumeMcEvent);
212
213 spin_lock_init(&pSchedContext->McThreadLock);
214#ifdef QCA_CONFIG_SMP
215 spin_lock_init(&pSchedContext->ol_rx_thread_lock);
216#endif
217
218 init_waitqueue_head(&pSchedContext->mcWaitQueue);
219 pSchedContext->mcEventFlag = 0;
220
221#ifdef QCA_CONFIG_SMP
222 init_waitqueue_head(&pSchedContext->ol_rx_wait_queue);
223 init_completion(&pSchedContext->ol_rx_start_event);
224 init_completion(&pSchedContext->ol_suspend_rx_event);
225 init_completion(&pSchedContext->ol_resume_rx_event);
226 init_completion(&pSchedContext->ol_rx_shutdown);
227 pSchedContext->ol_rx_event_flag = 0;
228 spin_lock_init(&pSchedContext->ol_rx_queue_lock);
229 spin_lock_init(&pSchedContext->cds_ol_rx_pkt_freeq_lock);
230 INIT_LIST_HEAD(&pSchedContext->ol_rx_thread_queue);
231 spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock);
232 INIT_LIST_HEAD(&pSchedContext->cds_ol_rx_pkt_freeq);
233 spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530234 if (cds_alloc_ol_rx_pkt_freeq(pSchedContext) != QDF_STATUS_SUCCESS) {
235 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800236 }
237 register_hotcpu_notifier(&cds_cpu_hotplug_notifier);
238 pSchedContext->cpu_hot_plug_notifier = &cds_cpu_hotplug_notifier;
239#endif
240 gp_cds_sched_context = pSchedContext;
241
242 /* Create the CDS Main Controller thread */
243 pSchedContext->McThread = kthread_create(cds_mc_thread, pSchedContext,
244 "cds_mc_thread");
245 if (IS_ERR(pSchedContext->McThread)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530246 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800247 "%s: Could not Create CDS Main Thread Controller",
248 __func__);
249 goto MC_THREAD_START_FAILURE;
250 }
251 wake_up_process(pSchedContext->McThread);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530252 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800253 "%s: CDS Main Controller thread Created", __func__);
254
255#ifdef QCA_CONFIG_SMP
256 pSchedContext->ol_rx_thread = kthread_create(cds_ol_rx_thread,
257 pSchedContext,
258 "cds_ol_rx_thread");
259 if (IS_ERR(pSchedContext->ol_rx_thread)) {
260
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530261 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800262 "%s: Could not Create CDS OL RX Thread",
263 __func__);
264 goto OL_RX_THREAD_START_FAILURE;
265
266 }
267 wake_up_process(pSchedContext->ol_rx_thread);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530268 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800269 ("CDS OL RX thread Created"));
270#endif
271 /*
272 * Now make sure all threads have started before we exit.
273 * Each thread should normally ACK back when it starts.
274 */
275 wait_for_completion_interruptible(&pSchedContext->McStartEvent);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530276 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800277 "%s: CDS MC Thread has started", __func__);
278#ifdef QCA_CONFIG_SMP
279 wait_for_completion_interruptible(&pSchedContext->ol_rx_start_event);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530280 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800281 "%s: CDS OL Rx Thread has started", __func__);
282#endif
283 /* We're good now: Let's get the ball rolling!!! */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530284 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800285 "%s: CDS Scheduler successfully Opened", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530286 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800287
288#ifdef QCA_CONFIG_SMP
289OL_RX_THREAD_START_FAILURE:
290 /* Try and force the Main thread controller to exit */
291 set_bit(MC_SHUTDOWN_EVENT_MASK, &pSchedContext->mcEventFlag);
292 set_bit(MC_POST_EVENT_MASK, &pSchedContext->mcEventFlag);
293 wake_up_interruptible(&pSchedContext->mcWaitQueue);
294 /* Wait for MC to exit */
295 wait_for_completion_interruptible(&pSchedContext->McShutdown);
296#endif
297
298MC_THREAD_START_FAILURE:
299 /* De-initialize all the message queues */
300 cds_sched_deinit_mqs(pSchedContext);
301
302#ifdef QCA_CONFIG_SMP
303 unregister_hotcpu_notifier(&cds_cpu_hotplug_notifier);
304 cds_free_ol_rx_pkt_freeq(gp_cds_sched_context);
305#endif
306
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530307 return QDF_STATUS_E_RESOURCES;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800308
309} /* cds_sched_open() */
310
311/**
312 * cds_mc_thread() - cds main controller thread execution handler
313 * @Arg: Pointer to the global CDS Sched Context
314 *
315 * Return: thread exit code
316 */
317static int cds_mc_thread(void *Arg)
318{
319 p_cds_sched_context pSchedContext = (p_cds_sched_context) Arg;
320 p_cds_msg_wrapper pMsgWrapper = NULL;
321 tpAniSirGlobal pMacContext = NULL;
322 tSirRetStatus macStatus = eSIR_SUCCESS;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530323 QDF_STATUS vStatus = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800324 int retWaitStatus = 0;
325 bool shutdown = false;
326 hdd_context_t *pHddCtx = NULL;
327 v_CONTEXT_t p_cds_context = NULL;
328
329 if (Arg == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530330 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800331 "%s: Bad Args passed", __func__);
332 return 0;
333 }
334 set_user_nice(current, -2);
335
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800336 /* Ack back to the context from which the main controller thread
337 * has been created
338 */
339 complete(&pSchedContext->McStartEvent);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530340 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800341 "%s: MC Thread %d (%s) starting up", __func__, current->pid,
342 current->comm);
343
344 /* Get the Global CDS Context */
345 p_cds_context = cds_get_global_context();
346 if (!p_cds_context) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530347 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL,
Ryan Hsud7e6fc72015-12-07 17:26:14 -0800348 "%s: Global CDS context is Null", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800349 return 0;
350 }
351
Anurag Chouhan6d760662016-02-20 16:05:43 +0530352 pHddCtx = cds_get_context(QDF_MODULE_ID_HDD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800353 if (!pHddCtx) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530354 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL,
Ryan Hsud7e6fc72015-12-07 17:26:14 -0800355 "%s: HDD context is Null", __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800356 return 0;
357 }
358
359 while (!shutdown) {
360 /* This implements the execution model algorithm */
361 retWaitStatus =
362 wait_event_interruptible(pSchedContext->mcWaitQueue,
363 test_bit(MC_POST_EVENT_MASK,
364 &pSchedContext->mcEventFlag)
365 || test_bit(MC_SUSPEND_EVENT_MASK,
366 &pSchedContext->mcEventFlag));
367
368 if (retWaitStatus == -ERESTARTSYS) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530369 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800370 "%s: wait_event_interruptible returned -ERESTARTSYS",
371 __func__);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530372 QDF_BUG(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800373 }
374 clear_bit(MC_POST_EVENT_MASK, &pSchedContext->mcEventFlag);
375
376 while (1) {
377 /* Check if MC needs to shutdown */
378 if (test_bit
379 (MC_SHUTDOWN_EVENT_MASK,
380 &pSchedContext->mcEventFlag)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530381 QDF_TRACE(QDF_MODULE_ID_QDF,
382 QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800383 "%s: MC thread signaled to shutdown",
384 __func__);
385 shutdown = true;
386 /* Check for any Suspend Indication */
387 if (test_bit
388 (MC_SUSPEND_EVENT_MASK,
389 &pSchedContext->mcEventFlag)) {
390 clear_bit(MC_SUSPEND_EVENT_MASK,
391 &pSchedContext->mcEventFlag);
392
393 /* Unblock anyone waiting on suspend */
394 complete(&pHddCtx->mc_sus_event_var);
395 }
396 break;
397 }
398 /* Check the SYS queue first */
399 if (!cds_is_mq_empty(&pSchedContext->sysMcMq)) {
400 /* Service the SYS message queue */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800401 pMsgWrapper =
402 cds_mq_get(&pSchedContext->sysMcMq);
403 if (pMsgWrapper == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530404 QDF_TRACE(QDF_MODULE_ID_QDF,
405 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800406 "%s: pMsgWrapper is NULL",
407 __func__);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530408 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800409 break;
410 }
411 vStatus =
412 sys_mc_process_msg(pSchedContext->pVContext,
413 pMsgWrapper->pVosMsg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530414 if (!QDF_IS_STATUS_SUCCESS(vStatus)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530415 QDF_TRACE(QDF_MODULE_ID_QDF,
416 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800417 "%s: Issue Processing SYS message",
418 __func__);
419 }
420 /* return message to the Core */
421 cds_core_return_msg(pSchedContext->pVContext,
422 pMsgWrapper);
423 continue;
424 }
425 /* Check the WMA queue */
426 if (!cds_is_mq_empty(&pSchedContext->wmaMcMq)) {
427 /* Service the WMA message queue */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800428 pMsgWrapper =
429 cds_mq_get(&pSchedContext->wmaMcMq);
430 if (pMsgWrapper == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530431 QDF_TRACE(QDF_MODULE_ID_QDF,
432 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800433 "%s: pMsgWrapper is NULL",
434 __func__);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530435 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800436 break;
437 }
438 vStatus =
439 wma_mc_process_msg(pSchedContext->pVContext,
440 pMsgWrapper->pVosMsg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530441 if (!QDF_IS_STATUS_SUCCESS(vStatus)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530442 QDF_TRACE(QDF_MODULE_ID_QDF,
443 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800444 "%s: Issue Processing WMA message",
445 __func__);
446 }
447 /* return message to the Core */
448 cds_core_return_msg(pSchedContext->pVContext,
449 pMsgWrapper);
450 continue;
451 }
452 /* Check the PE queue */
453 if (!cds_is_mq_empty(&pSchedContext->peMcMq)) {
454 /* Service the PE message queue */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800455 pMsgWrapper =
456 cds_mq_get(&pSchedContext->peMcMq);
457 if (NULL == pMsgWrapper) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530458 QDF_TRACE(QDF_MODULE_ID_QDF,
459 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800460 "%s: pMsgWrapper is NULL",
461 __func__);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530462 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800463 break;
464 }
465
466 /* Need some optimization */
467 pMacContext =
Anurag Chouhan6d760662016-02-20 16:05:43 +0530468 cds_get_context(QDF_MODULE_ID_PE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800469 if (NULL == pMacContext) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530470 QDF_TRACE(QDF_MODULE_ID_QDF,
471 QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800472 "MAC Context not ready yet");
473 cds_core_return_msg
474 (pSchedContext->pVContext,
475 pMsgWrapper);
476 continue;
477 }
478
479 macStatus =
480 pe_process_messages(pMacContext,
481 (tSirMsgQ *)
482 pMsgWrapper->pVosMsg);
483 if (eSIR_SUCCESS != macStatus) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530484 QDF_TRACE(QDF_MODULE_ID_QDF,
485 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800486 "%s: Issue Processing PE message",
487 __func__);
488 }
489 /* return message to the Core */
490 cds_core_return_msg(pSchedContext->pVContext,
491 pMsgWrapper);
492 continue;
493 }
494 /** Check the SME queue **/
495 if (!cds_is_mq_empty(&pSchedContext->smeMcMq)) {
496 /* Service the SME message queue */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800497 pMsgWrapper =
498 cds_mq_get(&pSchedContext->smeMcMq);
499 if (NULL == pMsgWrapper) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530500 QDF_TRACE(QDF_MODULE_ID_QDF,
501 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800502 "%s: pMsgWrapper is NULL",
503 __func__);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530504 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800505 break;
506 }
507
508 /* Need some optimization */
509 pMacContext =
Anurag Chouhan6d760662016-02-20 16:05:43 +0530510 cds_get_context(QDF_MODULE_ID_SME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800511 if (NULL == pMacContext) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530512 QDF_TRACE(QDF_MODULE_ID_QDF,
513 QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800514 "MAC Context not ready yet");
515 cds_core_return_msg
516 (pSchedContext->pVContext,
517 pMsgWrapper);
518 continue;
519 }
520
521 vStatus =
522 sme_process_msg((tHalHandle) pMacContext,
523 pMsgWrapper->pVosMsg);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530524 if (!QDF_IS_STATUS_SUCCESS(vStatus)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530525 QDF_TRACE(QDF_MODULE_ID_QDF,
526 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800527 "%s: Issue Processing SME message",
528 __func__);
529 }
530 /* return message to the Core */
531 cds_core_return_msg(pSchedContext->pVContext,
532 pMsgWrapper);
533 continue;
534 }
535 /* Check for any Suspend Indication */
536 if (test_bit
537 (MC_SUSPEND_EVENT_MASK,
538 &pSchedContext->mcEventFlag)) {
539 clear_bit(MC_SUSPEND_EVENT_MASK,
540 &pSchedContext->mcEventFlag);
541 spin_lock(&pSchedContext->McThreadLock);
Abhishek Singha2468092016-03-21 17:35:36 +0530542 INIT_COMPLETION(pSchedContext->ResumeMcEvent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800543 /* Mc Thread Suspended */
544 complete(&pHddCtx->mc_sus_event_var);
545
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800546 spin_unlock(&pSchedContext->McThreadLock);
547
548 /* Wait foe Resume Indication */
549 wait_for_completion_interruptible
550 (&pSchedContext->ResumeMcEvent);
551 }
552 break; /* All queues are empty now */
553 } /* while message loop processing */
554 } /* while true */
555 /* If we get here the MC thread must exit */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530556 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800557 "%s: MC Thread exiting!!!!", __func__);
558 complete_and_exit(&pSchedContext->McShutdown, 0);
559} /* cds_mc_thread() */
560
561#ifdef QCA_CONFIG_SMP
562/**
563 * cds_free_ol_rx_pkt_freeq() - free cds buffer free queue
564 * @pSchedContext - pointer to the global CDS Sched Context
565 *
566 * This API does mem free of the buffers available in free cds buffer
567 * queue which is used for Data rx processing.
568 *
569 * Return: none
570 */
571void cds_free_ol_rx_pkt_freeq(p_cds_sched_context pSchedContext)
572{
Nirav Shah36507802015-11-19 18:21:15 +0530573 struct cds_ol_rx_pkt *pkt;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800574
575 spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock);
Nirav Shah36507802015-11-19 18:21:15 +0530576 while (!list_empty(&pSchedContext->cds_ol_rx_pkt_freeq)) {
577 pkt = list_entry((&pSchedContext->cds_ol_rx_pkt_freeq)->next,
578 typeof(*pkt), list);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800579 list_del(&pkt->list);
580 spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530581 qdf_mem_free(pkt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800582 spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock);
583 }
584 spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock);
585}
586
587/**
588 * cds_alloc_ol_rx_pkt_freeq() - Function to allocate free buffer queue
589 * @pSchedContext - pointer to the global CDS Sched Context
590 *
591 * This API allocates CDS_MAX_OL_RX_PKT number of cds message buffers
592 * which are used for Rx data processing.
593 *
594 * Return: status of memory allocation
595 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530596static QDF_STATUS cds_alloc_ol_rx_pkt_freeq(p_cds_sched_context pSchedContext)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800597{
598 struct cds_ol_rx_pkt *pkt, *tmp;
599 int i;
600
601 for (i = 0; i < CDS_MAX_OL_RX_PKT; i++) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530602 pkt = qdf_mem_malloc(sizeof(*pkt));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800603 if (!pkt) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530604 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800605 "%s Vos packet allocation for ol rx thread failed",
606 __func__);
607 goto free;
608 }
609 memset(pkt, 0, sizeof(*pkt));
610 spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock);
611 list_add_tail(&pkt->list, &pSchedContext->cds_ol_rx_pkt_freeq);
612 spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock);
613 }
614
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530615 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800616
617free:
618 spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock);
619 list_for_each_entry_safe(pkt, tmp, &pSchedContext->cds_ol_rx_pkt_freeq,
620 list) {
621 list_del(&pkt->list);
622 spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530623 qdf_mem_free(pkt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800624 spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock);
625 }
626 spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530627 return QDF_STATUS_E_NOMEM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800628}
629
630/**
631 * cds_free_ol_rx_pkt() - api to release cds message to the freeq
632 * This api returns the cds message used for Rx data to the free queue
633 * @pSchedContext: Pointer to the global CDS Sched Context
634 * @pkt: CDS message buffer to be returned to free queue.
635 *
636 * Return: none
637 */
638void
639cds_free_ol_rx_pkt(p_cds_sched_context pSchedContext,
640 struct cds_ol_rx_pkt *pkt)
641{
642 memset(pkt, 0, sizeof(*pkt));
643 spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock);
644 list_add_tail(&pkt->list, &pSchedContext->cds_ol_rx_pkt_freeq);
645 spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock);
646}
647
648/**
649 * cds_alloc_ol_rx_pkt() - API to return next available cds message
650 * @pSchedContext: Pointer to the global CDS Sched Context
651 *
652 * This api returns next available cds message buffer used for rx data
653 * processing
654 *
655 * Return: Pointer to cds message buffer
656 */
657struct cds_ol_rx_pkt *cds_alloc_ol_rx_pkt(p_cds_sched_context pSchedContext)
658{
659 struct cds_ol_rx_pkt *pkt;
660
661 spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock);
662 if (list_empty(&pSchedContext->cds_ol_rx_pkt_freeq)) {
663 spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock);
664 return NULL;
665 }
666 pkt = list_first_entry(&pSchedContext->cds_ol_rx_pkt_freeq,
667 struct cds_ol_rx_pkt, list);
668 list_del(&pkt->list);
669 spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock);
670 return pkt;
671}
672
673/**
674 * cds_indicate_rxpkt() - indicate rx data packet
675 * @Arg: Pointer to the global CDS Sched Context
676 * @pkt: CDS data message buffer
677 *
678 * This api enqueues the rx packet into ol_rx_thread_queue and notifies
679 * cds_ol_rx_thread()
680 *
681 * Return: none
682 */
683void
684cds_indicate_rxpkt(p_cds_sched_context pSchedContext,
685 struct cds_ol_rx_pkt *pkt)
686{
687 spin_lock_bh(&pSchedContext->ol_rx_queue_lock);
688 list_add_tail(&pkt->list, &pSchedContext->ol_rx_thread_queue);
689 spin_unlock_bh(&pSchedContext->ol_rx_queue_lock);
690 set_bit(RX_POST_EVENT_MASK, &pSchedContext->ol_rx_event_flag);
691 wake_up_interruptible(&pSchedContext->ol_rx_wait_queue);
692}
693
694/**
695 * cds_drop_rxpkt_by_staid() - api to drop pending rx packets for a sta
696 * @pSchedContext: Pointer to the global CDS Sched Context
697 * @staId: Station Id
698 *
699 * This api drops queued packets for a station, to drop all the pending
700 * packets the caller has to send WLAN_MAX_STA_COUNT as staId.
701 *
702 * Return: none
703 */
704void cds_drop_rxpkt_by_staid(p_cds_sched_context pSchedContext, uint16_t staId)
705{
706 struct list_head local_list;
707 struct cds_ol_rx_pkt *pkt, *tmp;
Nirav Shahcbc6d722016-03-01 16:24:53 +0530708 qdf_nbuf_t buf, next_buf;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800709
710 INIT_LIST_HEAD(&local_list);
711 spin_lock_bh(&pSchedContext->ol_rx_queue_lock);
712 if (list_empty(&pSchedContext->ol_rx_thread_queue)) {
713 spin_unlock_bh(&pSchedContext->ol_rx_queue_lock);
714 return;
715 }
716 list_for_each_entry_safe(pkt, tmp, &pSchedContext->ol_rx_thread_queue,
717 list) {
718 if (pkt->staId == staId || staId == WLAN_MAX_STA_COUNT)
719 list_move_tail(&pkt->list, &local_list);
720 }
721 spin_unlock_bh(&pSchedContext->ol_rx_queue_lock);
722
Nirav Shah331172a2015-11-24 19:11:58 +0530723 list_for_each_entry_safe(pkt, tmp, &local_list, list) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800724 list_del(&pkt->list);
725 buf = pkt->Rxpkt;
726 while (buf) {
Nirav Shahcbc6d722016-03-01 16:24:53 +0530727 next_buf = qdf_nbuf_queue_next(buf);
728 qdf_nbuf_free(buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800729 buf = next_buf;
730 }
731 cds_free_ol_rx_pkt(pSchedContext, pkt);
732 }
733}
734
735/**
736 * cds_rx_from_queue() - function to process pending Rx packets
737 * @pSchedContext: Pointer to the global CDS Sched Context
738 *
739 * This api traverses the pending buffer list and calling the callback.
740 * This callback would essentially send the packet to HDD.
741 *
742 * Return: none
743 */
744static void cds_rx_from_queue(p_cds_sched_context pSchedContext)
745{
746 struct cds_ol_rx_pkt *pkt;
747 uint16_t sta_id;
748
749 spin_lock_bh(&pSchedContext->ol_rx_queue_lock);
750 while (!list_empty(&pSchedContext->ol_rx_thread_queue)) {
751 pkt = list_first_entry(&pSchedContext->ol_rx_thread_queue,
752 struct cds_ol_rx_pkt, list);
753 list_del(&pkt->list);
754 spin_unlock_bh(&pSchedContext->ol_rx_queue_lock);
755 sta_id = pkt->staId;
756 pkt->callback(pkt->context, pkt->Rxpkt, sta_id);
757 cds_free_ol_rx_pkt(pSchedContext, pkt);
758 spin_lock_bh(&pSchedContext->ol_rx_queue_lock);
759 }
760 spin_unlock_bh(&pSchedContext->ol_rx_queue_lock);
761}
762
763/**
764 * cds_ol_rx_thread() - cds main tlshim rx thread
765 * @Arg: pointer to the global CDS Sched Context
766 *
767 * This api is the thread handler for Tlshim Data packet processing.
768 *
769 * Return: thread exit code
770 */
771static int cds_ol_rx_thread(void *arg)
772{
773 p_cds_sched_context pSchedContext = (p_cds_sched_context) arg;
774 unsigned long pref_cpu = 0;
775 bool shutdown = false;
776 int status, i;
777 unsigned int num_cpus;
778
779 set_user_nice(current, -1);
780#ifdef MSM_PLATFORM
781 set_wake_up_idle(true);
782#endif
783
784 num_cpus = num_possible_cpus();
785 /* Find the available cpu core other than cpu 0 and
786 * bind the thread
787 */
788 for_each_online_cpu(i) {
789 if (i == 0)
790 continue;
791 pref_cpu = i;
792 if (num_cpus <= CDS_CORE_PER_CLUSTER)
793 break;
794 }
795 if (pref_cpu != 0 && (!cds_set_cpus_allowed_ptr(current, pref_cpu)))
796 affine_cpu = pref_cpu;
797
798 if (!arg) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530799 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800800 "%s: Bad Args passed", __func__);
801 return 0;
802 }
803
804 complete(&pSchedContext->ol_rx_start_event);
805
806 while (!shutdown) {
807 status =
808 wait_event_interruptible(pSchedContext->ol_rx_wait_queue,
809 test_bit(RX_POST_EVENT_MASK,
810 &pSchedContext->ol_rx_event_flag)
811 || test_bit(RX_SUSPEND_EVENT_MASK,
812 &pSchedContext->ol_rx_event_flag));
813 if (status == -ERESTARTSYS)
814 break;
815
816 clear_bit(RX_POST_EVENT_MASK, &pSchedContext->ol_rx_event_flag);
817 while (true) {
818 if (test_bit(RX_SHUTDOWN_EVENT_MASK,
819 &pSchedContext->ol_rx_event_flag)) {
820 clear_bit(RX_SHUTDOWN_EVENT_MASK,
821 &pSchedContext->ol_rx_event_flag);
822 if (test_bit(RX_SUSPEND_EVENT_MASK,
823 &pSchedContext->ol_rx_event_flag)) {
824 clear_bit(RX_SUSPEND_EVENT_MASK,
825 &pSchedContext->ol_rx_event_flag);
826 complete
827 (&pSchedContext->ol_suspend_rx_event);
828 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530829 QDF_TRACE(QDF_MODULE_ID_QDF,
830 QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800831 "%s: Shutting down OL RX Thread",
832 __func__);
833 shutdown = true;
834 break;
835 }
836 cds_rx_from_queue(pSchedContext);
837
838 if (test_bit(RX_SUSPEND_EVENT_MASK,
839 &pSchedContext->ol_rx_event_flag)) {
840 clear_bit(RX_SUSPEND_EVENT_MASK,
841 &pSchedContext->ol_rx_event_flag);
842 spin_lock(&pSchedContext->ol_rx_thread_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800843 INIT_COMPLETION
844 (pSchedContext->ol_resume_rx_event);
Abhishek Singha2468092016-03-21 17:35:36 +0530845 complete(&pSchedContext->ol_suspend_rx_event);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800846 spin_unlock(&pSchedContext->ol_rx_thread_lock);
847 wait_for_completion_interruptible
848 (&pSchedContext->ol_resume_rx_event);
849 }
850 break;
851 }
852 }
853
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530854 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800855 "%s: Exiting CDS OL rx thread", __func__);
856 complete_and_exit(&pSchedContext->ol_rx_shutdown, 0);
857}
858#endif
859
860/**
861 * cds_sched_close() - close the cds scheduler
862 * @p_cds_context: Pointer to the global CDS Context
863 *
864 * This api closes the CDS Scheduler upon successful closing:
865 * - All the message queues are flushed
866 * - The Main Controller thread is closed
867 * - The Tx thread is closed
868 *
869 *
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530870 * Return: qdf status
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800871 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530872QDF_STATUS cds_sched_close(void *p_cds_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800873{
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530874 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800875 "%s: invoked", __func__);
876 if (gp_cds_sched_context == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530877 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800878 "%s: gp_cds_sched_context == NULL", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530879 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800880 }
881 /* shut down MC Thread */
882 set_bit(MC_SHUTDOWN_EVENT_MASK, &gp_cds_sched_context->mcEventFlag);
883 set_bit(MC_POST_EVENT_MASK, &gp_cds_sched_context->mcEventFlag);
884 wake_up_interruptible(&gp_cds_sched_context->mcWaitQueue);
885 /* Wait for MC to exit */
886 wait_for_completion(&gp_cds_sched_context->McShutdown);
887 gp_cds_sched_context->McThread = 0;
888
889 /* Clean up message queues of MC thread */
890 cds_sched_flush_mc_mqs(gp_cds_sched_context);
891
892 /* Deinit all the queues */
893 cds_sched_deinit_mqs(gp_cds_sched_context);
894
895#ifdef QCA_CONFIG_SMP
896 /* Shut down Tlshim Rx thread */
897 set_bit(RX_SHUTDOWN_EVENT_MASK, &gp_cds_sched_context->ol_rx_event_flag);
898 set_bit(RX_POST_EVENT_MASK, &gp_cds_sched_context->ol_rx_event_flag);
899 wake_up_interruptible(&gp_cds_sched_context->ol_rx_wait_queue);
Ratnam Rachuri12553c62015-08-14 15:18:46 +0530900 wait_for_completion(&gp_cds_sched_context->ol_rx_shutdown);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800901 gp_cds_sched_context->ol_rx_thread = NULL;
902 cds_drop_rxpkt_by_staid(gp_cds_sched_context, WLAN_MAX_STA_COUNT);
903 cds_free_ol_rx_pkt_freeq(gp_cds_sched_context);
904 unregister_hotcpu_notifier(&cds_cpu_hotplug_notifier);
905#endif
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530906 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800907} /* cds_sched_close() */
908
909/**
910 * cds_sched_init_mqs() - initialize the cds scheduler message queues
911 * @p_cds_sched_context: Pointer to the Scheduler Context.
912 *
913 * This api initializes the cds scheduler message queues.
914 *
Anurag Chouhanf04e84f2016-03-03 10:12:12 +0530915 * Return: QDF status
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800916 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530917QDF_STATUS cds_sched_init_mqs(p_cds_sched_context pSchedContext)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800918{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530919 QDF_STATUS vStatus = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800920 /* Now intialize all the message queues */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530921 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800922 "%s: Initializing the WMA MC Message queue", __func__);
923 vStatus = cds_mq_init(&pSchedContext->wmaMcMq);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530924 if (!QDF_IS_STATUS_SUCCESS(vStatus)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530925 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800926 "%s: Failed to init WMA MC Message queue", __func__);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530927 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800928 return vStatus;
929 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530930 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800931 "%s: Initializing the PE MC Message queue", __func__);
932 vStatus = cds_mq_init(&pSchedContext->peMcMq);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530933 if (!QDF_IS_STATUS_SUCCESS(vStatus)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530934 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800935 "%s: Failed to init PE MC Message queue", __func__);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530936 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800937 return vStatus;
938 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530939 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800940 "%s: Initializing the SME MC Message queue", __func__);
941 vStatus = cds_mq_init(&pSchedContext->smeMcMq);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530942 if (!QDF_IS_STATUS_SUCCESS(vStatus)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530943 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800944 "%s: Failed to init SME MC Message queue", __func__);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530945 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800946 return vStatus;
947 }
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530948 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800949 "%s: Initializing the SYS MC Message queue", __func__);
950 vStatus = cds_mq_init(&pSchedContext->sysMcMq);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530951 if (!QDF_IS_STATUS_SUCCESS(vStatus)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530952 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800953 "%s: Failed to init SYS MC Message queue", __func__);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530954 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800955 return vStatus;
956 }
957
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530958 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800959} /* cds_sched_init_mqs() */
960
961/**
962 * cds_sched_deinit_mqs() - Deinitialize the cds scheduler message queues
963 * @p_cds_sched_context: Pointer to the Scheduler Context.
964 *
965 * Return: none
966 */
967void cds_sched_deinit_mqs(p_cds_sched_context pSchedContext)
968{
969 /* Now de-intialize all message queues */
970
971 /* MC WMA */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530972 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800973 "%s De-Initializing the WMA MC Message queue", __func__);
974 cds_mq_deinit(&pSchedContext->wmaMcMq);
975 /* MC PE */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530976 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800977 "%s De-Initializing the PE MC Message queue", __func__);
978 cds_mq_deinit(&pSchedContext->peMcMq);
979 /* MC SME */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530980 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800981 "%s De-Initializing the SME MC Message queue", __func__);
982 cds_mq_deinit(&pSchedContext->smeMcMq);
983 /* MC SYS */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530984 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800985 "%s De-Initializing the SYS MC Message queue", __func__);
986 cds_mq_deinit(&pSchedContext->sysMcMq);
987
988} /* cds_sched_deinit_mqs() */
989
990/**
991 * cds_sched_flush_mc_mqs() - flush all the MC thread message queues
992 * @pSchedContext: Pointer to global cds context
993 *
994 * Return: none
995 */
996void cds_sched_flush_mc_mqs(p_cds_sched_context pSchedContext)
997{
998 p_cds_msg_wrapper pMsgWrapper = NULL;
999 p_cds_contextType cds_ctx;
1000
1001 /* Here each of the MC thread MQ shall be drained and returned to the
1002 * Core. Before returning a wrapper to the Core, the CDS message shall
1003 * be freed first
1004 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301005 QDF_TRACE(QDF_MODULE_ID_QDF,
1006 QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001007 ("Flushing the MC Thread message queue"));
1008
1009 if (NULL == pSchedContext) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301010 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001011 "%s: pSchedContext is NULL", __func__);
1012 return;
1013 }
1014
1015 cds_ctx = (p_cds_contextType) (pSchedContext->pVContext);
1016 if (NULL == cds_ctx) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301017 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001018 "%s: cds_ctx is NULL", __func__);
1019 return;
1020 }
1021
1022 /* Flush the SYS Mq */
1023 while (NULL != (pMsgWrapper = cds_mq_get(&pSchedContext->sysMcMq))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301024 QDF_TRACE(QDF_MODULE_ID_QDF,
1025 QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001026 "%s: Freeing MC SYS message type %d ", __func__,
1027 pMsgWrapper->pVosMsg->type);
1028 cds_core_return_msg(pSchedContext->pVContext, pMsgWrapper);
1029 }
1030 /* Flush the WMA Mq */
1031 while (NULL != (pMsgWrapper = cds_mq_get(&pSchedContext->wmaMcMq))) {
1032 if (pMsgWrapper->pVosMsg != NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301033 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001034 "%s: Freeing MC WMA MSG message type %d",
1035 __func__, pMsgWrapper->pVosMsg->type);
1036 if (pMsgWrapper->pVosMsg->bodyptr) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301037 qdf_mem_free((void *)pMsgWrapper->
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001038 pVosMsg->bodyptr);
1039 }
1040
1041 pMsgWrapper->pVosMsg->bodyptr = NULL;
1042 pMsgWrapper->pVosMsg->bodyval = 0;
1043 pMsgWrapper->pVosMsg->type = 0;
1044 }
1045 cds_core_return_msg(pSchedContext->pVContext, pMsgWrapper);
1046 }
1047
1048 /* Flush the PE Mq */
1049 while (NULL != (pMsgWrapper = cds_mq_get(&pSchedContext->peMcMq))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301050 QDF_TRACE(QDF_MODULE_ID_QDF,
1051 QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001052 "%s: Freeing MC PE MSG message type %d", __func__,
1053 pMsgWrapper->pVosMsg->type);
1054 pe_free_msg(cds_ctx->pMACContext,
1055 (tSirMsgQ *) pMsgWrapper->pVosMsg);
1056 cds_core_return_msg(pSchedContext->pVContext, pMsgWrapper);
1057 }
1058 /* Flush the SME Mq */
1059 while (NULL != (pMsgWrapper = cds_mq_get(&pSchedContext->smeMcMq))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301060 QDF_TRACE(QDF_MODULE_ID_QDF,
1061 QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001062 "%s: Freeing MC SME MSG message type %d", __func__,
1063 pMsgWrapper->pVosMsg->type);
1064 sme_free_msg(cds_ctx->pMACContext, pMsgWrapper->pVosMsg);
1065 cds_core_return_msg(pSchedContext->pVContext, pMsgWrapper);
1066 }
1067} /* cds_sched_flush_mc_mqs() */
1068
1069/**
1070 * get_cds_sched_ctxt() - get cds scheduler context
1071 *
1072 * Return: none
1073 */
1074p_cds_sched_context get_cds_sched_ctxt(void)
1075{
1076 /* Make sure that Vos Scheduler context has been initialized */
1077 if (gp_cds_sched_context == NULL)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301078 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001079 "%s: gp_cds_sched_context == NULL", __func__);
1080
1081 return gp_cds_sched_context;
1082}
1083
1084/**
1085 * cds_ssr_protect_init() - initialize ssr protection debug functionality
1086 *
1087 * Return:
1088 * void
1089 */
1090void cds_ssr_protect_init(void)
1091{
1092 int i = 0;
1093
1094 spin_lock_init(&ssr_protect_lock);
1095
1096 while (i < MAX_SSR_PROTECT_LOG) {
1097 ssr_protect_log[i].func = NULL;
1098 ssr_protect_log[i].free = true;
1099 ssr_protect_log[i].pid = 0;
1100 i++;
1101 }
1102}
1103
1104/**
1105 * cds_print_external_threads() - print external threads stuck in driver
1106 *
1107 * Return:
1108 * void
1109 */
1110
1111static void cds_print_external_threads(void)
1112{
1113 int i = 0;
1114 unsigned long irq_flags;
1115
1116 spin_lock_irqsave(&ssr_protect_lock, irq_flags);
1117
1118 while (i < MAX_SSR_PROTECT_LOG) {
1119 if (!ssr_protect_log[i].free) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301120 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001121 "PID %d is stuck at %s", ssr_protect_log[i].pid,
1122 ssr_protect_log[i].func);
1123 }
1124 i++;
1125 }
1126
1127 spin_unlock_irqrestore(&ssr_protect_lock, irq_flags);
1128}
1129
1130/**
1131 * cds_ssr_protect() - start ssr protection
1132 * @caller_func: name of calling function.
1133 *
1134 * This function is called to keep track of active driver entry points
1135 *
1136 * Return: none
1137 */
1138void cds_ssr_protect(const char *caller_func)
1139{
1140 int count;
1141 int i = 0;
1142 bool status = false;
1143 unsigned long irq_flags;
1144
1145 count = atomic_inc_return(&ssr_protect_entry_count);
1146
1147 spin_lock_irqsave(&ssr_protect_lock, irq_flags);
1148
1149 while (i < MAX_SSR_PROTECT_LOG) {
1150 if (ssr_protect_log[i].free) {
1151 ssr_protect_log[i].func = caller_func;
1152 ssr_protect_log[i].free = false;
1153 ssr_protect_log[i].pid = current->pid;
1154 status = true;
1155 break;
1156 }
1157 i++;
1158 }
1159
1160 spin_unlock_irqrestore(&ssr_protect_lock, irq_flags);
1161
1162 if (!status)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301163 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001164 "Could not track PID %d call %s: log is full",
1165 current->pid, caller_func);
1166}
1167
1168/**
1169 * cds_ssr_unprotect() - stop ssr protection
1170 * @caller_func: name of calling function.
1171 *
1172 * Return: none
1173 */
1174void cds_ssr_unprotect(const char *caller_func)
1175{
1176 int count;
1177 int i = 0;
1178 bool status = false;
1179 unsigned long irq_flags;
1180
1181 count = atomic_dec_return(&ssr_protect_entry_count);
1182
1183 spin_lock_irqsave(&ssr_protect_lock, irq_flags);
1184
1185 while (i < MAX_SSR_PROTECT_LOG) {
1186 if (!ssr_protect_log[i].free) {
1187 if ((ssr_protect_log[i].pid == current->pid) &&
1188 !strcmp(ssr_protect_log[i].func, caller_func)) {
1189 ssr_protect_log[i].func = NULL;
1190 ssr_protect_log[i].free = true;
1191 ssr_protect_log[i].pid = 0;
1192 status = true;
1193 break;
1194 }
1195 }
1196 i++;
1197 }
1198
1199 spin_unlock_irqrestore(&ssr_protect_lock, irq_flags);
1200
1201 if (!status)
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301202 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001203 "Untracked call %s", caller_func);
1204}
1205
1206/**
Rajeev Kumardbc886e2016-01-19 12:56:04 -08001207 * cds_wait_for_external_threads_completion() - wait for external threads
1208 * completion before proceeding further
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001209 * @caller_func: name of calling function.
1210 *
1211 * Return: true if there is no active entry points in driver
1212 * false if there is at least one active entry in driver
1213 */
Rajeev Kumardbc886e2016-01-19 12:56:04 -08001214bool cds_wait_for_external_threads_completion(const char *caller_func)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001215{
1216 int count = MAX_SSR_WAIT_ITERATIONS;
1217
1218 while (count) {
1219
1220 if (!atomic_read(&ssr_protect_entry_count))
1221 break;
1222
1223 if (--count) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301224 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001225 "%s: Waiting for active entry points to exit",
1226 __func__);
1227 msleep(SSR_WAIT_SLEEP_TIME);
1228 }
1229 }
1230 /* at least one external thread is executing */
1231 if (!count) {
1232 cds_print_external_threads();
1233 return false;
1234 }
1235
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301236 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO,
Rajeev Kumardbc886e2016-01-19 12:56:04 -08001237 "Allowing SSR/Driver unload for %s", caller_func);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001238
1239 return true;
1240}
Srinivas Girigowdafe3e5b32015-11-23 11:56:36 -08001241
1242/**
1243 * cds_get_gfp_flags(): get GFP flags
1244 *
1245 * Based on the scheduled context, return GFP flags
1246 * Return: gfp flags
1247 */
1248int cds_get_gfp_flags(void)
1249{
1250 int flags = GFP_KERNEL;
1251
1252 if (in_interrupt() || in_atomic() || irqs_disabled())
1253 flags = GFP_ATOMIC;
1254
1255 return flags;
1256}