1 /*
2 * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <wlan_qct_sys.h>
20 #include <cds_api.h>
21 #include <sir_types.h>
22 #include <sir_params.h> /* needed for tSirMbMsg */
23 #include <sir_api.h> /* needed for SIR_... message types */
24 #include <wni_api.h> /* needed for WNI_... message types */
25 #include "ani_global.h"
26 #include "wma_types.h"
27 #include "sme_api.h"
28 #include "mac_init_api.h"
29 #include "qdf_trace.h"
30
31 /*
32 * Cookie for SYS messages. Note that anyone posting a SYS Message
33 * has to write the COOKIE in the reserved field of the message. The
34 * SYS Module relies on this COOKIE
35 */
36 #define SYS_MSG_COOKIE 0xFACE
37
38 /* SYS stop timeout 30 seconds */
39 #define SYS_STOP_TIMEOUT (30000)
40 static qdf_event_t g_stop_evt;
41
sys_build_message_header(SYS_MSG_ID msg_id,struct scheduler_msg * msg)42 QDF_STATUS sys_build_message_header(SYS_MSG_ID msg_id,
43 struct scheduler_msg *msg)
44 {
45 msg->type = msg_id;
46 msg->reserved = SYS_MSG_COOKIE;
47
48 return QDF_STATUS_SUCCESS;
49 }
50
51 /**
52 * umac_stop_complete_cb() - a callback when system stop completes
53 * @msg: pointer to actual message being handled
54 *
55 * this callback is used once system stop is completed.
56 *
57 * Return: QDF_STATUS
58 */
59 #ifdef QDF_ENABLE_TRACING
umac_stop_complete_cb(struct scheduler_msg * msg)60 static QDF_STATUS umac_stop_complete_cb(struct scheduler_msg *msg)
61 {
62 qdf_event_t *stop_evt = msg->bodyptr;
63 QDF_STATUS qdf_status = qdf_event_set(stop_evt);
64
65 QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status));
66
67 return qdf_status;
68 }
69 #else
umac_stop_complete_cb(struct scheduler_msg * msg)70 static QDF_STATUS umac_stop_complete_cb(struct scheduler_msg *msg)
71 {
72 return QDF_STATUS_SUCCESS;
73 }
74 #endif
75
umac_stop_flush_cb(struct scheduler_msg * msg)76 static inline QDF_STATUS umac_stop_flush_cb(struct scheduler_msg *msg)
77 {
78 return QDF_STATUS_SUCCESS;
79 }
80
81 /**
82 * umac_stop() - To post stop message to system module
83 *
84 * This API is used post a stop message to system module
85 *
86 * Return: QDF_STATUS
87 */
umac_stop(void)88 QDF_STATUS umac_stop(void)
89 {
90 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
91 struct scheduler_msg umac_stop_msg;
92
93 /* Initialize the stop event */
94 qdf_status = qdf_event_create(&g_stop_evt);
95
96 if (!QDF_IS_STATUS_SUCCESS(qdf_status))
97 return qdf_status;
98
99 /* post a message to SYS module in MC to stop SME and MAC */
100 sys_build_message_header(SYS_MSG_ID_UMAC_STOP, &umac_stop_msg);
101
102 /* Save the user callback and user data */
103 umac_stop_msg.callback = umac_stop_complete_cb;
104 umac_stop_msg.bodyptr = (void *)&g_stop_evt;
105 umac_stop_msg.flush_callback = umac_stop_flush_cb;
106
107 /* post the message.. */
108 qdf_status = scheduler_post_message(QDF_MODULE_ID_SYS,
109 QDF_MODULE_ID_SYS,
110 QDF_MODULE_ID_SYS, &umac_stop_msg);
111 if (!QDF_IS_STATUS_SUCCESS(qdf_status))
112 qdf_status = QDF_STATUS_E_BADMSG;
113
114 qdf_status = qdf_wait_single_event(&g_stop_evt, SYS_STOP_TIMEOUT);
115 QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status));
116
117 qdf_status = qdf_event_destroy(&g_stop_evt);
118 QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status));
119
120 return qdf_status;
121 }
122
123 /**
124 * sys_mc_process_msg() - to process system mc thread messages
125 * @pMsg: message pointer
126 *
127 * This API is used to process the message
128 *
129 * Return: QDF_STATUS
130 */
sys_mc_process_msg(struct scheduler_msg * pMsg)131 static QDF_STATUS sys_mc_process_msg(struct scheduler_msg *pMsg)
132 {
133 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
134 mac_handle_t mac_handle;
135
136 if (!pMsg) {
137 QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR,
138 "%s: NULL pointer to struct scheduler_msg", __func__);
139 QDF_ASSERT(0);
140 return QDF_STATUS_E_INVAL;
141 }
142
143 /*
144 * All 'new' SYS messages are identified by a cookie in the reserved
145 * field of the message as well as the message type. This prevents
146 * the possibility of overlap in the message types defined for new
147 * SYS messages with the 'legacy' message types. The legacy messages
148 * will not have this cookie in the reserved field
149 */
150 if (SYS_MSG_COOKIE == pMsg->reserved) {
151 /* Process all the new SYS messages.. */
152 switch (pMsg->type) {
153 case SYS_MSG_ID_UMAC_STOP:
154 QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR,
155 "Processing SYS MC STOP");
156 mac_handle = cds_get_context(QDF_MODULE_ID_PE);
157 if (!mac_handle)
158 break;
159
160 qdf_status = sme_stop(mac_handle);
161 QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status));
162 qdf_status = mac_stop(mac_handle);
163 QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status));
164 qdf_status = pMsg->callback(pMsg);
165 break;
166 case SYS_MSG_ID_DATA_STALL_MSG:
167 if (pMsg->callback)
168 qdf_status = pMsg->callback(pMsg);
169
170 qdf_mem_free(pMsg->bodyptr);
171 break;
172 default:
173 QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR,
174 "Unknown message type msgType= %d [0x%08x]",
175 pMsg->type, pMsg->type);
176 break;
177
178 }
179 } else {
180 QDF_TRACE(QDF_MODULE_ID_SYS,
181 QDF_TRACE_LEVEL_ERROR,
182 "Rx SYS unknown MC msgtype= %d [0x%08X]",
183 pMsg->type, pMsg->type);
184 QDF_ASSERT(0);
185 qdf_status = QDF_STATUS_E_BADMSG;
186
187 if (pMsg->bodyptr)
188 qdf_mem_free(pMsg->bodyptr);
189 }
190 return qdf_status;
191 }
192
sys_mc_process_handler(struct scheduler_msg * msg)193 QDF_STATUS sys_mc_process_handler(struct scheduler_msg *msg)
194 {
195 return sys_mc_process_msg(msg);
196 }
197
sys_process_mmh_msg(struct mac_context * mac,struct scheduler_msg * msg)198 void sys_process_mmh_msg(struct mac_context *mac, struct scheduler_msg *msg)
199 {
200 QDF_MODULE_ID dest_module = QDF_MODULE_ID_SYS;
201
202 if (!msg) {
203 QDF_ASSERT(0);
204 return;
205 }
206
207 switch (msg->type) {
208 case eWNI_SME_SYS_READY_IND:
209 /* Forward this message to the PE module */
210 dest_module = QDF_MODULE_ID_PE;
211 break;
212 default:
213 if ((msg->type >= eWNI_SME_MSG_TYPES_BEGIN) &&
214 (msg->type <= eWNI_SME_MSG_TYPES_END)) {
215 dest_module = QDF_MODULE_ID_SME;
216 break;
217 }
218
219 QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR,
220 "Message of ID %d is not yet handled by SYS",
221 msg->type);
222 QDF_ASSERT(0);
223 }
224
225 /*
226 * Post now the message to the appropriate module for handling
227 */
228 if (QDF_STATUS_SUCCESS != scheduler_post_message(QDF_MODULE_ID_SYS,
229 QDF_MODULE_ID_SYS,
230 dest_module,
231 msg))
232 qdf_mem_free(msg->bodyptr);
233 }
234