blob: cbcbfef6622ac88951df6745f7cd93653138abbb [file] [log] [blame]
Stephen Wangbce06672016-12-02 15:11:35 -08001/*
2 **************************************************************************
Stephen Wang3e2dbd12018-03-14 17:28:17 -07003 * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
Stephen Wangbce06672016-12-02 15:11:35 -08004 * 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 Shashidharadca0c82018-08-19 18:42:22 -070018#include "nss_vlan_log.h"
Stephen Wangbce06672016-12-02 15:11:35 -080019
20#define NSS_VLAN_TX_TIMEOUT 1000 /* 1 Second */
21
22/*
23 * Private data structure
24 */
25static struct nss_vlan_pvt {
26 struct semaphore sem;
27 struct completion complete;
28 int response;
29 void *cb;
30 void *app_data;
31} vlan_pvt;
32
33/*
Stephen Wange8b8d0d2017-02-24 17:05:22 -080034 * nss_vlan_get_context()
35 */
36struct nss_ctx_instance *nss_vlan_get_context(void)
37{
38 return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.vlan_handler_id];
39}
40EXPORT_SYMBOL(nss_vlan_get_context);
41
42/*
Stephen Wangbce06672016-12-02 15:11:35 -080043 * nss_vlan_verify_if_num()
44 * Verify if_num passed to us.
45 */
46static bool nss_vlan_verify_if_num(uint32_t if_num)
47{
48 if (!nss_is_dynamic_interface(if_num)) {
49 return false;
50 }
51
Stephen Wange8b8d0d2017-02-24 17:05:22 -080052 if (nss_dynamic_interface_get_type(nss_vlan_get_context(), if_num) != NSS_DYNAMIC_INTERFACE_TYPE_VLAN) {
Stephen Wangbce06672016-12-02 15:11:35 -080053 return false;
54 }
55
56 return true;
57}
58
59/*
60 * nss_vlan_handler()
61 * Handle NSS -> HLOS messages for vlan
62 */
63static void nss_vlan_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, void *app_data)
64{
65 struct nss_vlan_msg *nvm = (struct nss_vlan_msg *)ncm;
66 nss_vlan_msg_callback_t cb;
67
68 nss_assert(nss_vlan_verify_if_num(ncm->interface));
69
70 /*
Sachin Shashidharadca0c82018-08-19 18:42:22 -070071 * Trace messages.
72 */
73 nss_vlan_log_rx_msg(nvm);
74
75 /*
Stephen Wangbce06672016-12-02 15:11:35 -080076 * Is this a valid request/response packet?
77 */
78 if (ncm->type >= NSS_VLAN_MSG_TYPE_MAX) {
79 nss_warning("%p: received invalid message %d for vlan interface", nss_ctx, ncm->type);
80 return;
81 }
82
83 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_vlan_msg)) {
84 nss_warning("%p: length of message is greater than required: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
85 return;
86 }
87
88 /*
89 * Update the callback and app_data for NOTIFY messages, vlan sends all notify messages
90 * to the same callback/app_data.
91 */
Suruchi Agarwale4ad24a2018-06-11 12:03:46 +053092 if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) {
Stephen Wangbce06672016-12-02 15:11:35 -080093 ncm->cb = (nss_ptr_t)nss_ctx->nss_top->vlan_callback;
94 ncm->app_data = (nss_ptr_t)app_data;
95 }
96
97 /*
98 * Log failures
99 */
100 nss_core_log_msg_failures(nss_ctx, ncm);
101
102 /*
103 * Do we have a call back
104 */
105 if (!ncm->cb) {
106 return;
107 }
108
109 /*
110 * callback
111 */
112 cb = (nss_vlan_msg_callback_t)ncm->cb;
113 cb((void *)ncm->app_data, nvm);
114}
115
116/*
117 * nss_vlan_callback()
118 * Callback to handle the completion of NSS->HLOS messages.
119 */
120static void nss_vlan_callback(void *app_data, struct nss_vlan_msg *nvm)
121{
122 nss_vlan_msg_callback_t callback = (nss_vlan_msg_callback_t)vlan_pvt.cb;
123 void *data = vlan_pvt.app_data;
124
125 vlan_pvt.response = NSS_TX_SUCCESS;
126 vlan_pvt.cb = NULL;
127 vlan_pvt.app_data = NULL;
128
129 if (nvm->cm.response != NSS_CMN_RESPONSE_ACK) {
130 nss_warning("vlan error response %d\n", nvm->cm.response);
131 vlan_pvt.response = nvm->cm.response;
132 }
133
134 if (callback) {
135 callback(data, nvm);
136 }
137 complete(&vlan_pvt.complete);
138}
139
140/*
141 * nss_vlan_tx_msg()
142 * Transmit a vlan message to NSSFW
143 */
144nss_tx_status_t nss_vlan_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_vlan_msg *msg)
145{
Stephen Wangbce06672016-12-02 15:11:35 -0800146 struct nss_cmn_msg *ncm = &msg->cm;
Stephen Wangbce06672016-12-02 15:11:35 -0800147
148 /*
Sachin Shashidharadca0c82018-08-19 18:42:22 -0700149 * Trace messages.
150 */
151 nss_vlan_log_tx_msg(msg);
152
153 /*
Stephen Wangbce06672016-12-02 15:11:35 -0800154 * Sanity check the message
155 */
156 if (!nss_vlan_verify_if_num(ncm->interface)) {
157 nss_warning("%p: tx request for interface that is not a vlan: %d", nss_ctx, ncm->interface);
158 return NSS_TX_FAILURE;
159 }
160
161 if (ncm->type >= NSS_VLAN_MSG_TYPE_MAX) {
162 nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
163 return NSS_TX_FAILURE;
164 }
165
Stephen Wang3e2dbd12018-03-14 17:28:17 -0700166 return nss_core_send_cmd(nss_ctx, msg, sizeof(*msg), NSS_NBUF_PAYLOAD_SIZE);
Stephen Wangbce06672016-12-02 15:11:35 -0800167}
168EXPORT_SYMBOL(nss_vlan_tx_msg);
169
170/*
171 * nss_vlan_tx_msg_sync()
172 * Transmit a vlan message to NSS firmware synchronously.
173 */
174nss_tx_status_t nss_vlan_tx_msg_sync(struct nss_ctx_instance *nss_ctx, struct nss_vlan_msg *nvm)
175{
176 nss_tx_status_t status;
177 int ret = 0;
178
179 down(&vlan_pvt.sem);
180 vlan_pvt.cb = (void *)nvm->cm.cb;
181 vlan_pvt.app_data = (void *)nvm->cm.app_data;
182
183 nvm->cm.cb = (nss_ptr_t)nss_vlan_callback;
184 nvm->cm.app_data = (nss_ptr_t)NULL;
185
186 status = nss_vlan_tx_msg(nss_ctx, nvm);
187 if (status != NSS_TX_SUCCESS) {
188 nss_warning("%p: vlan_tx_msg failed\n", nss_ctx);
189 up(&vlan_pvt.sem);
190 return status;
191 }
192
193 ret = wait_for_completion_timeout(&vlan_pvt.complete, msecs_to_jiffies(NSS_VLAN_TX_TIMEOUT));
194 if (!ret) {
195 nss_warning("%p: vlan msg tx failed due to timeout\n", nss_ctx);
196 vlan_pvt.response = NSS_TX_FAILURE;
197 }
198
199 status = vlan_pvt.response;
200 up(&vlan_pvt.sem);
201 return status;
202}
203EXPORT_SYMBOL(nss_vlan_tx_msg_sync);
204
205/*
Stephen Wangbce06672016-12-02 15:11:35 -0800206 * nss_vlan_msg_init()
207 * Initialize nss_vlan_msg.
208 */
209void nss_vlan_msg_init(struct nss_vlan_msg *ncm, uint16_t if_num, uint32_t type, uint32_t len, void *cb, void *app_data)
210{
211 nss_cmn_msg_init(&ncm->cm, if_num, type, len, cb, app_data);
212}
213EXPORT_SYMBOL(nss_vlan_msg_init);
214
215/*
216 * nss_vlan_tx_change_mtu_msg
217 * API to send change mtu message to NSS FW
218 */
219nss_tx_status_t nss_vlan_tx_set_mtu_msg(uint32_t vlan_if_num, uint32_t mtu)
220{
221 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
222 struct nss_vlan_msg nvm;
223 struct nss_if_mtu_change *nimc;
224
225 if (!nss_ctx) {
226 nss_warning("Can't get nss context\n");
227 return NSS_TX_FAILURE;
228 }
229
230 if (nss_vlan_verify_if_num(vlan_if_num) == false) {
231 nss_warning("%p: received invalid interface %d", nss_ctx, vlan_if_num);
232 return NSS_TX_FAILURE;
233 }
234
235 nss_vlan_msg_init(&nvm, vlan_if_num, NSS_IF_MTU_CHANGE,
236 sizeof(struct nss_if_mtu_change), NULL, NULL);
237
238 nimc = &nvm.msg.if_msg.mtu_change;
239 nimc->min_buf_size = (uint16_t)mtu;
240
241 return nss_vlan_tx_msg_sync(nss_ctx, &nvm);
242}
243EXPORT_SYMBOL(nss_vlan_tx_set_mtu_msg);
244
245/*
246 * nss_vlan_tx_set_mac_addr_msg
247 * API to send change mac addr message to NSS FW
248 */
249nss_tx_status_t nss_vlan_tx_set_mac_addr_msg(uint32_t vlan_if_num, uint8_t *addr)
250{
251 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
252 struct nss_vlan_msg nvm;
253 struct nss_if_mac_address_set *nmas;
254
255 if (!nss_ctx) {
256 nss_warning("Can't get nss context\n");
257 return NSS_TX_FAILURE;
258 }
259
260 if (nss_vlan_verify_if_num(vlan_if_num) == false) {
261 nss_warning("%p: received invalid interface %d", nss_ctx, vlan_if_num);
262 return NSS_TX_FAILURE;
263 }
264
265 nss_vlan_msg_init(&nvm, vlan_if_num, NSS_IF_MAC_ADDR_SET,
266 sizeof(struct nss_if_mac_address_set), NULL, NULL);
267
268 nmas = &nvm.msg.if_msg.mac_address_set;
269 memcpy(nmas->mac_addr, addr, ETH_ALEN);
270 return nss_vlan_tx_msg_sync(nss_ctx, &nvm);
271}
272EXPORT_SYMBOL(nss_vlan_tx_set_mac_addr_msg);
273
274/*
275 * nss_vlan_tx_vsi_attach_msg
276 * API to send VSI attach message to NSS FW
277 */
278nss_tx_status_t nss_vlan_tx_vsi_attach_msg(uint32_t vlan_if_num, uint32_t vsi)
279{
280 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
281 struct nss_vlan_msg nvm;
282
283 if (!nss_ctx) {
284 nss_warning("Can't get nss context\n");
285 return NSS_TX_FAILURE;
286 }
287
288 if (nss_vlan_verify_if_num(vlan_if_num) == false) {
289 nss_warning("%p: received invalid interface %d\n", nss_ctx, vlan_if_num);
290 return NSS_TX_FAILURE;
291 }
292
293 nvm.msg.if_msg.vsi_assign.vsi = vsi;
294 nss_vlan_msg_init(&nvm, vlan_if_num, NSS_IF_VSI_ASSIGN,
295 sizeof(struct nss_if_vsi_assign), NULL, NULL);
296
297 return nss_vlan_tx_msg_sync(nss_ctx, &nvm);
298}
299EXPORT_SYMBOL(nss_vlan_tx_vsi_attach_msg);
300
301/*
302 * nss_vlan_tx_vsi_detach_msg
303 * API to send VSI detach message to NSS FW
304 */
305nss_tx_status_t nss_vlan_tx_vsi_detach_msg(uint32_t vlan_if_num, uint32_t vsi)
306{
307 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
308 struct nss_vlan_msg nvm;
309
310 if (!nss_ctx) {
311 nss_warning("Can't get nss context\n");
312 return NSS_TX_FAILURE;
313 }
314
315 if (nss_vlan_verify_if_num(vlan_if_num) == false) {
316 nss_warning("%p: received invalid interface %d\n", nss_ctx, vlan_if_num);
317 return NSS_TX_FAILURE;
318 }
319
320 nvm.msg.if_msg.vsi_unassign.vsi = vsi;
321 nss_vlan_msg_init(&nvm, vlan_if_num, NSS_IF_VSI_UNASSIGN,
322 sizeof(struct nss_if_vsi_unassign), NULL, NULL);
323
324 return nss_vlan_tx_msg_sync(nss_ctx, &nvm);
325}
326EXPORT_SYMBOL(nss_vlan_tx_vsi_detach_msg);
327
328/*
329 * nss_vlan_tx_add_tag_msg
330 * API to send vlan add tag message to NSS FW
331 */
332nss_tx_status_t nss_vlan_tx_add_tag_msg(uint32_t vlan_if_num, uint32_t vlan_tag, uint32_t next_hop, uint32_t physical_dev)
333{
334 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
335 struct nss_vlan_msg nvm;
336
337 if (!nss_ctx) {
338 nss_warning("Can't get nss context\n");
339 return NSS_TX_FAILURE;
340 }
341
342 if (nss_vlan_verify_if_num(vlan_if_num) == false) {
343 nss_warning("%p: received invalid interface %d\n", nss_ctx, vlan_if_num);
344 return NSS_TX_FAILURE;
345 }
346
347 nvm.msg.add_tag.next_hop = next_hop;
348 nvm.msg.add_tag.if_num = physical_dev;
349 nvm.msg.add_tag.vlan_tag = vlan_tag;
350 nss_vlan_msg_init(&nvm, vlan_if_num, NSS_VLAN_MSG_ADD_TAG,
351 sizeof(struct nss_vlan_msg_add_tag), NULL, NULL);
352
353 return nss_vlan_tx_msg_sync(nss_ctx, &nvm);
354}
355EXPORT_SYMBOL(nss_vlan_tx_add_tag_msg);
356
357/**
358 * @brief Register to send/receive vlan messages to NSS
359 *
360 * @param if_num NSS interface number
361 * @param vlan_data_callback Callback for vlan data
362 * @param netdev netdevice associated with the vlan interface
363 * @param features denotes the skb types supported by this interface
364 *
365 * @return nss_ctx_instance* NSS context
366 */
367struct nss_ctx_instance *nss_register_vlan_if(uint32_t if_num, nss_vlan_callback_t vlan_data_callback,
368 struct net_device *netdev, uint32_t features, void *app_ctx)
369{
Stephen Wang84e0e992016-09-07 12:31:40 -0700370 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
371
Stephen Wangbce06672016-12-02 15:11:35 -0800372 nss_assert(nss_vlan_verify_if_num(if_num));
373
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700374 nss_core_register_subsys_dp(nss_ctx, if_num, vlan_data_callback, NULL, app_ctx, netdev, features);
Stephen Wangbce06672016-12-02 15:11:35 -0800375
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700376 nss_core_register_handler(nss_ctx, if_num, nss_vlan_handler, app_ctx);
Stephen Wangbce06672016-12-02 15:11:35 -0800377
Stephen Wang84e0e992016-09-07 12:31:40 -0700378 return nss_ctx;
Stephen Wangbce06672016-12-02 15:11:35 -0800379}
380EXPORT_SYMBOL(nss_register_vlan_if);
381
382/*
383 * nss_unregister_vlan_if()
384 */
385void nss_unregister_vlan_if(uint32_t if_num)
386{
Stephen Wang84e0e992016-09-07 12:31:40 -0700387 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
388
Stephen Wangbce06672016-12-02 15:11:35 -0800389 nss_assert(nss_vlan_verify_if_num(if_num));
390
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700391 nss_core_unregister_subsys_dp(nss_ctx, if_num);
Stephen Wangbce06672016-12-02 15:11:35 -0800392
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700393 nss_core_unregister_handler(nss_ctx, if_num);
Stephen Wangbce06672016-12-02 15:11:35 -0800394}
395EXPORT_SYMBOL(nss_unregister_vlan_if);
396
397/*
398 * nss_vlan_register_handler()
399 * debugfs stats msg handler received on static vlan interface
400 */
401void nss_vlan_register_handler(void)
402{
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700403 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
404
Stephen Wangbce06672016-12-02 15:11:35 -0800405 nss_info("nss_vlan_register_handler\n");
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700406 nss_core_register_handler(nss_ctx, NSS_VLAN_INTERFACE, nss_vlan_handler, NULL);
Stephen Wangbce06672016-12-02 15:11:35 -0800407
408 sema_init(&vlan_pvt.sem, 1);
409 init_completion(&vlan_pvt.complete);
410}
411EXPORT_SYMBOL(nss_vlan_register_handler);