blob: a76fd6423c00150150f6ceba7757d922383647dc [file] [log] [blame]
Suman Ghosh85f353a2019-06-03 14:47:32 +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_clmap.c
19 * NSS clmap driver interface APIs
20 */
21#include "nss_core.h"
22#include "nss_clmap.h"
23#include "nss_cmn.h"
24#include "nss_tx_rx_common.h"
25#include "nss_clmap_stats.h"
26#include "nss_clmap_log.h"
27
28#define NSS_CLMAP_TX_TIMEOUT 3000
29
30/*
31 * Private data structure
32 */
33static struct nss_clmap_pvt {
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} clmap_pvt;
40
41/*
42 * nss_clmap_verify_if_num()
43 * Verify if_num passed to us.
44 */
45static bool nss_clmap_verify_if_num(uint32_t if_num)
46{
47 uint32_t type = nss_dynamic_interface_get_type(nss_clmap_get_ctx(), if_num);
48
49 return ((type == NSS_DYNAMIC_INTERFACE_TYPE_CLMAP_US) ||
50 (type == NSS_DYNAMIC_INTERFACE_TYPE_CLMAP_DS));
51}
52
53/*
54 * nss_clmap_callback()
55 * Callback to handle the completion of NSS->HLOS messages.
56 */
57static void nss_clmap_callback(void *app_data, struct nss_clmap_msg *nclm)
58{
59 clmap_pvt.response = NSS_TX_SUCCESS;
60 clmap_pvt.cb = NULL;
61 clmap_pvt.app_data = NULL;
62
63 if (nclm->cm.response != NSS_CMN_RESPONSE_ACK) {
64 nss_warning("clmap Error response %d\n", nclm->cm.response);
65 clmap_pvt.response = nclm->cm.response;
66 }
67
68 /*
69 * Write memory barrier.
70 */
71 smp_wmb();
72 complete(&clmap_pvt.complete);
73}
74
75/*
76 * nss_clmap_handler()
77 * Handle NSS -> HLOS messages for clmap.
78 */
79static void nss_clmap_msg_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
80{
81 struct nss_clmap_msg *nclm = (struct nss_clmap_msg *)ncm;
82 nss_clmap_msg_callback_t cb;
83
84 BUG_ON(!nss_clmap_verify_if_num(ncm->interface));
85 NSS_VERIFY_CTX_MAGIC(nss_ctx);
86
87 /*
88 * Is this a valid request/response packet?
89 */
90 if (ncm->type >= NSS_CLMAP_MSG_TYPE_MAX) {
91 nss_warning("%p: received invalid message %d for clmap interface", nss_ctx, ncm->type);
92 return;
93 }
94
95 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_clmap_msg)) {
96 nss_warning("%p: Length of message is greater than required: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
97 return;
98 }
99
100 /*
101 * Trace messages.
102 */
103 nss_core_log_msg_failures(nss_ctx, ncm);
104 nss_clmap_log_rx_msg(nclm);
105
106 switch (nclm->cm.type) {
107 case NSS_CLMAP_MSG_TYPE_SYNC_STATS:
108 nss_clmap_stats_sync(nss_ctx, &nclm->msg.stats, ncm->interface);
109 break;
110 }
111
112 /*
113 * Update the callback and app_data for NOTIFY messages.
114 */
115 if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) {
116 ncm->cb = (nss_ptr_t)nss_top_main.if_rx_msg_callback[ncm->interface];
117 ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[nss_ctx->id][ncm->interface].app_data;
118 }
119
120 /*
121 * Do we have a callback
122 */
123 cb = (nss_clmap_msg_callback_t)ncm->cb;
124 if (!cb) {
125 nss_trace("%p: cb is null for interface %d", nss_ctx, ncm->interface);
126 return;
127 }
128
129 cb((void *)ncm->app_data, ncm);
130}
131
132/*
133 * nss_clmap_tx_msg()
134 * Transmit a clmap message to NSS FW. Don't call this from softirq/interrupts.
135 */
136nss_tx_status_t nss_clmap_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_clmap_msg *msg)
137{
138 struct nss_cmn_msg *ncm = &msg->cm;
139
140 if (!nss_clmap_verify_if_num(msg->cm.interface)) {
141 return NSS_TX_FAILURE_BAD_PARAM;
142 }
143
144 if (ncm->type >= NSS_CLMAP_MSG_TYPE_MAX) {
145 return NSS_TX_FAILURE_BAD_PARAM;
146 }
147
148 /*
149 * Trace messages.
150 */
151 nss_clmap_log_tx_msg(msg);
152
153 return nss_core_send_cmd(nss_ctx, msg, sizeof(*msg), NSS_NBUF_PAYLOAD_SIZE);
154}
155EXPORT_SYMBOL(nss_clmap_tx_msg);
156
157/*
158 * nss_clmap_tx_msg_sync()
159 * Transmit a clmap message to NSS firmware synchronously.
160 */
161nss_tx_status_t nss_clmap_tx_msg_sync(struct nss_ctx_instance *nss_ctx, struct nss_clmap_msg *nclm)
162{
163 nss_tx_status_t status;
164 int ret;
165
166 down(&clmap_pvt.sem);
167 nclm->cm.cb = (nss_ptr_t)nss_clmap_callback;
168 nclm->cm.app_data = (nss_ptr_t)NULL;
169
170 status = nss_clmap_tx_msg(nss_ctx, nclm);
171 if (status != NSS_TX_SUCCESS) {
172 nss_warning("%p: clmap_tx_msg failed\n", nss_ctx);
173 up(&clmap_pvt.sem);
174 return status;
175 }
176
177 ret = wait_for_completion_timeout(&clmap_pvt.complete, msecs_to_jiffies(NSS_CLMAP_TX_TIMEOUT));
178 if (!ret) {
179 nss_warning("%p: clmap tx sync failed due to timeout\n", nss_ctx);
180 clmap_pvt.response = NSS_TX_FAILURE;
181 }
182
183 status = clmap_pvt.response;
184 up(&clmap_pvt.sem);
185 return status;
186}
187EXPORT_SYMBOL(nss_clmap_tx_msg_sync);
188
189/*
190 * nss_clmap_tx_buf()
191 * Transmit data buffer (skb) to a NSS interface number
192 */
193nss_tx_status_t nss_clmap_tx_buf(struct nss_ctx_instance *nss_ctx, struct sk_buff *buf, uint32_t if_num)
194{
195 BUG_ON(!nss_clmap_verify_if_num(if_num));
196
197 return nss_core_send_packet(nss_ctx, buf, if_num, H2N_BIT_FLAG_VIRTUAL_BUFFER);
198}
199EXPORT_SYMBOL(nss_clmap_tx_buf);
200
201/*
202 * nss_clmap_unregister()
203 * Un-register a clmap interface from NSS.
204 */
205bool nss_clmap_unregister(uint32_t if_num)
206{
207 struct nss_ctx_instance *nss_ctx;
208
209 nss_ctx = nss_clmap_get_ctx();
210 NSS_VERIFY_CTX_MAGIC(nss_ctx);
211
212 if (!nss_clmap_verify_if_num(if_num)) {
213 nss_warning("%p: clmap unregister request received for invalid interface %d", nss_ctx, if_num);
214 return false;
215 }
216
217 nss_clmap_stats_session_unregister(if_num);
218 nss_core_unregister_handler(nss_ctx, if_num);
219 nss_core_unregister_subsys_dp(nss_ctx, if_num);
220 nss_top_main.if_rx_msg_callback[if_num] = NULL;
221
222 return true;
223}
224EXPORT_SYMBOL(nss_clmap_unregister);
225
226/*
227 * nss_clmap_register()
228 * Registers a clmap interface with the NSS.
229 */
230struct nss_ctx_instance *nss_clmap_register(uint32_t if_num,
231 uint32_t di_type,
232 nss_clmap_buf_callback_t data_cb,
233 nss_clmap_msg_callback_t notify_cb,
234 struct net_device *netdev,
235 uint32_t features)
236{
237 struct nss_ctx_instance *nss_ctx;
238 int core_status;
239 bool stats_status = false;
240
241 nss_ctx = nss_clmap_get_ctx();
242 NSS_VERIFY_CTX_MAGIC(nss_ctx);
243
244 if (!nss_clmap_verify_if_num(if_num)) {
245 nss_warning("%p: clmap register request received for invalid interface %d", nss_ctx, if_num);
246 return NULL;
247 }
248
249 if (di_type == NSS_DYNAMIC_INTERFACE_TYPE_CLMAP_US) {
250 stats_status = nss_clmap_stats_session_register(if_num, NSS_CLMAP_INTERFACE_TYPE_US, netdev);
251 } else {
252 stats_status = nss_clmap_stats_session_register(if_num, NSS_CLMAP_INTERFACE_TYPE_DS, netdev);
253 }
254
255 if (!stats_status) {
256 nss_warning("%p: statistics registration failed for interface: %d\n", nss_ctx, if_num);
257 return NULL;
258 }
259
260 core_status = nss_core_register_handler(nss_ctx, if_num, nss_clmap_msg_handler, (void *)netdev);
261 if (core_status != NSS_CORE_STATUS_SUCCESS) {
262 nss_clmap_stats_session_unregister(if_num);
263 nss_warning("%p: NSS core register handler failed for if_num:%d with error :%d", nss_ctx, if_num, core_status);
264 return NULL;
265 }
266
267 nss_core_register_subsys_dp(nss_ctx, if_num, data_cb, NULL, (void *)netdev, netdev, features);
268 nss_core_set_subsys_dp_type(nss_ctx, netdev, if_num, di_type);
269 nss_top_main.if_rx_msg_callback[if_num] = notify_cb;
270
271 return nss_ctx;
272}
273EXPORT_SYMBOL(nss_clmap_register);
274
275/*
276 * nss_clmap_ifnum_with_core_id()
277 * Append core ID to clmap interface num.
278 */
279int nss_clmap_ifnum_with_core_id(int if_num)
280{
281 struct nss_ctx_instance *nss_ctx = nss_clmap_get_ctx();
282
283 NSS_VERIFY_CTX_MAGIC(nss_ctx);
284 if (!nss_is_dynamic_interface(if_num)) {
285 nss_warning("%p: Invalid if_num: %d, must be a dynamic interface\n", nss_ctx, if_num);
286 return 0;
287 }
288 return NSS_INTERFACE_NUM_APPEND_COREID(nss_ctx, if_num);
289}
290EXPORT_SYMBOL(nss_clmap_ifnum_with_core_id);
291
292/*
293 * nss_clmap_msg_init()
294 * Initialize clmap message.
295 */
296void nss_clmap_msg_init(struct nss_clmap_msg *ncm, uint16_t if_num, uint32_t type, uint32_t len,
297 nss_clmap_msg_callback_t cb, void *app_data)
298{
299 nss_cmn_msg_init(&ncm->cm, if_num, type, len, (void*)cb, app_data);
300}
301EXPORT_SYMBOL(nss_clmap_msg_init);
302
303/*
304 * nss_clmap_get_ctx()
305 * Return a clmap NSS context.
306 */
307struct nss_ctx_instance *nss_clmap_get_ctx()
308{
309 struct nss_ctx_instance *nss_ctx;
310
311 nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.clmap_handler_id];
312 return nss_ctx;
313}
314EXPORT_SYMBOL(nss_clmap_get_ctx);
315
316/*
317 * nss_clmap_init()
318 * Initializes clmap. Gets called from nss_init.c.
319 */
320void nss_clmap_init()
321{
322 nss_clmap_stats_dentry_create();
323 sema_init(&clmap_pvt.sem, 1);
324 init_completion(&clmap_pvt.complete);
325}