blob: 40b262393e5d6744cd87673387b4ae7a59089823 [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"
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 */
Suruchi Agarwale4ad24a2018-06-11 12:03:46 +053086 if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) {
Stephen Wangbce06672016-12-02 15:11:35 -080087 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{
Stephen Wangbce06672016-12-02 15:11:35 -0800140 struct nss_cmn_msg *ncm = &msg->cm;
Stephen Wangbce06672016-12-02 15:11:35 -0800141
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
Stephen Wang3e2dbd12018-03-14 17:28:17 -0700155 return nss_core_send_cmd(nss_ctx, msg, sizeof(*msg), NSS_NBUF_PAYLOAD_SIZE);
Stephen Wangbce06672016-12-02 15:11:35 -0800156}
157EXPORT_SYMBOL(nss_vlan_tx_msg);
158
159/*
160 * nss_vlan_tx_msg_sync()
161 * Transmit a vlan message to NSS firmware synchronously.
162 */
163nss_tx_status_t nss_vlan_tx_msg_sync(struct nss_ctx_instance *nss_ctx, struct nss_vlan_msg *nvm)
164{
165 nss_tx_status_t status;
166 int ret = 0;
167
168 down(&vlan_pvt.sem);
169 vlan_pvt.cb = (void *)nvm->cm.cb;
170 vlan_pvt.app_data = (void *)nvm->cm.app_data;
171
172 nvm->cm.cb = (nss_ptr_t)nss_vlan_callback;
173 nvm->cm.app_data = (nss_ptr_t)NULL;
174
175 status = nss_vlan_tx_msg(nss_ctx, nvm);
176 if (status != NSS_TX_SUCCESS) {
177 nss_warning("%p: vlan_tx_msg failed\n", nss_ctx);
178 up(&vlan_pvt.sem);
179 return status;
180 }
181
182 ret = wait_for_completion_timeout(&vlan_pvt.complete, msecs_to_jiffies(NSS_VLAN_TX_TIMEOUT));
183 if (!ret) {
184 nss_warning("%p: vlan msg tx failed due to timeout\n", nss_ctx);
185 vlan_pvt.response = NSS_TX_FAILURE;
186 }
187
188 status = vlan_pvt.response;
189 up(&vlan_pvt.sem);
190 return status;
191}
192EXPORT_SYMBOL(nss_vlan_tx_msg_sync);
193
194/*
Stephen Wangbce06672016-12-02 15:11:35 -0800195 * nss_vlan_msg_init()
196 * Initialize nss_vlan_msg.
197 */
198void nss_vlan_msg_init(struct nss_vlan_msg *ncm, uint16_t if_num, uint32_t type, uint32_t len, void *cb, void *app_data)
199{
200 nss_cmn_msg_init(&ncm->cm, if_num, type, len, cb, app_data);
201}
202EXPORT_SYMBOL(nss_vlan_msg_init);
203
204/*
205 * nss_vlan_tx_change_mtu_msg
206 * API to send change mtu message to NSS FW
207 */
208nss_tx_status_t nss_vlan_tx_set_mtu_msg(uint32_t vlan_if_num, uint32_t mtu)
209{
210 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
211 struct nss_vlan_msg nvm;
212 struct nss_if_mtu_change *nimc;
213
214 if (!nss_ctx) {
215 nss_warning("Can't get nss context\n");
216 return NSS_TX_FAILURE;
217 }
218
219 if (nss_vlan_verify_if_num(vlan_if_num) == false) {
220 nss_warning("%p: received invalid interface %d", nss_ctx, vlan_if_num);
221 return NSS_TX_FAILURE;
222 }
223
224 nss_vlan_msg_init(&nvm, vlan_if_num, NSS_IF_MTU_CHANGE,
225 sizeof(struct nss_if_mtu_change), NULL, NULL);
226
227 nimc = &nvm.msg.if_msg.mtu_change;
228 nimc->min_buf_size = (uint16_t)mtu;
229
230 return nss_vlan_tx_msg_sync(nss_ctx, &nvm);
231}
232EXPORT_SYMBOL(nss_vlan_tx_set_mtu_msg);
233
234/*
235 * nss_vlan_tx_set_mac_addr_msg
236 * API to send change mac addr message to NSS FW
237 */
238nss_tx_status_t nss_vlan_tx_set_mac_addr_msg(uint32_t vlan_if_num, uint8_t *addr)
239{
240 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
241 struct nss_vlan_msg nvm;
242 struct nss_if_mac_address_set *nmas;
243
244 if (!nss_ctx) {
245 nss_warning("Can't get nss context\n");
246 return NSS_TX_FAILURE;
247 }
248
249 if (nss_vlan_verify_if_num(vlan_if_num) == false) {
250 nss_warning("%p: received invalid interface %d", nss_ctx, vlan_if_num);
251 return NSS_TX_FAILURE;
252 }
253
254 nss_vlan_msg_init(&nvm, vlan_if_num, NSS_IF_MAC_ADDR_SET,
255 sizeof(struct nss_if_mac_address_set), NULL, NULL);
256
257 nmas = &nvm.msg.if_msg.mac_address_set;
258 memcpy(nmas->mac_addr, addr, ETH_ALEN);
259 return nss_vlan_tx_msg_sync(nss_ctx, &nvm);
260}
261EXPORT_SYMBOL(nss_vlan_tx_set_mac_addr_msg);
262
263/*
264 * nss_vlan_tx_vsi_attach_msg
265 * API to send VSI attach message to NSS FW
266 */
267nss_tx_status_t nss_vlan_tx_vsi_attach_msg(uint32_t vlan_if_num, uint32_t vsi)
268{
269 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
270 struct nss_vlan_msg nvm;
271
272 if (!nss_ctx) {
273 nss_warning("Can't get nss context\n");
274 return NSS_TX_FAILURE;
275 }
276
277 if (nss_vlan_verify_if_num(vlan_if_num) == false) {
278 nss_warning("%p: received invalid interface %d\n", nss_ctx, vlan_if_num);
279 return NSS_TX_FAILURE;
280 }
281
282 nvm.msg.if_msg.vsi_assign.vsi = vsi;
283 nss_vlan_msg_init(&nvm, vlan_if_num, NSS_IF_VSI_ASSIGN,
284 sizeof(struct nss_if_vsi_assign), NULL, NULL);
285
286 return nss_vlan_tx_msg_sync(nss_ctx, &nvm);
287}
288EXPORT_SYMBOL(nss_vlan_tx_vsi_attach_msg);
289
290/*
291 * nss_vlan_tx_vsi_detach_msg
292 * API to send VSI detach message to NSS FW
293 */
294nss_tx_status_t nss_vlan_tx_vsi_detach_msg(uint32_t vlan_if_num, uint32_t vsi)
295{
296 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
297 struct nss_vlan_msg nvm;
298
299 if (!nss_ctx) {
300 nss_warning("Can't get nss context\n");
301 return NSS_TX_FAILURE;
302 }
303
304 if (nss_vlan_verify_if_num(vlan_if_num) == false) {
305 nss_warning("%p: received invalid interface %d\n", nss_ctx, vlan_if_num);
306 return NSS_TX_FAILURE;
307 }
308
309 nvm.msg.if_msg.vsi_unassign.vsi = vsi;
310 nss_vlan_msg_init(&nvm, vlan_if_num, NSS_IF_VSI_UNASSIGN,
311 sizeof(struct nss_if_vsi_unassign), NULL, NULL);
312
313 return nss_vlan_tx_msg_sync(nss_ctx, &nvm);
314}
315EXPORT_SYMBOL(nss_vlan_tx_vsi_detach_msg);
316
317/*
318 * nss_vlan_tx_add_tag_msg
319 * API to send vlan add tag message to NSS FW
320 */
321nss_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)
322{
323 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
324 struct nss_vlan_msg nvm;
325
326 if (!nss_ctx) {
327 nss_warning("Can't get nss context\n");
328 return NSS_TX_FAILURE;
329 }
330
331 if (nss_vlan_verify_if_num(vlan_if_num) == false) {
332 nss_warning("%p: received invalid interface %d\n", nss_ctx, vlan_if_num);
333 return NSS_TX_FAILURE;
334 }
335
336 nvm.msg.add_tag.next_hop = next_hop;
337 nvm.msg.add_tag.if_num = physical_dev;
338 nvm.msg.add_tag.vlan_tag = vlan_tag;
339 nss_vlan_msg_init(&nvm, vlan_if_num, NSS_VLAN_MSG_ADD_TAG,
340 sizeof(struct nss_vlan_msg_add_tag), NULL, NULL);
341
342 return nss_vlan_tx_msg_sync(nss_ctx, &nvm);
343}
344EXPORT_SYMBOL(nss_vlan_tx_add_tag_msg);
345
346/**
347 * @brief Register to send/receive vlan messages to NSS
348 *
349 * @param if_num NSS interface number
350 * @param vlan_data_callback Callback for vlan data
351 * @param netdev netdevice associated with the vlan interface
352 * @param features denotes the skb types supported by this interface
353 *
354 * @return nss_ctx_instance* NSS context
355 */
356struct nss_ctx_instance *nss_register_vlan_if(uint32_t if_num, nss_vlan_callback_t vlan_data_callback,
357 struct net_device *netdev, uint32_t features, void *app_ctx)
358{
Stephen Wang84e0e992016-09-07 12:31:40 -0700359 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
360
Stephen Wangbce06672016-12-02 15:11:35 -0800361 nss_assert(nss_vlan_verify_if_num(if_num));
362
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700363 nss_core_register_subsys_dp(nss_ctx, if_num, vlan_data_callback, NULL, app_ctx, netdev, features);
Stephen Wangbce06672016-12-02 15:11:35 -0800364
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700365 nss_core_register_handler(nss_ctx, if_num, nss_vlan_handler, app_ctx);
Stephen Wangbce06672016-12-02 15:11:35 -0800366
Stephen Wang84e0e992016-09-07 12:31:40 -0700367 return nss_ctx;
Stephen Wangbce06672016-12-02 15:11:35 -0800368}
369EXPORT_SYMBOL(nss_register_vlan_if);
370
371/*
372 * nss_unregister_vlan_if()
373 */
374void nss_unregister_vlan_if(uint32_t if_num)
375{
Stephen Wang84e0e992016-09-07 12:31:40 -0700376 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
377
Stephen Wangbce06672016-12-02 15:11:35 -0800378 nss_assert(nss_vlan_verify_if_num(if_num));
379
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700380 nss_core_unregister_subsys_dp(nss_ctx, if_num);
Stephen Wangbce06672016-12-02 15:11:35 -0800381
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700382 nss_core_unregister_handler(nss_ctx, if_num);
Stephen Wangbce06672016-12-02 15:11:35 -0800383}
384EXPORT_SYMBOL(nss_unregister_vlan_if);
385
386/*
387 * nss_vlan_register_handler()
388 * debugfs stats msg handler received on static vlan interface
389 */
390void nss_vlan_register_handler(void)
391{
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700392 struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
393
Stephen Wangbce06672016-12-02 15:11:35 -0800394 nss_info("nss_vlan_register_handler\n");
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700395 nss_core_register_handler(nss_ctx, NSS_VLAN_INTERFACE, nss_vlan_handler, NULL);
Stephen Wangbce06672016-12-02 15:11:35 -0800396
397 sema_init(&vlan_pvt.sem, 1);
398 init_completion(&vlan_pvt.complete);
399}
400EXPORT_SYMBOL(nss_vlan_register_handler);