blob: de61250af0e67cc7b4364ce9bb1724685875e4d6 [file] [log] [blame]
Varsha Mishrae58d93b2017-05-20 20:54:41 +05301/*
2 **************************************************************************
Subhranil Choudhury912f0682019-05-22 13:21:11 +05303 * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
Varsha Mishrae58d93b2017-05-20 20:54:41 +05304 * 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 copies.
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
13 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 **************************************************************************
15 */
16
17#include "nss_tx_rx_common.h"
Yu Huang8c107082017-07-24 14:58:26 -070018#include "nss_wifili_stats.h"
Sachin Shashidharc7b2e002018-08-20 13:52:51 -070019#include "nss_wifili_log.h"
Varsha Mishrae58d93b2017-05-20 20:54:41 +053020
21#define NSS_WIFILI_TX_TIMEOUT 1000 /* Millisecond to jiffies*/
22
23/*
24 * nss_wifili_pvt
25 * Private data structure
26 */
27static struct nss_wifili_pvt {
28 struct semaphore sem;
29 struct completion complete;
30 int response;
31 void *cb;
32 void *app_data;
33} wifili_pvt;
34
35/*
Varsha Mishrae58d93b2017-05-20 20:54:41 +053036 * nss_wifili_handler()
37 * Handle NSS -> HLOS messages for wifi
38 */
39static void nss_wifili_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
40{
41 struct nss_wifili_msg *ntm = (struct nss_wifili_msg *)ncm;
42 void *ctx;
43 nss_wifili_msg_callback_t cb;
44
45 nss_info("%p: NSS->HLOS message for wifili\n", nss_ctx);
46
47 /*
48 * The interface number shall be wifili soc interface or wifili radio interface
49 */
Subhranil Choudhury912f0682019-05-22 13:21:11 +053050 BUG_ON((nss_is_dynamic_interface(ncm->interface))
51 || ((ncm->interface != NSS_WIFILI_INTERNAL_INTERFACE)
52 && (ncm->interface != NSS_WIFILI_EXTERNAL_INTERFACE0)
53 && (ncm->interface != NSS_WIFILI_EXTERNAL_INTERFACE1)));
Varsha Mishrae58d93b2017-05-20 20:54:41 +053054
55 /*
Sachin Shashidharc7b2e002018-08-20 13:52:51 -070056 * Trace messages.
57 */
58 nss_wifili_log_rx_msg(ntm);
59
60 /*
Varsha Mishrae58d93b2017-05-20 20:54:41 +053061 * Is this a valid request/response packet?
62 */
63 if (ncm->type >= NSS_WIFILI_MAX_MSG) {
64 nss_warning("%p: Received invalid message %d for wifili interface", nss_ctx, ncm->type);
65 return;
66 }
67
68 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_wifili_msg)) {
69 nss_warning("%p: Length of message is greater than required: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
70 return;
71 }
72
73 /*
74 * Snoop messages for local driver and handle
75 */
76 switch (ntm->cm.type) {
Aniruddha Paul1b170c22017-05-29 12:30:39 +053077 case NSS_WIFILI_STATS_MSG:
Varsha Mishrae58d93b2017-05-20 20:54:41 +053078 nss_wifili_stats_sync(nss_ctx, &ntm->msg.wlsoc_stats, ncm->interface);
79 break;
80 }
81
82 /*
83 * Update the callback and app_data for notify messages, wifili sends all notify messages
84 * to the same callback/app_data.
85 */
Suruchi Agarwale4ad24a2018-06-11 12:03:46 +053086 if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) {
Varsha Mishrae58d93b2017-05-20 20:54:41 +053087 ncm->cb = (nss_ptr_t)nss_ctx->nss_top->wifili_msg_callback;
88 }
89
90 /*
91 * Log failures
92 */
93 nss_core_log_msg_failures(nss_ctx, ncm);
94
95 /*
96 * Do we have a call back
97 */
98 if (!ncm->cb) {
99 nss_info("%p: cb null for wifili interface %d", nss_ctx, ncm->interface);
100 return;
101 }
102
103 /*
104 * Get callback & context
105 */
106 cb = (nss_wifili_msg_callback_t)ncm->cb;
107 ctx = nss_ctx->subsys_dp_register[ncm->interface].ndev;
108
109 /*
110 * call wifili msg callback
111 */
112 if (!ctx) {
113 nss_warning("%p: Event received for wifili interface %d before registration", nss_ctx, ncm->interface);
114 return;
115 }
116
117 cb(ctx, ntm);
118}
119
120/*
121 * nss_wifili_callback()
122 * Callback to handle the completion of NSS->HLOS messages.
123 */
124static void nss_wifili_callback(void *app_data, struct nss_wifili_msg *nvm)
125{
126 nss_wifili_msg_callback_t callback = (nss_wifili_msg_callback_t)wifili_pvt.cb;
127 void *data = wifili_pvt.app_data;
128
129 wifili_pvt.response = NSS_TX_SUCCESS;
130 wifili_pvt.cb = NULL;
131 wifili_pvt.app_data = NULL;
132
133 if (nvm->cm.response != NSS_CMN_RESPONSE_ACK) {
134 nss_warning("wifili error response %d\n", nvm->cm.response);
135 wifili_pvt.response = nvm->cm.response;
136 }
137
138 if (callback) {
139 callback(data, nvm);
140 }
141 complete(&wifili_pvt.complete);
142}
143
144/*
145 * nss_wifili_tx_msg
146 * Transmit a wifili message to NSS FW
147 *
148 * NOTE: The caller is expected to handle synchronous wait for message
149 * response if needed.
150 */
151nss_tx_status_t nss_wifili_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_wifili_msg *msg)
152{
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530153 struct nss_cmn_msg *ncm = &msg->cm;
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530154
Sachin Shashidharc7b2e002018-08-20 13:52:51 -0700155 /*
156 * Trace messages.
157 */
158 nss_wifili_log_tx_msg(msg);
159
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530160 if (ncm->type >= NSS_WIFILI_MAX_MSG) {
161 nss_warning("%p: wifili message type out of range: %d", nss_ctx, ncm->type);
162 return NSS_TX_FAILURE;
163 }
164
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530165 /*
Subhranil Choudhury912f0682019-05-22 13:21:11 +0530166 * The interface number shall be one of the wifili soc interfaces
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530167 */
Subhranil Choudhury912f0682019-05-22 13:21:11 +0530168 if ((ncm->interface != NSS_WIFILI_INTERNAL_INTERFACE)
169 && (ncm->interface != NSS_WIFILI_EXTERNAL_INTERFACE0)
170 && (ncm->interface != NSS_WIFILI_EXTERNAL_INTERFACE1)) {
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530171 nss_warning("%p: tx request for interface that is not a wifili: %d", nss_ctx, ncm->interface);
172 return NSS_TX_FAILURE;
173 }
174
Stephen Wang3e2dbd12018-03-14 17:28:17 -0700175 return nss_core_send_cmd(nss_ctx, msg, sizeof(*msg), NSS_NBUF_PAYLOAD_SIZE);
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530176}
177EXPORT_SYMBOL(nss_wifili_tx_msg);
178
179/*
180 * nss_wifili_tx_msg_sync()
181 * Transmit a wifili message to NSS firmware synchronously.
182 */
183nss_tx_status_t nss_wifili_tx_msg_sync(struct nss_ctx_instance *nss_ctx, struct nss_wifili_msg *nvm)
184{
185 nss_tx_status_t status;
186 int ret = 0;
187
188 down(&wifili_pvt.sem);
189 wifili_pvt.cb = (void *)nvm->cm.cb;
190 wifili_pvt.app_data = (void *)nvm->cm.app_data;
191
192 nvm->cm.cb = (nss_ptr_t)nss_wifili_callback;
193 nvm->cm.app_data = (nss_ptr_t)NULL;
194
195 status = nss_wifili_tx_msg(nss_ctx, nvm);
196 if (status != NSS_TX_SUCCESS) {
197 nss_warning("%p: wifili_tx_msg failed\n", nss_ctx);
198 up(&wifili_pvt.sem);
199 return status;
200 }
201
202 ret = wait_for_completion_timeout(&wifili_pvt.complete, msecs_to_jiffies(NSS_WIFILI_TX_TIMEOUT));
203 if (!ret) {
204 nss_warning("%p: wifili msg tx failed due to timeout\n", nss_ctx);
205 wifili_pvt.response = NSS_TX_FAILURE;
206 }
207
208 status = wifili_pvt.response;
209 up(&wifili_pvt.sem);
210 return status;
211}
212EXPORT_SYMBOL(nss_wifili_tx_msg_sync);
213
214/*
215 * nss_wifili_get_context()
216 */
217struct nss_ctx_instance *nss_wifili_get_context(void)
218{
219 return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.wifi_handler_id];
220}
221EXPORT_SYMBOL(nss_wifili_get_context);
222
223/*
syed touqeer pasha282abcb2019-11-26 15:19:37 +0530224 * nss_get_available_wifili_external_if()
225 * Check and return the available external interface
226 */
227uint32_t nss_get_available_wifili_external_if(void)
228{
229 struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.wifi_handler_id];
230 /*
231 * Check if the external interface is registered.
232 * Return the interface number if not registered.
233 */
234 if (!(nss_ctx->subsys_dp_register[NSS_WIFILI_EXTERNAL_INTERFACE0].ndev)) {
235 return NSS_WIFILI_EXTERNAL_INTERFACE0;
236 }
237
238 if (!(nss_ctx->subsys_dp_register[NSS_WIFILI_EXTERNAL_INTERFACE1].ndev)) {
239 return NSS_WIFILI_EXTERNAL_INTERFACE1;
240 }
241
242 nss_warning("%p: No available external intefaces\n", nss_ctx);
243
244 return NSS_MAX_NET_INTERFACES;
245}
246EXPORT_SYMBOL(nss_get_available_wifili_external_if);
247
248/*
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530249 * nss_wifili_msg_init()
250 * Initialize nss_wifili_msg.
251 */
252void nss_wifili_msg_init(struct nss_wifili_msg *ncm, uint16_t if_num, uint32_t type, uint32_t len, void *cb, void *app_data)
253{
254 nss_cmn_msg_init(&ncm->cm, if_num, type, len, cb, app_data);
255}
256EXPORT_SYMBOL(nss_wifili_msg_init);
257
258/*
259 ****************************************
260 * Register/Unregister/Miscellaneous APIs
261 ****************************************
262 */
263
264/*
265 * nss_register_wifili_if()
266 * Register wifili with nss driver
267 */
268struct nss_ctx_instance *nss_register_wifili_if(uint32_t if_num, nss_wifili_callback_t wifili_callback,
269 nss_wifili_callback_t wifili_ext_callback,
270 nss_wifili_msg_callback_t event_callback, struct net_device *netdev, uint32_t features)
271{
272 struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.wifi_handler_id];
273
274 /*
275 * The interface number shall be wifili soc interface
276 */
Subhranil Choudhury912f0682019-05-22 13:21:11 +0530277 nss_assert((if_num == NSS_WIFILI_INTERNAL_INTERFACE)
278 || (if_num == NSS_WIFILI_EXTERNAL_INTERFACE0)
279 || (if_num == NSS_WIFILI_EXTERNAL_INTERFACE1));
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530280
Aniruddha Paul1b170c22017-05-29 12:30:39 +0530281 nss_info("nss_register_wifili_if if_num %d wifictx %p", if_num, netdev);
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530282
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700283 nss_core_register_subsys_dp(nss_ctx, if_num, wifili_callback, wifili_ext_callback, NULL, netdev, features);
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530284
285 nss_top_main.wifili_msg_callback = event_callback;
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530286
287 return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.wifi_handler_id];
288}
289EXPORT_SYMBOL(nss_register_wifili_if);
290
291/*
292 * nss_unregister_wifili_if()
293 * Unregister wifili with nss driver
294 */
295void nss_unregister_wifili_if(uint32_t if_num)
296{
297 struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.wifi_handler_id];
298
299 /*
300 * The interface number shall be wifili soc interface
301 */
Subhranil Choudhury912f0682019-05-22 13:21:11 +0530302 nss_assert((if_num == NSS_WIFILI_INTERNAL_INTERFACE)
303 || (if_num == NSS_WIFILI_EXTERNAL_INTERFACE0)
304 || (if_num == NSS_WIFILI_EXTERNAL_INTERFACE1));
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530305
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700306 nss_core_unregister_subsys_dp(nss_ctx, if_num);
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530307}
308EXPORT_SYMBOL(nss_unregister_wifili_if);
309
310/*
311 * nss_register_wifili_radio_if()
312 * Register wifili radio with nss driver
313 */
314struct nss_ctx_instance *nss_register_wifili_radio_if(uint32_t if_num, nss_wifili_callback_t wifili_callback,
315 nss_wifili_callback_t wifili_ext_callback,
316 nss_wifili_msg_callback_t event_callback, struct net_device *netdev, uint32_t features)
317{
318 struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.wifi_handler_id];
319
320 /*
321 * The interface number shall be wifili radio dynamic interface
322 */
323 nss_assert(nss_is_dynamic_interface(if_num));
Aniruddha Paul1b170c22017-05-29 12:30:39 +0530324 nss_info("nss_register_wifili_if if_num %d wifictx %p", if_num, netdev);
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530325
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700326 nss_core_register_subsys_dp(nss_ctx, if_num, wifili_callback, wifili_ext_callback, NULL, netdev, features);
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530327
328 return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.wifi_handler_id];
329}
330EXPORT_SYMBOL(nss_register_wifili_radio_if);
331
332/*
333 * nss_unregister_wifili_radio_if()
334 * Unregister wifili radio with nss driver
335 */
336void nss_unregister_wifili_radio_if(uint32_t if_num)
337{
338 struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.wifi_handler_id];
339
340 /*
341 * The interface number shall be wifili radio dynamic interface
342 */
343 nss_assert(nss_is_dynamic_interface(if_num));
344
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700345 nss_core_unregister_subsys_dp(nss_ctx, if_num);
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530346}
347EXPORT_SYMBOL(nss_unregister_wifili_radio_if);
348
349/*
350 * nss_wifili_register_handler()
351 * Register handle for notfication messages received on wifi interface
352 */
Aniruddha Paul1b170c22017-05-29 12:30:39 +0530353void nss_wifili_register_handler(void)
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530354{
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700355 struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.wifi_handler_id];
356
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530357 nss_info("nss_wifili_register_handler");
Subhranil Choudhury912f0682019-05-22 13:21:11 +0530358 nss_core_register_handler(nss_ctx, NSS_WIFILI_INTERNAL_INTERFACE, nss_wifili_handler, NULL);
359 nss_core_register_handler(nss_ctx, NSS_WIFILI_EXTERNAL_INTERFACE0, nss_wifili_handler, NULL);
360 nss_core_register_handler(nss_ctx, NSS_WIFILI_EXTERNAL_INTERFACE1, nss_wifili_handler, NULL);
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530361
Yu Huang8c107082017-07-24 14:58:26 -0700362 nss_wifili_stats_dentry_create();
363
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530364 sema_init(&wifili_pvt.sem, 1);
365 init_completion(&wifili_pvt.complete);
366}