blob: cb6d64eb88e5f9787dbe0240adf9dfead2434607 [file] [log] [blame]
Anurag Chouhanffaf2202016-02-06 17:16:44 +05301/*
2 * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
3 *
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 * DOC: cds_mc_timer.c
30 * Connectivity driver services timer APIs
31 */
32
33#include <qdf_mc_timer.h>
34#include "cds_mc_timer.h"
35#include <wlan_qct_sys.h>
36#include <qdf_trace.h>
37#include "cds_mq.h"
38
39/**
40 * cds_linux_timer_callback() - timer callback, gets called at time out.
41 * @data: unsigned long, holds the timer object.
42 *
43 * Return: None
44 */
45void cds_linux_timer_callback(unsigned long data)
46{
47 qdf_mc_timer_t *timer = (qdf_mc_timer_t *)data;
48 cds_msg_t msg;
49 QDF_STATUS status;
50
51 qdf_mc_timer_callback_t callback = NULL;
52 void *user_data = NULL;
53 QDF_TIMER_TYPE type = QDF_TIMER_TYPE_SW;
54
55 QDF_ASSERT(timer);
56
57 if (timer == NULL) {
58 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
59 "%s Null pointer passed in!", __func__);
60 return;
61 }
62
63 qdf_spin_lock_irqsave(&timer->platform_info.spinlock);
64
65 switch (timer->state) {
66 case QDF_TIMER_STATE_STARTING:
67 /* we are in this state because someone just started the timer,
68 * MC timer got started and expired, but the time content have
69 * not been updated this is a rare race condition!
70 */
71 timer->state = QDF_TIMER_STATE_STOPPED;
72 status = QDF_STATUS_E_ALREADY;
73 break;
74
75 case QDF_TIMER_STATE_STOPPED:
76 status = QDF_STATUS_E_ALREADY;
77 break;
78
79 case QDF_TIMER_STATE_UNUSED:
80 status = QDF_STATUS_E_EXISTS;
81 break;
82
83 case QDF_TIMER_STATE_RUNNING:
84 /* need to go to stop state here because the call-back function
85 * may restart timer (to emulate periodic timer)
86 */
87 timer->state = QDF_TIMER_STATE_STOPPED;
88 /* copy the relevant timer information to local variables;
89 * once we exits from this critical section, the timer content
90 * may be modified by other tasks
91 */
92 callback = timer->callback;
93 user_data = timer->user_data;
94 type = timer->type;
95 status = QDF_STATUS_SUCCESS;
96 break;
97
98 default:
99 QDF_ASSERT(0);
100 status = QDF_STATUS_E_FAULT;
101 break;
102 }
103
104 qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock);
105
106 if (QDF_STATUS_SUCCESS != status) {
107 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
108 "TIMER callback called in a wrong state=%d",
109 timer->state);
110 return;
111 }
112
113 qdf_try_allowing_sleep(type);
114
115 if (callback == NULL) {
116 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
117 "%s: No TIMER callback, Could not enqueue timer to any queue",
118 __func__);
119 QDF_ASSERT(0);
120 return;
121 }
122
123 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO,
124 "TIMER callback: running on MC thread");
125 /* serialize to the MC thread */
126 sys_build_message_header(SYS_MSG_ID_MC_TIMER, &msg);
127 msg.callback = callback;
128 msg.bodyptr = user_data;
129 msg.bodyval = 0;
130
131 if (cds_mq_post_message(CDS_MQ_ID_SYS, &msg) == QDF_STATUS_SUCCESS)
132 return;
133 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
134 "%s: Could not enqueue timer to any queue", __func__);
135 QDF_ASSERT(0);
136}