blob: d562127b2657fd515b04d8ac435ddcbbba1be2b6 [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/*
33 * nss_vlan_verify_if_num()
34 * Verify if_num passed to us.
35 */
36static bool nss_vlan_verify_if_num(uint32_t if_num)
37{
38 if (!nss_is_dynamic_interface(if_num)) {
39 return false;
40 }
41
42 if (nss_dynamic_interface_get_type(if_num) != NSS_DYNAMIC_INTERFACE_TYPE_VLAN) {
43 return false;
44 }
45
46 return true;
47}
48
49/*
50 * nss_vlan_handler()
51 * Handle NSS -> HLOS messages for vlan
52 */
53static void nss_vlan_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, void *app_data)
54{
55 struct nss_vlan_msg *nvm = (struct nss_vlan_msg *)ncm;
56 nss_vlan_msg_callback_t cb;
57
58 nss_assert(nss_vlan_verify_if_num(ncm->interface));
59
60 /*
61 * Is this a valid request/response packet?
62 */
63 if (ncm->type >= NSS_VLAN_MSG_TYPE_MAX) {
64 nss_warning("%p: received invalid message %d for vlan interface", nss_ctx, ncm->type);
65 return;
66 }
67
68 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_vlan_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 * Update the callback and app_data for NOTIFY messages, vlan sends all notify messages
75 * to the same callback/app_data.
76 */
77 if (ncm->response == NSS_CMM_RESPONSE_NOTIFY) {
78 ncm->cb = (nss_ptr_t)nss_ctx->nss_top->vlan_callback;
79 ncm->app_data = (nss_ptr_t)app_data;
80 }
81
82 /*
83 * Log failures
84 */
85 nss_core_log_msg_failures(nss_ctx, ncm);
86
87 /*
88 * Do we have a call back
89 */
90 if (!ncm->cb) {
91 return;
92 }
93
94 /*
95 * callback
96 */
97 cb = (nss_vlan_msg_callback_t)ncm->cb;
98 cb((void *)ncm->app_data, nvm);
99}
100
101/*
102 * nss_vlan_callback()
103 * Callback to handle the completion of NSS->HLOS messages.
104 */
105static void nss_vlan_callback(void *app_data, struct nss_vlan_msg *nvm)
106{
107 nss_vlan_msg_callback_t callback = (nss_vlan_msg_callback_t)vlan_pvt.cb;
108 void *data = vlan_pvt.app_data;
109
110 vlan_pvt.response = NSS_TX_SUCCESS;
111 vlan_pvt.cb = NULL;
112 vlan_pvt.app_data = NULL;
113
114 if (nvm->cm.response != NSS_CMN_RESPONSE_ACK) {
115 nss_warning("vlan error response %d\n", nvm->cm.response);
116 vlan_pvt.response = nvm->cm.response;
117 }
118
119 if (callback) {
120 callback(data, nvm);
121 }
122 complete(&vlan_pvt.complete);
123}
124
125/*
126 * nss_vlan_tx_msg()
127 * Transmit a vlan message to NSSFW
128 */
129nss_tx_status_t nss_vlan_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_vlan_msg *msg)
130{
131 struct nss_vlan_msg *nm;
132 struct nss_cmn_msg *ncm = &msg->cm;
133 struct sk_buff *nbuf;
134 int32_t status;
135
136 NSS_VERIFY_CTX_MAGIC(nss_ctx);
137 if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
138 nss_warning("%p: vlan msg dropped as core not ready", nss_ctx);
139 return NSS_TX_FAILURE_NOT_READY;
140 }
141
142 /*
143 * Sanity check the message
144 */
145 if (!nss_vlan_verify_if_num(ncm->interface)) {
146 nss_warning("%p: tx request for interface that is not a vlan: %d", nss_ctx, ncm->interface);
147 return NSS_TX_FAILURE;
148 }
149
150 if (ncm->type >= NSS_VLAN_MSG_TYPE_MAX) {
151 nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
152 return NSS_TX_FAILURE;
153 }
154
155 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_vlan_msg)) {
156 nss_warning("%p: message length is invalid: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
157 return NSS_TX_FAILURE;
158 }
159
160 nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
161 if (unlikely(!nbuf)) {
162 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
163 nss_warning("%p: msg dropped as command allocation failed", nss_ctx);
164 return NSS_TX_FAILURE;
165 }
166
167 /*
168 * Copy the message to our skb
169 */
170 nm = (struct nss_vlan_msg *)skb_put(nbuf, sizeof(struct nss_vlan_msg));
171 memcpy(nm, msg, sizeof(struct nss_vlan_msg));
172
173 status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0);
174 if (status != NSS_CORE_STATUS_SUCCESS) {
175 dev_kfree_skb_any(nbuf);
176 nss_warning("%p: Unable to enqueue 'vlan message'", nss_ctx);
177 return NSS_TX_FAILURE;
178 }
179
180 nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
181
182 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CMD_REQ]);
183 return NSS_TX_SUCCESS;
184}
185EXPORT_SYMBOL(nss_vlan_tx_msg);
186
187/*
188 * nss_vlan_tx_msg_sync()
189 * Transmit a vlan message to NSS firmware synchronously.
190 */
191nss_tx_status_t nss_vlan_tx_msg_sync(struct nss_ctx_instance *nss_ctx, struct nss_vlan_msg *nvm)
192{
193 nss_tx_status_t status;
194 int ret = 0;
195
196 down(&vlan_pvt.sem);
197 vlan_pvt.cb = (void *)nvm->cm.cb;
198 vlan_pvt.app_data = (void *)nvm->cm.app_data;
199
200 nvm->cm.cb = (nss_ptr_t)nss_vlan_callback;
201 nvm->cm.app_data = (nss_ptr_t)NULL;
202
203 status = nss_vlan_tx_msg(nss_ctx, nvm);
204 if (status != NSS_TX_SUCCESS) {
205 nss_warning("%p: vlan_tx_msg failed\n", nss_ctx);
206 up(&vlan_pvt.sem);
207 return status;
208 }
209
210 ret = wait_for_completion_timeout(&vlan_pvt.complete, msecs_to_jiffies(NSS_VLAN_TX_TIMEOUT));
211 if (!ret) {
212 nss_warning("%p: vlan msg tx failed due to timeout\n", nss_ctx);
213 vlan_pvt.response = NSS_TX_FAILURE;
214 }
215
216 status = vlan_pvt.response;
217 up(&vlan_pvt.sem);
218 return status;
219}
220EXPORT_SYMBOL(nss_vlan_tx_msg_sync);
221
222/*
223 * nss_vlan_get_context()
224 */
225struct nss_ctx_instance *nss_vlan_get_context(void)
226{
227 return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.vlan_handler_id];
228}
229EXPORT_SYMBOL(nss_vlan_get_context);
230
231/*
232 * 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);