1/*
2 **************************************************************************
3 * Copyright (c) 2013 - 2015, 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_tx_rx_virt_if.c
19 *	NSS virtual/redirect handler APIs
20 */
21
22#include "nss_tx_rx_common.h"
23#include <net/arp.h>
24
25#define NSS_TX_RX_VIRT_IF_TX_TIMEOUT		3000 /* 3 Seconds */
26#define NSS_TX_RX_VIRT_IF_GET_INDEX(if_num)	(if_num-NSS_DYNAMIC_IF_START)
27#define NSS_TX_RX_VIRT_IF_802_3_PKT		0x2
28#define NSS_TX_RX_VIRT_IF_NATIVE_WIFI_PKT 	0x3
29
30extern int nss_ctl_redirect;
31
32/*
33 * Data structure that holds the virtual interface context.
34 */
35static struct nss_tx_rx_virt_if_handle *nss_tx_rx_virt_if_handles[NSS_MAX_DYNAMIC_INTERFACES];
36
37/*
38 * Spinlock to protect the global data structure virt_handle.
39 */
40DEFINE_SPINLOCK(nss_tx_rx_virt_if_lock);
41
42/*
43 * nss_tx_rx_virt_if_stats_sync()
44 *	Sync stats from the NSS FW
45 */
46static void nss_tx_rx_virt_if_stats_sync(struct nss_tx_rx_virt_if_handle *handle,
47					struct nss_tx_rx_virt_if_stats *nwis)
48{
49	struct nss_tx_rx_virt_if_stats *stats = &handle->stats;
50
51	stats->node_stats.rx_packets += nwis->node_stats.rx_packets;
52	stats->node_stats.rx_bytes += nwis->node_stats.rx_bytes;
53	stats->node_stats.rx_dropped += nwis->node_stats.rx_dropped;
54	stats->node_stats.tx_packets += nwis->node_stats.tx_packets;
55	stats->node_stats.tx_bytes += nwis->node_stats.tx_bytes;
56	stats->tx_enqueue_failed += nwis->tx_enqueue_failed;
57	stats->shaper_enqueue_failed += nwis->shaper_enqueue_failed;
58}
59
60/*
61 * nss_tx_rx_virt_if_msg_handler()
62 *	Handle msg responses from the FW on virtual interfaces
63 */
64static void nss_tx_rx_virt_if_msg_handler(struct nss_ctx_instance *nss_ctx,
65					struct nss_cmn_msg *ncm,
66					__attribute__((unused))void *app_data)
67{
68	struct nss_tx_rx_virt_if_msg *nvim = (struct nss_tx_rx_virt_if_msg *)ncm;
69	int32_t if_num;
70
71	nss_tx_rx_virt_if_msg_callback_t cb;
72	struct nss_tx_rx_virt_if_handle *handle = NULL;
73
74	/*
75	 * Sanity check the message type
76	 */
77	if (ncm->type > NSS_VIRT_IF_MAX_MSG_TYPES) {
78		nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
79		return;
80	}
81
82	/*
83	 * Messages value that are within the base class are handled by the base class.
84	 */
85	if (ncm->type < NSS_IF_MAX_MSG_TYPES) {
86		return nss_if_msg_handler(nss_ctx, ncm, app_data);
87	}
88
89	if (!NSS_IS_IF_TYPE(DYNAMIC, ncm->interface)) {
90		nss_warning("%p: response for another interface: %d", nss_ctx, ncm->interface);
91		return;
92	}
93
94	if_num = NSS_TX_RX_VIRT_IF_GET_INDEX(ncm->interface);
95
96	spin_lock_bh(&nss_tx_rx_virt_if_lock);
97	if (!nss_tx_rx_virt_if_handles[if_num]) {
98		spin_unlock_bh(&nss_tx_rx_virt_if_lock);
99		nss_warning("%p: redir_if handle is NULL\n", nss_ctx);
100		return;
101	}
102
103	handle = nss_tx_rx_virt_if_handles[if_num];
104	spin_unlock_bh(&nss_tx_rx_virt_if_lock);
105
106	switch (nvim->cm.type) {
107	case NSS_VIRT_IF_STATS_SYNC_MSG:
108		nss_tx_rx_virt_if_stats_sync(handle, &nvim->msg.stats);
109		break;
110	}
111
112	/*
113	 * Log failures
114	 */
115	nss_core_log_msg_failures(nss_ctx, ncm);
116
117	/*
118	 * Update the callback and app_data for NOTIFY messages, IPv4 sends all notify messages
119	 * to the same callback/app_data.
120	 */
121	if (ncm->response == NSS_CMM_RESPONSE_NOTIFY) {
122		ncm->cb = (uint32_t)nss_ctx->nss_top->if_rx_msg_callback[ncm->interface];
123		ncm->app_data = (uint32_t)nss_ctx->nss_top->subsys_dp_register[ncm->interface].ndev;
124	}
125
126	/*
127	 * Do we have a callback?
128	 */
129	if (!ncm->cb) {
130		return;
131	}
132
133	/*
134	 * Callback
135	 */
136	cb = (nss_tx_rx_virt_if_msg_callback_t)ncm->cb;
137	cb((void *)ncm->app_data, ncm);
138}
139
140/*
141 * nss_tx_rx_virt_if_callback
142 *	Callback to handle the completion of NSS ->HLOS messages.
143 */
144static void nss_tx_rx_virt_if_callback(void *app_data, struct nss_cmn_msg *ncm)
145{
146	struct nss_tx_rx_virt_if_handle *handle = (struct nss_tx_rx_virt_if_handle *)app_data;
147	struct nss_tx_rx_virt_if_pvt *nvip = handle->pvt;
148
149	if (ncm->response != NSS_CMN_RESPONSE_ACK) {
150		nss_warning("%p: redir_if Error response %d\n", handle->nss_ctx, ncm->response);
151		nvip->response = NSS_TX_FAILURE;
152		complete(&nvip->complete);
153		return;
154	}
155
156	nvip->response = NSS_TX_SUCCESS;
157	complete(&nvip->complete);
158}
159
160/*
161 * nss_register_virt_if()
162 */
163void *nss_register_virt_if(void *ctx,
164				nss_virt_if_rx_callback_t rx_callback,
165				struct net_device *netdev)
166{
167	struct nss_tx_rx_virt_if_handle *handle = (struct nss_tx_rx_virt_if_handle *)ctx;
168
169	int32_t if_num;
170
171	if (!handle) {
172		nss_warning("handle is NULL\n");
173		return NULL;
174	}
175
176	if_num = handle->if_num;
177
178	nss_top_main.subsys_dp_register[if_num].ndev = netdev;
179	nss_top_main.subsys_dp_register[if_num].cb = rx_callback;
180	nss_top_main.subsys_dp_register[if_num].app_data = NULL;
181	nss_top_main.subsys_dp_register[if_num].features = (uint32_t)netdev->features;
182
183	nss_top_main.if_rx_msg_callback[if_num] = NULL;
184
185	return ctx;
186}
187
188/*
189 * nss_unregister_virt_if()
190 */
191void nss_unregister_virt_if(void *ctx)
192{
193	struct nss_tx_rx_virt_if_handle *handle = (struct nss_tx_rx_virt_if_handle *)ctx;
194	int32_t if_num;
195
196	if (!handle) {
197		nss_warning("handle is NULL\n");
198		return;
199	}
200
201	if_num = handle->if_num;
202
203	nss_top_main.subsys_dp_register[if_num].ndev = NULL;
204	nss_top_main.subsys_dp_register[if_num].cb = NULL;
205	nss_top_main.subsys_dp_register[if_num].app_data = NULL;
206	nss_top_main.subsys_dp_register[if_num].features = 0;
207
208	nss_top_main.if_rx_msg_callback[if_num] = NULL;
209}
210
211/*
212 * nss_tx_virt_if_recvbuf()
213 *	HLOS interface has received a packet which we redirect to the NSS, if appropriate to do so.
214 */
215nss_tx_status_t nss_tx_virt_if_recvbuf(void *ctx, struct sk_buff *skb, uint32_t nwifi)
216{
217	struct nss_tx_rx_virt_if_handle *handle = (struct nss_tx_rx_virt_if_handle *)ctx;
218	int32_t if_num = handle->if_num;
219	struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
220	nss_tx_status_t status;
221	int push_mac_header = 0;
222
223	if (unlikely(nss_ctl_redirect == 0)) {
224		return NSS_TX_FAILURE_NOT_ENABLED;
225	}
226
227	if (unlikely(skb->vlan_tci)) {
228		return NSS_TX_FAILURE_NOT_SUPPORTED;
229	}
230
231	nss_assert(NSS_IS_IF_TYPE(DYNAMIC, if_num));
232	nss_trace("%p: Virtual Rx packet, if_num:%d, skb:%p", nss_ctx, if_num, skb);
233
234	/*
235	 * Get the NSS context that will handle this packet and check that it is initialised and ready
236	 */
237	NSS_VERIFY_CTX_MAGIC(nss_ctx);
238	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
239		nss_warning("%p: Virtual Rx packet dropped as core not ready", nss_ctx);
240		return NSS_TX_FAILURE_NOT_READY;
241	}
242
243	/*
244	 * Sanity check the SKB to ensure that it's suitable for us
245	 */
246	if (unlikely(skb->len <= ETH_HLEN)) {
247		nss_warning("%p: Virtual Rx packet: %p too short", nss_ctx, skb);
248		return NSS_TX_FAILURE_TOO_SHORT;
249	}
250
251	if (unlikely(skb_shinfo(skb)->nr_frags != 0)) {
252		/*
253		 * TODO: If we have a connection matching rule for this skbuff,
254		 * do we need to flush it??
255		 */
256		nss_warning("%p: Delivering the packet to Linux because of fragmented skb: %p\n", nss_ctx, skb);
257		return NSS_TX_FAILURE_NOT_SUPPORTED;
258	}
259
260	/*
261	 * We differentiate between skbs with priority to identify native vs non-native wifi pkts
262	 */
263	if (nwifi) {
264		skb->priority = NSS_TX_RX_VIRT_IF_NATIVE_WIFI_PKT;
265	} else {
266		skb->priority = NSS_TX_RX_VIRT_IF_802_3_PKT;
267
268		/*
269		 * NSS expects to see buffer from Ethernet header onwards.
270		 * If the wireless driver has called eth_type_trans to remove
271		 * the ethernet header, we need to push back the header
272		 */
273		if (unlikely((skb->data - skb_mac_header(skb)) == ETH_HLEN)) {
274			skb_push(skb, ETH_HLEN);
275			push_mac_header = 1;
276		}
277	}
278
279	/*
280	 * Direct the buffer to the NSS
281	 */
282	status = nss_core_send_buffer(nss_ctx, if_num, skb, NSS_IF_DATA_QUEUE_0,
283					H2N_BUFFER_PACKET, H2N_BIT_FLAG_VIRTUAL_BUFFER);
284	if (unlikely(status != NSS_CORE_STATUS_SUCCESS)) {
285		nss_warning("%p: Virtual Rx packet unable to enqueue\n", nss_ctx);
286
287		if (unlikely(push_mac_header)) {
288			skb_pull(skb, ETH_HLEN);
289		}
290
291		return NSS_TX_FAILURE_QUEUE;
292	}
293
294	/*
295	 * Kick the NSS awake so it can process our new entry.
296	 */
297	nss_hal_send_interrupt(nss_ctx->nmap,
298				nss_ctx->h2n_desc_rings[NSS_IF_DATA_QUEUE_0].desc_ring.int_bit,
299				NSS_REGS_H2N_INTR_STATUS_DATA_COMMAND_QUEUE);
300	NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_PACKET]);
301	return NSS_TX_SUCCESS;
302}
303
304/*
305 * @brief Forward virtual interface packets
306 *	This function expects packet with L3 header and eth_type_trans
307 *	has been called before calling this api
308 *
309 * @param nss_ctx NSS context (provided during registeration)
310 * @param os_buf OS buffer (e.g. skbuff)
311 * @return nss_tx_status_t Tx status
312 */
313nss_tx_status_t nss_tx_virt_if_rxbuf(void *ctx, struct sk_buff *os_buf)
314{
315
316	return nss_tx_virt_if_recvbuf(ctx, os_buf, 0);
317}
318
319/*
320 * @brief Forward Native wifi packet from virtual interface
321 *	Expects packet with qca-nwifi format
322 *
323 * @param nss_ctx NSS context (provided during registeration)
324 * @param os_buf OS buffer (e.g. skbuff)
325 * @return nss_tx_status_t Tx status
326 */
327nss_tx_status_t nss_tx_virt_if_rx_nwifibuf(void *ctx, struct sk_buff *os_buf)
328{
329
330	return nss_tx_virt_if_recvbuf(ctx, os_buf, 1);
331}
332
333/*
334 * nss_tx_rx_virt_if_msg_init()
335 *	Initialize redir specific message structure.
336 */
337static void nss_tx_rx_virt_if_msg_init(struct nss_tx_rx_virt_if_msg *nrim,
338					uint16_t if_num,
339					uint32_t type,
340					uint32_t len,
341					nss_tx_rx_virt_if_msg_callback_t cb,
342					struct nss_tx_rx_virt_if_handle *app_data)
343{
344	nss_cmn_msg_init(&nrim->cm, if_num, type, len, (void *)cb, (void *)app_data);
345}
346
347/*
348 * nss_tx_rx_virt_if_handle_create_sync()
349 *	Initialize redir handle which holds the if_num and stats per interface.
350 */
351static struct nss_tx_rx_virt_if_handle *nss_tx_rx_virt_if_handle_create(struct nss_ctx_instance *nss_ctx, int32_t if_num, int32_t *cmd_rsp)
352{
353	int32_t index;
354	struct nss_tx_rx_virt_if_handle *handle;
355
356	index = NSS_TX_RX_VIRT_IF_GET_INDEX(if_num);
357
358	handle = (struct nss_tx_rx_virt_if_handle *)kzalloc(sizeof(struct nss_tx_rx_virt_if_handle),
359									GFP_KERNEL);
360	if (!handle) {
361		nss_warning("%p: handle memory alloc failed\n", nss_ctx);
362		*cmd_rsp = NSS_TX_RX_VIRT_IF_ALLOC_FAILURE;
363		goto error1;
364	}
365
366	handle->nss_ctx = nss_ctx;
367	handle->if_num = if_num;
368	handle->pvt = (struct nss_tx_rx_virt_if_pvt *)kzalloc(sizeof(struct nss_tx_rx_virt_if_pvt),
369								GFP_KERNEL);
370	if (!handle->pvt) {
371		nss_warning("%p: failure allocating memory for nss_tx_rx_virt_if_pvt\n", nss_ctx);
372		*cmd_rsp = NSS_TX_RX_VIRT_IF_ALLOC_FAILURE;
373		goto error2;
374	}
375
376	handle->cb = NULL;
377	handle->app_data = NULL;
378
379	spin_lock_bh(&nss_tx_rx_virt_if_lock);
380	nss_tx_rx_virt_if_handles[index] = handle;
381	spin_unlock_bh(&nss_tx_rx_virt_if_lock);
382
383	*cmd_rsp = NSS_VIRT_IF_SUCCESS;
384
385	return handle;
386
387error2:
388	kfree(handle);
389error1:
390	return NULL;
391}
392
393/*
394 * nss_tx_rx_virt_if_register_handler_sync()
395 * 	register msg handler for redir interface and initialize semaphore and completion.
396 */
397static uint32_t nss_tx_rx_virt_if_register_handler(struct nss_tx_rx_virt_if_handle *handle)
398{
399	uint32_t ret;
400	struct nss_tx_rx_virt_if_pvt *nrip = NULL;
401	int32_t if_num = handle->if_num;
402
403	ret = nss_core_register_handler(if_num, nss_tx_rx_virt_if_msg_handler, NULL);
404	if (ret != NSS_CORE_STATUS_SUCCESS) {
405		nss_warning("%d: Message handler failed to be registered for interface\n", if_num);
406		return NSS_TX_RX_VIRT_IF_CORE_FAILURE;
407	}
408
409	nrip = handle->pvt;
410	if (!nrip->sem_init_done) {
411		sema_init(&nrip->sem, 1);
412		init_completion(&nrip->complete);
413		nrip->sem_init_done = 1;
414	}
415
416	return NSS_TX_RX_VIRT_IF_SUCCESS;
417}
418
419/*
420 * nss_tx_rx_virt_if_tx_msg()
421 */
422nss_tx_status_t nss_tx_rx_virt_if_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_tx_rx_virt_if_msg *nrim)
423{
424	int32_t status;
425	struct sk_buff *nbuf;
426	struct nss_cmn_msg *ncm = &nrim->cm;
427	struct nss_tx_rx_virt_if_msg *nrim2;
428
429	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
430		nss_warning("Interface could not be created as core not ready");
431		return NSS_TX_FAILURE;
432	}
433
434	/*
435	 * Sanity check the message
436	 */
437	if (!NSS_IS_IF_TYPE(DYNAMIC, ncm->interface)) {
438		nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
439		return NSS_TX_FAILURE;
440	}
441
442	if (ncm->type > NSS_TX_RX_VIRT_IF_MAX_MSG_TYPES) {
443		nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
444		return NSS_TX_FAILURE;
445	}
446
447	if (ncm->len > sizeof(struct nss_tx_rx_virt_if_msg)) {
448		nss_warning("%p: invalid length: %d. Length of redir msg is %d",
449				nss_ctx, ncm->len, sizeof(struct nss_tx_rx_virt_if_msg));
450		return NSS_TX_FAILURE;
451	}
452
453	nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
454	if (unlikely(!nbuf)) {
455		NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
456		nss_warning("%p: redir interface %d: command allocation failed", nss_ctx, ncm->interface);
457		return NSS_TX_FAILURE;
458	}
459
460	nrim2 = (struct nss_tx_rx_virt_if_msg *)skb_put(nbuf, sizeof(struct nss_tx_rx_virt_if_msg));
461	memcpy(nrim2, nrim, sizeof(struct nss_tx_rx_virt_if_msg));
462
463	status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0);
464	if (status != NSS_CORE_STATUS_SUCCESS) {
465		dev_kfree_skb_any(nbuf);
466		nss_warning("%p: Unable to enqueue 'virtual interface' command\n", nss_ctx);
467		return NSS_TX_FAILURE;
468	}
469
470	nss_hal_send_interrupt(nss_ctx->nmap,
471				nss_ctx->h2n_desc_rings[NSS_IF_CMD_QUEUE].desc_ring.int_bit,
472				NSS_REGS_H2N_INTR_STATUS_DATA_COMMAND_QUEUE);
473
474	/*
475	 * The context returned is the redir interface # which is, essentially, the index into the if_ctx
476	 * array that is holding the net_device pointer
477	 */
478	return NSS_TX_SUCCESS;
479}
480
481/*
482 * nss_tx_rx_virt_if_tx_msg_sync
483 *	Send a message from HLOS to NSS synchronously.
484 */
485static nss_tx_status_t nss_tx_rx_virt_if_tx_msg_sync(struct nss_tx_rx_virt_if_handle *handle,
486							struct nss_tx_rx_virt_if_msg *nvim)
487{
488	nss_tx_status_t status;
489	int ret = 0;
490	struct nss_tx_rx_virt_if_pvt *nrip = handle->pvt;
491	struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
492
493	down(&nrip->sem);
494
495	status = nss_tx_rx_virt_if_tx_msg(nss_ctx, nvim);
496	if (status != NSS_TX_SUCCESS) {
497		nss_warning("%p: nss_tx_rx_virt_if_msg failed\n", nss_ctx);
498		up(&nrip->sem);
499		return status;
500	}
501
502	ret = wait_for_completion_timeout(&nrip->complete,
503						msecs_to_jiffies(NSS_TX_RX_VIRT_IF_TX_TIMEOUT));
504	if (!ret) {
505		nss_warning("%p: redir_if tx failed due to timeout\n", nss_ctx);
506		nrip->response = NSS_TX_FAILURE;
507	}
508
509	status = nrip->response;
510	up(&nrip->sem);
511
512	return status;
513}
514
515/*
516 * nss_tx_rx_virt_if_handle_destroy()
517 *	Destroy the redir handle either due to request from user or due to error, synchronously.
518 */
519static int nss_tx_rx_virt_if_handle_destroy(struct nss_tx_rx_virt_if_handle *handle)
520{
521	nss_tx_status_t status;
522	int32_t if_num = handle->if_num;
523	int32_t index = NSS_TX_RX_VIRT_IF_GET_INDEX(if_num);
524	struct nss_ctx_instance *nss_ctx = NULL;
525
526	nss_ctx = handle->nss_ctx;
527	status = nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_VIRTIF_DEPRECATED);
528	if (status != NSS_TX_SUCCESS) {
529		nss_warning("%p: Dynamic interface destroy failed status %d\n", nss_ctx, status);
530		return status;
531	}
532
533	spin_lock_bh(&nss_tx_rx_virt_if_lock);
534	nss_tx_rx_virt_if_handles[index] = NULL;
535	spin_unlock_bh(&nss_tx_rx_virt_if_lock);
536
537	kfree(handle->pvt);
538	kfree(handle);
539
540	return status;
541}
542
543/*
544 * nss_create_virt_if()
545 *	Create a virtual interface synchronously.
546 */
547void *nss_create_virt_if(struct net_device *netdev)
548{
549	struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.wlan_handler_id];
550	struct nss_tx_rx_virt_if_msg nrim;
551	struct nss_tx_rx_virt_if_create_msg *nrcm;
552	uint32_t ret;
553	struct nss_tx_rx_virt_if_handle *handle = NULL;
554	int32_t if_num;
555
556	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
557		nss_warning("%p: Interface could not be created as core not ready\n", nss_ctx);
558		return NULL;
559	}
560
561	if_num = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_VIRTIF_DEPRECATED);
562	if (if_num < 0) {
563		nss_warning("%p: failure allocating redir if\n", nss_ctx);
564		return NULL;
565	}
566
567	handle = nss_tx_rx_virt_if_handle_create(nss_ctx, if_num, &ret);
568	if (!handle) {
569		nss_warning("%p:redir_if handle creation failed ret %d\n", nss_ctx, ret);
570		nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_VIRTIF_DEPRECATED);
571		return NULL;
572	}
573
574	/* Initializes the semaphore and also sets the msg handler for if_num */
575	ret = nss_tx_rx_virt_if_register_handler(handle);
576	if (ret != NSS_VIRT_IF_SUCCESS) {
577		nss_warning("%p: Registration handler failed reason: %d\n", nss_ctx, ret);
578		goto error;
579	}
580
581	nss_tx_rx_virt_if_msg_init(&nrim, handle->if_num, NSS_TX_RX_VIRT_IF_TX_CREATE_MSG,
582				sizeof(struct nss_tx_rx_virt_if_create_msg), nss_tx_rx_virt_if_callback, handle);
583
584	nrcm = &nrim.msg.if_create;
585	nrcm->flags = 0;
586	memcpy(nrcm->mac_addr, netdev->dev_addr, ETH_ALEN);
587
588	ret = nss_tx_rx_virt_if_tx_msg_sync(handle, &nrim);
589	if (ret != NSS_TX_SUCCESS) {
590		nss_warning("%p: nss_tx_rx_virt_if_tx_msg_sync failed %u\n", nss_ctx, ret);
591		goto error;
592	}
593
594	spin_lock_bh(&nss_top_main.lock);
595	if (!nss_top_main.subsys_dp_register[handle->if_num].ndev) {
596		nss_top_main.subsys_dp_register[handle->if_num].ndev = netdev;
597	}
598	spin_unlock_bh(&nss_top_main.lock);
599
600	/*
601	 * Hold a reference to the net_device
602	 */
603	dev_hold(netdev);
604
605	/*
606	 * The context returned is the handle interface # which contains all the info related to
607	 * the interface if_num.
608	 */
609
610	return (void*)handle;
611
612error:
613	nss_tx_rx_virt_if_handle_destroy(handle);
614	return NULL;
615}
616
617/*
618 * nss_destroy_virt_if()
619 *	Destroy a virtual interface synchronously.
620 */
621nss_tx_status_t nss_destroy_virt_if(void *ctx)
622{
623	struct nss_tx_rx_virt_if_handle *handle = (struct nss_tx_rx_virt_if_handle *)ctx;
624	nss_tx_status_t status;
625	struct net_device *dev;
626	int32_t if_num;
627	struct nss_ctx_instance *nss_ctx;
628	uint32_t ret;
629
630	if (!handle) {
631		nss_warning("handle is NULL\n");
632		return NSS_TX_FAILURE_BAD_PARAM;
633	}
634
635	if_num = handle->if_num;
636	nss_ctx = handle->nss_ctx;
637
638	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
639		nss_warning("%p: Interface could not be destroyed as core not ready\n", nss_ctx);
640		return NSS_TX_FAILURE_NOT_READY;
641	}
642
643	spin_lock_bh(&nss_top_main.lock);
644	if (!nss_top_main.subsys_dp_register[if_num].ndev) {
645		spin_unlock_bh(&nss_top_main.lock);
646		nss_warning("%p: Unregister redir interface %d: no context\n", nss_ctx, if_num);
647		return NSS_TX_FAILURE_BAD_PARAM;
648	}
649
650	dev = nss_top_main.subsys_dp_register[if_num].ndev;
651	nss_top_main.subsys_dp_register[if_num].ndev = NULL;
652	spin_unlock_bh(&nss_top_main.lock);
653	dev_put(dev);
654
655	status = nss_tx_rx_virt_if_handle_destroy(handle);
656	if (status != NSS_TX_SUCCESS) {
657		nss_warning("%p: handle destroy failed for if_num %d\n", nss_ctx, if_num);
658		return NSS_TX_FAILURE;
659	}
660
661	ret = nss_core_unregister_handler(if_num);
662	if (ret != NSS_CORE_STATUS_SUCCESS) {
663		nss_warning("%p: Not able to unregister handler for redir_if interface %d with NSS core\n", nss_ctx, if_num);
664		return NSS_TX_FAILURE_BAD_PARAM;
665	}
666
667	return status;
668}
669
670/*
671 * nss_tx_rx_virt_if_copy_stats()
672 *	Copy stats from the redir_if handle to buffer(line)
673 */
674int32_t nss_tx_rx_virt_if_copy_stats(int32_t if_num, int i, char *line)
675{
676	int32_t bytes = 0;
677	struct nss_tx_rx_virt_if_stats *stats;
678	int32_t ifnum;
679	uint32_t len = 80;
680	struct nss_tx_rx_virt_if_handle *handle = NULL;
681
682	if (if_num < 0) {
683		nss_warning("invalid if_num\n");
684		return 0;
685	}
686
687	ifnum = NSS_TX_RX_VIRT_IF_GET_INDEX(if_num);
688
689	spin_lock_bh(&nss_tx_rx_virt_if_lock);
690	if (!nss_tx_rx_virt_if_handles[ifnum]) {
691		spin_unlock_bh(&nss_tx_rx_virt_if_lock);
692		goto end;
693	}
694
695	handle = nss_tx_rx_virt_if_handles[ifnum];
696	spin_unlock_bh(&nss_tx_rx_virt_if_lock);
697
698	stats = &handle->stats;
699
700	switch (i) {
701	case 0:
702		bytes = scnprintf(line, len, "rx_packets=%d\n",
703					stats->node_stats.rx_packets);
704		break;
705
706	case 1:
707		bytes = scnprintf(line, len, "rx_bytes=%d\n",
708					stats->node_stats.rx_bytes);
709		break;
710
711	case 2:
712		bytes = scnprintf(line, len, "rx_dropped=%d\n",
713					stats->node_stats.rx_dropped);
714		break;
715
716	case 3:
717		bytes = scnprintf(line, len, "tx_packets=%d\n",
718					stats->node_stats.tx_packets);
719		break;
720
721	case 4:
722		bytes = scnprintf(line, len, "tx_bytes=%d\n",
723					stats->node_stats.tx_bytes);
724		break;
725
726	case 5:
727		bytes = scnprintf(line, len, "tx_enqueue_failed=%d\n",
728						stats->tx_enqueue_failed);
729		break;
730
731	case 6:
732		bytes = scnprintf(line, len, "shaper_enqueue_failed=%d\n",
733						stats->shaper_enqueue_failed);
734		break;
735	}
736
737end:
738	return bytes;
739}
740
741EXPORT_SYMBOL(nss_tx_virt_if_rxbuf);
742EXPORT_SYMBOL(nss_tx_virt_if_rx_nwifibuf);
743EXPORT_SYMBOL(nss_create_virt_if);
744EXPORT_SYMBOL(nss_destroy_virt_if);
745EXPORT_SYMBOL(nss_register_virt_if);
746EXPORT_SYMBOL(nss_unregister_virt_if);
747