blob: 35b477997b2f2f68850e2fc5d9d484e429d84bcb [file] [log] [blame]
Sakthi Vignesh Radhakrishnan4577f9b2016-08-23 11:29:40 -07001/*
2 **************************************************************************
Stephen Wang3e2dbd12018-03-14 17:28:17 -07003 * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
Sakthi Vignesh Radhakrishnan4577f9b2016-08-23 11:29:40 -07004 * 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"
Sachin Shashidhar07b00612018-05-18 15:10:50 -070018#include "nss_bridge_log.h"
Sakthi Vignesh Radhakrishnan4577f9b2016-08-23 11:29:40 -070019
20#define NSS_BRIDGE_TX_TIMEOUT 1000 /* 1 Second */
21
22/*
23 * Private data structure
24 */
25static struct nss_bridge_pvt {
26 struct semaphore sem;
27 struct completion complete;
28 int response;
29 void *cb;
30 void *app_data;
31} bridge_pvt;
32
33/*
34 * nss_bridge_handler()
35 * Handle NSS -> HLOS messages for bridge
36 */
37static void nss_bridge_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, void *app_data)
38{
39 struct nss_bridge_msg *nbm = (struct nss_bridge_msg *)ncm;
Sakthi Vignesh Radhakrishnan4577f9b2016-08-23 11:29:40 -070040 nss_bridge_msg_callback_t cb;
41
42 BUG_ON(!nss_is_dynamic_interface(ncm->interface));
43
44 /*
45 * Is this a valid request/response packet?
46 */
47 if (ncm->type >= NSS_BRIDGE_MSG_TYPE_MAX) {
48 nss_warning("%p: received invalid message %d for bridge interface", nss_ctx, ncm->type);
49 return;
50 }
51
52 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_bridge_msg)) {
53 nss_warning("%p: length of message is greater than required: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
54 return;
55 }
56
57 /*
Sachin Shashidhar07b00612018-05-18 15:10:50 -070058 * Trace Messages
59 */
60 nss_bridge_log_rx_msg(nbm);
61
62 /*
Sakthi Vignesh Radhakrishnan4577f9b2016-08-23 11:29:40 -070063 * Log failures
64 */
65 nss_core_log_msg_failures(nss_ctx, ncm);
66
67 /*
68 * Update the callback and app_data for NOTIFY messages, IPv4 sends all notify messages
69 * to the same callback/app_data.
70 */
Suruchi Agarwale4ad24a2018-06-11 12:03:46 +053071 if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) {
Stephen Wangaed46332016-12-12 17:29:03 -080072 ncm->cb = (nss_ptr_t)nss_ctx->nss_top->bridge_callback;
73 ncm->app_data = (nss_ptr_t)nss_ctx->nss_top->bridge_ctx;
Sakthi Vignesh Radhakrishnan4577f9b2016-08-23 11:29:40 -070074 }
75
76 /*
77 * Do we have a call back
78 */
79 if (!ncm->cb) {
80 return;
81 }
82
83 /*
84 * callback
85 */
86 cb = (nss_bridge_msg_callback_t)ncm->cb;
87 cb((void *)ncm->app_data, nbm);
88}
89
90/*
Stephen Wange8b8d0d2017-02-24 17:05:22 -080091 * nss_bridge_get_context()
92 */
93struct nss_ctx_instance *nss_bridge_get_context(void)
94{
95 return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.bridge_handler_id];
96}
97EXPORT_SYMBOL(nss_bridge_get_context);
98
99/*
Sakthi Vignesh Radhakrishnan4577f9b2016-08-23 11:29:40 -0700100 * nss_bridge_callback()
101 * Callback to handle the completion of NSS->HLOS messages.
102 */
103static void nss_bridge_callback(void *app_data, struct nss_bridge_msg *nbm)
104{
105 nss_bridge_msg_callback_t callback = (nss_bridge_msg_callback_t)bridge_pvt.cb;
106 void *data = bridge_pvt.app_data;
107
108 bridge_pvt.response = NSS_TX_SUCCESS;
109 bridge_pvt.cb = NULL;
110 bridge_pvt.app_data = NULL;
111
112 if (nbm->cm.response != NSS_CMN_RESPONSE_ACK) {
113 nss_warning("bridge error response %d\n", nbm->cm.response);
114 bridge_pvt.response = nbm->cm.response;
115 }
116
117 if (callback) {
118 callback(data, nbm);
119 }
120 complete(&bridge_pvt.complete);
121}
122
123/*
Sakthi Vignesh Radhakrishnan2842f9c2017-07-27 13:56:07 -0700124 * nss_bridge_verify_if_num()
125 * Verify if_num passed to us.
126 */
127bool nss_bridge_verify_if_num(uint32_t if_num)
128{
129 if (nss_is_dynamic_interface(if_num) == false) {
130 return false;
131 }
132
133 if (nss_dynamic_interface_get_type(nss_bridge_get_context(), if_num) != NSS_DYNAMIC_INTERFACE_TYPE_BRIDGE) {
134 return false;
135 }
136
137 return true;
138}
139EXPORT_SYMBOL(nss_bridge_verify_if_num);
140
141/*
Sakthi Vignesh Radhakrishnan4577f9b2016-08-23 11:29:40 -0700142 * nss_bridge_tx_msg()
143 * Transmit a bridge message to NSSFW
144 */
145nss_tx_status_t nss_bridge_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_bridge_msg *msg)
146{
Sakthi Vignesh Radhakrishnan4577f9b2016-08-23 11:29:40 -0700147 struct nss_cmn_msg *ncm = &msg->cm;
Sakthi Vignesh Radhakrishnan4577f9b2016-08-23 11:29:40 -0700148
149 /*
150 * Sanity check the message
151 */
152 if (!nss_is_dynamic_interface(ncm->interface)) {
153 nss_warning("%p: tx request for interface that is not a bridge: %d", nss_ctx, ncm->interface);
154 return NSS_TX_FAILURE;
155 }
156
157 if (ncm->type >= NSS_BRIDGE_MSG_TYPE_MAX) {
158 nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
159 return NSS_TX_FAILURE;
160 }
161
Sachin Shashidhar07b00612018-05-18 15:10:50 -0700162 /*
163 * Trace Messages
164 */
165 nss_bridge_log_tx_msg(msg);
166
Stephen Wang3e2dbd12018-03-14 17:28:17 -0700167 return nss_core_send_cmd(nss_ctx, msg, sizeof(*msg), NSS_NBUF_PAYLOAD_SIZE);
Sakthi Vignesh Radhakrishnan4577f9b2016-08-23 11:29:40 -0700168}
169EXPORT_SYMBOL(nss_bridge_tx_msg);
170
171/*
172 * nss_bridge_tx_msg_sync()
173 * Transmit a bridge message to NSS firmware synchronously.
174 */
175nss_tx_status_t nss_bridge_tx_msg_sync(struct nss_ctx_instance *nss_ctx, struct nss_bridge_msg *nbm)
176{
177 nss_tx_status_t status;
178 int ret = 0;
179
180 down(&bridge_pvt.sem);
181 bridge_pvt.cb = (void *)nbm->cm.cb;
182 bridge_pvt.app_data = (void *)nbm->cm.app_data;
183
Stephen Wangaed46332016-12-12 17:29:03 -0800184 nbm->cm.cb = (nss_ptr_t)nss_bridge_callback;
185 nbm->cm.app_data = (nss_ptr_t)NULL;
Sakthi Vignesh Radhakrishnan4577f9b2016-08-23 11:29:40 -0700186
187 status = nss_bridge_tx_msg(nss_ctx, nbm);
188 if (status != NSS_TX_SUCCESS) {
189 nss_warning("%p: bridge_tx_msg failed\n", nss_ctx);
190 up(&bridge_pvt.sem);
191 return status;
192 }
193
194 ret = wait_for_completion_timeout(&bridge_pvt.complete, msecs_to_jiffies(NSS_BRIDGE_TX_TIMEOUT));
195
196 if (!ret) {
197 nss_warning("%p: bridge msg tx failed due to timeout\n", nss_ctx);
198 bridge_pvt.response = NSS_TX_FAILURE;
199 }
200
201 status = bridge_pvt.response;
202 up(&bridge_pvt.sem);
203 return status;
204}
205EXPORT_SYMBOL(nss_bridge_tx_msg_sync);
206
207/*
Sakthi Vignesh Radhakrishnan4577f9b2016-08-23 11:29:40 -0700208 * nss_bridge_msg_init()
209 * Initialize nss_bridge_msg.
210 */
211void nss_bridge_msg_init(struct nss_bridge_msg *ncm, uint16_t if_num, uint32_t type, uint32_t len, void *cb, void *app_data)
212{
213 nss_cmn_msg_init(&ncm->cm, if_num, type, len, cb, app_data);
214}
215EXPORT_SYMBOL(nss_bridge_msg_init);
216
217/*
Yu Huang417e4ed2016-10-05 15:02:03 -0700218 * nss_bridge_tx_vsi_assign_msg
219 * API to send vsi assign message to NSS FW
220 */
221nss_tx_status_t nss_bridge_tx_vsi_assign_msg(uint32_t if_num, uint32_t vsi)
222{
223 struct nss_ctx_instance *nss_ctx = nss_bridge_get_context();
224 struct nss_bridge_msg nbm;
225
226 if (!nss_ctx) {
227 nss_warning("Can't get nss context\n");
228 return NSS_TX_FAILURE;
229 }
230
231 if (nss_bridge_verify_if_num(if_num) == false) {
232 nss_warning("%p: invalid interface %d", nss_ctx, if_num);
233 return NSS_TX_FAILURE;
234 }
235
236 nss_bridge_msg_init(&nbm, if_num, NSS_IF_VSI_ASSIGN,
237 sizeof(struct nss_if_vsi_assign), NULL, NULL);
238
239 nbm.msg.if_msg.vsi_assign.vsi = vsi;
240
241 return nss_bridge_tx_msg_sync(nss_ctx, &nbm);
242}
243EXPORT_SYMBOL(nss_bridge_tx_vsi_assign_msg);
244
245/*
246 * nss_bridge_tx_vsi_unassign_msg
247 * API to send vsi unassign message to NSS FW
248 */
249nss_tx_status_t nss_bridge_tx_vsi_unassign_msg(uint32_t if_num, uint32_t vsi)
250{
251 struct nss_ctx_instance *nss_ctx = nss_bridge_get_context();
252 struct nss_bridge_msg nbm;
253
254 if (!nss_ctx) {
255 nss_warning("Can't get nss context\n");
256 return NSS_TX_FAILURE;
257 }
258
259 if (nss_bridge_verify_if_num(if_num) == false) {
260 nss_warning("%p: invalid interface %d", nss_ctx, if_num);
261 return NSS_TX_FAILURE;
262 }
263
264 nss_bridge_msg_init(&nbm, if_num, NSS_IF_VSI_UNASSIGN,
265 sizeof(struct nss_if_vsi_unassign), NULL, NULL);
266
267 nbm.msg.if_msg.vsi_unassign.vsi = vsi;
268
269 return nss_bridge_tx_msg_sync(nss_ctx, &nbm);
270}
271EXPORT_SYMBOL(nss_bridge_tx_vsi_unassign_msg);
272
273/*
Sakthi Vignesh Radhakrishnan4577f9b2016-08-23 11:29:40 -0700274 * nss_bridge_tx_change_mtu_msg
275 * API to send change mtu message to NSS FW
276 */
277nss_tx_status_t nss_bridge_tx_set_mtu_msg(uint32_t bridge_if_num, uint32_t mtu)
278{
279 struct nss_ctx_instance *nss_ctx = nss_bridge_get_context();
280 struct nss_bridge_msg nbm;
281 struct nss_if_mtu_change *nimc;
282
283 if (!nss_ctx) {
284 nss_warning("Can't get nss context\n");
285 return NSS_TX_FAILURE;
286 }
287
288 if (nss_bridge_verify_if_num(bridge_if_num) == false) {
289 nss_warning("%p: received invalid interface %d", nss_ctx, bridge_if_num);
290 return NSS_TX_FAILURE;
291 }
292
293 nss_bridge_msg_init(&nbm, bridge_if_num, NSS_IF_MTU_CHANGE,
294 sizeof(struct nss_if_mtu_change), NULL, NULL);
295
296 nimc = &nbm.msg.if_msg.mtu_change;
297 nimc->min_buf_size = (uint16_t)mtu;
298
299 return nss_bridge_tx_msg_sync(nss_ctx, &nbm);
300}
301EXPORT_SYMBOL(nss_bridge_tx_set_mtu_msg);
302
303/*
304 * nss_bridge_tx_set_mac_addr_msg
305 * API to send change mac addr message to NSS FW
306 */
307nss_tx_status_t nss_bridge_tx_set_mac_addr_msg(uint32_t bridge_if_num, uint8_t *addr)
308{
309 struct nss_ctx_instance *nss_ctx = nss_bridge_get_context();
310 struct nss_bridge_msg nbm;
311 struct nss_if_mac_address_set *nmas;
312
313 if (!nss_ctx) {
314 nss_warning("Can't get nss context\n");
315 return NSS_TX_FAILURE;
316 }
317
318 if (nss_bridge_verify_if_num(bridge_if_num) == false) {
319 nss_warning("%p: received invalid interface %d", nss_ctx, bridge_if_num);
320 return NSS_TX_FAILURE;
321 }
322
323 nss_bridge_msg_init(&nbm, bridge_if_num, NSS_IF_MAC_ADDR_SET,
324 sizeof(struct nss_if_mac_address_set), NULL, NULL);
325
326 nmas = &nbm.msg.if_msg.mac_address_set;
327 memcpy(nmas->mac_addr, addr, ETH_ALEN);
328 return nss_bridge_tx_msg_sync(nss_ctx, &nbm);
329}
330EXPORT_SYMBOL(nss_bridge_tx_set_mac_addr_msg);
331
332/*
333 * nss_bridge_tx_join_msg
334 * API to send slave join message to NSS FW
335 */
336nss_tx_status_t nss_bridge_tx_join_msg(uint32_t bridge_if_num, struct net_device *netdev)
337{
338 struct nss_ctx_instance *nss_ctx = nss_bridge_get_context();
339 struct nss_bridge_msg nbm;
340 uint32_t slave_if_num;
341
342 if (!nss_ctx) {
343 nss_warning("Can't get nss context\n");
344 return NSS_TX_FAILURE;
345 }
346
347 if (nss_bridge_verify_if_num(bridge_if_num) == false) {
348 nss_warning("%p: received invalid interface %d\n", nss_ctx, bridge_if_num);
349 return NSS_TX_FAILURE;
350 }
351
352 slave_if_num = nss_cmn_get_interface_number_by_dev(netdev);
353 if (slave_if_num < 0) {
354 nss_warning("%p: invalid slave device %p\n", nss_ctx, netdev);
355 return NSS_TX_FAILURE;
356 }
357
358 nbm.msg.br_join.if_num = slave_if_num;
359 nss_bridge_msg_init(&nbm, bridge_if_num, NSS_BRIDGE_MSG_JOIN,
360 sizeof(struct nss_bridge_join_msg), NULL, NULL);
361
362 return nss_bridge_tx_msg_sync(nss_ctx, &nbm);
363}
364EXPORT_SYMBOL(nss_bridge_tx_join_msg);
365
366/*
367 * nss_bridge_tx_leave_msg
368 * API to send slave leave message to NSS FW
369 */
370nss_tx_status_t nss_bridge_tx_leave_msg(uint32_t bridge_if_num, struct net_device *netdev)
371{
372 struct nss_ctx_instance *nss_ctx = nss_bridge_get_context();
373 struct nss_bridge_msg nbm;
374 uint32_t slave_if_num;
375
376 if (!nss_ctx) {
377 nss_warning("Can't get nss context\n");
378 return NSS_TX_FAILURE;
379 }
380
381 if (nss_bridge_verify_if_num(bridge_if_num) == false) {
382 nss_warning("%p: received invalid interface %d\n", nss_ctx, bridge_if_num);
383 return NSS_TX_FAILURE;
384 }
385
386 slave_if_num = nss_cmn_get_interface_number_by_dev(netdev);
387 if (slave_if_num < 0) {
388 nss_warning("%p: invalid slave device %p\n", nss_ctx, netdev);
389 return NSS_TX_FAILURE;
390 }
391
392 nbm.msg.br_leave.if_num = slave_if_num;
393 nss_bridge_msg_init(&nbm, bridge_if_num, NSS_BRIDGE_MSG_LEAVE,
394 sizeof(struct nss_bridge_leave_msg), NULL, NULL);
395
396 return nss_bridge_tx_msg_sync(nss_ctx, &nbm);
397}
398EXPORT_SYMBOL(nss_bridge_tx_leave_msg);
399
400/*
Amit Gupta12664522018-03-20 12:11:57 +0530401 * nss_bridge_tx_set_fdb_learn_msg
402 * API to send FDB learn message to NSS FW
403 */
404nss_tx_status_t nss_bridge_tx_set_fdb_learn_msg(uint32_t bridge_if_num, enum nss_bridge_fdb_learn_mode fdb_learn)
405{
406 struct nss_ctx_instance *nss_ctx = nss_bridge_get_context();
407 struct nss_bridge_msg nbm;
408
409 if (!nss_ctx) {
410 nss_warning("Can't get nss context\n");
411 return NSS_TX_FAILURE;
412 }
413
414 if (nss_bridge_verify_if_num(bridge_if_num) == false) {
415 nss_warning("%p: received invalid interface %d\n", nss_ctx, bridge_if_num);
416 return NSS_TX_FAILURE;
417 }
418
419 if (fdb_learn >= NSS_BRIDGE_FDB_LEARN_MODE_MAX) {
420 nss_warning("%p: received invalid fdb learn mode %d\n", nss_ctx, fdb_learn);
421 return NSS_TX_FAILURE;
422 }
423
424 nss_bridge_msg_init(&nbm, bridge_if_num, NSS_BRIDGE_MSG_SET_FDB_LEARN,
425 sizeof(struct nss_bridge_set_fdb_learn_msg), NULL, NULL);
426
427 nbm.msg.fdb_learn.mode = fdb_learn;
428
429 return nss_bridge_tx_msg_sync(nss_ctx, &nbm);
430}
431EXPORT_SYMBOL(nss_bridge_tx_set_fdb_learn_msg);
432
433/*
Sakthi Vignesh Radhakrishnan4577f9b2016-08-23 11:29:40 -0700434 * nss_bridge_init()
435 */
436void nss_bridge_init(void)
437{
438 sema_init(&bridge_pvt.sem, 1);
439 init_completion(&bridge_pvt.complete);
440}
441
442/*
443 * nss_bridge_unregister()
444 */
Yu Huang12323ff2017-03-02 15:01:04 -0800445void nss_bridge_unregister(uint32_t if_num)
Sakthi Vignesh Radhakrishnan4577f9b2016-08-23 11:29:40 -0700446{
Yu Huang12323ff2017-03-02 15:01:04 -0800447 struct nss_ctx_instance *nss_ctx = nss_bridge_get_context();
448
449 nss_assert(nss_bridge_verify_if_num(if_num));
450
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700451 nss_core_unregister_subsys_dp(nss_ctx, if_num);
Yu Huang12323ff2017-03-02 15:01:04 -0800452
453 nss_top_main.bridge_callback = NULL;
454
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700455 nss_core_unregister_handler(nss_ctx, if_num);
Sakthi Vignesh Radhakrishnan4577f9b2016-08-23 11:29:40 -0700456}
457EXPORT_SYMBOL(nss_bridge_unregister);
458
459/*
460 * nss_bridge_register()
461 */
Yu Huang12323ff2017-03-02 15:01:04 -0800462struct nss_ctx_instance *nss_bridge_register(uint32_t if_num, struct net_device *netdev,
463 nss_bridge_callback_t bridge_data_cb,
464 nss_bridge_msg_callback_t bridge_msg_cb,
465 uint32_t features,
466 void *app_data)
Sakthi Vignesh Radhakrishnan4577f9b2016-08-23 11:29:40 -0700467{
Yu Huang12323ff2017-03-02 15:01:04 -0800468 struct nss_ctx_instance *nss_ctx = nss_bridge_get_context();
469
470 nss_assert(nss_bridge_verify_if_num(if_num));
471
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700472 nss_core_register_subsys_dp(nss_ctx, if_num, bridge_data_cb, NULL, app_data, netdev, features);
Yu Huang12323ff2017-03-02 15:01:04 -0800473
474 nss_top_main.bridge_callback = bridge_msg_cb;
475
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700476 nss_core_register_handler(nss_ctx, if_num, nss_bridge_handler, app_data);
Yu Huang12323ff2017-03-02 15:01:04 -0800477 return nss_ctx;
Sakthi Vignesh Radhakrishnan4577f9b2016-08-23 11:29:40 -0700478}
479EXPORT_SYMBOL(nss_bridge_register);
480
481/*
482 * nss_bridge_notify_register()
483 * Register to receive bridge notify messages.
484 */
485struct nss_ctx_instance *nss_bridge_notify_register(nss_bridge_msg_callback_t cb, void *app_data)
486{
487 nss_top_main.bridge_callback = cb;
488 nss_top_main.bridge_ctx = app_data;
489 return nss_bridge_get_context();
490}
491EXPORT_SYMBOL(nss_bridge_notify_register);
492
493/*
494 * nss_bridge_notify_unregister()
495 * Unregister to receive bridge notify messages.
496 */
497void nss_bridge_notify_unregister(void)
498{
499 nss_top_main.bridge_callback = NULL;
500}
501EXPORT_SYMBOL(nss_bridge_notify_unregister);