blob: 0d78a719ac58331c043dfa0c01e7af8b3ddae546 [file] [log] [blame]
Suman Ghosh85f353a2019-06-03 14:47:32 +05301/*
2 **************************************************************************
Kyle Swensondd7b2962021-03-16 13:46:32 -06003 * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
Suman Ghosh85f353a2019-06-03 14:47:32 +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 /*
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) {
Kyle Swensondd7b2962021-03-16 13:46:32 -060091 nss_warning("%px: received invalid message %d for clmap interface", nss_ctx, ncm->type);
Suman Ghosh85f353a2019-06-03 14:47:32 +053092 return;
93 }
94
95 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_clmap_msg)) {
Kyle Swensondd7b2962021-03-16 13:46:32 -060096 nss_warning("%px: Length of message is greater than required: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
Suman Ghosh85f353a2019-06-03 14:47:32 +053097 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) {
Kyle Swensondd7b2962021-03-16 13:46:32 -0600116 ncm->cb = (nss_ptr_t)nss_core_get_msg_handler(nss_ctx, ncm->interface);
117 ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[ncm->interface].app_data;
Suman Ghosh85f353a2019-06-03 14:47:32 +0530118 }
119
120 /*
121 * Do we have a callback
122 */
123 cb = (nss_clmap_msg_callback_t)ncm->cb;
124 if (!cb) {
Kyle Swensondd7b2962021-03-16 13:46:32 -0600125 nss_trace("%px: cb is null for interface %d", nss_ctx, ncm->interface);
Suman Ghosh85f353a2019-06-03 14:47:32 +0530126 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) {
Kyle Swensondd7b2962021-03-16 13:46:32 -0600172 nss_warning("%px: clmap_tx_msg failed\n", nss_ctx);
Suman Ghosh85f353a2019-06-03 14:47:32 +0530173 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) {
Kyle Swensondd7b2962021-03-16 13:46:32 -0600179 nss_warning("%px: clmap tx sync failed due to timeout\n", nss_ctx);
Suman Ghosh85f353a2019-06-03 14:47:32 +0530180 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;
Kyle Swensondd7b2962021-03-16 13:46:32 -0600208 int status;
Suman Ghosh85f353a2019-06-03 14:47:32 +0530209
210 nss_ctx = nss_clmap_get_ctx();
211 NSS_VERIFY_CTX_MAGIC(nss_ctx);
212
213 if (!nss_clmap_verify_if_num(if_num)) {
Kyle Swensondd7b2962021-03-16 13:46:32 -0600214 nss_warning("%px: clmap unregister request received for invalid interface %d", nss_ctx, if_num);
Suman Ghosh85f353a2019-06-03 14:47:32 +0530215 return false;
216 }
217
Kyle Swensondd7b2962021-03-16 13:46:32 -0600218 status = nss_core_unregister_msg_handler(nss_ctx, if_num);
219 if (status != NSS_CORE_STATUS_SUCCESS) {
220 nss_warning("%px: Failed to unregister handler for clmap NSS I/F:%u\n", nss_ctx, if_num);
221 return false;
222 }
223
Suman Ghosh85f353a2019-06-03 14:47:32 +0530224 nss_core_unregister_subsys_dp(nss_ctx, if_num);
Kyle Swensondd7b2962021-03-16 13:46:32 -0600225 nss_core_unregister_handler(nss_ctx, if_num);
226 nss_clmap_stats_session_unregister(if_num);
Suman Ghosh85f353a2019-06-03 14:47:32 +0530227
228 return true;
229}
230EXPORT_SYMBOL(nss_clmap_unregister);
231
232/*
233 * nss_clmap_register()
234 * Registers a clmap interface with the NSS.
235 */
236struct nss_ctx_instance *nss_clmap_register(uint32_t if_num,
237 uint32_t di_type,
238 nss_clmap_buf_callback_t data_cb,
239 nss_clmap_msg_callback_t notify_cb,
240 struct net_device *netdev,
241 uint32_t features)
242{
243 struct nss_ctx_instance *nss_ctx;
244 int core_status;
245 bool stats_status = false;
246
247 nss_ctx = nss_clmap_get_ctx();
248 NSS_VERIFY_CTX_MAGIC(nss_ctx);
249
250 if (!nss_clmap_verify_if_num(if_num)) {
Kyle Swensondd7b2962021-03-16 13:46:32 -0600251 nss_warning("%px: clmap register request received for invalid interface %d", nss_ctx, if_num);
252 goto fail;
Suman Ghosh85f353a2019-06-03 14:47:32 +0530253 }
254
255 if (di_type == NSS_DYNAMIC_INTERFACE_TYPE_CLMAP_US) {
256 stats_status = nss_clmap_stats_session_register(if_num, NSS_CLMAP_INTERFACE_TYPE_US, netdev);
257 } else {
258 stats_status = nss_clmap_stats_session_register(if_num, NSS_CLMAP_INTERFACE_TYPE_DS, netdev);
259 }
260
261 if (!stats_status) {
Kyle Swensondd7b2962021-03-16 13:46:32 -0600262 nss_warning("%px: statistics registration failed for interface: %d\n", nss_ctx, if_num);
263 goto fail;
Suman Ghosh85f353a2019-06-03 14:47:32 +0530264 }
265
266 core_status = nss_core_register_handler(nss_ctx, if_num, nss_clmap_msg_handler, (void *)netdev);
267 if (core_status != NSS_CORE_STATUS_SUCCESS) {
Kyle Swensondd7b2962021-03-16 13:46:32 -0600268 goto core_reg_fail;
269 }
270
271 core_status = nss_core_register_msg_handler(nss_ctx, if_num, notify_cb);
272 if (core_status != NSS_CORE_STATUS_SUCCESS) {
273 goto msg_reg_fail;
Suman Ghosh85f353a2019-06-03 14:47:32 +0530274 }
275
276 nss_core_register_subsys_dp(nss_ctx, if_num, data_cb, NULL, (void *)netdev, netdev, features);
277 nss_core_set_subsys_dp_type(nss_ctx, netdev, if_num, di_type);
Suman Ghosh85f353a2019-06-03 14:47:32 +0530278
279 return nss_ctx;
Kyle Swensondd7b2962021-03-16 13:46:32 -0600280
281msg_reg_fail:
282 nss_core_unregister_handler(nss_ctx, if_num);
283core_reg_fail:
284 nss_clmap_stats_session_unregister(if_num);
285 nss_warning("%px: NSS core register handler failed for if_num:%d with error :%d", nss_ctx, if_num, core_status);
286fail:
287 return NULL;
288
Suman Ghosh85f353a2019-06-03 14:47:32 +0530289}
290EXPORT_SYMBOL(nss_clmap_register);
291
292/*
293 * nss_clmap_ifnum_with_core_id()
294 * Append core ID to clmap interface num.
295 */
296int nss_clmap_ifnum_with_core_id(int if_num)
297{
298 struct nss_ctx_instance *nss_ctx = nss_clmap_get_ctx();
299
300 NSS_VERIFY_CTX_MAGIC(nss_ctx);
301 if (!nss_is_dynamic_interface(if_num)) {
Kyle Swensondd7b2962021-03-16 13:46:32 -0600302 nss_warning("%px: Invalid if_num: %d, must be a dynamic interface\n", nss_ctx, if_num);
Suman Ghosh85f353a2019-06-03 14:47:32 +0530303 return 0;
304 }
305 return NSS_INTERFACE_NUM_APPEND_COREID(nss_ctx, if_num);
306}
307EXPORT_SYMBOL(nss_clmap_ifnum_with_core_id);
308
309/*
310 * nss_clmap_msg_init()
311 * Initialize clmap message.
312 */
313void nss_clmap_msg_init(struct nss_clmap_msg *ncm, uint16_t if_num, uint32_t type, uint32_t len,
314 nss_clmap_msg_callback_t cb, void *app_data)
315{
316 nss_cmn_msg_init(&ncm->cm, if_num, type, len, (void*)cb, app_data);
317}
318EXPORT_SYMBOL(nss_clmap_msg_init);
319
320/*
321 * nss_clmap_get_ctx()
322 * Return a clmap NSS context.
323 */
324struct nss_ctx_instance *nss_clmap_get_ctx()
325{
326 struct nss_ctx_instance *nss_ctx;
327
328 nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.clmap_handler_id];
329 return nss_ctx;
330}
331EXPORT_SYMBOL(nss_clmap_get_ctx);
332
333/*
334 * nss_clmap_init()
335 * Initializes clmap. Gets called from nss_init.c.
336 */
337void nss_clmap_init()
338{
339 nss_clmap_stats_dentry_create();
340 sema_init(&clmap_pvt.sem, 1);
341 init_completion(&clmap_pvt.complete);
342}