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