blob: 5996b5482752e04fc63c1c70c19bd835045c5436 [file] [log] [blame]
Radhakrishna Jiguru1c9b2252013-08-27 23:57:48 +05301/*
2 **************************************************************************
Stephen Wangaed46332016-12-12 17:29:03 -08003 * Copyright (c) 2013-2017, 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
17/*
18 * nss_stats.c
19 * NSS stats APIs
20 *
21 */
22
ratheesh kannoth93ba95c2017-07-13 15:52:52 +053023#include "nss_tx_rx_common.h"
Yu Huang8c107082017-07-24 14:58:26 -070024#include "nss_core.h"
25#include "nss_stats.h"
Thomas Wuc3e382c2014-10-29 15:35:13 -070026
27/*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053028 * nss_stats_str_drv
29 * Host driver stats strings
30 */
31static int8_t *nss_stats_str_drv[NSS_STATS_DRV_MAX] = {
32 "nbuf_alloc_errors",
Sachin Shashidhar475012b2017-03-13 16:56:07 -070033 "paged_buf_alloc_errors",
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053034 "tx_queue_full[0]",
35 "tx_queue_full[1]",
36 "tx_buffers_empty",
Sachin Shashidhar475012b2017-03-13 16:56:07 -070037 "tx_paged_buffers_empty",
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053038 "tx_buffers_pkt",
39 "tx_buffers_cmd",
40 "tx_buffers_crypto",
Murat Sezginb6e1a012015-09-29 14:06:37 -070041 "tx_buffers_reuse",
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053042 "rx_buffers_empty",
43 "rx_buffers_pkt",
44 "rx_buffers_cmd_resp",
45 "rx_buffers_status_sync",
46 "rx_buffers_crypto",
Thomas Wu0acd8162014-12-07 15:43:39 -080047 "rx_buffers_virtual",
48 "tx_skb_simple",
49 "tx_skb_nr_frags",
50 "tx_skb_fraglist",
51 "rx_skb_simple",
52 "rx_skb_nr_frags",
53 "rx_skb_fraglist",
Sundarajan Srinivasan6e0366b2015-01-20 12:10:42 -080054 "rx_bad_desciptor",
Thomas Wu1fbf5212015-06-04 14:38:40 -070055 "nss_skb_count",
56 "rx_chain_seg_processed",
57 "rx_frag_seg_processed"
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053058};
59
60/*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053061 * nss_stats_str_gmac
62 * GMAC stats strings
63 */
64static int8_t *nss_stats_str_gmac[NSS_STATS_GMAC_MAX] = {
65 "ticks",
66 "worst_ticks",
67 "iterations"
68};
69
70/*
Abhishek Rastogi84d95d02014-03-26 19:31:31 +053071 * nss_stats_str_node
72 * Interface stats strings per node
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053073 */
Abhishek Rastogi84d95d02014-03-26 19:31:31 +053074static int8_t *nss_stats_str_node[NSS_STATS_NODE_MAX] = {
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053075 "rx_packets",
76 "rx_bytes",
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053077 "tx_packets",
ratheesh kannoth93ba95c2017-07-13 15:52:52 +053078 "tx_bytes",
79 "rx_queue_0_dropped",
80 "rx_queue_1_dropped",
81 "rx_queue_2_dropped",
82 "rx_queue_3_dropped",
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053083};
84
85/*
Yu Huang8c107082017-07-24 14:58:26 -070086 * nss_stats_create_dentry()
87 * Create statistics debug entry for subsystem.
Murat Sezgin99dab642014-08-28 14:40:34 -070088 */
Yu Huang8c107082017-07-24 14:58:26 -070089void nss_stats_create_dentry(char *name, const struct file_operations *ops)
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053090{
Yu Huang8c107082017-07-24 14:58:26 -070091 if (!debugfs_create_file(name, 0400, nss_top_main.stats_dentry, &nss_top_main, ops)) {
92 nss_warning("Faied to create debug entry for subsystem %s\n", name);
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053093 }
Yu Huang8c107082017-07-24 14:58:26 -070094}
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053095
Yu Huang8c107082017-07-24 14:58:26 -070096/*
97 * nss_stats_fill_common_stats()
98 * Fill common node statistics.
99 */
100size_t nss_stats_fill_common_stats(uint32_t if_num, char *lbuf, size_t size_wr, size_t size_al)
101{
102 uint64_t stats_shadow[NSS_STATS_NODE_MAX];
103 int i;
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530104
Abhishek Rastogia1a07972014-04-01 19:43:33 +0530105 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "common node stats:\n\n");
Abhishek Rastogi84d95d02014-03-26 19:31:31 +0530106 spin_lock_bh(&nss_top_main.stats_lock);
107 for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
Yu Huang8c107082017-07-24 14:58:26 -0700108 stats_shadow[i] = nss_top_main.stats_node[if_num][i];
Abhishek Rastogi84d95d02014-03-26 19:31:31 +0530109 }
Abhishek Rastogi84d95d02014-03-26 19:31:31 +0530110 spin_unlock_bh(&nss_top_main.stats_lock);
111
112 for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
113 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
114 "%s = %llu\n", nss_stats_str_node[i], stats_shadow[i]);
115 }
116
Yu Huang8c107082017-07-24 14:58:26 -0700117 return size_wr;
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530118}
119
120/*
Yu Huang8c107082017-07-24 14:58:26 -0700121 * nss_drv_stats_read()
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530122 * Read HLOS driver stats
123 */
Yu Huang8c107082017-07-24 14:58:26 -0700124static ssize_t nss_drv_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530125{
126 int32_t i;
127
128 /*
129 * max output lines = #stats + start tag line + end tag line + three blank lines
130 */
131 uint32_t max_output_lines = NSS_STATS_DRV_MAX + 5;
132 size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
133 size_t size_wr = 0;
134 ssize_t bytes_read = 0;
135 uint64_t *stats_shadow;
136
137 char *lbuf = kzalloc(size_al, GFP_KERNEL);
138 if (unlikely(lbuf == NULL)) {
139 nss_warning("Could not allocate memory for local statistics buffer");
140 return 0;
141 }
142
143 stats_shadow = kzalloc(NSS_STATS_DRV_MAX * 8, GFP_KERNEL);
144 if (unlikely(stats_shadow == NULL)) {
145 nss_warning("Could not allocate memory for local shadow buffer");
Ankit Dhanuka14999992014-11-12 15:35:11 +0530146 kfree(lbuf);
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530147 return 0;
148 }
149
150 size_wr = scnprintf(lbuf, size_al, "drv stats start:\n\n");
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530151 for (i = 0; (i < NSS_STATS_DRV_MAX); i++) {
Sundarajan Srinivasan62fee7e2015-01-22 11:13:10 -0800152 stats_shadow[i] = NSS_PKT_STATS_READ(&nss_top_main.stats_drv[i]);
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530153 }
154
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530155 for (i = 0; (i < NSS_STATS_DRV_MAX); i++) {
156 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
157 "%s = %llu\n", nss_stats_str_drv[i], stats_shadow[i]);
158 }
159
160 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\ndrv stats end\n\n");
161 bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
162 kfree(lbuf);
163 kfree(stats_shadow);
164
165 return bytes_read;
166}
167
168/*
Yu Huang8c107082017-07-24 14:58:26 -0700169 * nss_gmac_stats_read()
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530170 * Read GMAC stats
171 */
Yu Huang8c107082017-07-24 14:58:26 -0700172static ssize_t nss_gmac_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530173{
174 uint32_t i, id;
175
176 /*
177 * max output lines = ((#stats + start tag + one blank) * #GMACs) + start/end tag + 3 blank
178 */
179 uint32_t max_output_lines = ((NSS_STATS_GMAC_MAX + 2) * NSS_MAX_PHYSICAL_INTERFACES) + 5;
180 size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
181 size_t size_wr = 0;
182 ssize_t bytes_read = 0;
183 uint64_t *stats_shadow;
184
185 char *lbuf = kzalloc(size_al, GFP_KERNEL);
186 if (unlikely(lbuf == NULL)) {
187 nss_warning("Could not allocate memory for local statistics buffer");
188 return 0;
189 }
190
191 stats_shadow = kzalloc(NSS_STATS_GMAC_MAX * 8, GFP_KERNEL);
192 if (unlikely(stats_shadow == NULL)) {
193 nss_warning("Could not allocate memory for local shadow buffer");
Ankit Dhanuka14999992014-11-12 15:35:11 +0530194 kfree(lbuf);
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530195 return 0;
196 }
197
198 size_wr = scnprintf(lbuf, size_al, "gmac stats start:\n\n");
199
200 for (id = 0; id < NSS_MAX_PHYSICAL_INTERFACES; id++) {
201 spin_lock_bh(&nss_top_main.stats_lock);
202 for (i = 0; (i < NSS_STATS_GMAC_MAX); i++) {
203 stats_shadow[i] = nss_top_main.stats_gmac[id][i];
204 }
205
206 spin_unlock_bh(&nss_top_main.stats_lock);
207
208 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "GMAC ID: %d\n", id);
209 for (i = 0; (i < NSS_STATS_GMAC_MAX); i++) {
210 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
211 "%s = %llu\n", nss_stats_str_gmac[i], stats_shadow[i]);
212 }
Aniruddha Paul1b170c22017-05-29 12:30:39 +0530213 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n");
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530214 }
215
216 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\ngmac stats end\n\n");
217 bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
218 kfree(lbuf);
219 kfree(stats_shadow);
220
221 return bytes_read;
222}
223
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700224/*
Yu Huang8c107082017-07-24 14:58:26 -0700225 * nss_wt_stats_read()
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700226 * Reads and formats worker thread statistics and outputs them to ubuf
227 */
Yu Huang8c107082017-07-24 14:58:26 -0700228static ssize_t nss_wt_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700229{
230 struct nss_stats_data *data = fp->private_data;
231 struct nss_ctx_instance *nss_ctx = data->nss_ctx;
232 struct nss_project_irq_stats *shadow;
233 uint32_t thread_count = nss_ctx->worker_thread_count;
234 uint32_t irq_count = nss_ctx->irq_count;
235
236 /*
237 * Three lines for each IRQ
238 */
239 uint32_t max_output_lines = thread_count * 3 * irq_count;
240 size_t size_al = max_output_lines * NSS_STATS_MAX_STR_LENGTH;
241 size_t size_wr = 0;
242 ssize_t bytes_read = 0;
243 char *lbuf;
244 int i;
245 int j;
246
247 lbuf = kzalloc(size_al, GFP_KERNEL);
248 if (unlikely(!lbuf)) {
249 nss_warning("Could not allocate memory for local statistics buffer\n");
250 return 0;
251 }
252
253 shadow = kzalloc(thread_count * irq_count * sizeof(struct nss_project_irq_stats), GFP_KERNEL);
254 if (unlikely(!shadow)) {
255 nss_warning("Could not allocate memory for stats shadow\n");
256 kfree(lbuf);
257 return 0;
258 }
259
260 spin_lock_bh(&nss_top_main.stats_lock);
261 if (unlikely(!nss_ctx->wt_stats)) {
262 spin_unlock_bh(&nss_top_main.stats_lock);
263 nss_warning("Worker thread statistics not allocated\n");
264 kfree(lbuf);
265 kfree(shadow);
266 return 0;
267 }
268 for (i = 0; i < thread_count; ++i) {
269
270 /*
271 * The statistics shadow is an array with thread_count * irq_count
272 * items in it. Each item is located at the index:
Yu Huang8c107082017-07-24 14:58:26 -0700273 * (thread number) * (irq_count) + (irq number)
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700274 * thus simulating a two-dimensional array.
275 */
276 for (j = 0; j < irq_count; ++j) {
277 shadow[i * irq_count + j] = nss_ctx->wt_stats[i].irq_stats[j];
278 }
279 }
280 spin_unlock_bh(&nss_top_main.stats_lock);
281
282 for (i = 0; i < thread_count; ++i) {
283 for (j = 0; j < irq_count; ++j) {
284 struct nss_project_irq_stats *is = &(shadow[i * irq_count + j]);
285 if (!(is->count)) {
286 continue;
287 }
288
289 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
290 "t-%d:irq-%d callback: 0x%x, count: %llu\n",
291 i, j, is->callback, is->count);
292 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
293 "t-%d:irq-%d tick min: %10u avg: %10u max:%10u\n",
294 i, j, is->ticks_min, is->ticks_avg, is->ticks_max);
295 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
296 "t-%d:irq-%d insn min: %10u avg: %10u max:%10u\n\n",
297 i, j, is->insn_min, is->insn_avg, is->insn_max);
298 }
299 }
300 bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
301 kfree(lbuf);
302 kfree(shadow);
303
304 return bytes_read;
305}
306
307/*
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700308 * nss_stats_open()
309 */
Yu Huang8c107082017-07-24 14:58:26 -0700310int nss_stats_open(struct inode *inode, struct file *filp)
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700311{
312 struct nss_stats_data *data = NULL;
313
314 data = kzalloc(sizeof(struct nss_stats_data), GFP_KERNEL);
315 if (!data) {
316 return -ENOMEM;
317 }
318 memset(data, 0, sizeof (struct nss_stats_data));
319 data->if_num = NSS_DYNAMIC_IF_START;
Ankit Dhanuka6228ebd2014-11-05 17:26:01 +0530320 data->index = 0;
Stephen Wangaed46332016-12-12 17:29:03 -0800321 data->edma_id = (nss_ptr_t)inode->i_private;
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700322 data->nss_ctx = (struct nss_ctx_instance *)(inode->i_private);
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700323 filp->private_data = data;
324
325 return 0;
326}
327
328/*
329 * nss_stats_release()
330 */
Yu Huang8c107082017-07-24 14:58:26 -0700331int nss_stats_release(struct inode *inode, struct file *filp)
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700332{
333 struct nss_stats_data *data = filp->private_data;
334
335 if (data) {
336 kfree(data);
337 }
338
339 return 0;
340}
341
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530342/*
343 * drv_stats_ops
344 */
345NSS_STATS_DECLARE_FILE_OPERATIONS(drv)
346
347/*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530348 * gmac_stats_ops
349 */
350NSS_STATS_DECLARE_FILE_OPERATIONS(gmac)
351
352/*
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700353 * wt_stats_ops
354 */
355NSS_STATS_DECLARE_FILE_OPERATIONS(wt)
Yu Huang8c107082017-07-24 14:58:26 -0700356
357/*
358 * nss_stats_clean()
359 * Cleanup NSS statistics files
360 */
361void nss_stats_clean(void)
362{
363 /*
364 * Remove debugfs tree
365 */
366 if (likely(nss_top_main.top_dentry != NULL)) {
367 debugfs_remove_recursive(nss_top_main.top_dentry);
368 nss_top_main.top_dentry = NULL;
369 }
370}
371
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700372/*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530373 * nss_stats_init()
374 * Enable NSS statistics
375 */
376void nss_stats_init(void)
377{
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700378 struct dentry *core_dentry = NULL;
379 struct dentry *wt_dentry = NULL;
Shashank Balashankar512cb602016-08-01 17:57:42 -0700380 char file_name[10];
Yu Huang8c107082017-07-24 14:58:26 -0700381 int i;
Shashank Balashankar512cb602016-08-01 17:57:42 -0700382
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530383 /*
384 * NSS driver entry
385 */
386 nss_top_main.top_dentry = debugfs_create_dir("qca-nss-drv", NULL);
387 if (unlikely(nss_top_main.top_dentry == NULL)) {
388 nss_warning("Failed to create qca-nss-drv directory in debugfs");
389
390 /*
391 * Non availability of debugfs directory is not a catastrophy
392 * We can still go ahead with other initialization
393 */
394 return;
395 }
396
397 nss_top_main.stats_dentry = debugfs_create_dir("stats", nss_top_main.top_dentry);
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +0530398 if (unlikely(nss_top_main.stats_dentry == NULL)) {
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530399 nss_warning("Failed to create qca-nss-drv directory in debugfs");
400
401 /*
402 * Non availability of debugfs directory is not a catastrophy
403 * We can still go ahead with rest of initialization
404 */
405 return;
406 }
407
408 /*
409 * Create files to obtain statistics
410 */
411
412 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530413 * drv_stats
414 */
Yu Huang8c107082017-07-24 14:58:26 -0700415 nss_stats_create_dentry("drv", &nss_drv_stats_ops);
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530416
417 /*
418 * gmac_stats
419 */
Yu Huang8c107082017-07-24 14:58:26 -0700420 nss_stats_create_dentry("gmac", &nss_gmac_stats_ops);
Aniruddha Paul1b170c22017-05-29 12:30:39 +0530421
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700422 /*
423 * Per-project stats
424 */
425 nss_top_main.project_dentry = debugfs_create_dir("project",
426 nss_top_main.stats_dentry);
427 if (unlikely(nss_top_main.project_dentry == NULL)) {
428 nss_warning("Failed to create qca-nss-drv/stats/project directory in debugfs");
429 return;
430 }
431
432 for (i = 0; i < NSS_MAX_CORES; ++i) {
433 memset(file_name, 0, sizeof(file_name));
434 scnprintf(file_name, sizeof(file_name), "core%d", i);
435 core_dentry = debugfs_create_dir(file_name,
436 nss_top_main.project_dentry);
437 if (unlikely(core_dentry == NULL)) {
438 nss_warning("Failed to create qca-nss-drv/stats/project/core%d directory in debugfs", i);
439 return;
440 }
441
442 wt_dentry = debugfs_create_file("worker_threads",
443 0400,
444 core_dentry,
445 &(nss_top_main.nss[i]),
Yu Huang8c107082017-07-24 14:58:26 -0700446 &nss_wt_stats_ops);
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700447 if (unlikely(wt_dentry == NULL)) {
448 nss_warning("Failed to create qca-nss-drv/stats/project/core%d/worker_threads file in debugfs", i);
449 return;
450 }
451 }
452
Saurabh Misra96998db2014-07-10 12:15:48 -0700453 nss_log_init();
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530454}