blob: 46c6711fb35cf16e1f90596a0a044b7c385c7004 [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/*
224 * nss_wifili_msg_init()
225 * Initialize nss_wifili_msg.
226 */
227void nss_wifili_msg_init(struct nss_wifili_msg *ncm, uint16_t if_num, uint32_t type, uint32_t len, void *cb, void *app_data)
228{
229 nss_cmn_msg_init(&ncm->cm, if_num, type, len, cb, app_data);
230}
231EXPORT_SYMBOL(nss_wifili_msg_init);
232
233/*
234 ****************************************
235 * Register/Unregister/Miscellaneous APIs
236 ****************************************
237 */
238
239/*
240 * nss_register_wifili_if()
241 * Register wifili with nss driver
242 */
243struct nss_ctx_instance *nss_register_wifili_if(uint32_t if_num, nss_wifili_callback_t wifili_callback,
244 nss_wifili_callback_t wifili_ext_callback,
245 nss_wifili_msg_callback_t event_callback, struct net_device *netdev, uint32_t features)
246{
247 struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.wifi_handler_id];
248
249 /*
250 * The interface number shall be wifili soc interface
251 */
Subhranil Choudhury912f0682019-05-22 13:21:11 +0530252 nss_assert((if_num == NSS_WIFILI_INTERNAL_INTERFACE)
253 || (if_num == NSS_WIFILI_EXTERNAL_INTERFACE0)
254 || (if_num == NSS_WIFILI_EXTERNAL_INTERFACE1));
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530255
Aniruddha Paul1b170c22017-05-29 12:30:39 +0530256 nss_info("nss_register_wifili_if if_num %d wifictx %p", if_num, netdev);
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530257
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700258 nss_core_register_subsys_dp(nss_ctx, if_num, wifili_callback, wifili_ext_callback, NULL, netdev, features);
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530259
260 nss_top_main.wifili_msg_callback = event_callback;
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530261
262 return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.wifi_handler_id];
263}
264EXPORT_SYMBOL(nss_register_wifili_if);
265
266/*
267 * nss_unregister_wifili_if()
268 * Unregister wifili with nss driver
269 */
270void nss_unregister_wifili_if(uint32_t if_num)
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
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700281 nss_core_unregister_subsys_dp(nss_ctx, if_num);
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530282}
283EXPORT_SYMBOL(nss_unregister_wifili_if);
284
285/*
286 * nss_register_wifili_radio_if()
287 * Register wifili radio with nss driver
288 */
289struct nss_ctx_instance *nss_register_wifili_radio_if(uint32_t if_num, nss_wifili_callback_t wifili_callback,
290 nss_wifili_callback_t wifili_ext_callback,
291 nss_wifili_msg_callback_t event_callback, struct net_device *netdev, uint32_t features)
292{
293 struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.wifi_handler_id];
294
295 /*
296 * The interface number shall be wifili radio dynamic interface
297 */
298 nss_assert(nss_is_dynamic_interface(if_num));
Aniruddha Paul1b170c22017-05-29 12:30:39 +0530299 nss_info("nss_register_wifili_if if_num %d wifictx %p", if_num, netdev);
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530300
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700301 nss_core_register_subsys_dp(nss_ctx, if_num, wifili_callback, wifili_ext_callback, NULL, netdev, features);
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530302
303 return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.wifi_handler_id];
304}
305EXPORT_SYMBOL(nss_register_wifili_radio_if);
306
307/*
308 * nss_unregister_wifili_radio_if()
309 * Unregister wifili radio with nss driver
310 */
311void nss_unregister_wifili_radio_if(uint32_t if_num)
312{
313 struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.wifi_handler_id];
314
315 /*
316 * The interface number shall be wifili radio dynamic interface
317 */
318 nss_assert(nss_is_dynamic_interface(if_num));
319
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700320 nss_core_unregister_subsys_dp(nss_ctx, if_num);
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530321}
322EXPORT_SYMBOL(nss_unregister_wifili_radio_if);
323
324/*
325 * nss_wifili_register_handler()
326 * Register handle for notfication messages received on wifi interface
327 */
Aniruddha Paul1b170c22017-05-29 12:30:39 +0530328void nss_wifili_register_handler(void)
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530329{
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700330 struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.wifi_handler_id];
331
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530332 nss_info("nss_wifili_register_handler");
Subhranil Choudhury912f0682019-05-22 13:21:11 +0530333 nss_core_register_handler(nss_ctx, NSS_WIFILI_INTERNAL_INTERFACE, nss_wifili_handler, NULL);
334 nss_core_register_handler(nss_ctx, NSS_WIFILI_EXTERNAL_INTERFACE0, nss_wifili_handler, NULL);
335 nss_core_register_handler(nss_ctx, NSS_WIFILI_EXTERNAL_INTERFACE1, nss_wifili_handler, NULL);
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530336
Yu Huang8c107082017-07-24 14:58:26 -0700337 nss_wifili_stats_dentry_create();
338
Varsha Mishrae58d93b2017-05-20 20:54:41 +0530339 sema_init(&wifili_pvt.sem, 1);
340 init_completion(&wifili_pvt.complete);
341}