blob: 7178ed754dac62d82626cc295f5ff7af6c304a27 [file] [log] [blame]
ratheesh kannotheb2a0a82017-05-04 09:20:17 +05301/*
2 **************************************************************************
Stephen Wang3e2dbd12018-03-14 17:28:17 -07003 * Copyright (c) 2017-2018, 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
ratheesh kannoth7746db22017-05-16 14:16:43 +053034static atomic64_t pkt_cb_addr = ATOMIC64_INIT(0);
35
36/*
Suman Ghoshb2faf662018-07-13 17:34:12 +053037 * nss_gre_inner_rx_handler()
38 * GRE inner rx handler.
ratheesh kannoth7746db22017-05-16 14:16:43 +053039 */
Suman Ghoshb2faf662018-07-13 17:34:12 +053040static void nss_gre_inner_rx_handler(struct net_device *dev, struct sk_buff *skb,
ratheesh kannoth7746db22017-05-16 14:16:43 +053041 __attribute__((unused)) struct napi_struct *napi)
42{
43 nss_gre_data_callback_t cb;
44
45 nss_gre_pkt_callback_t scb = (nss_gre_pkt_callback_t)(unsigned long)atomic64_read(&pkt_cb_addr);
46 if (unlikely(scb)) {
47 struct nss_gre_info *info = (struct nss_gre_info *)netdev_priv(dev);
48 if (likely(info->next_dev)) {
49 scb(info->next_dev, skb);
50 }
51 }
52
Suman Ghoshb2faf662018-07-13 17:34:12 +053053 cb = nss_top_main.gre_inner_data_callback;
54 cb(dev, skb, 0);
55}
56
57/*
58 * nss_gre_outer_rx_handler()
59 * GRE outer rx handler.
60 */
61static void nss_gre_outer_rx_handler(struct net_device *dev, struct sk_buff *skb,
62 __attribute__((unused)) struct napi_struct *napi)
63{
64 nss_gre_data_callback_t cb;
65
66 nss_gre_pkt_callback_t scb = (nss_gre_pkt_callback_t)(unsigned long)atomic64_read(&pkt_cb_addr);
67 if (unlikely(scb)) {
68 struct nss_gre_info *info = (struct nss_gre_info *)netdev_priv(dev);
69 if (likely(info->next_dev)) {
70 scb(info->next_dev, skb);
71 }
72 }
73
74 cb = nss_top_main.gre_outer_data_callback;
ratheesh kannoth7746db22017-05-16 14:16:43 +053075 cb(dev, skb, 0);
76}
77
ratheesh kannotheb2a0a82017-05-04 09:20:17 +053078/*
ratheesh kannotheb2a0a82017-05-04 09:20:17 +053079 * nss_gre_msg_handler()
80 * Handle NSS -> HLOS messages for GRE
81 */
82static void nss_gre_msg_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
83{
84 struct nss_gre_msg *ntm = (struct nss_gre_msg *)ncm;
85 void *ctx;
86
87 nss_gre_msg_callback_t cb;
88
89 NSS_VERIFY_CTX_MAGIC(nss_ctx);
90 BUG_ON(!(nss_is_dynamic_interface(ncm->interface) || ncm->interface == NSS_GRE_INTERFACE));
91
92 /*
Sachin Shashidhar159a64a2018-07-31 16:16:51 -070093 * Trace Messages
94 */
95 nss_gre_log_rx_msg(ntm);
96
97 /*
ratheesh kannotheb2a0a82017-05-04 09:20:17 +053098 * Is this a valid request/response packet?
99 */
100 if (ncm->type >= NSS_GRE_MSG_MAX) {
101 nss_warning("%p: received invalid message %d for GRE STD interface", nss_ctx, ncm->type);
102 return;
103 }
104
105 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_gre_msg)) {
106 nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
107 return;
108 }
109
110 switch (ntm->cm.type) {
111 case NSS_GRE_MSG_SESSION_STATS:
112 /*
113 * debug stats embedded in stats msg
114 */
Yu Huang8c107082017-07-24 14:58:26 -0700115 nss_gre_stats_session_debug_sync(nss_ctx, &ntm->msg.sstats, ncm->interface);
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530116 break;
117
118 case NSS_GRE_MSG_BASE_STATS:
Yu Huang8c107082017-07-24 14:58:26 -0700119 nss_gre_stats_base_debug_sync(nss_ctx, &ntm->msg.bstats);
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530120 break;
121
122 default:
123 break;
124
125 }
126
127 /*
128 * Update the callback and app_data for NOTIFY messages, gre sends all notify messages
129 * to the same callback/app_data.
130 */
Suruchi Agarwale4ad24a2018-06-11 12:03:46 +0530131 if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) {
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530132 ncm->cb = (nss_ptr_t)nss_ctx->nss_top->gre_msg_callback;
133 ncm->app_data = (nss_ptr_t)nss_ctx->subsys_dp_register[ncm->interface].app_data;
134 }
135
136 /*
137 * Log failures
138 */
139 nss_core_log_msg_failures(nss_ctx, ncm);
140
141 /*
142 * callback
143 */
144 cb = (nss_gre_msg_callback_t)ncm->cb;
145 ctx = (void *)ncm->app_data;
146
147 /*
148 * call gre-std callback
149 */
150 if (!cb) {
151 nss_warning("%p: No callback for gre-std interface %d",
152 nss_ctx, ncm->interface);
153 return;
154 }
155
156 cb(ctx, ntm);
157}
158
159/*
160 * nss_gre_callback()
161 * Callback to handle the completion of HLOS-->NSS messages.
162 */
163static void nss_gre_callback(void *app_data, struct nss_gre_msg *nim)
164{
165 nss_gre_msg_callback_t callback = (nss_gre_msg_callback_t)nss_gre_pvt.cb;
166 void *data = nss_gre_pvt.app_data;
167
168 nss_gre_pvt.cb = NULL;
169 nss_gre_pvt.app_data = NULL;
170
171 if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
172 nss_warning("gre Error response %d\n", nim->cm.response);
173 nss_gre_pvt.response = NSS_TX_FAILURE;
174 } else {
175 nss_gre_pvt.response = NSS_TX_SUCCESS;
176 }
177
178 if (callback) {
179 callback(data, nim);
180 }
181
182 complete(&nss_gre_pvt.complete);
183}
184
185/*
ratheesh kannoth7746db22017-05-16 14:16:43 +0530186 * nss_gre_register_pkt_callback()
187 * Register for data callback.
188 */
189void nss_gre_register_pkt_callback(nss_gre_pkt_callback_t cb)
190{
191 atomic64_set(&pkt_cb_addr, (unsigned long)cb);
192}
193EXPORT_SYMBOL(nss_gre_register_pkt_callback);
194
195/*
196 * nss_gre_unregister_pkt_callback()
197 * Unregister for data callback.
198 */
199void nss_gre_unregister_pkt_callback()
200{
201 atomic64_set(&pkt_cb_addr, 0);
202}
203EXPORT_SYMBOL(nss_gre_unregister_pkt_callback);
204
205/*
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530206 * nss_gre_tx_msg()
207 * Transmit a GRE message to NSS firmware
208 */
209nss_tx_status_t nss_gre_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_gre_msg *msg)
210{
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530211 struct nss_cmn_msg *ncm = &msg->cm;
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530212
213 /*
214 * Sanity check the message
215 */
216 if (!nss_is_dynamic_interface(ncm->interface)) {
217 nss_warning("%p: tx request for non dynamic interface: %d", nss_ctx, ncm->interface);
218 return NSS_TX_FAILURE;
219 }
220
221 if (ncm->type > NSS_GRE_MSG_MAX) {
222 nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
223 return NSS_TX_FAILURE;
224 }
225
Sachin Shashidhar159a64a2018-07-31 16:16:51 -0700226 /*
227 * Trace Messages
228 */
229 nss_gre_log_tx_msg(msg);
230
Stephen Wang3e2dbd12018-03-14 17:28:17 -0700231 return nss_core_send_cmd(nss_ctx, msg, sizeof(*msg), NSS_NBUF_PAYLOAD_SIZE);
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530232}
233EXPORT_SYMBOL(nss_gre_tx_msg);
234
235/*
236 * nss_gre_tx_msg_sync()
237 * Transmit a GRE message to NSS firmware synchronously.
238 */
239nss_tx_status_t nss_gre_tx_msg_sync(struct nss_ctx_instance *nss_ctx, struct nss_gre_msg *msg)
240{
241 nss_tx_status_t status;
242 int ret = 0;
243
244 down(&nss_gre_pvt.sem);
245 nss_gre_pvt.cb = (void *)msg->cm.cb;
246 nss_gre_pvt.app_data = (void *)msg->cm.app_data;
247
248 msg->cm.cb = (nss_ptr_t)nss_gre_callback;
249 msg->cm.app_data = (nss_ptr_t)NULL;
250
251 status = nss_gre_tx_msg(nss_ctx, msg);
252 if (status != NSS_TX_SUCCESS) {
253 nss_warning("%p: gre_tx_msg failed\n", nss_ctx);
254 up(&nss_gre_pvt.sem);
255 return status;
256 }
257 ret = wait_for_completion_timeout(&nss_gre_pvt.complete, msecs_to_jiffies(NSS_GRE_TX_TIMEOUT));
258
259 if (!ret) {
260 nss_warning("%p: GRE STD tx sync failed due to timeout\n", nss_ctx);
261 nss_gre_pvt.response = NSS_TX_FAILURE;
262 }
263
264 status = nss_gre_pvt.response;
265 up(&nss_gre_pvt.sem);
266 return status;
267}
268EXPORT_SYMBOL(nss_gre_tx_msg_sync);
269
270/*
271 * nss_gre_tx_buf()
272 * Send packet to GRE interface owned by NSS
273 */
274nss_tx_status_t nss_gre_tx_buf(struct nss_ctx_instance *nss_ctx, uint32_t if_num, struct sk_buff *skb)
275{
Stephen Wang3e2dbd12018-03-14 17:28:17 -0700276 return nss_core_send_packet(nss_ctx, skb, if_num, H2N_BIT_FLAG_VIRTUAL_BUFFER);
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530277}
278EXPORT_SYMBOL(nss_gre_tx_buf);
279
280/*
281 ***********************************
282 * Register/Unregister/Miscellaneous APIs
283 ***********************************
284 */
285
286/*
287 * nss_gre_register_if()
288 * Register data and message handlers for GRE.
289 */
Suman Ghoshb2faf662018-07-13 17:34:12 +0530290struct 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 +0530291 nss_gre_msg_callback_t event_callback, struct net_device *netdev, uint32_t features)
292{
293 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 +0530294
295 nss_assert(nss_ctx);
296 nss_assert(nss_is_dynamic_interface(if_num));
297
Suman Ghoshb2faf662018-07-13 17:34:12 +0530298 switch (type) {
299 case NSS_DYNAMIC_INTERFACE_TYPE_GRE_INNER:
300 nss_core_register_subsys_dp(nss_ctx, if_num, nss_gre_inner_rx_handler, NULL, netdev, netdev, features);
301 nss_top_main.gre_inner_data_callback = data_callback;
302 break;
303
304 case NSS_DYNAMIC_INTERFACE_TYPE_GRE_OUTER:
305 nss_core_register_subsys_dp(nss_ctx, if_num, nss_gre_outer_rx_handler, NULL, netdev, netdev, features);
306 nss_top_main.gre_outer_data_callback = data_callback;
307 break;
308
309 default:
310 nss_warning("%p: Unable to register. Wrong interface type %d\n", nss_ctx, type);
311 return NULL;
312 }
313
314 nss_core_set_subsys_dp_type(nss_ctx, netdev, if_num, type);
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530315
316 nss_top_main.gre_msg_callback = event_callback;
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530317
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700318 nss_core_register_handler(nss_ctx, if_num, nss_gre_msg_handler, NULL);
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530319
Yu Huang8c107082017-07-24 14:58:26 -0700320 nss_gre_stats_session_register(if_num, netdev);
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530321
322 return nss_ctx;
323}
324EXPORT_SYMBOL(nss_gre_register_if);
325
326/*
327 * nss_gre_unregister_if()
328 * Unregister data and message handler.
329 */
330void nss_gre_unregister_if(uint32_t if_num)
331{
332 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 +0530333 struct net_device *dev;
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530334
335 nss_assert(nss_ctx);
336 nss_assert(nss_is_dynamic_interface(if_num));
337
Suman Ghoshb2faf662018-07-13 17:34:12 +0530338 dev = nss_cmn_get_interface_dev(nss_ctx, if_num);
339 if (!dev) {
340 nss_warning("%p: Unable to find net device for the interface %d\n", nss_ctx, if_num);
341 return;
342 }
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530343
Suman Ghoshb2faf662018-07-13 17:34:12 +0530344 nss_core_unregister_subsys_dp(nss_ctx, if_num);
345 nss_core_set_subsys_dp_type(nss_ctx, dev, if_num, NSS_DYNAMIC_INTERFACE_TYPE_NONE);
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530346 nss_top_main.gre_msg_callback = NULL;
347
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700348 nss_core_unregister_handler(nss_ctx, if_num);
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530349
Yu Huang8c107082017-07-24 14:58:26 -0700350 nss_gre_stats_session_unregister(if_num);
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530351}
352EXPORT_SYMBOL(nss_gre_unregister_if);
353
354/*
355 * nss_get_gre_context()
356 */
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700357struct nss_ctx_instance *nss_gre_get_context(void)
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530358{
359 return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.gre_handler_id];
360}
361EXPORT_SYMBOL(nss_gre_get_context);
362
363/*
364 * nss_gre_msg_init()
365 * Initialize nss_gre msg.
366 */
367void nss_gre_msg_init(struct nss_gre_msg *ncm, uint16_t if_num, uint32_t type, uint32_t len, void *cb, void *app_data)
368{
369 nss_cmn_msg_init(&ncm->cm, if_num, type, len, cb, app_data);
370}
371EXPORT_SYMBOL(nss_gre_msg_init);
372
373/*
374 * nss_gre_register_handler()
375 * debugfs stats msg handler received on static gre interface
376 */
377void nss_gre_register_handler(void)
378{
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700379 struct nss_ctx_instance *nss_ctx = nss_gre_get_context();
380
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530381 nss_info("nss_gre_register_handler");
382 sema_init(&nss_gre_pvt.sem, 1);
383 init_completion(&nss_gre_pvt.complete);
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700384 nss_core_register_handler(nss_ctx, NSS_GRE_INTERFACE, nss_gre_msg_handler, NULL);
Yu Huang8c107082017-07-24 14:58:26 -0700385 nss_gre_stats_dentry_create();
ratheesh kannotheb2a0a82017-05-04 09:20:17 +0530386}