blob: c5d1ee26e6b1895490286288adb3a94ab4ace590 [file] [log] [blame]
ratheesh kannotheb2a0a82017-05-04 09:20:17 +05301/*
2 **************************************************************************
Suruchi Sumane93a7e82019-06-10 17:31:25 +05303 * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
ratheesh kannotheb2a0a82017-05-04 09:20:17 +05304 * 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"
Yu Huang8c107082017-07-24 14:58:26 -070018#include "nss_gre_stats.h"
Sachin Shashidhar159a64a2018-07-31 16:16:51 -070019#include "nss_gre_log.h"
ratheesh kannotheb2a0a82017-05-04 09:20:17 +053020
21#define NSS_GRE_TX_TIMEOUT 3000 /* 3 Seconds */
22
23/*
24 * Private data structure
25 */
26static struct {
27 struct semaphore sem;
28 struct completion complete;
29 int response;
30 void *cb;
31 void *app_data;
32} nss_gre_pvt;
33
Suruchi Sumane93a7e82019-06-10 17:31:25 +053034/*
35 * TODO: Register separate callbacks for inner and outer GRE nodes.
36 */
ratheesh kannoth7746db22017-05-16 14:16:43 +053037static atomic64_t pkt_cb_addr = ATOMIC64_INIT(0);
38
39/*
Suman Ghoshb2faf662018-07-13 17:34:12 +053040 * nss_gre_inner_rx_handler()
41 * GRE inner rx handler.
ratheesh kannoth7746db22017-05-16 14:16:43 +053042 */
Suman Ghoshb2faf662018-07-13 17:34:12 +053043static void nss_gre_inner_rx_handler(struct net_device *dev, struct sk_buff *skb,
ratheesh kannoth7746db22017-05-16 14:16:43 +053044 __attribute__((unused)) struct napi_struct *napi)
45{
46 nss_gre_data_callback_t cb;
47
48 nss_gre_pkt_callback_t scb = (nss_gre_pkt_callback_t)(unsigned long)atomic64_read(&pkt_cb_addr);
49 if (unlikely(scb)) {
50 struct nss_gre_info *info = (struct nss_gre_info *)netdev_priv(dev);
Suruchi Sumane93a7e82019-06-10 17:31:25 +053051 if (likely(info->next_dev_inner)) {
52 scb(info->next_dev_inner, skb);
ratheesh kannoth7746db22017-05-16 14:16:43 +053053 }
54 }
55
Suman Ghoshb2faf662018-07-13 17:34:12 +053056 cb = nss_top_main.gre_inner_data_callback;
57 cb(dev, skb, 0);
58}
59
60/*
61 * nss_gre_outer_rx_handler()
62 * GRE outer rx handler.
63 */
64static void nss_gre_outer_rx_handler(struct net_device *dev, struct sk_buff *skb,
65 __attribute__((unused)) struct napi_struct *napi)
66{
67 nss_gre_data_callback_t cb;
68
69 nss_gre_pkt_callback_t scb = (nss_gre_pkt_callback_t)(unsigned long)atomic64_read(&pkt_cb_addr);
70 if (unlikely(scb)) {
71 struct nss_gre_info *info = (struct nss_gre_info *)netdev_priv(dev);
Suruchi Sumane93a7e82019-06-10 17:31:25 +053072 if (likely(info->next_dev_outer)) {
73 scb(info->next_dev_outer, skb);
Suman Ghoshb2faf662018-07-13 17:34:12 +053074 }
75 }
76
77 cb = nss_top_main.gre_outer_data_callback;
ratheesh kannoth7746db22017-05-16 14:16:43 +053078 cb(dev, skb, 0);
79}
80
ratheesh kannotheb2a0a82017-05-04 09:20:17 +053081/*
ratheesh kannotheb2a0a82017-05-04 09:20:17 +053082 * nss_gre_msg_handler()
83 * Handle NSS -> HLOS messages for GRE
84 */
85static void nss_gre_msg_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
86{
87 struct nss_gre_msg *ntm = (struct nss_gre_msg *)ncm;
88 void *ctx;
89
90 nss_gre_msg_callback_t cb;
91
92 NSS_VERIFY_CTX_MAGIC(nss_ctx);
93 BUG_ON(!(nss_is_dynamic_interface(ncm->interface) || ncm->interface == NSS_GRE_INTERFACE));
94
95 /*
Sachin Shashidhar159a64a2018-07-31 16:16:51 -070096 * Trace Messages
97 */
98 nss_gre_log_rx_msg(ntm);
99
100 /*
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530101 * Is this a valid request/response packet?
102 */
103 if (ncm->type >= NSS_GRE_MSG_MAX) {
104 nss_warning("%p: received invalid message %d for GRE STD interface", nss_ctx, ncm->type);
105 return;
106 }
107
108 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_gre_msg)) {
109 nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
110 return;
111 }
112
113 switch (ntm->cm.type) {
114 case NSS_GRE_MSG_SESSION_STATS:
115 /*
116 * debug stats embedded in stats msg
117 */
Yu Huang8c107082017-07-24 14:58:26 -0700118 nss_gre_stats_session_debug_sync(nss_ctx, &ntm->msg.sstats, ncm->interface);
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530119 break;
120
121 case NSS_GRE_MSG_BASE_STATS:
Yu Huang8c107082017-07-24 14:58:26 -0700122 nss_gre_stats_base_debug_sync(nss_ctx, &ntm->msg.bstats);
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530123 break;
124
125 default:
126 break;
127
128 }
129
130 /*
131 * Update the callback and app_data for NOTIFY messages, gre sends all notify messages
132 * to the same callback/app_data.
133 */
Suruchi Agarwale4ad24a2018-06-11 12:03:46 +0530134 if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) {
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530135 ncm->cb = (nss_ptr_t)nss_ctx->nss_top->gre_msg_callback;
136 ncm->app_data = (nss_ptr_t)nss_ctx->subsys_dp_register[ncm->interface].app_data;
137 }
138
139 /*
140 * Log failures
141 */
142 nss_core_log_msg_failures(nss_ctx, ncm);
143
144 /*
145 * callback
146 */
147 cb = (nss_gre_msg_callback_t)ncm->cb;
148 ctx = (void *)ncm->app_data;
149
150 /*
151 * call gre-std callback
152 */
153 if (!cb) {
154 nss_warning("%p: No callback for gre-std interface %d",
155 nss_ctx, ncm->interface);
156 return;
157 }
158
159 cb(ctx, ntm);
160}
161
162/*
163 * nss_gre_callback()
164 * Callback to handle the completion of HLOS-->NSS messages.
165 */
166static void nss_gre_callback(void *app_data, struct nss_gre_msg *nim)
167{
168 nss_gre_msg_callback_t callback = (nss_gre_msg_callback_t)nss_gre_pvt.cb;
169 void *data = nss_gre_pvt.app_data;
170
171 nss_gre_pvt.cb = NULL;
172 nss_gre_pvt.app_data = NULL;
173
174 if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
175 nss_warning("gre Error response %d\n", nim->cm.response);
176 nss_gre_pvt.response = NSS_TX_FAILURE;
177 } else {
178 nss_gre_pvt.response = NSS_TX_SUCCESS;
179 }
180
181 if (callback) {
182 callback(data, nim);
183 }
184
185 complete(&nss_gre_pvt.complete);
186}
187
188/*
ratheesh kannoth7746db22017-05-16 14:16:43 +0530189 * nss_gre_register_pkt_callback()
190 * Register for data callback.
191 */
192void nss_gre_register_pkt_callback(nss_gre_pkt_callback_t cb)
193{
194 atomic64_set(&pkt_cb_addr, (unsigned long)cb);
195}
196EXPORT_SYMBOL(nss_gre_register_pkt_callback);
197
198/*
199 * nss_gre_unregister_pkt_callback()
200 * Unregister for data callback.
201 */
202void nss_gre_unregister_pkt_callback()
203{
204 atomic64_set(&pkt_cb_addr, 0);
205}
206EXPORT_SYMBOL(nss_gre_unregister_pkt_callback);
207
208/*
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530209 * nss_gre_tx_msg()
210 * Transmit a GRE message to NSS firmware
211 */
212nss_tx_status_t nss_gre_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_gre_msg *msg)
213{
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530214 struct nss_cmn_msg *ncm = &msg->cm;
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530215
216 /*
217 * Sanity check the message
218 */
219 if (!nss_is_dynamic_interface(ncm->interface)) {
220 nss_warning("%p: tx request for non dynamic interface: %d", nss_ctx, ncm->interface);
221 return NSS_TX_FAILURE;
222 }
223
224 if (ncm->type > NSS_GRE_MSG_MAX) {
225 nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
226 return NSS_TX_FAILURE;
227 }
228
Sachin Shashidhar159a64a2018-07-31 16:16:51 -0700229 /*
230 * Trace Messages
231 */
232 nss_gre_log_tx_msg(msg);
233
Stephen Wang3e2dbd12018-03-14 17:28:17 -0700234 return nss_core_send_cmd(nss_ctx, msg, sizeof(*msg), NSS_NBUF_PAYLOAD_SIZE);
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530235}
236EXPORT_SYMBOL(nss_gre_tx_msg);
237
238/*
239 * nss_gre_tx_msg_sync()
240 * Transmit a GRE message to NSS firmware synchronously.
241 */
242nss_tx_status_t nss_gre_tx_msg_sync(struct nss_ctx_instance *nss_ctx, struct nss_gre_msg *msg)
243{
244 nss_tx_status_t status;
245 int ret = 0;
246
247 down(&nss_gre_pvt.sem);
248 nss_gre_pvt.cb = (void *)msg->cm.cb;
249 nss_gre_pvt.app_data = (void *)msg->cm.app_data;
250
251 msg->cm.cb = (nss_ptr_t)nss_gre_callback;
252 msg->cm.app_data = (nss_ptr_t)NULL;
253
254 status = nss_gre_tx_msg(nss_ctx, msg);
255 if (status != NSS_TX_SUCCESS) {
256 nss_warning("%p: gre_tx_msg failed\n", nss_ctx);
257 up(&nss_gre_pvt.sem);
258 return status;
259 }
260 ret = wait_for_completion_timeout(&nss_gre_pvt.complete, msecs_to_jiffies(NSS_GRE_TX_TIMEOUT));
261
262 if (!ret) {
263 nss_warning("%p: GRE STD tx sync failed due to timeout\n", nss_ctx);
264 nss_gre_pvt.response = NSS_TX_FAILURE;
265 }
266
267 status = nss_gre_pvt.response;
268 up(&nss_gre_pvt.sem);
269 return status;
270}
271EXPORT_SYMBOL(nss_gre_tx_msg_sync);
272
273/*
274 * nss_gre_tx_buf()
275 * Send packet to GRE interface owned by NSS
276 */
277nss_tx_status_t nss_gre_tx_buf(struct nss_ctx_instance *nss_ctx, uint32_t if_num, struct sk_buff *skb)
278{
Aniruddha Paul38d72f42019-08-20 16:51:31 +0530279 return nss_core_send_packet(nss_ctx, skb, if_num, H2N_BIT_FLAG_VIRTUAL_BUFFER | H2N_BIT_FLAG_BUFFER_REUSABLE);
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530280}
281EXPORT_SYMBOL(nss_gre_tx_buf);
282
283/*
284 ***********************************
285 * Register/Unregister/Miscellaneous APIs
286 ***********************************
287 */
288
289/*
290 * nss_gre_register_if()
291 * Register data and message handlers for GRE.
292 */
Suman Ghoshb2faf662018-07-13 17:34:12 +0530293struct nss_ctx_instance *nss_gre_register_if(uint32_t if_num, uint32_t type, nss_gre_data_callback_t data_callback,
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530294 nss_gre_msg_callback_t event_callback, struct net_device *netdev, uint32_t features)
295{
296 struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.gre_handler_id];
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530297
298 nss_assert(nss_ctx);
299 nss_assert(nss_is_dynamic_interface(if_num));
300
Suman Ghoshb2faf662018-07-13 17:34:12 +0530301 switch (type) {
302 case NSS_DYNAMIC_INTERFACE_TYPE_GRE_INNER:
303 nss_core_register_subsys_dp(nss_ctx, if_num, nss_gre_inner_rx_handler, NULL, netdev, netdev, features);
304 nss_top_main.gre_inner_data_callback = data_callback;
305 break;
306
307 case NSS_DYNAMIC_INTERFACE_TYPE_GRE_OUTER:
308 nss_core_register_subsys_dp(nss_ctx, if_num, nss_gre_outer_rx_handler, NULL, netdev, netdev, features);
309 nss_top_main.gre_outer_data_callback = data_callback;
310 break;
311
312 default:
313 nss_warning("%p: Unable to register. Wrong interface type %d\n", nss_ctx, type);
314 return NULL;
315 }
316
317 nss_core_set_subsys_dp_type(nss_ctx, netdev, if_num, type);
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530318
319 nss_top_main.gre_msg_callback = event_callback;
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530320
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700321 nss_core_register_handler(nss_ctx, if_num, nss_gre_msg_handler, NULL);
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530322
Yu Huang8c107082017-07-24 14:58:26 -0700323 nss_gre_stats_session_register(if_num, netdev);
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530324
325 return nss_ctx;
326}
327EXPORT_SYMBOL(nss_gre_register_if);
328
329/*
330 * nss_gre_unregister_if()
331 * Unregister data and message handler.
332 */
333void nss_gre_unregister_if(uint32_t if_num)
334{
335 struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.gre_handler_id];
Suman Ghoshb2faf662018-07-13 17:34:12 +0530336 struct net_device *dev;
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530337
338 nss_assert(nss_ctx);
339 nss_assert(nss_is_dynamic_interface(if_num));
340
Suman Ghoshb2faf662018-07-13 17:34:12 +0530341 dev = nss_cmn_get_interface_dev(nss_ctx, if_num);
342 if (!dev) {
343 nss_warning("%p: Unable to find net device for the interface %d\n", nss_ctx, if_num);
344 return;
345 }
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530346
Suman Ghoshb2faf662018-07-13 17:34:12 +0530347 nss_core_unregister_subsys_dp(nss_ctx, if_num);
348 nss_core_set_subsys_dp_type(nss_ctx, dev, if_num, NSS_DYNAMIC_INTERFACE_TYPE_NONE);
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530349 nss_top_main.gre_msg_callback = NULL;
350
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700351 nss_core_unregister_handler(nss_ctx, if_num);
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530352
Yu Huang8c107082017-07-24 14:58:26 -0700353 nss_gre_stats_session_unregister(if_num);
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530354}
355EXPORT_SYMBOL(nss_gre_unregister_if);
356
357/*
358 * nss_get_gre_context()
359 */
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700360struct nss_ctx_instance *nss_gre_get_context(void)
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530361{
362 return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.gre_handler_id];
363}
364EXPORT_SYMBOL(nss_gre_get_context);
365
366/*
Suruchi Sumane93a7e82019-06-10 17:31:25 +0530367 * nss_gre_ifnum_with_core_id()
368 * Append core id to GRE interface num.
369 */
370int nss_gre_ifnum_with_core_id(int if_num)
371{
372 struct nss_ctx_instance *nss_ctx = nss_gre_get_context();
373
374 NSS_VERIFY_CTX_MAGIC(nss_ctx);
375 if (!nss_is_dynamic_interface(if_num)) {
376 nss_warning("%p: Invalid if_num: %d, must be a dynamic interface\n", nss_ctx, if_num);
377 return 0;
378 }
379
380 return NSS_INTERFACE_NUM_APPEND_COREID(nss_ctx, if_num);
381}
382EXPORT_SYMBOL(nss_gre_ifnum_with_core_id);
383
384/*
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530385 * nss_gre_msg_init()
386 * Initialize nss_gre msg.
387 */
388void nss_gre_msg_init(struct nss_gre_msg *ncm, uint16_t if_num, uint32_t type, uint32_t len, void *cb, void *app_data)
389{
390 nss_cmn_msg_init(&ncm->cm, if_num, type, len, cb, app_data);
391}
392EXPORT_SYMBOL(nss_gre_msg_init);
393
394/*
395 * nss_gre_register_handler()
396 * debugfs stats msg handler received on static gre interface
397 */
398void nss_gre_register_handler(void)
399{
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700400 struct nss_ctx_instance *nss_ctx = nss_gre_get_context();
401
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530402 nss_info("nss_gre_register_handler");
403 sema_init(&nss_gre_pvt.sem, 1);
404 init_completion(&nss_gre_pvt.complete);
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700405 nss_core_register_handler(nss_ctx, NSS_GRE_INTERFACE, nss_gre_msg_handler, NULL);
Yu Huang8c107082017-07-24 14:58:26 -0700406 nss_gre_stats_dentry_create();
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530407}