blob: d8174ded3ebe3d58c19d33861c9f810e50aa33fe [file] [log] [blame]
Apoorv Gupta9e184d42019-07-09 12:46:42 +05301/*
2 **************************************************************************
3 * Copyright (c) 2019, 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/*
18 * nss_vxlan.c
19 * NSS VxLAN driver interface APIs
20 */
21#include "nss_core.h"
22#include "nss_vxlan.h"
23#include "nss_cmn.h"
24#include "nss_tx_rx_common.h"
25#include "nss_vxlan_log.h"
26#include "nss_vxlan_stats.h"
27
28#define NSS_VXLAN_TX_TIMEOUT 3000
29
30/*
31 * Private data structure
32 */
33static struct {
34 struct semaphore sem; /* Semaphore structure. */
35 struct completion complete; /* Completion structure. */
36 int response; /* Response from FW. */
37 void *cb; /* Original cb for msgs. */
38 void *app_data; /* Original app_data for msgs. */
39} nss_vxlan_pvt;
40
41/*
42 * nss_vxlan_verify_if_num()
43 * Verify if_num passed to us.
44 */
45static bool nss_vxlan_verify_if_num(uint32_t if_num)
46{
47 uint32_t type;
48
49 if (if_num == NSS_VXLAN_INTERFACE) {
50 return true;
51 }
52
53 type = nss_dynamic_interface_get_type(nss_vxlan_get_ctx(), if_num);
54
55 return ((type == NSS_DYNAMIC_INTERFACE_TYPE_VXLAN_INNER) ||
56 (type == NSS_DYNAMIC_INTERFACE_TYPE_VXLAN_OUTER));
57}
58
59/*
60 * nss_vxlan_callback()
61 * Callback to handle the completion of NSS->HLOS messages.
62 */
63static void nss_vxlan_callback(void *app_data, struct nss_cmn_msg *msg)
64{
65 nss_vxlan_msg_callback_t callback = (nss_vxlan_msg_callback_t)nss_vxlan_pvt.cb;
66 void *data = nss_vxlan_pvt.app_data;
67
68 nss_vxlan_pvt.response = NSS_TX_SUCCESS;
69 nss_vxlan_pvt.cb = NULL;
70 nss_vxlan_pvt.app_data = NULL;
71
72 if (msg->response != NSS_CMN_RESPONSE_ACK) {
73 nss_warning("Vxlan Error response %d\n", msg->response);
74 nss_vxlan_pvt.response = NSS_TX_FAILURE;
75 }
76
77 if (callback) {
78 callback(data, msg);
79 }
80 complete(&nss_vxlan_pvt.complete);
81}
82
83/*
84 * nss_vxlan_handler()
85 * Handle NSS -> HLOS messages for vxlan.
86 */
87static void nss_vxlan_msg_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
88{
89 struct nss_vxlan_msg *nvm = (struct nss_vxlan_msg *)ncm;
90 nss_vxlan_msg_callback_t cb;
91
92 BUG_ON(!nss_vxlan_verify_if_num(ncm->interface));
93
94 /*
95 * Is this a valid request/response packet?
96 */
97 if (ncm->type >= NSS_VXLAN_MSG_TYPE_MAX) {
98 nss_warning("%p: received invalid message %d for vxlan interface", nss_ctx, ncm->type);
99 return;
100 }
101
102 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_vxlan_msg)) {
103 nss_warning("%p: Length of message is greater than required: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
104 return;
105 }
106
107 /*
108 * Log messages.
109 */
110 nss_core_log_msg_failures(nss_ctx, ncm);
111 nss_vxlan_log_rx_msg(nvm);
112
113 switch (nvm->cm.type) {
114 case NSS_VXLAN_MSG_TYPE_STATS_SYNC:
115 /*
116 * Update common node statistics
117 */
118 nss_vxlan_stats_sync(nss_ctx, nvm);
119 }
120
121 /*
122 * Update the callback for NOTIFY messages
123 */
124 if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) {
125 ncm->cb = (nss_ptr_t)nss_ctx->nss_top->if_rx_msg_callback[ncm->interface];
126 }
127
128 cb = (nss_vxlan_msg_callback_t)ncm->cb;
129
130 /*
131 * Do we have a callback?
132 */
133 if (!cb) {
134 nss_trace("%p: cb is null for interface %d\n", nss_ctx, ncm->interface);
135 return;
136 }
137
138 cb((void *)nss_ctx->subsys_dp_register[ncm->interface].ndev, ncm);
139}
140
141/*
142 * nss_vxlan_tx_msg()
143 * Transmit a vxlan message to NSS FW. Don't call this from softirq/interrupts.
144 */
145nss_tx_status_t nss_vxlan_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_vxlan_msg *nvm)
146{
147 struct nss_cmn_msg *ncm = &nvm->cm;
148
149 if (!nss_vxlan_verify_if_num(ncm->interface)) {
150 nss_warning("%p: wrong interface number %u\n", nss_ctx, nvm->cm.interface);
151 return NSS_TX_FAILURE_BAD_PARAM;
152 }
153
154 if (ncm->type >= NSS_VXLAN_MSG_TYPE_MAX) {
155 nss_warning("%p: wrong message type %u\n", nss_ctx, ncm->type);
156 return NSS_TX_FAILURE_BAD_PARAM;
157 }
158
159 /*
160 * Trace messages.
161 */
162 nss_vxlan_log_tx_msg(nvm);
163
164 return nss_core_send_cmd(nss_ctx, nvm, sizeof(*nvm), NSS_NBUF_PAYLOAD_SIZE);
165}
166EXPORT_SYMBOL(nss_vxlan_tx_msg);
167
168/*
169 * nss_vxlan_tx_msg_sync()
170 * Transmit a vxlan message to NSS firmware synchronously.
171 */
172nss_tx_status_t nss_vxlan_tx_msg_sync(struct nss_ctx_instance *nss_ctx, struct nss_vxlan_msg *nvm)
173{
174 nss_tx_status_t status;
175 int ret;
176
177 down(&nss_vxlan_pvt.sem);
178 nss_vxlan_pvt.cb = (void *)nvm->cm.cb;
179 nss_vxlan_pvt.app_data = (void *)nvm->cm.app_data;
180
181 nvm->cm.cb = (nss_ptr_t)nss_vxlan_callback;
182 nvm->cm.app_data = (nss_ptr_t)NULL;
183
184 status = nss_vxlan_tx_msg(nss_ctx, nvm);
185 if (status != NSS_TX_SUCCESS) {
186 nss_warning("%p: vxlan_tx_msg failed\n", nss_ctx);
187 up(&nss_vxlan_pvt.sem);
188 return status;
189 }
190
191 ret = wait_for_completion_timeout(&nss_vxlan_pvt.complete, msecs_to_jiffies(NSS_VXLAN_TX_TIMEOUT));
192 if (!ret) {
193 nss_warning("%p: vxlan tx sync failed due to timeout\n", nss_ctx);
194 nss_vxlan_pvt.response = NSS_TX_FAILURE;
195 }
196
197 status = nss_vxlan_pvt.response;
198 up(&nss_vxlan_pvt.sem);
199 return status;
200}
201EXPORT_SYMBOL(nss_vxlan_tx_msg_sync);
202
203/*
204 * nss_vxlan_msg_init()
205 * Initialize VxLAN message.
206 */
207void nss_vxlan_msg_init(struct nss_vxlan_msg *nvm, uint16_t if_num, uint32_t type, uint32_t len,
208 nss_vxlan_msg_callback_t cb, void *app_data)
209{
210 nss_cmn_msg_init(&nvm->cm, if_num, type, len, (void*)cb, app_data);
211}
212EXPORT_SYMBOL(nss_vxlan_msg_init);
213
214/*
215 * nss_vxlan_unregister_if()
216 * Unregister a data packet notifier with NSS FW.
217 */
218bool nss_vxlan_unregister_if(uint32_t if_num)
219{
220 struct nss_ctx_instance *nss_ctx;
221
222 nss_ctx = nss_vxlan_get_ctx();
223 if (!nss_vxlan_verify_if_num(if_num)) {
224 nss_warning("%p: data unregister received for invalid interface %d", nss_ctx, if_num);
225 return false;
226 }
227
228 nss_core_unregister_handler(nss_ctx, if_num);
229 nss_core_unregister_subsys_dp(nss_ctx, if_num);
230 return true;
231}
232EXPORT_SYMBOL(nss_vxlan_unregister_if);
233
234/*
235 * nss_vxlan_register_if()
236 * Registers a data packet notifier with NSS FW.
237 */
238struct nss_ctx_instance *nss_vxlan_register_if(uint32_t if_num,
239 uint32_t type,
240 nss_vxlan_buf_callback_t data_cb,
241 nss_vxlan_msg_callback_t notify_cb,
242 struct net_device *netdev,
243 uint32_t features)
244{
245 struct nss_ctx_instance *nss_ctx;
246 int core_status;
247
248 nss_ctx = nss_vxlan_get_ctx();
249 if (!nss_vxlan_verify_if_num(if_num)) {
250 nss_warning("%p: data register received for invalid interface %d", nss_ctx, if_num);
251 return NULL;
252 }
253
254 core_status = nss_core_register_handler(nss_ctx, if_num, nss_vxlan_msg_handler, NULL);
255 if (core_status != NSS_CORE_STATUS_SUCCESS) {
256 nss_warning("%p: nss core register handler failed for if_num:%d with error :%d", nss_ctx, if_num, core_status);
257 return NULL;
258 }
259
260 nss_core_register_subsys_dp(nss_ctx, if_num, data_cb, NULL, NULL, netdev, features);
261 nss_core_set_subsys_dp_type(nss_ctx, netdev, if_num, type);
262 nss_top_main.if_rx_msg_callback[if_num] = (nss_if_rx_msg_callback_t)notify_cb;
263 return nss_ctx;
264}
265EXPORT_SYMBOL(nss_vxlan_register_if);
266
267/*
268 * nss_vxlan_ifnum_with_core_id()
269 * Append core id to vxlan interface num.
270 */
271int nss_vxlan_ifnum_with_core_id(int if_num)
272{
273 struct nss_ctx_instance *nss_ctx = nss_vxlan_get_ctx();
274
275 NSS_VERIFY_CTX_MAGIC(nss_ctx);
276
277 if (!nss_vxlan_verify_if_num(if_num)) {
278 nss_warning("%p: Invalid if_num: %d, must be a dynamic interface\n", nss_ctx, if_num);
279 return 0;
280 }
281 return NSS_INTERFACE_NUM_APPEND_COREID(nss_ctx, if_num);
282}
283EXPORT_SYMBOL(nss_vxlan_ifnum_with_core_id);
284
285/*
286 * nss_vxlan_get_ctx()
287 * Return a VxLAN NSS context.
288 */
289struct nss_ctx_instance *nss_vxlan_get_ctx()
290{
291 struct nss_ctx_instance *nss_ctx;
292
293 nss_ctx = &nss_top_main.nss[nss_top_main.vxlan_handler_id];
294 return nss_ctx;
295}
296EXPORT_SYMBOL(nss_vxlan_get_ctx);
297
298/*
299 * nss_vxlan_init()
300 * Initializes Vxlan. Gets called from nss_init.c.
301 */
302void nss_vxlan_init()
303{
304 uint32_t core_status;
305 struct nss_ctx_instance *nss_ctx = nss_vxlan_get_ctx();
306 if (!nss_ctx) {
307 nss_warning("%p: VxLAN is not registered", nss_ctx);
308 return;
309 }
310
311 nss_vxlan_stats_dentry_create();
312 sema_init(&nss_vxlan_pvt.sem, 1);
313 init_completion(&nss_vxlan_pvt.complete);
314 core_status = nss_core_register_handler(nss_ctx, NSS_VXLAN_INTERFACE, nss_vxlan_msg_handler, NULL);
315
316 if (core_status != NSS_CORE_STATUS_SUCCESS) {
317 nss_warning("%p: nss core register handler failed for if_num:%d with error :%d", nss_ctx, NSS_VXLAN_INTERFACE, core_status);
318 }
319
320}