blob: 1fd5d3fb6c5cdae9584861e9e8208489894320fe [file] [log] [blame]
Stephen Wangbce06672016-12-02 15:11:35 -08001/*
2 **************************************************************************
3 * Copyright (c) 2017, The Linux Foundation. All rights reserved.
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 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"
18
19#define NSS_VLAN_TX_TIMEOUT 1000 /* 1 Second */
20
21/*
22 * Private data structure
23 */
24static struct nss_vlan_pvt {
25 struct semaphore sem;
26 struct completion complete;
27 int response;
28 void *cb;
29 void *app_data;
30} vlan_pvt;
31
32/*
Stephen Wange8b8d0d2017-02-24 17:05:22 -080033 * nss_vlan_get_context()
34 */
35struct nss_ctx_instance *nss_vlan_get_context(void)
36{
37 return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.vlan_handler_id];
38}
39EXPORT_SYMBOL(nss_vlan_get_context);
40
41/*
Stephen Wangbce06672016-12-02 15:11:35 -080042 * nss_vlan_verify_if_num()
43 * Verify if_num passed to us.
44 */
45static bool nss_vlan_verify_if_num(uint32_t if_num)
46{
47 if (!nss_is_dynamic_interface(if_num)) {
48 return false;
49 }
50
Stephen Wange8b8d0d2017-02-24 17:05:22 -080051 if (nss_dynamic_interface_get_type(nss_vlan_get_context(), if_num) != NSS_DYNAMIC_INTERFACE_TYPE_VLAN) {
Stephen Wangbce06672016-12-02 15:11:35 -080052 return false;
53 }
54
55 return true;
56}
57
58/*
59 * nss_vlan_handler()
60 * Handle NSS -> HLOS messages for vlan
61 */
62static void nss_vlan_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, void *app_data)
63{
64 struct nss_vlan_msg *nvm = (struct nss_vlan_msg *)ncm;
65 nss_vlan_msg_callback_t cb;
66
67 nss_assert(nss_vlan_verify_if_num(ncm->interface));
68
69 /*
70 * Is this a valid request/response packet?
71 */
72 if (ncm->type >= NSS_VLAN_MSG_TYPE_MAX) {
73 nss_warning("%p: received invalid message %d for vlan interface", nss_ctx, ncm->type);
74 return;
75 }
76
77 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_vlan_msg)) {
78 nss_warning("%p: length of message is greater than required: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
79 return;
80 }
81
82 /*
83 * Update the callback and app_data for NOTIFY messages, vlan sends all notify messages
84 * to the same callback/app_data.
85 */
86 if (ncm->response == NSS_CMM_RESPONSE_NOTIFY) {
87 ncm->cb = (nss_ptr_t)nss_ctx->nss_top->vlan_callback;
88 ncm->app_data = (nss_ptr_t)app_data;
89 }
90
91 /*
92 * Log failures
93 */
94 nss_core_log_msg_failures(nss_ctx, ncm);
95
96 /*
97 * Do we have a call back
98 */
99 if (!ncm->cb) {
100 return;
101 }
102
103 /*
104 * callback
105 */
106 cb = (nss_vlan_msg_callback_t)ncm->cb;
107 cb((void *)ncm->app_data, nvm);
108}
109
110/*
111 * nss_vlan_callback()
112 * Callback to handle the completion of NSS->HLOS messages.
113 */
114static void nss_vlan_callback(void *app_data, struct nss_vlan_msg *nvm)
115{
116 nss_vlan_msg_callback_t callback = (nss_vlan_msg_callback_t)vlan_pvt.cb;
117 void *data = vlan_pvt.app_data;
118
119 vlan_pvt.response = NSS_TX_SUCCESS;
120 vlan_pvt.cb = NULL;
121 vlan_pvt.app_data = NULL;
122
123 if (nvm->cm.response != NSS_CMN_RESPONSE_ACK) {
124 nss_warning("vlan error response %d\n", nvm->cm.response);
125 vlan_pvt.response = nvm->cm.response;
126 }
127
128 if (callback) {
129 callback(data, nvm);
130 }
131 complete(&vlan_pvt.complete);
132}
133
134/*
135 * nss_vlan_tx_msg()
136 * Transmit a vlan message to NSSFW
137 */
138nss_tx_status_t nss_vlan_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_vlan_msg *msg)
139{
140 struct nss_vlan_msg *nm;
141 struct nss_cmn_msg *ncm = &msg->cm;
142 struct sk_buff *nbuf;
143 int32_t status;
144
145 NSS_VERIFY_CTX_MAGIC(nss_ctx);
146 if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
147 nss_warning("%p: vlan msg dropped as core not ready", nss_ctx);
148 return NSS_TX_FAILURE_NOT_READY;
149 }
150
151 /*
152 * Sanity check the message
153 */
154 if (!nss_vlan_verify_if_num(ncm->interface)) {
155 nss_warning("%p: tx request for interface that is not a vlan: %d", nss_ctx, ncm->interface);
156 return NSS_TX_FAILURE;
157 }
158
159 if (ncm->type >= NSS_VLAN_MSG_TYPE_MAX) {
160 nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
161 return NSS_TX_FAILURE;
162 }
163
164 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_vlan_msg)) {
165 nss_warning("%p: message length is invalid: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
166 return NSS_TX_FAILURE;
167 }
168
169 nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
170 if (unlikely(!nbuf)) {
171 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
172 nss_warning("%p: msg dropped as command allocation failed", nss_ctx);
173 return NSS_TX_FAILURE;
174 }
175
176 /*
177 * Copy the message to our skb
178 */
179 nm = (struct nss_vlan_msg *)skb_put(nbuf, sizeof(struct nss_vlan_msg));
180 memcpy(nm, msg, sizeof(struct nss_vlan_msg));
181
182 status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0);
183 if (status != NSS_CORE_STATUS_SUCCESS) {
184 dev_kfree_skb_any(nbuf);
185 nss_warning("%p: Unable to enqueue 'vlan message'", nss_ctx);
186 return NSS_TX_FAILURE;
187 }
188
189 nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
190
191 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CMD_REQ]);
192 return NSS_TX_SUCCESS;
193}
194EXPORT_SYMBOL(nss_vlan_tx_msg);
195
196/*
197 * nss_vlan_tx_msg_sync()
198 * Transmit a vlan message to NSS firmware synchronously.
199 */
200nss_tx_status_t nss_vlan_tx_msg_sync(struct nss_ctx_instance *nss_ctx, struct nss_vlan_msg *nvm)
201{
202 nss_tx_status_t status;
203 int ret = 0;
204
205 down(&vlan_pvt.sem);
206 vlan_pvt.cb = (void *)nvm->cm.cb;
207 vlan_pvt.app_data = (void *)nvm->cm.app_data;
208
209 nvm->cm.cb = (nss_ptr_t)nss_vlan_callback;
210 nvm->cm.app_data = (nss_ptr_t)NULL;
211
212 status = nss_vlan_tx_msg(nss_ctx, nvm);
213 if (status != NSS_TX_SUCCESS) {
214 nss_warning("%p: vlan_tx_msg failed\n", nss_ctx);
215 up(&vlan_pvt.sem);
216 return status;
217 }
218
219 ret = wait_for_completion_timeout(&vlan_pvt.complete, msecs_to_jiffies(NSS_VLAN_TX_TIMEOUT));
220 if (!ret) {
221 nss_warning("%p: vlan msg tx failed due to timeout\n", nss_ctx);
222 vlan_pvt.response = NSS_TX_FAILURE;
223 }
224
225 status = vlan_pvt.response;
226 up(&vlan_pvt.sem);
227 return status;
228}
229EXPORT_SYMBOL(nss_vlan_tx_msg_sync);
230
231/*
Stephen Wangbce06672016-12-02 15:11:35 -0800232 * nss_vlan_msg_init()
233 * Initialize nss_vlan_msg.
234 */
235void nss_vlan_msg_init(struct nss_vlan_msg *ncm, uint16_t if_num, uint32_t type, uint32_t len, void *cb, void *app_data)
236{
237 nss_cmn_msg_init(&ncm->cm, if_num, type, len, cb, app_data);
238}
239EXPORT_SYMBOL(nss_vlan_msg_init);
240
241/*
242 * nss_vlan_tx_change_mtu_msg
243 * API to send change mtu message to NSS FW
244 */
245nss_tx_status_t nss_vlan_tx_set_mtu_msg(uint32_t vlan_if_num, uint32_t mtu)
246{
247 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
248 struct nss_vlan_msg nvm;
249 struct nss_if_mtu_change *nimc;
250
251 if (!nss_ctx) {
252 nss_warning("Can't get nss context\n");
253 return NSS_TX_FAILURE;
254 }
255
256 if (nss_vlan_verify_if_num(vlan_if_num) == false) {
257 nss_warning("%p: received invalid interface %d", nss_ctx, vlan_if_num);
258 return NSS_TX_FAILURE;
259 }
260
261 nss_vlan_msg_init(&nvm, vlan_if_num, NSS_IF_MTU_CHANGE,
262 sizeof(struct nss_if_mtu_change), NULL, NULL);
263
264 nimc = &nvm.msg.if_msg.mtu_change;
265 nimc->min_buf_size = (uint16_t)mtu;
266
267 return nss_vlan_tx_msg_sync(nss_ctx, &nvm);
268}
269EXPORT_SYMBOL(nss_vlan_tx_set_mtu_msg);
270
271/*
272 * nss_vlan_tx_set_mac_addr_msg
273 * API to send change mac addr message to NSS FW
274 */
275nss_tx_status_t nss_vlan_tx_set_mac_addr_msg(uint32_t vlan_if_num, uint8_t *addr)
276{
277 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
278 struct nss_vlan_msg nvm;
279 struct nss_if_mac_address_set *nmas;
280
281 if (!nss_ctx) {
282 nss_warning("Can't get nss context\n");
283 return NSS_TX_FAILURE;
284 }
285
286 if (nss_vlan_verify_if_num(vlan_if_num) == false) {
287 nss_warning("%p: received invalid interface %d", nss_ctx, vlan_if_num);
288 return NSS_TX_FAILURE;
289 }
290
291 nss_vlan_msg_init(&nvm, vlan_if_num, NSS_IF_MAC_ADDR_SET,
292 sizeof(struct nss_if_mac_address_set), NULL, NULL);
293
294 nmas = &nvm.msg.if_msg.mac_address_set;
295 memcpy(nmas->mac_addr, addr, ETH_ALEN);
296 return nss_vlan_tx_msg_sync(nss_ctx, &nvm);
297}
298EXPORT_SYMBOL(nss_vlan_tx_set_mac_addr_msg);
299
300/*
301 * nss_vlan_tx_vsi_attach_msg
302 * API to send VSI attach message to NSS FW
303 */
304nss_tx_status_t nss_vlan_tx_vsi_attach_msg(uint32_t vlan_if_num, uint32_t vsi)
305{
306 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
307 struct nss_vlan_msg nvm;
308
309 if (!nss_ctx) {
310 nss_warning("Can't get nss context\n");
311 return NSS_TX_FAILURE;
312 }
313
314 if (nss_vlan_verify_if_num(vlan_if_num) == false) {
315 nss_warning("%p: received invalid interface %d\n", nss_ctx, vlan_if_num);
316 return NSS_TX_FAILURE;
317 }
318
319 nvm.msg.if_msg.vsi_assign.vsi = vsi;
320 nss_vlan_msg_init(&nvm, vlan_if_num, NSS_IF_VSI_ASSIGN,
321 sizeof(struct nss_if_vsi_assign), NULL, NULL);
322
323 return nss_vlan_tx_msg_sync(nss_ctx, &nvm);
324}
325EXPORT_SYMBOL(nss_vlan_tx_vsi_attach_msg);
326
327/*
328 * nss_vlan_tx_vsi_detach_msg
329 * API to send VSI detach message to NSS FW
330 */
331nss_tx_status_t nss_vlan_tx_vsi_detach_msg(uint32_t vlan_if_num, uint32_t vsi)
332{
333 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
334 struct nss_vlan_msg nvm;
335
336 if (!nss_ctx) {
337 nss_warning("Can't get nss context\n");
338 return NSS_TX_FAILURE;
339 }
340
341 if (nss_vlan_verify_if_num(vlan_if_num) == false) {
342 nss_warning("%p: received invalid interface %d\n", nss_ctx, vlan_if_num);
343 return NSS_TX_FAILURE;
344 }
345
346 nvm.msg.if_msg.vsi_unassign.vsi = vsi;
347 nss_vlan_msg_init(&nvm, vlan_if_num, NSS_IF_VSI_UNASSIGN,
348 sizeof(struct nss_if_vsi_unassign), NULL, NULL);
349
350 return nss_vlan_tx_msg_sync(nss_ctx, &nvm);
351}
352EXPORT_SYMBOL(nss_vlan_tx_vsi_detach_msg);
353
354/*
355 * nss_vlan_tx_add_tag_msg
356 * API to send vlan add tag message to NSS FW
357 */
358nss_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)
359{
360 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
361 struct nss_vlan_msg nvm;
362
363 if (!nss_ctx) {
364 nss_warning("Can't get nss context\n");
365 return NSS_TX_FAILURE;
366 }
367
368 if (nss_vlan_verify_if_num(vlan_if_num) == false) {
369 nss_warning("%p: received invalid interface %d\n", nss_ctx, vlan_if_num);
370 return NSS_TX_FAILURE;
371 }
372
373 nvm.msg.add_tag.next_hop = next_hop;
374 nvm.msg.add_tag.if_num = physical_dev;
375 nvm.msg.add_tag.vlan_tag = vlan_tag;
376 nss_vlan_msg_init(&nvm, vlan_if_num, NSS_VLAN_MSG_ADD_TAG,
377 sizeof(struct nss_vlan_msg_add_tag), NULL, NULL);
378
379 return nss_vlan_tx_msg_sync(nss_ctx, &nvm);
380}
381EXPORT_SYMBOL(nss_vlan_tx_add_tag_msg);
382
383/**
384 * @brief Register to send/receive vlan messages to NSS
385 *
386 * @param if_num NSS interface number
387 * @param vlan_data_callback Callback for vlan data
388 * @param netdev netdevice associated with the vlan interface
389 * @param features denotes the skb types supported by this interface
390 *
391 * @return nss_ctx_instance* NSS context
392 */
393struct nss_ctx_instance *nss_register_vlan_if(uint32_t if_num, nss_vlan_callback_t vlan_data_callback,
394 struct net_device *netdev, uint32_t features, void *app_ctx)
395{
Stephen Wang84e0e992016-09-07 12:31:40 -0700396 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
397
Stephen Wangbce06672016-12-02 15:11:35 -0800398 nss_assert(nss_vlan_verify_if_num(if_num));
399
Stephen Wang84e0e992016-09-07 12:31:40 -0700400 nss_ctx->subsys_dp_register[if_num].ndev = netdev;
401 nss_ctx->subsys_dp_register[if_num].cb = vlan_data_callback;
402 nss_ctx->subsys_dp_register[if_num].app_data = app_ctx;
403 nss_ctx->subsys_dp_register[if_num].features = features;
Stephen Wangbce06672016-12-02 15:11:35 -0800404
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700405 nss_core_register_handler(nss_ctx, if_num, nss_vlan_handler, app_ctx);
Stephen Wangbce06672016-12-02 15:11:35 -0800406
Stephen Wang84e0e992016-09-07 12:31:40 -0700407 return nss_ctx;
Stephen Wangbce06672016-12-02 15:11:35 -0800408}
409EXPORT_SYMBOL(nss_register_vlan_if);
410
411/*
412 * nss_unregister_vlan_if()
413 */
414void nss_unregister_vlan_if(uint32_t if_num)
415{
Stephen Wang84e0e992016-09-07 12:31:40 -0700416 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
417
Stephen Wangbce06672016-12-02 15:11:35 -0800418 nss_assert(nss_vlan_verify_if_num(if_num));
419
Stephen Wang84e0e992016-09-07 12:31:40 -0700420 nss_ctx->subsys_dp_register[if_num].ndev = NULL;
421 nss_ctx->subsys_dp_register[if_num].cb = NULL;
422 nss_ctx->subsys_dp_register[if_num].app_data = NULL;
423 nss_ctx->subsys_dp_register[if_num].features = 0;
Stephen Wangbce06672016-12-02 15:11:35 -0800424
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700425 nss_core_unregister_handler(nss_ctx, if_num);
Stephen Wangbce06672016-12-02 15:11:35 -0800426}
427EXPORT_SYMBOL(nss_unregister_vlan_if);
428
429/*
430 * nss_vlan_register_handler()
431 * debugfs stats msg handler received on static vlan interface
432 */
433void nss_vlan_register_handler(void)
434{
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700435 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
436
Stephen Wangbce06672016-12-02 15:11:35 -0800437 nss_info("nss_vlan_register_handler\n");
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700438 nss_core_register_handler(nss_ctx, NSS_VLAN_INTERFACE, nss_vlan_handler, NULL);
Stephen Wangbce06672016-12-02 15:11:35 -0800439
440 sema_init(&vlan_pvt.sem, 1);
441 init_completion(&vlan_pvt.complete);
442}
443EXPORT_SYMBOL(nss_vlan_register_handler);