blob: 92a42edd85126332421dd3315e6c819733a88698 [file] [log] [blame]
Murat Sezgine5079aa2017-06-07 18:09:38 -07001/*
2 **************************************************************************
3 * Copyright (c) 2017, 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_dscp2pri.c
19 * NSS dscp2pri node APIs
20 */
21
22#include "nss_tx_rx_common.h"
23
24#define NSS_DSCP2PRI_PARAM_FIELD_COUNT 3
25#define NSS_DSCP2PRI_ARRAY_SIZE 64
26
27/*
28 * dscp2pri mapping structure.
29 */
30struct nss_dscp2pri_map {
31 uint8_t action; /* Action associated with the DSCP value.*/
32 uint8_t priority; /* Priority associated with the DSCP value. */
33};
34
35struct nss_dscp2pri_map mapping[NSS_DSCP2PRI_ARRAY_SIZE];
36
37/*
38 * Private data structure
39 */
40static struct nss_dscp2pri_pvt {
41 struct semaphore sem;
42 struct completion complete;
43 int response;
44 void *cb;
45 void *app_data;
46} dscp2pri_pvt;
47
48/*
49 * nss_dscp2pri_usage()
50 * Help function shows the usage of the command.
51 */
52static void nss_dscp2pri_usage(void)
53{
54 nss_info_always("\nUsage:\n");
55 nss_info_always("echo <dscp> <action> <prio> > /proc/sys/dev/nss/dscp2pri/map\n\n");
56 nss_info_always("dscp[0-63] action[0-1] prio[0-3]:\n\n");
57}
58
59/*
60 * nss_dscp2pri_msg_init()
61 * Initialize dscp2pri message.
62 */
63static void nss_dscp2pri_msg_init(struct nss_dscp2pri_msg *ndm, uint16_t if_num, uint32_t type,
64 uint32_t len, nss_dscp2pri_msg_callback_t cb, void *app_data)
65{
66 nss_cmn_msg_init(&ndm->cm, if_num, type, len, (void *)cb, app_data);
67}
68
69/*
70 * nss_dscp2pri_tx_msg()
71 * TX message function.
72 */
73static nss_tx_status_t nss_dscp2pri_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_dscp2pri_msg *ndm)
74{
75 struct nss_dscp2pri_msg *ndm2;
76 struct nss_cmn_msg *ncm = &ndm->cm;
77 struct sk_buff *nbuf;
78 nss_tx_status_t status;
79
80 NSS_VERIFY_CTX_MAGIC(nss_ctx);
81 if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
82 return NSS_TX_FAILURE_NOT_READY;
83 }
84
85 /*
86 * Sanity check the message
87 */
88 if (ncm->interface != NSS_DSCP2PRI_INTERFACE) {
89 nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
90 return NSS_TX_FAILURE;
91 }
92
93 if (ncm->type >= NSS_DSCP2PRI_METADATA_TYPE_MAX) {
94 nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
95 return NSS_TX_FAILURE;
96 }
97
98 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_dscp2pri_msg)) {
99 nss_warning("%p: tx request for another interface: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
100 return NSS_TX_FAILURE;
101 }
102
103 nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
104 if (unlikely(!nbuf)) {
105 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
106 return NSS_TX_FAILURE;
107 }
108
109 /*
110 * Copy the message to our skb.
111 */
112 ndm2 = (struct nss_dscp2pri_msg *)skb_put(nbuf, sizeof(struct nss_dscp2pri_msg));
113 memcpy(ndm2, ndm, sizeof(struct nss_dscp2pri_msg));
114 status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0);
115 if (status != NSS_CORE_STATUS_SUCCESS) {
116 dev_kfree_skb_any(nbuf);
117 nss_info("%p: unable to send dscp2pri message\n", nss_ctx);
118 return NSS_TX_FAILURE;
119 }
120
121 nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
122 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CMD_REQ]);
123 return NSS_TX_SUCCESS;
124}
125
126/*
127 * nss_dscp2pri_configure_mapping_callback_async()
128 * Callback function for async messages.
129 */
130static void nss_dscp2pri_configure_mapping_callback_async(void *app_data, struct nss_dscp2pri_msg *ndm)
131{
132 if (ndm->cm.response != NSS_CMN_RESPONSE_ACK) {
133 nss_warning("%p: nss dscp2pri configure mapping tx async failed: %d\n",
134 &dscp2pri_pvt, ndm->cm.error);
135 return;
136 }
137
138 nss_info("%p: nss dscp2pri configure mapping tx async succeeded\n", &dscp2pri_pvt);
139
140 /*
141 * NSS firmware acknowleged the configuration, so update the mapping table on HOST side as well.
142 * Note that action value was sent to NSS firmware as opaque, because action is not needed in
143 * NSS firmware. It is only used in HOST code.
144 */
145 mapping[ndm->msg.configure_mapping.dscp].action = ndm->msg.configure_mapping.opaque;
146 mapping[ndm->msg.configure_mapping.dscp].priority = ndm->msg.configure_mapping.priority;
147}
148
149/*
150 * nss_dscp2pri_configure_mapping_callback_sync()
151 * Callback function for sync messages.
152 */
153static void nss_dscp2pri_configure_mapping_callback_sync(void *app_data, struct nss_dscp2pri_msg *ndm)
154{
155 nss_dscp2pri_msg_callback_t callback = (nss_dscp2pri_msg_callback_t)dscp2pri_pvt.cb;
156 void *data = (void *)dscp2pri_pvt.app_data;
157
158 dscp2pri_pvt.cb = NULL;
159 dscp2pri_pvt.app_data = NULL;
160
161 if (ndm->cm.response != NSS_CMN_RESPONSE_ACK) {
162 dscp2pri_pvt.response = NSS_FAILURE;
163 complete(&dscp2pri_pvt.complete);
164 nss_warning("%p: nss dscp2pri configure mapping tx sync failed: %d\n",
165 &dscp2pri_pvt, ndm->cm.error);
166 return;
167 }
168
169 nss_info("%p: nss dscp2pri configure mapping tx sync succeeded\n",
170 &dscp2pri_pvt);
171
172 dscp2pri_pvt.response = NSS_SUCCESS;
173
174 if (callback) {
175 callback(data, ndm);
176 }
177
178 complete(&dscp2pri_pvt.complete);
179}
180
181/*
182 * nss_dscp2pri_configure_mapping_async()
183 * Async implementation for sending message to NSS.
184 */
185static nss_tx_status_t nss_dscp2pri_configure_mapping_async(struct nss_dscp2pri_msg *ndm)
186{
187 struct nss_top_instance *nss_top = &nss_top_main;
188 struct nss_ctx_instance *nss_ctx = &nss_top->nss[0];
189
190 nss_tx_status_t status = nss_dscp2pri_tx_msg(nss_ctx, ndm);
191 if (status != NSS_TX_SUCCESS) {
192 nss_warning("nss_dscp2pri tx error to send configure mapping message\n");
193 return status;
194 }
195
196 return NSS_TX_SUCCESS;
197}
198
199/*
200 * nss_dscp2pri_configure_mapping_sync()
201 * Sync implementation for sending message to NSS.
202 */
203static nss_tx_status_t nss_dscp2pri_configure_mapping_sync(struct nss_dscp2pri_msg *ndm)
204{
205 nss_tx_status_t status;
206 int ret;
207
208 down(&dscp2pri_pvt.sem);
209 dscp2pri_pvt.response = NSS_FAILURE;
210
211 dscp2pri_pvt.cb = (void *)ndm->cm.cb;
212 dscp2pri_pvt.app_data = (void *)ndm->cm.app_data;
213
214 ndm->cm.cb = (nss_ptr_t)nss_dscp2pri_configure_mapping_callback_sync;
215 ndm->cm.app_data = (nss_ptr_t)ndm;
216
217 status = nss_dscp2pri_configure_mapping_async(ndm);
218 if (status != NSS_TX_SUCCESS) {
219 goto failure;
220 }
221
222 /*
223 * Blocking call, wait till we get ACK for this msg.
224 */
225 ret = wait_for_completion_timeout(&dscp2pri_pvt.complete,
226 msecs_to_jiffies(NSS_CONN_CFG_TIMEOUT));
227 if (!ret) {
228 nss_warning("Waiting for ack time out for configure mapping message\n");
229 goto failure;
230 }
231
232 up(&dscp2pri_pvt.sem);
233 return dscp2pri_pvt.response;
234
235failure:
236 dscp2pri_pvt.response = NSS_TX_FAILURE;
237 up(&dscp2pri_pvt.sem);
238 return NSS_TX_FAILURE;
239}
240
241/*
242 * nss_dscp2pri_sysctl_map_handler()
243 * Sysctl handler for dscp/pri mappings.
244 */
245static int nss_dscp2pri_sysctl_map_handler(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
246{
247 int count;
248 size_t cp_bytes = 0;
249 char w_buf[7];
250 loff_t w_offset = 0;
251 char *str;
252 char *tokens[NSS_DSCP2PRI_PARAM_FIELD_COUNT];
253 unsigned int dscp, priority, action;
254 struct nss_dscp2pri_configure_mapping *cfg;
255 struct nss_dscp2pri_msg ndm;
256 nss_tx_status_t status;
257 int ret;
258
259 /*
260 * It's a read operation
261 */
262 if (!write) {
263 /*
264 * (64 * 8) + 22 bytes for the buffer size is sufficient to write
265 * the table including the spaces and new line characters.
266 */
267 char r_buf[(NSS_DSCP2PRI_ARRAY_SIZE * 8) + 22] = {0};
268 int i, len;
269
270 /*
271 * Write the priority values to the first line of the output.
272 */
273 len = scnprintf(r_buf + cp_bytes, 11, "%s: ", "priority");
274 cp_bytes += len;
275 for (i = 0; i < NSS_DSCP2PRI_ARRAY_SIZE; i++) {
276 len = scnprintf(r_buf + cp_bytes, 4, "%d ", mapping[i].priority);
277 if (!len) {
278 nss_warning("failed to read from buffer %d\n", mapping[i].priority);
279 return -EFAULT;
280 }
281 cp_bytes += len;
282 }
283
284 /*
285 * Add new line character at the end.
286 */
287 len = scnprintf(r_buf + cp_bytes, 4, "\n");
288 cp_bytes += len;
289
290 /*
291 * Write the action values to the second line of the output.
292 */
293 len = scnprintf(r_buf + cp_bytes, 11, "%s: ", "action");
294 cp_bytes += len;
295 for (i = 0; i < NSS_DSCP2PRI_ARRAY_SIZE; i++) {
296 len = scnprintf(r_buf + cp_bytes, 4, "%d ", mapping[i].action);
297 if (!len) {
298 nss_warning("failed to read from buffer %d\n", mapping[i].action);
299 return -EFAULT;
300 }
301 cp_bytes += len;
302 }
303
304 /*
305 * Add new line character at the end.
306 */
307 len = scnprintf(r_buf + cp_bytes, 4, "\n");
308 cp_bytes += len;
309
310 cp_bytes = simple_read_from_buffer(buffer, *lenp, ppos, r_buf, cp_bytes);
311 *lenp = cp_bytes;
312 return 0;
313 }
314
315 /*
316 * Buffer length cannot be more than 7 and less than 6.
317 */
318 if (*lenp < 6 || *lenp > 7) {
319 nss_warning("Buffer is not correct. Invalid lenght: %d\n", (int)*lenp);
320 nss_dscp2pri_usage();
321 return 0;
322 }
323
324 /*
325 * It's a write operation
326 */
327 cp_bytes = simple_write_to_buffer(w_buf, *lenp, &w_offset, buffer, 7);
328 if (cp_bytes != *lenp) {
329 nss_warning("failed to write to buffer\n");
330 return -EFAULT;
331 }
332
333 count = 0;
334 str = w_buf;
335 tokens[count] = strsep(&str, " ");
336 while (tokens[count] != NULL) {
337 count++;
338 if (count == NSS_DSCP2PRI_PARAM_FIELD_COUNT) {
339 nss_warning("maximum allowed field count is %d\n", NSS_DSCP2PRI_PARAM_FIELD_COUNT);
340 break;
341 }
342 tokens[count] = strsep(&str, " ");
343 }
344
345 /*
346 * Did we read enough number of parameters from the command line.
347 * There must be 2 parameters.
348 */
349 if (count != NSS_DSCP2PRI_PARAM_FIELD_COUNT) {
350 nss_warning("param fields are less than expected: %d\n", count);
351 nss_dscp2pri_usage();
352 return 0;
353 }
354
355 /*
356 * Write the tokens to integers.
357 */
358 ret = sscanf(tokens[0], "%u", &dscp);
359 if (ret != 1) {
360 nss_warning("failed to write the dscp token to integer\n");
361 return -EFAULT;
362 }
363
364 ret = sscanf(tokens[1], "%u", &action);
365 if (ret != 1) {
366 nss_warning("failed to write the action token to integer\n");
367 return -EFAULT;
368 }
369
370 ret = sscanf(tokens[2], "%u", &priority);
371 if (ret != 1) {
372 nss_warning("failed to write the priority token to integer\n");
373 return -EFAULT;
374 }
375
376 /*
377 * dscp value cannot be higher than 63.
378 */
379 if (dscp >= NSS_DSCP2PRI_ARRAY_SIZE) {
380 nss_warning("invalid dscp value: %d\n", dscp);
381 nss_dscp2pri_usage();
382 return 0;
383 }
384
385 /*
386 * Action can be 0 or 1.
387 * 0: NSS_DSCP2PRI_ACTION_NOT_ACCEL
388 * 1: NSS_DSCP2PRI_ACTION_ACCEL
389 */
390 if (action >= NSS_DSCP2PRI_ACTION_MAX) {
391 nss_warning("invalid action value: %d\n", action);
392 nss_dscp2pri_usage();
393 return 0;
394 }
395
396 /*
397 * Priority must be less than NSS_DSCP2PRI_PRIORITY_MAX which is 4.
398 */
399 if (priority >= NSS_DSCP2PRI_PRIORITY_MAX) {
400 nss_warning("invalid priority value: %d\n", priority);
401 nss_dscp2pri_usage();
402 return 0;
403 }
404
405 nss_info("dscp: %d action: %d priority: %d\n", dscp, action, priority);
406
407 /*
408 * Write the dscp, priority and opaque values to the message fields.
409 * Opaque is set to action value and when the message is acknowledged
410 * by NSS firmware it is used to set the action value in the mapping table.
411 */
412 cfg = &ndm.msg.configure_mapping;
413 cfg->dscp = (uint8_t)dscp;
414 cfg->opaque = (uint8_t)action;
415 cfg->priority = (uint8_t)priority;
416
417 /*
418 * Initialize message.
419 */
420 nss_dscp2pri_msg_init(&ndm, NSS_DSCP2PRI_INTERFACE,
421 NSS_DSCP2PRI_METADATA_TYPE_CONFIGURE_MAPPING,
422 sizeof(struct nss_dscp2pri_configure_mapping),
423 nss_dscp2pri_configure_mapping_callback_async,
424 (void *)&ndm);
425
426 /*
427 * Send the message to the NSS.
428 */
429 status = nss_dscp2pri_configure_mapping_sync(&ndm);
430 if (status != NSS_TX_SUCCESS) {
431 return -EFAULT;
432 }
433
434 return 0;
435}
436
437/*
438 * nss_dscp2pri_configure_handler()
439 * Handles NSS -> HLOS messages for dscp2pri node.
440 */
441static void nss_dscp2pri_configure_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
442{
443 struct nss_dscp2pri_msg *ndm = (struct nss_dscp2pri_msg *)ncm;
444 nss_dscp2pri_msg_callback_t cb;
445
446 BUG_ON(ncm->interface != NSS_DSCP2PRI_INTERFACE);
447
448 /*
449 * Is this a valid request/response packet?
450 */
451 if (ncm->type >= NSS_DSCP2PRI_METADATA_TYPE_MAX) {
452 nss_warning("%p: received invalid message %d for dscp2pri interface", nss_ctx, ncm->type);
453 return;
454 }
455
456 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_dscp2pri_msg)) {
457 nss_warning("%p: Length of message is greater than required: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
458 return;
459 }
460
461 nss_core_log_msg_failures(nss_ctx, ncm);
462
463 /*
464 * Do we have a callback
465 */
466 if (!ncm->cb) {
467 nss_trace("%p: cb is null for interface %d", nss_ctx, ncm->interface);
468 return;
469 }
470
471 cb = (nss_dscp2pri_msg_callback_t)ncm->cb;
472 cb((void *)ncm->app_data, ndm);
473}
474
475static struct ctl_table nss_dscp2pri_table[] = {
476 {
477 .procname = "map",
478 .data = &mapping[NSS_DSCP2PRI_ARRAY_SIZE],
479 .maxlen = sizeof(struct nss_dscp2pri_map),
480 .mode = 0644,
481 .proc_handler = &nss_dscp2pri_sysctl_map_handler,
482 },
483
484 { }
485};
486
487static struct ctl_table nss_dscp2pri_dir[] = {
488 {
489 .procname = "dscp2pri",
490 .mode = 0555,
491 .child = nss_dscp2pri_table,
492 },
493 { }
494};
495
496
497static struct ctl_table nss_dscp2pri_root_dir[] = {
498 {
499 .procname = "nss",
500 .mode = 0555,
501 .child = nss_dscp2pri_dir,
502 },
503 { }
504};
505
506static struct ctl_table nss_dscp2pri_root[] = {
507 {
508 .procname = "dev",
509 .mode = 0555,
510 .child = nss_dscp2pri_root_dir,
511 },
512 { }
513};
514
515static struct ctl_table_header *nss_dscp2pri_header;
516
517/*
518 * nss_dscp2pri_get_action()
519 * Gets the action value of the dscp.
520 */
521enum nss_dscp2pri_action nss_dscp2pri_get_action(uint8_t dscp)
522{
523 return mapping[dscp].action;
524}
525EXPORT_SYMBOL(nss_dscp2pri_get_action);
526
527/*
528 * nss_dscp2pri_register_sysctl()
529 */
530void nss_dscp2pri_register_sysctl(void)
531{
532 /*
533 * Register sysctl table.
534 */
535 nss_dscp2pri_header = register_sysctl_table(nss_dscp2pri_root);
536}
537
538/*
539 * nss_dscp2pri_unregister_sysctl()
540 * Unregister sysctl specific to n2h
541 */
542void nss_dscp2pri_unregister_sysctl(void)
543{
544 /*
545 * Unregister sysctl table.
546 */
547 if (nss_dscp2pri_header) {
548 unregister_sysctl_table(nss_dscp2pri_header);
549 }
550}
551
552/*
553 * nss_dscp2pri_register_handler()
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700554 * Registering handler for receiving notify msg from dscp2pri node on NSS.
Murat Sezgine5079aa2017-06-07 18:09:38 -0700555 */
556void nss_dscp2pri_register_handler(void)
557{
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700558 struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[0];
Murat Sezgine5079aa2017-06-07 18:09:38 -0700559 int i;
560
561 /*
562 * Initialize the mapping table with the default values.
563 */
564 for (i = 0; i < NSS_DSCP2PRI_ARRAY_SIZE; i++) {
565 mapping[i].priority = NSS_DSCP2PRI_PRIORITY_BE;
566 mapping[i].action = NSS_DSCP2PRI_ACTION_ACCEL;
567 }
568
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700569 nss_core_register_handler(nss_ctx, NSS_DSCP2PRI_INTERFACE, nss_dscp2pri_configure_handler, NULL);
Murat Sezgine5079aa2017-06-07 18:09:38 -0700570
571 /*
572 * dscp2pri sema init.
573 */
574 sema_init(&dscp2pri_pvt.sem, 1);
575 init_completion(&dscp2pri_pvt.complete);
576}