blob: f6d6f41ad821e31cc90e3c325c13dc9e830336d8 [file] [log] [blame]
Radhakrishna Jiguru1c9b2252013-08-27 23:57:48 +05301/*
2 **************************************************************************
Cemil Coskun26be6162019-06-28 15:44:48 -07003 * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
Radhakrishna Jiguru1c9b2252013-08-27 23:57:48 +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 */
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053016
Yu Huang8c107082017-07-24 14:58:26 -070017#include "nss_core.h"
Thomas Wuc3e382c2014-10-29 15:35:13 -070018
19/*
Sakthi Vignesh Radhakrishnan150c5592019-07-02 10:17:44 -070020 * Maximum banner length:
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053021 */
Sakthi Vignesh Radhakrishnan150c5592019-07-02 10:17:44 -070022#define NSS_STATS_BANNER_MAX_LENGTH 80
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053023
24/*
Sakthi Vignesh Radhakrishnan150c5592019-07-02 10:17:44 -070025 * Maximum number of digits a stats value can have:
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053026 */
Sakthi Vignesh Radhakrishnan150c5592019-07-02 10:17:44 -070027#define NSS_STATS_DIGITS_MAX 16
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053028
29/*
Sakthi Vignesh Radhakrishnan150c5592019-07-02 10:17:44 -070030 * Max characters for a node name.
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053031 */
Sakthi Vignesh Radhakrishnan150c5592019-07-02 10:17:44 -070032#define NSS_STATS_NODE_NAME_MAX 24
33
34/*
35 * common stats
36 */
37struct nss_stats_info nss_stats_str_node[NSS_STATS_NODE_MAX] = {
38 {"rx_pkts" , NSS_STATS_TYPE_COMMON},
39 {"rx_byts" , NSS_STATS_TYPE_COMMON},
40 {"tx_pkts" , NSS_STATS_TYPE_COMMON},
41 {"tx_byts" , NSS_STATS_TYPE_COMMON},
42 {"rx_queue[0]_drops" , NSS_STATS_TYPE_DROP},
43 {"rx_queue[1]_drops" , NSS_STATS_TYPE_DROP},
44 {"rx_queue[2]_drops" , NSS_STATS_TYPE_DROP},
45 {"rx_queue[3]_drops" , NSS_STATS_TYPE_DROP}
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053046};
47
Sakthi Vignesh Radhakrishnan150c5592019-07-02 10:17:44 -070048int nonzero_stats_print = 0;
49
50/*
51 * nss_stats_spacing()
52 * Framework to maintain consistent spacing between stats value and stats type.
53 */
54static size_t nss_stats_spacing(uint64_t stats_val, char *lbuf, size_t size_wr, size_t size_al)
55{
56 int i;
57 int digit_counter = (stats_val == 0 ? 1 : 0);
58 while (stats_val != 0) {
59 /*
60 * TODO: need to check for (nss_ptr_t)
61 */
62 stats_val = (nss_ptr_t)stats_val / 10;
63 digit_counter++;
64 }
65
66 for (i = 0; i < NSS_STATS_DIGITS_MAX - digit_counter; i++) {
67 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, " ");
68 }
69
70 return size_wr;
71}
72
73/*
74 * nss_stats_nonzero_handler()
75 * Handler to take nonzero stats print configuration.
76 */
77static int nss_stats_nonzero_handler(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
78{
79 int ret;
80 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
81 return ret;
82}
83
84static struct ctl_table nss_stats_table[] = {
85 {
86 .procname = "non_zero_stats",
87 .data = &nonzero_stats_print,
88 .maxlen = sizeof(int),
89 .mode = 0644,
90 .proc_handler = &nss_stats_nonzero_handler,
91 },
92 { }
93};
94
95static struct ctl_table nss_stats_dir[] = {
96 {
97 .procname = "stats",
98 .mode = 0555,
99 .child = nss_stats_table,
100 },
101 { }
102};
103
104static struct ctl_table nss_stats_root_dir[] = {
105 {
106 .procname = "nss",
107 .mode = 0555,
108 .child = nss_stats_dir,
109 },
110 { }
111};
112
113static struct ctl_table nss_stats_root[] = {
114 {
115 .procname = "dev",
116 .mode = 0555,
117 .child = nss_stats_root_dir,
118 },
119 { }
120};
121static struct ctl_table_header *nss_stats_header;
122
123/*
124 * nss_stats_register_sysctl()
125 * Register a sysctl table for stats.
126 */
127void nss_stats_register_sysctl(void)
128{
129 /*
130 * Register sysctl table.
131 */
132 nss_stats_header = register_sysctl_table(nss_stats_root);
133}
134
135/*
136 * nss_stats_open()
137 * Opens stats file.
138 */
139int nss_stats_open(struct inode *inode, struct file *filp)
140{
141 struct nss_stats_data *data = NULL;
142
143 data = kzalloc(sizeof(struct nss_stats_data), GFP_KERNEL);
144 if (!data) {
145 return -ENOMEM;
146 }
147
148 memset(data, 0, sizeof (struct nss_stats_data));
149 data->if_num = NSS_DYNAMIC_IF_START;
150 data->index = 0;
151 data->edma_id = (nss_ptr_t)inode->i_private;
152 data->nss_ctx = (struct nss_ctx_instance *)(inode->i_private);
153 filp->private_data = data;
154
155 return 0;
156}
157
158/*
159 * nss_stats_release()
160 * Releases stats file.
161 */
162int nss_stats_release(struct inode *inode, struct file *filp)
163{
164 struct nss_stats_data *data = filp->private_data;
165
166 if (data) {
167 kfree(data);
168 }
169
170 return 0;
171}
172
173/*
174 * nss_stats_clean()
175 * Cleanup NSS statistics files.
176 */
177void nss_stats_clean(void)
178{
179 /*
180 * Remove debugfs tree
181 */
182 if (likely(nss_top_main.top_dentry != NULL)) {
183 debugfs_remove_recursive(nss_top_main.top_dentry);
184 nss_top_main.top_dentry = NULL;
185 }
186}
187
188/*
189 * nss_stats_fill_common_stats()
190 * Fill common node statistics.
191 */
192size_t nss_stats_fill_common_stats(uint32_t if_num, char *lbuf, size_t size_wr, size_t size_al, char *node)
193{
194 uint64_t stats_val[NSS_STATS_NODE_MAX];
195 int i;
196 spin_lock_bh(&nss_top_main.stats_lock);
197 for (i = 0; i < NSS_STATS_NODE_MAX; i++) {
198 stats_val[i] = nss_top_main.stats_node[if_num][i];
199 }
200
201 spin_unlock_bh(&nss_top_main.stats_lock);
202 size_wr = nss_stats_print(node, NULL, NSS_STATS_SINGLE_CORE, NSS_STATS_SINGLE_INSTANCE, nss_stats_str_node, stats_val, NSS_STATS_NODE_MAX, lbuf, size_wr, size_al);
203 return size_wr;
204}
205
206/*
207 * nss_stats_banner()
208 * Printing banner for node.
209 */
210size_t nss_stats_banner(char *lbuf, size_t size_wr, size_t size_al, char *node)
211{
212 uint16_t banner_char_length, i;
213 char node_upr[NSS_STATS_NODE_NAME_MAX + 1];
214
215 if (strlen(node) > NSS_STATS_NODE_NAME_MAX) {
216 nss_warning("Node name %s larger than %d characters\n", node, NSS_STATS_NODE_NAME_MAX);
217 return 0;
218 }
219
220 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n");
221 for (i = 0; i < NSS_STATS_BANNER_MAX_LENGTH ; i++) {
222 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "_");
223 }
224
225 banner_char_length = (uint16_t)((NSS_STATS_BANNER_MAX_LENGTH - (strlen(node) + 2)) / 2);
226
227 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n\n");
228 for (i = 0; i < banner_char_length; i++) {
229 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "<");
230 }
231
232 strlcpy(node_upr, node, NSS_STATS_NODE_NAME_MAX);
233 for (i = 0; node_upr[i] != '\0' && i < NSS_STATS_NODE_NAME_MAX; i++) {
234 node_upr[i] = toupper(node_upr[i]);
235 }
236
237 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, " %s ", node);
238 for (i = 0; i < banner_char_length; i++) {
239 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, ">");
240 }
241
242 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n");
243 for (i = 0; i < NSS_STATS_BANNER_MAX_LENGTH; i++) {
244 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "_");
245 }
246
247 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n\n");
248 return size_wr;
249}
250
251/*
252 * nss_stats_print()
253 * Helper API to print stats.
254 */
255size_t nss_stats_print(char *node, char *stat_details, int core_num, int instance, struct nss_stats_info *stats_info, uint64_t *stats_val, uint16_t max, char *lbuf, size_t size_wr, size_t size_al)
256{
257 uint16_t i, j;
258 uint16_t maxlen = 0;
259 char stats_string[NSS_STATS_MAX_STR_LENGTH];
260 char node_lwr[NSS_STATS_NODE_NAME_MAX + 1];
261
262 if (strlen(node) > NSS_STATS_NODE_NAME_MAX) {
263 nss_warning("Node name %s (%u chars) is longer than max chars of %d\n",
264 node, (uint32_t)strlen(node), NSS_STATS_NODE_NAME_MAX);
265 return 0;
266 }
267
268 /*
269 * Calculating the maximum of the array for indentation purposes.
270 */
271 for (i = 0; i < max; i++){
272 if (strlen(stats_info[i].stats_name) > maxlen) {
273 maxlen = strlen(stats_info[i].stats_name);
274 }
275 }
276
277 if (core_num >= 0) {
278 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n***** \n");
279 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "***** CORE %d \n", core_num);
280 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "*****\n");
281 }
282
283 if (stat_details != NULL) {
284 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n#%s\n\n", stat_details);
285 }
286
287 for (i = 0; i < max; i++){
288 if (nonzero_stats_print == 1 && stats_val[i] == 0) {
289 continue;
290 }
291
292 strlcpy(stats_string, stats_info[i].stats_name, NSS_STATS_MAX_STR_LENGTH);
293
294 /*
295 * Converting uppercase to lower case.
296 */
297 for (j = 0; stats_string[j] != '\0' && j < NSS_STATS_MAX_STR_LENGTH; j++) {
298 stats_string[j] = tolower(stats_string[j]);
299 }
300
301 strlcpy(node_lwr, node, NSS_STATS_NODE_NAME_MAX);
302 for (j = 0; node_lwr[j] != '\0' && j < NSS_STATS_NODE_NAME_MAX; j++) {
303 node_lwr[j] = tolower(node_lwr[j]);
304 }
305
306 /*
307 * Space before %s is needed to avoid printing stat name from start of the line.
308 */
309 if (instance < 0) {
310 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\t%s_%s", node_lwr, stats_string);
311 } else {
312 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\t%s[%d]_%s", node_lwr, instance, stats_string);
313 }
314
315 for (j = 0; j < (1 + maxlen - strlen(stats_string)); j++){
316 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, " ");
317 }
318
319 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "= %llu", stats_val[i]);
320 size_wr = nss_stats_spacing(stats_val[i], lbuf, size_wr, size_al);
321
322 /*
323 * Switch case will take care of the indentation and spacing details.
324 */
325 switch (stats_info[i].stats_type) {
326 case NSS_STATS_TYPE_COMMON:
327 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "common\n");
328 break;
329
330 case NSS_STATS_TYPE_SPECIAL:
331 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "special\n");
332 break;
333
334 case NSS_STATS_TYPE_DROP:
335 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "drop\n");
336 break;
337
338 case NSS_STATS_TYPE_ERROR:
339 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "error\n");
340 break;
341
342 case NSS_STATS_TYPE_EXCEPTION:
343 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "exception\n");
344 break;
345
346 default:
347 nss_warning("unknown statistics type");
348 break;
349 }
350 }
351
352 return size_wr;
353}
354
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530355/*
Yu Huang8c107082017-07-24 14:58:26 -0700356 * nss_stats_create_dentry()
357 * Create statistics debug entry for subsystem.
Murat Sezgin99dab642014-08-28 14:40:34 -0700358 */
Yu Huang8c107082017-07-24 14:58:26 -0700359void nss_stats_create_dentry(char *name, const struct file_operations *ops)
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530360{
Yu Huang8c107082017-07-24 14:58:26 -0700361 if (!debugfs_create_file(name, 0400, nss_top_main.stats_dentry, &nss_top_main, ops)) {
Cemil Coskun26be6162019-06-28 15:44:48 -0700362 nss_warning("Failed to create debug entry for subsystem %s\n", name);
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530363 }
Yu Huang8c107082017-07-24 14:58:26 -0700364}
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530365
Yu Huang8c107082017-07-24 14:58:26 -0700366/*
Sakthi Vignesh Radhakrishnan150c5592019-07-02 10:17:44 -0700367 * TODO: Move the rest of the code to (nss_wt_stats.c, nss_gmac_stats.c, nss_drv_stats.c) accordingly.
Yu Huang8c107082017-07-24 14:58:26 -0700368 */
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700369
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530370/*
371 * drv_stats_ops
372 */
373NSS_STATS_DECLARE_FILE_OPERATIONS(drv)
374
375/*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530376 * gmac_stats_ops
377 */
378NSS_STATS_DECLARE_FILE_OPERATIONS(gmac)
379
380/*
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700381 * wt_stats_ops
382 */
383NSS_STATS_DECLARE_FILE_OPERATIONS(wt)
Yu Huang8c107082017-07-24 14:58:26 -0700384
385/*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530386 * nss_stats_init()
Sakthi Vignesh Radhakrishnan150c5592019-07-02 10:17:44 -0700387 * Enable NSS statistics.
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530388 */
389void nss_stats_init(void)
390{
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700391 struct dentry *core_dentry = NULL;
392 struct dentry *wt_dentry = NULL;
Shashank Balashankar512cb602016-08-01 17:57:42 -0700393 char file_name[10];
Yu Huang8c107082017-07-24 14:58:26 -0700394 int i;
Shashank Balashankar512cb602016-08-01 17:57:42 -0700395
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530396 /*
397 * NSS driver entry
398 */
399 nss_top_main.top_dentry = debugfs_create_dir("qca-nss-drv", NULL);
400 if (unlikely(nss_top_main.top_dentry == NULL)) {
401 nss_warning("Failed to create qca-nss-drv directory in debugfs");
402
403 /*
Sakthi Vignesh Radhakrishnan150c5592019-07-02 10:17:44 -0700404 * Non availability of debugfs directory is not a catastrophy.
405 * We can still go ahead with other initialization.
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530406 */
407 return;
408 }
409
410 nss_top_main.stats_dentry = debugfs_create_dir("stats", nss_top_main.top_dentry);
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +0530411 if (unlikely(nss_top_main.stats_dentry == NULL)) {
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530412 nss_warning("Failed to create qca-nss-drv directory in debugfs");
413
414 /*
Sakthi Vignesh Radhakrishnan150c5592019-07-02 10:17:44 -0700415 * Non availability of debugfs directory is not a catastrophy.
416 * We can still go ahead with rest of initialization.
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530417 */
418 return;
419 }
420
421 /*
Sakthi Vignesh Radhakrishnan150c5592019-07-02 10:17:44 -0700422 * Create files to obtain statistics.
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530423 */
424
425 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530426 * drv_stats
427 */
Yu Huang8c107082017-07-24 14:58:26 -0700428 nss_stats_create_dentry("drv", &nss_drv_stats_ops);
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530429
430 /*
431 * gmac_stats
432 */
Yu Huang8c107082017-07-24 14:58:26 -0700433 nss_stats_create_dentry("gmac", &nss_gmac_stats_ops);
Aniruddha Paul1b170c22017-05-29 12:30:39 +0530434
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700435 /*
436 * Per-project stats
437 */
438 nss_top_main.project_dentry = debugfs_create_dir("project",
439 nss_top_main.stats_dentry);
440 if (unlikely(nss_top_main.project_dentry == NULL)) {
441 nss_warning("Failed to create qca-nss-drv/stats/project directory in debugfs");
442 return;
443 }
444
Suman Ghosh9f7b3702018-09-21 19:51:40 +0530445 for (i = 0; i < nss_top_main.num_nss; ++i) {
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700446 memset(file_name, 0, sizeof(file_name));
447 scnprintf(file_name, sizeof(file_name), "core%d", i);
448 core_dentry = debugfs_create_dir(file_name,
449 nss_top_main.project_dentry);
450 if (unlikely(core_dentry == NULL)) {
451 nss_warning("Failed to create qca-nss-drv/stats/project/core%d directory in debugfs", i);
452 return;
453 }
454
455 wt_dentry = debugfs_create_file("worker_threads",
456 0400,
457 core_dentry,
458 &(nss_top_main.nss[i]),
Yu Huang8c107082017-07-24 14:58:26 -0700459 &nss_wt_stats_ops);
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700460 if (unlikely(wt_dentry == NULL)) {
461 nss_warning("Failed to create qca-nss-drv/stats/project/core%d/worker_threads file in debugfs", i);
462 return;
463 }
464 }
465
Saurabh Misra96998db2014-07-10 12:15:48 -0700466 nss_log_init();
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530467}