blob: 71fca9de32b3401dd56022deaf041a2b98616400 [file] [log] [blame]
Radhakrishna Jiguru1c9b2252013-08-27 23:57:48 +05301/*
2 **************************************************************************
Stephen Wang3e2dbd12018-03-14 17:28:17 -07003 * Copyright (c) 2013-2018, 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",
Stephen Wang3e2dbd12018-03-14 17:28:17 -070057 "rx_frag_seg_processed",
58 "tx_buffers_cmd_queue_full",
Stephen Wang02636862018-04-05 22:13:12 -070059#ifdef NSS_MULTI_H2N_DATA_RING_SUPPORT
60 "tx_buffers_data_queue_0",
61 "tx_buffers_data_queue_1",
62 "tx_buffers_data_queue_2",
63 "tx_buffers_data_queue_3",
64 "tx_buffers_data_queue_4",
65 "tx_buffers_data_queue_5",
66 "tx_buffers_data_queue_6",
67 "tx_buffers_data_queue_7",
68#endif
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053069};
70
71/*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053072 * nss_stats_str_gmac
73 * GMAC stats strings
74 */
75static int8_t *nss_stats_str_gmac[NSS_STATS_GMAC_MAX] = {
76 "ticks",
77 "worst_ticks",
78 "iterations"
79};
80
81/*
Abhishek Rastogi84d95d02014-03-26 19:31:31 +053082 * nss_stats_str_node
83 * Interface stats strings per node
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053084 */
Abhishek Rastogi84d95d02014-03-26 19:31:31 +053085static int8_t *nss_stats_str_node[NSS_STATS_NODE_MAX] = {
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053086 "rx_packets",
87 "rx_bytes",
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053088 "tx_packets",
ratheesh kannoth93ba95c2017-07-13 15:52:52 +053089 "tx_bytes",
90 "rx_queue_0_dropped",
91 "rx_queue_1_dropped",
92 "rx_queue_2_dropped",
93 "rx_queue_3_dropped",
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053094};
95
96/*
Yu Huang8c107082017-07-24 14:58:26 -070097 * nss_stats_create_dentry()
98 * Create statistics debug entry for subsystem.
Murat Sezgin99dab642014-08-28 14:40:34 -070099 */
Yu Huang8c107082017-07-24 14:58:26 -0700100void nss_stats_create_dentry(char *name, const struct file_operations *ops)
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530101{
Yu Huang8c107082017-07-24 14:58:26 -0700102 if (!debugfs_create_file(name, 0400, nss_top_main.stats_dentry, &nss_top_main, ops)) {
103 nss_warning("Faied to create debug entry for subsystem %s\n", name);
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530104 }
Yu Huang8c107082017-07-24 14:58:26 -0700105}
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530106
Yu Huang8c107082017-07-24 14:58:26 -0700107/*
108 * nss_stats_fill_common_stats()
109 * Fill common node statistics.
110 */
111size_t nss_stats_fill_common_stats(uint32_t if_num, char *lbuf, size_t size_wr, size_t size_al)
112{
113 uint64_t stats_shadow[NSS_STATS_NODE_MAX];
114 int i;
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530115
Abhishek Rastogia1a07972014-04-01 19:43:33 +0530116 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "common node stats:\n\n");
Abhishek Rastogi84d95d02014-03-26 19:31:31 +0530117 spin_lock_bh(&nss_top_main.stats_lock);
118 for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
Yu Huang8c107082017-07-24 14:58:26 -0700119 stats_shadow[i] = nss_top_main.stats_node[if_num][i];
Abhishek Rastogi84d95d02014-03-26 19:31:31 +0530120 }
Abhishek Rastogi84d95d02014-03-26 19:31:31 +0530121 spin_unlock_bh(&nss_top_main.stats_lock);
122
123 for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
124 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
125 "%s = %llu\n", nss_stats_str_node[i], stats_shadow[i]);
126 }
127
Yu Huang8c107082017-07-24 14:58:26 -0700128 return size_wr;
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530129}
130
131/*
Yu Huang8c107082017-07-24 14:58:26 -0700132 * nss_drv_stats_read()
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530133 * Read HLOS driver stats
134 */
Yu Huang8c107082017-07-24 14:58:26 -0700135static 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 +0530136{
137 int32_t i;
138
139 /*
140 * max output lines = #stats + start tag line + end tag line + three blank lines
141 */
142 uint32_t max_output_lines = NSS_STATS_DRV_MAX + 5;
143 size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
144 size_t size_wr = 0;
145 ssize_t bytes_read = 0;
146 uint64_t *stats_shadow;
147
148 char *lbuf = kzalloc(size_al, GFP_KERNEL);
149 if (unlikely(lbuf == NULL)) {
150 nss_warning("Could not allocate memory for local statistics buffer");
151 return 0;
152 }
153
154 stats_shadow = kzalloc(NSS_STATS_DRV_MAX * 8, GFP_KERNEL);
155 if (unlikely(stats_shadow == NULL)) {
156 nss_warning("Could not allocate memory for local shadow buffer");
Ankit Dhanuka14999992014-11-12 15:35:11 +0530157 kfree(lbuf);
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530158 return 0;
159 }
160
161 size_wr = scnprintf(lbuf, size_al, "drv stats start:\n\n");
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530162 for (i = 0; (i < NSS_STATS_DRV_MAX); i++) {
Sundarajan Srinivasan62fee7e2015-01-22 11:13:10 -0800163 stats_shadow[i] = NSS_PKT_STATS_READ(&nss_top_main.stats_drv[i]);
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530164 }
165
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530166 for (i = 0; (i < NSS_STATS_DRV_MAX); i++) {
167 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
168 "%s = %llu\n", nss_stats_str_drv[i], stats_shadow[i]);
169 }
170
171 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\ndrv stats end\n\n");
172 bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
173 kfree(lbuf);
174 kfree(stats_shadow);
175
176 return bytes_read;
177}
178
179/*
Yu Huang8c107082017-07-24 14:58:26 -0700180 * nss_gmac_stats_read()
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530181 * Read GMAC stats
182 */
Yu Huang8c107082017-07-24 14:58:26 -0700183static 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 +0530184{
185 uint32_t i, id;
186
187 /*
188 * max output lines = ((#stats + start tag + one blank) * #GMACs) + start/end tag + 3 blank
189 */
190 uint32_t max_output_lines = ((NSS_STATS_GMAC_MAX + 2) * NSS_MAX_PHYSICAL_INTERFACES) + 5;
191 size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
192 size_t size_wr = 0;
193 ssize_t bytes_read = 0;
194 uint64_t *stats_shadow;
195
196 char *lbuf = kzalloc(size_al, GFP_KERNEL);
197 if (unlikely(lbuf == NULL)) {
198 nss_warning("Could not allocate memory for local statistics buffer");
199 return 0;
200 }
201
202 stats_shadow = kzalloc(NSS_STATS_GMAC_MAX * 8, GFP_KERNEL);
203 if (unlikely(stats_shadow == NULL)) {
204 nss_warning("Could not allocate memory for local shadow buffer");
Ankit Dhanuka14999992014-11-12 15:35:11 +0530205 kfree(lbuf);
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530206 return 0;
207 }
208
209 size_wr = scnprintf(lbuf, size_al, "gmac stats start:\n\n");
210
211 for (id = 0; id < NSS_MAX_PHYSICAL_INTERFACES; id++) {
212 spin_lock_bh(&nss_top_main.stats_lock);
213 for (i = 0; (i < NSS_STATS_GMAC_MAX); i++) {
214 stats_shadow[i] = nss_top_main.stats_gmac[id][i];
215 }
216
217 spin_unlock_bh(&nss_top_main.stats_lock);
218
219 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "GMAC ID: %d\n", id);
220 for (i = 0; (i < NSS_STATS_GMAC_MAX); i++) {
221 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
222 "%s = %llu\n", nss_stats_str_gmac[i], stats_shadow[i]);
223 }
Aniruddha Paul1b170c22017-05-29 12:30:39 +0530224 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n");
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530225 }
226
227 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\ngmac stats end\n\n");
228 bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
229 kfree(lbuf);
230 kfree(stats_shadow);
231
232 return bytes_read;
233}
234
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700235/*
Yu Huang8c107082017-07-24 14:58:26 -0700236 * nss_wt_stats_read()
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700237 * Reads and formats worker thread statistics and outputs them to ubuf
238 */
Yu Huang8c107082017-07-24 14:58:26 -0700239static 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 -0700240{
241 struct nss_stats_data *data = fp->private_data;
242 struct nss_ctx_instance *nss_ctx = data->nss_ctx;
243 struct nss_project_irq_stats *shadow;
244 uint32_t thread_count = nss_ctx->worker_thread_count;
245 uint32_t irq_count = nss_ctx->irq_count;
246
247 /*
248 * Three lines for each IRQ
249 */
250 uint32_t max_output_lines = thread_count * 3 * irq_count;
251 size_t size_al = max_output_lines * NSS_STATS_MAX_STR_LENGTH;
252 size_t size_wr = 0;
253 ssize_t bytes_read = 0;
254 char *lbuf;
255 int i;
256 int j;
257
258 lbuf = kzalloc(size_al, GFP_KERNEL);
259 if (unlikely(!lbuf)) {
260 nss_warning("Could not allocate memory for local statistics buffer\n");
261 return 0;
262 }
263
264 shadow = kzalloc(thread_count * irq_count * sizeof(struct nss_project_irq_stats), GFP_KERNEL);
265 if (unlikely(!shadow)) {
266 nss_warning("Could not allocate memory for stats shadow\n");
267 kfree(lbuf);
268 return 0;
269 }
270
271 spin_lock_bh(&nss_top_main.stats_lock);
272 if (unlikely(!nss_ctx->wt_stats)) {
273 spin_unlock_bh(&nss_top_main.stats_lock);
274 nss_warning("Worker thread statistics not allocated\n");
275 kfree(lbuf);
276 kfree(shadow);
277 return 0;
278 }
279 for (i = 0; i < thread_count; ++i) {
280
281 /*
282 * The statistics shadow is an array with thread_count * irq_count
283 * items in it. Each item is located at the index:
Yu Huang8c107082017-07-24 14:58:26 -0700284 * (thread number) * (irq_count) + (irq number)
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700285 * thus simulating a two-dimensional array.
286 */
287 for (j = 0; j < irq_count; ++j) {
288 shadow[i * irq_count + j] = nss_ctx->wt_stats[i].irq_stats[j];
289 }
290 }
291 spin_unlock_bh(&nss_top_main.stats_lock);
292
293 for (i = 0; i < thread_count; ++i) {
294 for (j = 0; j < irq_count; ++j) {
295 struct nss_project_irq_stats *is = &(shadow[i * irq_count + j]);
296 if (!(is->count)) {
297 continue;
298 }
299
300 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
301 "t-%d:irq-%d callback: 0x%x, count: %llu\n",
302 i, j, is->callback, is->count);
303 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
304 "t-%d:irq-%d tick min: %10u avg: %10u max:%10u\n",
305 i, j, is->ticks_min, is->ticks_avg, is->ticks_max);
306 size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
307 "t-%d:irq-%d insn min: %10u avg: %10u max:%10u\n\n",
308 i, j, is->insn_min, is->insn_avg, is->insn_max);
309 }
310 }
311 bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
312 kfree(lbuf);
313 kfree(shadow);
314
315 return bytes_read;
316}
317
318/*
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700319 * nss_stats_open()
320 */
Yu Huang8c107082017-07-24 14:58:26 -0700321int nss_stats_open(struct inode *inode, struct file *filp)
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700322{
323 struct nss_stats_data *data = NULL;
324
325 data = kzalloc(sizeof(struct nss_stats_data), GFP_KERNEL);
326 if (!data) {
327 return -ENOMEM;
328 }
329 memset(data, 0, sizeof (struct nss_stats_data));
330 data->if_num = NSS_DYNAMIC_IF_START;
Ankit Dhanuka6228ebd2014-11-05 17:26:01 +0530331 data->index = 0;
Stephen Wangaed46332016-12-12 17:29:03 -0800332 data->edma_id = (nss_ptr_t)inode->i_private;
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700333 data->nss_ctx = (struct nss_ctx_instance *)(inode->i_private);
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700334 filp->private_data = data;
335
336 return 0;
337}
338
339/*
340 * nss_stats_release()
341 */
Yu Huang8c107082017-07-24 14:58:26 -0700342int nss_stats_release(struct inode *inode, struct file *filp)
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700343{
344 struct nss_stats_data *data = filp->private_data;
345
346 if (data) {
347 kfree(data);
348 }
349
350 return 0;
351}
352
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530353/*
354 * drv_stats_ops
355 */
356NSS_STATS_DECLARE_FILE_OPERATIONS(drv)
357
358/*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530359 * gmac_stats_ops
360 */
361NSS_STATS_DECLARE_FILE_OPERATIONS(gmac)
362
363/*
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700364 * wt_stats_ops
365 */
366NSS_STATS_DECLARE_FILE_OPERATIONS(wt)
Yu Huang8c107082017-07-24 14:58:26 -0700367
368/*
369 * nss_stats_clean()
370 * Cleanup NSS statistics files
371 */
372void nss_stats_clean(void)
373{
374 /*
375 * Remove debugfs tree
376 */
377 if (likely(nss_top_main.top_dentry != NULL)) {
378 debugfs_remove_recursive(nss_top_main.top_dentry);
379 nss_top_main.top_dentry = NULL;
380 }
381}
382
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700383/*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530384 * nss_stats_init()
385 * Enable NSS statistics
386 */
387void nss_stats_init(void)
388{
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700389 struct dentry *core_dentry = NULL;
390 struct dentry *wt_dentry = NULL;
Shashank Balashankar512cb602016-08-01 17:57:42 -0700391 char file_name[10];
Yu Huang8c107082017-07-24 14:58:26 -0700392 int i;
Shashank Balashankar512cb602016-08-01 17:57:42 -0700393
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530394 /*
395 * NSS driver entry
396 */
397 nss_top_main.top_dentry = debugfs_create_dir("qca-nss-drv", NULL);
398 if (unlikely(nss_top_main.top_dentry == NULL)) {
399 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 other initialization
404 */
405 return;
406 }
407
408 nss_top_main.stats_dentry = debugfs_create_dir("stats", nss_top_main.top_dentry);
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +0530409 if (unlikely(nss_top_main.stats_dentry == NULL)) {
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530410 nss_warning("Failed to create qca-nss-drv directory in debugfs");
411
412 /*
413 * Non availability of debugfs directory is not a catastrophy
414 * We can still go ahead with rest of initialization
415 */
416 return;
417 }
418
419 /*
420 * Create files to obtain statistics
421 */
422
423 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530424 * drv_stats
425 */
Yu Huang8c107082017-07-24 14:58:26 -0700426 nss_stats_create_dentry("drv", &nss_drv_stats_ops);
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530427
428 /*
429 * gmac_stats
430 */
Yu Huang8c107082017-07-24 14:58:26 -0700431 nss_stats_create_dentry("gmac", &nss_gmac_stats_ops);
Aniruddha Paul1b170c22017-05-29 12:30:39 +0530432
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700433 /*
434 * Per-project stats
435 */
436 nss_top_main.project_dentry = debugfs_create_dir("project",
437 nss_top_main.stats_dentry);
438 if (unlikely(nss_top_main.project_dentry == NULL)) {
439 nss_warning("Failed to create qca-nss-drv/stats/project directory in debugfs");
440 return;
441 }
442
443 for (i = 0; i < NSS_MAX_CORES; ++i) {
444 memset(file_name, 0, sizeof(file_name));
445 scnprintf(file_name, sizeof(file_name), "core%d", i);
446 core_dentry = debugfs_create_dir(file_name,
447 nss_top_main.project_dentry);
448 if (unlikely(core_dentry == NULL)) {
449 nss_warning("Failed to create qca-nss-drv/stats/project/core%d directory in debugfs", i);
450 return;
451 }
452
453 wt_dentry = debugfs_create_file("worker_threads",
454 0400,
455 core_dentry,
456 &(nss_top_main.nss[i]),
Yu Huang8c107082017-07-24 14:58:26 -0700457 &nss_wt_stats_ops);
Jackson Bockusc2a4e682017-06-23 11:59:29 -0700458 if (unlikely(wt_dentry == NULL)) {
459 nss_warning("Failed to create qca-nss-drv/stats/project/core%d/worker_threads file in debugfs", i);
460 return;
461 }
462 }
463
Saurabh Misra96998db2014-07-10 12:15:48 -0700464 nss_log_init();
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530465}