blob: a54c08a743ef32605d6419d069e74c8e7a440a80 [file] [log] [blame]
Cemil Coskun9165c762017-12-04 14:35:24 -08001/*
2 **************************************************************************
Cemil Coskun697b5592019-10-24 07:55:51 -07003 * Copyright (c) 2013-2017, 2019 The Linux Foundation. All rights reserved.
Cemil Coskun9165c762017-12-04 14:35:24 -08004 * 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_rps.c
19 * NSS RPS based APIs
20 */
21
22#include "nss_tx_rx_common.h"
23
24#define NSS_RPS_MAX_CORE_HASH_BITMAP ((1 << (NSS_HOST_CORES)) - 1)
25 /**< Maximum value that when all cores are available. */
26#define NSS_RPS_PRI_MAP_PARAM_FIELD_COUNT 2
27
28int nss_rps_config __read_mostly;
29int nss_rps_hash_bitmap = NSS_RPS_MAX_CORE_HASH_BITMAP;
30int nss_rps_pri_map[NSS_MAX_NUM_PRI];
31
32/*
33 * It is used to parse priority and core from the input.
34 */
35struct nss_rps_pri_map_parse_data {
36 uint8_t pri; /**< Priority Index. */
37 int8_t core; /**< Host core-id. */
38};
39
40/*
41 * Private data structure.
42 */
43struct nss_rps_pvt {
44 struct semaphore sem; /* Semaphore structure. */
45 struct completion complete; /* Completion structure. */
46 int response; /* Response from FW. */
47 void *cb; /* Original cb for sync msgs. */
48 void *app_data; /* Original app_data for sync msgs. */
49};
50
51static struct nss_rps_pvt nss_rps_cfg_pvt;
52
53/*
54 * nss_rps_pri_map_usage()
55 * Help function shows the usage of the command.
56 */
57static inline void nss_rps_pri_map_usage(void)
58{
59 nss_info_always("\nUsage:\n");
60 nss_info_always("echo <priority> <core> > /proc/sys/dev/nss/rps/pri_map\n\n");
61 nss_info_always("priority[0 to %u] core[-1 to %u]:\n\n",
62 NSS_MAX_NUM_PRI - 1,
63 NSS_HOST_CORES - 1);
64}
65
66/*
67 * nss_rps_pri_map_print()
68 * Sysctl handler for printing rps/pri mapping.
69 */
70static int nss_rps_pri_map_print(struct ctl_table *ctl, void __user *buffer,
71 size_t *lenp, loff_t *ppos, int *pri_map)
72{
73 char *r_buf;
74 int i, len;
75 size_t cp_bytes = 0;
76
77 /*
78 * (2 * 4) + 12 bytes for the buffer size is sufficient to write
79 * the table including the spaces and new line characters.
80 */
81 r_buf = kzalloc(((4 * NSS_MAX_NUM_PRI) + 12) * sizeof(char),
82 GFP_KERNEL);
83 if (!r_buf) {
84 nss_warning("Failed to alloc buffer to print pri map\n");
85 return -EFAULT;
86 }
87
88 /*
89 * Write the core values that corresponds to each priorities.
90 */
91 len = scnprintf(r_buf + cp_bytes, 8, "Cores: ");
92 cp_bytes += len;
93 for (i = 0; i < NSS_MAX_NUM_PRI; i++) {
94 len = scnprintf(r_buf + cp_bytes, 4, "%d ", pri_map[i]);
95 if (!len) {
96 nss_warning("failed to read from buffer %d\n", pri_map[i]);
97 kfree(r_buf);
98 return -EFAULT;
99 }
100 cp_bytes += len;
101 }
102
103 /*
104 * Add new line character at the end.
105 */
106 len = scnprintf(r_buf + cp_bytes, 4, "\n");
107 cp_bytes += len;
108
109 cp_bytes = simple_read_from_buffer(buffer, *lenp, ppos, r_buf, cp_bytes);
110 *lenp = cp_bytes;
111 kfree(r_buf);
112 return 0;
113}
114
115/*
116 * nss_rps_pri_map_parse()
117 * Sysctl handler for rps/pri mappings.
118 */
119static int nss_rps_pri_map_parse(struct ctl_table *ctl, void __user *buffer,
120 size_t *lenp, loff_t *ppos, struct nss_rps_pri_map_parse_data *out)
121{
122 size_t cp_bytes = 0;
123 char w_buf[5];
124 loff_t w_offset = 0;
125 char *str;
126 unsigned int pri;
127 int core, res;
128
129 /*
130 * Buffer length cannot be different than 4 or 5.
131 */
132 if (*lenp < 4 || *lenp > 5) {
133 nss_warning("Buffer is not correct. Invalid lenght: %d\n", (int)*lenp);
134 return -EINVAL;
135 }
136
137 /*
138 * It's a write operation
139 */
140 cp_bytes = simple_write_to_buffer(w_buf, *lenp, &w_offset, buffer, 5);
141 if (cp_bytes != *lenp) {
142 nss_warning("failed to write to buffer\n");
143 return -EFAULT;
144 }
145
146 str = w_buf;
147 res = sscanf(str, "%u %d", &pri, &core);
148 if (res != NSS_RPS_PRI_MAP_PARAM_FIELD_COUNT) {
149 nss_warning("failed to read the buffer\n");
150 return -EFAULT;
151 }
152 /*
153 * pri value cannot be higher than NSS_MAX_NUM_PRI.
154 */
155 if (pri >= NSS_MAX_NUM_PRI) {
156 nss_warning("invalid pri value: %d\n", pri);
157 return -EINVAL;
158 }
159
160 /*
161 * Host core must be less than NSS_HOST_CORE.
162 */
163 if (core >= NSS_HOST_CORES || core < NSS_N2H_RPS_PRI_DEFAULT) {
164 nss_warning("invalid priority value: %d\n", core);
165 return -EINVAL;
166 }
167
168 nss_info("priority: %d core: %d\n", pri, core);
169
170 out->pri = pri;
171 out->core = core;
172 return 0;
173}
174
175/*
176 * nss_rps_cfg_callback()
177 * Callback function for rps configuration.
178 */
179static void nss_rps_cfg_callback(void *app_data, struct nss_n2h_msg *nnm)
180{
181 struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)app_data;
182 if (nnm->cm.response != NSS_CMN_RESPONSE_ACK) {
183
184 /*
185 * Error, hence we are not updating the nss_rps
186 * Send a FAILURE to restore the current value
187 * to its previous state.
188 */
189 nss_rps_cfg_pvt.response = NSS_FAILURE;
190 complete(&nss_rps_cfg_pvt.complete);
191 nss_warning("%p: RPS configuration failed : %d\n", nss_ctx,
192 nnm->cm.error);
193 return;
194 }
195
196 nss_info("%p: RPS configuration succeeded: %d\n", nss_ctx,
197 nnm->cm.error);
198 nss_ctx->rps_en = nnm->msg.rps_cfg.enable;
199 nss_rps_cfg_pvt.response = NSS_SUCCESS;
200 complete(&nss_rps_cfg_pvt.complete);
201}
202
203/*
204 * nss_rps_pri_map_cfg_callback()
205 * Callback function for rps pri map configuration.
206 */
207static void nss_rps_pri_map_cfg_callback(void *app_data, struct nss_n2h_msg *nnm)
208{
209 if (nnm->cm.response != NSS_CMN_RESPONSE_ACK) {
210
211 /*
212 * Error, hence we are not updating the nss_pri_map
213 * Send a failure to restore the current value
214 * to its previous state.
215 */
216 nss_rps_cfg_pvt.response = NSS_FAILURE;
217 complete(&nss_rps_cfg_pvt.complete);
218 nss_warning("%p: RPS pri_map configuration failed : %d\n",
219 app_data, nnm->cm.error);
220 return;
221 }
222
223 nss_info("%p: RPS pri_map configuration succeeded: %d\n",
224 app_data, nnm->cm.error);
225
226 nss_rps_cfg_pvt.response = NSS_SUCCESS;
227 complete(&nss_rps_cfg_pvt.complete);
228}
229
230/*
231 * nss_rps_cfg()
232 * Send Message to NSS to enable RPS.
233 */
234static nss_tx_status_t nss_rps_cfg(struct nss_ctx_instance *nss_ctx, int enable_rps)
235{
236 struct nss_n2h_msg nnm;
237 nss_tx_status_t nss_tx_status;
238 int ret;
239
240 down(&nss_rps_cfg_pvt.sem);
241 nss_n2h_msg_init(&nnm, NSS_N2H_INTERFACE, NSS_TX_METADATA_TYPE_N2H_RPS_CFG,
242 sizeof(struct nss_n2h_rps),
243 nss_rps_cfg_callback,
244 (void *)nss_ctx);
245
246 nnm.msg.rps_cfg.enable = enable_rps;
247
248 nss_tx_status = nss_n2h_tx_msg(nss_ctx, &nnm);
249
250 if (nss_tx_status != NSS_TX_SUCCESS) {
251 nss_warning("%p: nss_tx error setting rps\n", nss_ctx);
252
253 up(&nss_rps_cfg_pvt.sem);
254 return NSS_FAILURE;
255 }
256
257 /*
258 * Blocking call, wait till we get ACK for this msg.
259 */
260 ret = wait_for_completion_timeout(&nss_rps_cfg_pvt.complete, msecs_to_jiffies(NSS_CONN_CFG_TIMEOUT));
261 if (ret == 0) {
262 nss_warning("%p: Waiting for ack timed out\n", nss_ctx);
263 up(&nss_rps_cfg_pvt.sem);
264 return NSS_FAILURE;
265 }
266
267 /*
268 * ACK/NACK received from NSS FW
269 * If NACK: Handler function will restore nss_rps_config
270 * to previous state.
271 */
272 if (NSS_FAILURE == nss_rps_cfg_pvt.response) {
273 up(&nss_rps_cfg_pvt.sem);
274 return NSS_FAILURE;
275 }
276
277 up(&nss_rps_cfg_pvt.sem);
278 return NSS_SUCCESS;
279}
280
281/*
282 * nss_rps_ipv4_hash_bitmap_cfg()
283 * Send Message to NSS to configure hash_bitmap.
284 */
285static nss_tx_status_t nss_rps_ipv4_hash_bitmap_cfg(struct nss_ctx_instance *nss_ctx, int hash_bitmap)
286{
287 struct nss_ipv4_msg nim;
288 nss_tx_status_t nss_tx_status;
289
290 down(&nss_rps_cfg_pvt.sem);
291 nss_ipv4_msg_init(&nim, NSS_IPV4_RX_INTERFACE, NSS_IPV4_TX_RPS_HASH_BITMAP_CFG_MSG,
292 sizeof(struct nss_ipv4_rps_hash_bitmap_cfg_msg),
293 NULL, NULL);
294
295 nim.msg.rps_hash_bitmap.hash_bitmap = hash_bitmap;
296
297 nss_tx_status = nss_ipv4_tx_sync(nss_ctx, &nim);
298
299 if (nss_tx_status != NSS_TX_SUCCESS) {
300 nss_warning("%p: nss_tx error setting rps\n", nss_ctx);
301
302 up(&nss_rps_cfg_pvt.sem);
303 return NSS_FAILURE;
304 }
305
306 up(&nss_rps_cfg_pvt.sem);
307 return NSS_SUCCESS;
308}
309
310/*
311 * nss_rps_ipv6_hash_bitmap_cfg()
312 * Send Message to NSS to configure hash_bitmap.
313 */
314static nss_tx_status_t nss_rps_ipv6_hash_bitmap_cfg(struct nss_ctx_instance *nss_ctx, int hash_bitmap)
315{
316 struct nss_ipv6_msg nim;
317 nss_tx_status_t nss_tx_status;
318
319 down(&nss_rps_cfg_pvt.sem);
320 nss_ipv6_msg_init(&nim, NSS_IPV6_RX_INTERFACE, NSS_IPV6_TX_RPS_HASH_BITMAP_CFG_MSG,
321 sizeof(struct nss_ipv4_rps_hash_bitmap_cfg_msg),
322 NULL, NULL);
323
324 nim.msg.rps_hash_bitmap.hash_bitmap = hash_bitmap;
325
326 nss_tx_status = nss_ipv6_tx_sync(nss_ctx, &nim);
327
328 if (nss_tx_status != NSS_TX_SUCCESS) {
329 nss_warning("%p: nss_tx error setting rps\n", nss_ctx);
330
331 up(&nss_rps_cfg_pvt.sem);
332 return NSS_FAILURE;
333 }
334
335 up(&nss_rps_cfg_pvt.sem);
336 return NSS_SUCCESS;
337}
338
339/*
340 * nss_rps_pri_map_cfg()
341 * Send Message to NSS to configure pri_map.
342 */
343static nss_tx_status_t nss_rps_pri_map_cfg(struct nss_ctx_instance *nss_ctx, int *pri_map)
344{
345 struct nss_n2h_msg nnm;
346 struct nss_n2h_rps_pri_map *rps_pri_map;
347 nss_tx_status_t nss_tx_status;
348 int ret, i;
349
350 down(&nss_rps_cfg_pvt.sem);
351 nss_n2h_msg_init(&nnm, NSS_N2H_INTERFACE, NSS_TX_METADATA_TYPE_N2H_RPS_PRI_MAP_CFG,
352 sizeof(struct nss_n2h_rps_pri_map),
353 nss_rps_pri_map_cfg_callback,
354 (void *)nss_ctx);
355
356 rps_pri_map = &nnm.msg.rps_pri_map;
357
358 /*
359 * Fill entries at pri_map.
360 */
361 for (i = 0; i < NSS_MAX_NUM_PRI; i++) {
362 rps_pri_map->pri_map[i] = pri_map[i];
363 }
364
365 nss_tx_status = nss_n2h_tx_msg(nss_ctx, &nnm);
366
367 if (nss_tx_status != NSS_TX_SUCCESS) {
368 nss_warning("%p: nss_tx error setting rps\n", nss_ctx);
369
370 up(&nss_rps_cfg_pvt.sem);
371 return NSS_FAILURE;
372 }
373
374 /*
375 * Blocking call, wait till we get ACK for this msg.
376 */
377 ret = wait_for_completion_timeout(&nss_rps_cfg_pvt.complete, msecs_to_jiffies(NSS_CONN_CFG_TIMEOUT));
378 if (ret == 0) {
379 nss_warning("%p: Waiting for ack timed out\n", nss_ctx);
380 up(&nss_rps_cfg_pvt.sem);
381 return NSS_FAILURE;
382 }
383
384 /*
385 * ACK/NACK received from NSS FW
386 * If NACK: Handler function will restore nss_rps_config
387 * to previous state.
388 */
389 if (NSS_FAILURE == nss_rps_cfg_pvt.response) {
390 up(&nss_rps_cfg_pvt.sem);
391 return NSS_FAILURE;
392 }
393
394 up(&nss_rps_cfg_pvt.sem);
395 return NSS_SUCCESS;
396}
397
398/*
399 * nss_rps_cfg_handler()
400 * Enable NSS RPS.
401 */
402static int nss_rps_cfg_handler(struct ctl_table *ctl, int write,
403 void __user *buffer, size_t *lenp, loff_t *ppos)
404{
405 struct nss_top_instance *nss_top = &nss_top_main;
Cemil Coskun697b5592019-10-24 07:55:51 -0700406 struct nss_ctx_instance *nss_ctx;
407 int ret, ret_rps, current_state, i;
Cemil Coskun9165c762017-12-04 14:35:24 -0800408 current_state = nss_rps_config;
409 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
410
411 if (ret != NSS_SUCCESS) {
412 return ret;
413 }
414
415 if (!write) {
416 return ret;
417 }
418
Cemil Coskun9165c762017-12-04 14:35:24 -0800419 if (nss_rps_config == 0) {
420 nss_info_always("Runtime disabling of NSS RPS not supported\n");
421 return ret;
422 }
423
Cemil Coskun697b5592019-10-24 07:55:51 -0700424 if (nss_rps_config != 1) {
425 nss_info_always("Invalid input value. Valid values are 0 and 1\n");
426 return ret;
427 }
428
429 for (i = 0; i < nss_top_main.num_nss; i++) {
430 nss_ctx = &nss_top->nss[i];
431 nss_info("Enabling NSS RPS\n");
432 ret_rps = nss_rps_cfg(nss_ctx, 1);
433
434 /*
435 * In here, we also need to revert the state of the previously enabled cores.
436 * However, runtime disabling is currently not supported since queues are not
437 * flushed in NSS FW.
438 * TODO: Flush queues in NSS FW.
439 */
440 if (ret_rps != NSS_SUCCESS) {
441 nss_warning("%p: rps enabling failed\n", nss_ctx);
442 nss_rps_config = current_state;
443 return ret_rps;
444 }
445 }
446 return NSS_SUCCESS;
Cemil Coskun9165c762017-12-04 14:35:24 -0800447}
448
449/*
450 * nss_rps_hash_bitmap_cfg_handler()
451 * Configure NSS rps_hash_bitmap
452 */
453static int nss_rps_hash_bitmap_cfg_handler(struct ctl_table *ctl, int write,
454 void __user *buffer, size_t *lenp, loff_t *ppos)
455{
456 struct nss_top_instance *nss_top = &nss_top_main;
457 struct nss_ctx_instance *nss_ctx = &nss_top->nss[0];
458 int ret, ret_ipv4, ret_ipv6, current_state;
459
460 current_state = nss_rps_hash_bitmap;
461 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
462
463 if (ret != NSS_SUCCESS) {
464 nss_rps_hash_bitmap = current_state;
465 return ret;
466 }
467
468 if (!write) {
469 return ret;
470 }
471
472 if (nss_rps_hash_bitmap <= (NSS_RPS_MAX_CORE_HASH_BITMAP)) {
473 nss_info("Configuring NSS RPS hash_bitmap\n");
474 ret_ipv4 = nss_rps_ipv4_hash_bitmap_cfg(nss_ctx, nss_rps_hash_bitmap);
475
476 if (ret_ipv4 != NSS_SUCCESS) {
477 nss_warning("%p: ipv4 hash_bitmap config message failed\n", nss_ctx);
478 nss_rps_hash_bitmap = current_state;
479 return ret_ipv4;
480 }
481
482 ret_ipv6 = nss_rps_ipv6_hash_bitmap_cfg(nss_ctx, nss_rps_hash_bitmap);
483
484 if (ret_ipv6 != NSS_SUCCESS) {
485 nss_warning("%p: ipv6 hash_bitmap config message failed\n", nss_ctx);
486 nss_rps_hash_bitmap = current_state;
487 if (nss_rps_ipv4_hash_bitmap_cfg(nss_ctx, nss_rps_hash_bitmap != NSS_SUCCESS)) {
488 nss_warning("%p: ipv4 and ipv6 have different hash_bitmaps.\n", nss_ctx);
489 }
490 return ret_ipv6;
491 }
492
493 return 0;
494 }
495
496 nss_info_always("Invalid input value. Valid values are less than %d\n", (NSS_RPS_MAX_CORE_HASH_BITMAP));
497 return ret;
498}
499
500/* nss_rps_pri_map_cfg_handler()
501 * Configure NSS rps_pri_map
502 */
503static int nss_rps_pri_map_cfg_handler(struct ctl_table *ctl, int write,
504 void __user *buffer, size_t *lenp, loff_t *ppos)
505{
506 struct nss_top_instance *nss_top = &nss_top_main;
507 struct nss_ctx_instance *nss_ctx = &nss_top->nss[0];
508
509 int ret, ret_pri_map;
510 struct nss_rps_pri_map_parse_data out, current_state;
511 if (!write) {
512 return nss_rps_pri_map_print(ctl, buffer, lenp, ppos, nss_rps_pri_map);
513 }
514
515 ret = nss_rps_pri_map_parse(ctl, buffer, lenp, ppos, &out);
516
517 if (ret != NSS_SUCCESS) {
518 nss_rps_pri_map_usage();
519 return ret;
520 }
521
522 nss_info("Configuring NSS RPS Priority Map\n");
523 current_state.pri = out.pri;
524 current_state.core = nss_rps_pri_map[out.pri];
525 nss_rps_pri_map[out.pri] = out.core;
526 ret_pri_map = nss_rps_pri_map_cfg(nss_ctx, nss_rps_pri_map);
527 if (ret_pri_map != NSS_SUCCESS) {
528 nss_rps_pri_map[current_state.pri] = current_state.core;
529 nss_warning("%p: pri_map config message failed\n", nss_ctx);
530 }
531
532 return ret_pri_map;
533}
534
535static struct ctl_table nss_rps_table[] = {
536 {
537 .procname = "enable",
538 .data = &nss_rps_config,
539 .maxlen = sizeof(int),
540 .mode = 0644,
541 .proc_handler = &nss_rps_cfg_handler,
542 },
543 {
544 .procname = "hash_bitmap",
545 .data = &nss_rps_hash_bitmap,
546 .maxlen = sizeof(int),
547 .mode = 0644,
548 .proc_handler = &nss_rps_hash_bitmap_cfg_handler,
549 },
550 {
551 .procname = "pri_map",
552 .data = &nss_rps_pri_map[NSS_MAX_NUM_PRI],
553 .maxlen = sizeof(int),
554 .mode = 0644,
555 .proc_handler = &nss_rps_pri_map_cfg_handler,
556 },
557 { }
558};
559
560static struct ctl_table nss_rps_dir[] = {
561 {
562 .procname = "rps",
563 .mode = 0555,
564 .child = nss_rps_table,
565 },
566 { }
567};
568
569static struct ctl_table nss_rps_root_dir[] = {
570 {
571 .procname = "nss",
572 .mode = 0555,
573 .child = nss_rps_dir,
574 },
575 { }
576};
577
578static struct ctl_table nss_rps_root[] = {
579 {
580 .procname = "dev",
581 .mode = 0555,
582 .child = nss_rps_root_dir,
583 },
584 { }
585};
586
587static struct ctl_table_header *nss_rps_header;
588
589/*
590 * nss_rps_pri_map_init_handler()
591 * Initialize pri_map for priority based rps selection.
592 */
593void nss_rps_pri_map_init_handler(void)
594{
595 int i;
596
597 /*
598 Initialize the mapping table with the default values.
599 */
600 for (i = 0; i < NSS_MAX_NUM_PRI; i++) {
601 nss_rps_pri_map[i] = NSS_N2H_RPS_PRI_DEFAULT;
602 }
603
604}
605
606/*
607 * nss_rps_register_sysctl()
608 */
609void nss_rps_register_sysctl(void)
610{
611
612 /*
613 * rps sema init.
614 */
615 sema_init(&nss_rps_cfg_pvt.sem, 1);
616 init_completion(&nss_rps_cfg_pvt.complete);
617
618 nss_rps_pri_map_init_handler();
619
620 /*
621 * Register sysctl table.
622 */
623 nss_rps_header = register_sysctl_table(nss_rps_root);
624}
625
626/*
627 * nss_rps_unregister_sysctl()
628 * Unregister sysctl specific to rps
629 */
630void nss_rps_unregister_sysctl(void)
631{
632 /*
633 * Unregister sysctl table.
634 */
635 if (nss_rps_header) {
636 unregister_sysctl_table(nss_rps_header);
637 }
638}