1/*
2 **************************************************************************
3 * Copyright (c) 2014-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#include "nss_tx_rx_common.h"
18
19/*
20 * nss_sjack_node_sync_update()
21 *	Update sjack node stats.
22 */
23static void nss_sjack_node_sync_update(struct nss_ctx_instance *nss_ctx, struct nss_sjack_stats_sync_msg *nins)
24{
25	struct nss_top_instance *nss_top = nss_ctx->nss_top;
26
27	/*
28	 * Update SJACK node stats.
29	 */
30	spin_lock_bh(&nss_top->stats_lock);
31	nss_top->stats_node[NSS_SJACK_INTERFACE][NSS_STATS_NODE_RX_PKTS] += nins->node_stats.rx_packets;
32	nss_top->stats_node[NSS_SJACK_INTERFACE][NSS_STATS_NODE_RX_BYTES] += nins->node_stats.rx_bytes;
33	nss_top->stats_node[NSS_SJACK_INTERFACE][NSS_STATS_NODE_RX_DROPPED] += nins->node_stats.rx_dropped;
34	nss_top->stats_node[NSS_SJACK_INTERFACE][NSS_STATS_NODE_TX_PKTS] += nins->node_stats.tx_packets;
35	nss_top->stats_node[NSS_SJACK_INTERFACE][NSS_STATS_NODE_TX_BYTES] += nins->node_stats.tx_bytes;
36	spin_unlock_bh(&nss_top->stats_lock);
37}
38
39/*
40 * nss_sjack_handler()
41 * 	Handle NSS -> HLOS messages for sjack
42 */
43static void nss_sjack_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm,
44				__attribute__((unused))void *app_data)
45{
46	void *ctx;
47	nss_sjack_msg_callback_t cb;
48	struct nss_sjack_msg *nsm = (struct nss_sjack_msg *)ncm;
49
50	BUG_ON(ncm->interface != NSS_SJACK_INTERFACE);
51
52	/*
53	 * Is this a valid request/response packet?
54	 */
55	if (ncm->type >=  NSS_SJACK_MAX_MSG_TYPE) {
56		nss_warning("%p: received invalid message %d for sjack interface", nss_ctx, ncm->type);
57		return;
58	}
59
60	if (ncm->len > sizeof(struct nss_sjack_msg)) {
61		nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
62		return;
63	}
64
65	/*
66	 * Update the callback and app_data for NOTIFY messages, sjack sends all notify messages
67	 * to the same callback/app_data.
68	 */
69	if (ncm->response == NSS_CMM_RESPONSE_NOTIFY) {
70		ncm->cb = (uint32_t)nss_ctx->nss_top->if_rx_msg_callback[ncm->interface];
71	}
72
73	/*
74	 * Log failures
75	 */
76	nss_core_log_msg_failures(nss_ctx, ncm);
77
78	switch (ncm->type) {
79	case NSS_SJACK_STATS_SYNC_MSG:
80		/*
81		 * Update sjack statistics on node sync.
82		 */
83		nss_sjack_node_sync_update(nss_ctx, &nsm->msg.stats_sync);
84		break;
85	}
86
87	/*
88	 * Do we have a call back
89	 */
90	if (!ncm->cb) {
91		return;
92	}
93
94	/*
95	 * callback
96	 */
97	cb = (nss_sjack_msg_callback_t)ncm->cb;
98	ctx =  nss_ctx->nss_top->subsys_dp_register[ncm->interface].ndev;
99
100	cb(ctx, ncm);
101}
102
103
104/*
105 * nss_sjack_tx_msg()
106 * 	Transmit a sjack message to NSSFW
107 */
108nss_tx_status_t nss_sjack_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_sjack_msg *msg)
109{
110	struct nss_sjack_msg *nm;
111	struct nss_cmn_msg *ncm = &msg->cm;
112	struct sk_buff *nbuf;
113	int32_t status;
114
115	NSS_VERIFY_CTX_MAGIC(nss_ctx);
116	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
117		nss_warning("%p: sjack msg dropped as core not ready", nss_ctx);
118		return NSS_TX_FAILURE_NOT_READY;
119	}
120
121	/*
122	 * Sanity check the message
123	 */
124	if (ncm->interface != NSS_SJACK_INTERFACE) {
125		nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
126		return NSS_TX_FAILURE;
127	}
128
129	if (ncm->type > NSS_SJACK_MAX_MSG_TYPE) {
130		nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
131		return NSS_TX_FAILURE;
132	}
133
134	if (ncm->len > sizeof(struct nss_sjack_msg)) {
135		nss_warning("%p: message length is invalid: %d", nss_ctx, ncm->len);
136		return NSS_TX_FAILURE;
137	}
138
139	nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
140	if (unlikely(!nbuf)) {
141		NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
142		nss_warning("%p: msg dropped as command allocation failed", nss_ctx);
143		return NSS_TX_FAILURE;
144	}
145
146	/*
147	 * Copy the message to our skb
148	 */
149	nm = (struct nss_sjack_msg *)skb_put(nbuf, sizeof(struct nss_sjack_msg));
150	memcpy(nm, msg, sizeof(struct nss_sjack_msg));
151
152	status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0);
153	if (status != NSS_CORE_STATUS_SUCCESS) {
154		dev_kfree_skb_any(nbuf);
155		nss_warning("%p: Unable to enqueue 'sjack message' \n", nss_ctx);
156		return NSS_TX_FAILURE;
157	}
158
159	nss_hal_send_interrupt(nss_ctx->nmap, nss_ctx->h2n_desc_rings[NSS_IF_CMD_QUEUE].desc_ring.int_bit,
160				NSS_REGS_H2N_INTR_STATUS_DATA_COMMAND_QUEUE);
161
162	NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CMD_REQ]);
163	return NSS_TX_SUCCESS;
164}
165
166/*
167 * nss_sjack_register_if()
168 */
169struct nss_ctx_instance *nss_sjack_register_if(uint32_t if_num, struct net_device *netdev,
170						nss_sjack_msg_callback_t event_callback)
171{
172	nss_assert(if_num == NSS_SJACK_INTERFACE);
173
174	nss_top_main.subsys_dp_register[if_num].ndev = netdev;
175
176	nss_top_main.if_rx_msg_callback[if_num] = event_callback;
177
178	return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.sjack_handler_id];
179}
180
181/*
182 * nss_sjack_unregister_if()
183 */
184void nss_sjack_unregister_if(uint32_t if_num)
185{
186	nss_assert(if_num == NSS_SJACK_INTERFACE);
187
188	nss_top_main.subsys_dp_register[if_num].ndev = NULL;
189	nss_top_main.if_rx_msg_callback[if_num] = NULL;
190
191	return;
192}
193
194/*
195 * nss_sjack_register_handler()
196 *	Registering handler for sending msg to sjack node on NSS.
197 */
198void nss_sjack_register_handler(void)
199{
200	nss_core_register_handler(NSS_SJACK_INTERFACE, nss_sjack_handler, NULL);
201}
202
203EXPORT_SYMBOL(nss_sjack_register_if);
204EXPORT_SYMBOL(nss_sjack_unregister_if);
205EXPORT_SYMBOL(nss_sjack_tx_msg);
206