1/*
2 **************************************************************************
3 * Copyright (c) 2013-2015, 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_stats.c
19 *	NSS stats APIs
20 *
21 */
22
23#include "nss_core.h"
24
25/*
26 * Maximum string length:
27 * This should be equal to maximum string size of any stats
28 * inclusive of stats value
29 */
30#define NSS_STATS_MAX_STR_LENGTH 96
31
32/*
33 * Global variables/extern declarations
34 */
35extern struct nss_top_instance nss_top_main;
36
37extern int32_t nss_tx_rx_virt_if_copy_stats(int32_t if_num, int i, char *line);
38
39uint64_t stats_shadow_pppoe_except[NSS_PPPOE_NUM_SESSION_PER_INTERFACE][NSS_PPPOE_EXCEPTION_EVENT_MAX];
40
41/*
42 * Private data for every file descriptor
43 */
44struct nss_stats_data {
45	uint32_t if_num;	/**< Interface number for stats */
46	uint32_t index;		/**< Index for GRE_REDIR stats */
47};
48
49/*
50 * Statistics structures
51 */
52
53/*
54 * nss_stats_str_ipv4
55 *	IPv4 stats strings
56 */
57static int8_t *nss_stats_str_ipv4[NSS_STATS_IPV4_MAX] = {
58	"rx_pkts",
59	"rx_bytes",
60	"tx_pkts",
61	"tx_bytes",
62	"create_requests",
63	"create_collisions",
64	"create_invalid_interface",
65	"destroy_requests",
66	"destroy_misses",
67	"hash_hits",
68	"hash_reorders",
69	"flushes",
70	"evictions",
71	"fragmentations",
72	"mc_create_requests",
73	"mc_update_requests",
74	"mc_create_invalid_interface",
75	"mc_destroy_requests",
76	"mc_destroy_misses",
77	"mc_flushes",
78};
79
80/*
81 * nss_stats_str_ipv4_reasm
82 *	IPv4 reassembly stats strings
83 */
84static int8_t *nss_stats_str_ipv4_reasm[NSS_STATS_IPV4_REASM_MAX] = {
85	"evictions",
86	"alloc_fails",
87	"timeouts",
88};
89
90/*
91 * nss_stats_str_ipv6
92 *	IPv6 stats strings
93 */
94static int8_t *nss_stats_str_ipv6[NSS_STATS_IPV6_MAX] = {
95	"rx_pkts",
96	"rx_bytes",
97	"tx_pkts",
98	"tx_bytes",
99	"create_requests",
100	"create_collisions",
101	"create_invalid_interface",
102	"destroy_requests",
103	"destroy_misses",
104	"hash_hits",
105	"hash_reorders",
106	"flushes",
107	"evictions",
108	"fragmentations",
109	"frag_fails",
110	"mc_create_requests",
111	"mc_update_requests",
112	"mc_create_invalid_interface",
113	"mc_destroy_requests",
114	"mc_destroy_misses",
115	"mc_flushes",
116};
117
118/*
119 * nss_stats_str_ipv6_reasm
120 *	IPv6 reassembly stats strings
121 */
122static int8_t *nss_stats_str_ipv6_reasm[NSS_STATS_IPV6_REASM_MAX] = {
123	"alloc_fails",
124	"timeouts",
125	"discards",
126};
127
128/*
129 * nss_stats_str_n2h
130 *	N2H stats strings
131 */
132static int8_t *nss_stats_str_n2h[NSS_STATS_N2H_MAX] = {
133	"queue_dropped",
134	"ticks",
135	"worst_ticks",
136	"iterations",
137	"pbuf_ocm_alloc_fails",
138	"pbuf_ocm_free_count",
139	"pbuf_ocm_total_count",
140	"pbuf_default_alloc_fails",
141	"pbuf_default_free_count",
142	"pbuf_default_total_count",
143	"payload_fails",
144	"payload_free_count",
145	"h2n_control_packets",
146	"h2n_control_bytes",
147	"n2h_control_packets",
148	"n2h_control_bytes",
149	"h2n_data_packets",
150	"h2n_data_bytes",
151	"n2h_data_packets",
152	"n2h_data_bytes",
153	"n2h_tot_payloads",
154	"n2h_data_interface_invalid",
155};
156
157/*
158 * nss_stats_str_lso_rx
159 *	LSO_RX stats strings
160 */
161static int8_t *nss_stats_str_lso_rx[NSS_STATS_LSO_RX_MAX] = {
162	"tx_dropped",
163	"dropped",
164	"pbuf_alloc_fail",
165	"pbuf_reference_fail"
166};
167
168/*
169 * nss_stats_str_drv
170 *	Host driver stats strings
171 */
172static int8_t *nss_stats_str_drv[NSS_STATS_DRV_MAX] = {
173	"nbuf_alloc_errors",
174	"tx_queue_full[0]",
175	"tx_queue_full[1]",
176	"tx_buffers_empty",
177	"tx_buffers_pkt",
178	"tx_buffers_cmd",
179	"tx_buffers_crypto",
180	"rx_buffers_empty",
181	"rx_buffers_pkt",
182	"rx_buffers_cmd_resp",
183	"rx_buffers_status_sync",
184	"rx_buffers_crypto",
185	"rx_buffers_virtual",
186	"tx_skb_simple",
187	"tx_skb_nr_frags",
188	"tx_skb_fraglist",
189	"rx_skb_simple",
190	"rx_skb_nr_frags",
191	"rx_skb_fraglist",
192	"rx_bad_desciptor",
193	"nss_skb_count",
194	"rx_chain_seg_processed",
195	"rx_frag_seg_processed"
196};
197
198/*
199 * nss_stats_str_pppoe
200 *	PPPoE stats strings
201 */
202static int8_t *nss_stats_str_pppoe[NSS_STATS_PPPOE_MAX] = {
203	"create_requests",
204	"create_failures",
205	"destroy_requests",
206	"destroy_misses"
207};
208
209/*
210 * nss_stats_str_gmac
211 *	GMAC stats strings
212 */
213static int8_t *nss_stats_str_gmac[NSS_STATS_GMAC_MAX] = {
214	"ticks",
215	"worst_ticks",
216	"iterations"
217};
218
219/*
220 * nss_stats_str_node
221 *	Interface stats strings per node
222 */
223static int8_t *nss_stats_str_node[NSS_STATS_NODE_MAX] = {
224	"rx_packets",
225	"rx_bytes",
226	"rx_dropped",
227	"tx_packets",
228	"tx_bytes"
229};
230
231/*
232 * nss_stats_str_eth_rx
233 *	eth_rx stats strings
234 */
235static int8_t *nss_stats_str_eth_rx[NSS_STATS_ETH_RX_MAX] = {
236	"ticks",
237	"worst_ticks",
238	"iterations"
239};
240
241/*
242 * nss_stats_str_if_exception_unknown
243 *	Interface stats strings for unknown exceptions
244 */
245static int8_t *nss_stats_str_if_exception_eth_rx[NSS_EXCEPTION_EVENT_ETH_RX_MAX] = {
246	"UNKNOWN_L3_PROTOCOL",
247	"ETH_HDR_MISSING",
248	"VLAN_MISSING"
249};
250
251/*
252 * nss_stats_str_if_exception_ipv4
253 *	Interface stats strings for ipv4 exceptions
254 */
255static int8_t *nss_stats_str_if_exception_ipv4[NSS_EXCEPTION_EVENT_IPV4_MAX] = {
256	"IPV4_ICMP_HEADER_INCOMPLETE",
257	"IPV4_ICMP_UNHANDLED_TYPE",
258	"IPV4_ICMP_IPV4_HEADER_INCOMPLETE",
259	"IPV4_ICMP_IPV4_UDP_HEADER_INCOMPLETE",
260	"IPV4_ICMP_IPV4_TCP_HEADER_INCOMPLETE",
261	"IPV4_ICMP_IPV4_UNKNOWN_PROTOCOL",
262	"IPV4_ICMP_NO_ICME",
263	"IPV4_ICMP_FLUSH_TO_HOST",
264	"IPV4_TCP_HEADER_INCOMPLETE",
265	"IPV4_TCP_NO_ICME",
266	"IPV4_TCP_IP_OPTION",
267	"IPV4_TCP_IP_FRAGMENT",
268	"IPV4_TCP_SMALL_TTL",
269	"IPV4_TCP_NEEDS_FRAGMENTATION",
270	"IPV4_TCP_FLAGS",
271	"IPV4_TCP_SEQ_EXCEEDS_RIGHT_EDGE",
272	"IPV4_TCP_SMALL_DATA_OFFS",
273	"IPV4_TCP_BAD_SACK",
274	"IPV4_TCP_BIG_DATA_OFFS",
275	"IPV4_TCP_SEQ_BEFORE_LEFT_EDGE",
276	"IPV4_TCP_ACK_EXCEEDS_RIGHT_EDGE",
277	"IPV4_TCP_ACK_BEFORE_LEFT_EDGE",
278	"IPV4_UDP_HEADER_INCOMPLETE",
279	"IPV4_UDP_NO_ICME",
280	"IPV4_UDP_IP_OPTION",
281	"IPV4_UDP_IP_FRAGMENT",
282	"IPV4_UDP_SMALL_TTL",
283	"IPV4_UDP_NEEDS_FRAGMENTATION",
284	"IPV4_WRONG_TARGET_MAC",
285	"IPV4_HEADER_INCOMPLETE",
286	"IPV4_BAD_TOTAL_LENGTH",
287	"IPV4_BAD_CHECKSUM",
288	"IPV4_NON_INITIAL_FRAGMENT",
289	"IPV4_DATAGRAM_INCOMPLETE",
290	"IPV4_OPTIONS_INCOMPLETE",
291	"IPV4_UNKNOWN_PROTOCOL",
292	"IPV4_ESP_HEADER_INCOMPLETE",
293	"IPV4_ESP_NO_ICME",
294	"IPV4_ESP_IP_OPTION",
295	"IPV4_ESP_IP_FRAGMENT",
296	"IPV4_ESP_SMALL_TTL",
297	"IPV4_ESP_NEEDS_FRAGMENTATION",
298	"IPV4_INGRESS_VID_MISMATCH",
299	"IPV4_INGRESS_VID_MISSING",
300	"IPV4_6RD_NO_ICME",
301	"IPV4_6RD_IP_OPTION",
302	"IPV4_6RD_IP_FRAGMENT",
303	"IPV4_6RD_NEEDS_FRAGMENTATION",
304	"IPV4_DSCP_MARKING_MISMATCH",
305	"IPV4_VLAN_MARKING_MISMATCH",
306	"IPV4_INTERFACE_MISMATCH",
307	"IPV4_GRE_HEADER_INCOMPLETE",
308	"IPV4_GRE_NO_ICME",
309	"IPV4_GRE_IP_OPTION",
310	"IPV4_GRE_IP_FRAGMENT",
311	"IPV4_GRE_SMALL_TTL",
312	"IPV4_GRE_NEEDS_FRAGMENTATION",
313	"IPV4_FRAG_DF_SET",
314	"IPV4_FRAG_FAIL",
315	"IPV4_DESTROY",
316	"IPV4_ICMP_IPV4_UDPLITE_HEADER_INCOMPLETE",
317	"IPV4_UDPLITE_HEADER_INCOMPLETE",
318	"IPV4_UDPLITE_NO_ICME",
319	"IPV4_UDPLITE_IP_OPTION",
320	"IPV4_UDPLITE_IP_FRAGMENT",
321	"IPV4_UDPLITE_SMALL_TTL",
322	"IPV4_UDPLITE_NEEDS_FRAGMENTATION",
323	"IPV4_MC_UDP_NO_ICME",
324	"IPV4_MC_MEM_ALLOC_FAILURE",
325	"IPV4_MC_UPDATE_FAILURE",
326	"IPV4_MC_PBUF_ALLOC_FAILURE"
327};
328
329/*
330 * nss_stats_str_if_exception_ipv6
331 *	Interface stats strings for ipv6 exceptions
332 */
333static int8_t *nss_stats_str_if_exception_ipv6[NSS_EXCEPTION_EVENT_IPV6_MAX] = {
334	"IPV6_ICMP_HEADER_INCOMPLETE",
335	"IPV6_ICMP_UNHANDLED_TYPE",
336	"IPV6_ICMP_IPV6_HEADER_INCOMPLETE",
337	"IPV6_ICMP_IPV6_UDP_HEADER_INCOMPLETE",
338	"IPV6_ICMP_IPV6_TCP_HEADER_INCOMPLETE",
339	"IPV6_ICMP_IPV6_UNKNOWN_PROTOCOL",
340	"IPV6_ICMP_NO_ICME",
341	"IPV6_ICMP_FLUSH_TO_HOST",
342	"IPV6_TCP_HEADER_INCOMPLETE",
343	"IPV6_TCP_NO_ICME",
344	"IPV6_TCP_SMALL_HOP_LIMIT",
345	"IPV6_TCP_NEEDS_FRAGMENTATION",
346	"IPV6_TCP_FLAGS",
347	"IPV6_TCP_SEQ_EXCEEDS_RIGHT_EDGE",
348	"IPV6_TCP_SMALL_DATA_OFFS",
349	"IPV6_TCP_BAD_SACK",
350	"IPV6_TCP_BIG_DATA_OFFS",
351	"IPV6_TCP_SEQ_BEFORE_LEFT_EDGE",
352	"IPV6_TCP_ACK_EXCEEDS_RIGHT_EDGE",
353	"IPV6_TCP_ACK_BEFORE_LEFT_EDGE",
354	"IPV6_UDP_HEADER_INCOMPLETE",
355	"IPV6_UDP_NO_ICME",
356	"IPV6_UDP_SMALL_HOP_LIMIT",
357	"IPV6_UDP_NEEDS_FRAGMENTATION",
358	"IPV6_WRONG_TARGET_MAC",
359	"IPV6_HEADER_INCOMPLETE",
360	"IPV6_UNKNOWN_PROTOCOL",
361	"IPV6_INGRESS_VID_MISMATCH",
362	"IPV6_INGRESS_VID_MISSING",
363	"IPV6_DSCP_MARKING_MISMATCH",
364	"IPV6_VLAN_MARKING_MISMATCH",
365	"IPV6_INTERFACE_MISMATCH",
366	"IPV6_GRE_NO_ICME",
367	"IPV6_GRE_NEEDS_FRAGMENTATION",
368	"IPV6_GRE_SMALL_HOP_LIMIT",
369	"IPV6_DESTROY",
370	"IPV6_ICMP_IPV6_UDPLITE_HEADER_INCOMPLETE",
371	"IPV6_UDPLITE_HEADER_INCOMPLETE",
372	"IPV6_UDPLITE_NO_ICME",
373	"IPV6_UDPLITE_SMALL_HOP_LIMIT",
374	"IPV6_UDPLITE_NEEDS_FRAGMENTATION",
375	"IPV6_MC_UDP_NO_ICME",
376	"IPV6_MC_MEM_ALLOC_FAILURE",
377	"IPV6_MC_UPDATE_FAILURE",
378	"IPV6_MC_PBUF_ALLOC_FAILURE"
379};
380
381/*
382 * nss_stats_str_if_exception_pppoe
383 *	Interface stats strings for PPPoE exceptions
384 */
385static int8_t *nss_stats_str_if_exception_pppoe[NSS_PPPOE_EXCEPTION_EVENT_MAX] = {
386	"PPPOE_WRONG_VERSION_OR_TYPE",
387	"PPPOE_WRONG_CODE",
388	"PPPOE_HEADER_INCOMPLETE",
389	"PPPOE_UNSUPPORTED_PPP_PROTOCOL",
390	"PPPOE_INTERFACE_MISMATCH"
391};
392
393/*
394 * nss_stats_str_wifi
395 * 	Wifi statistics strings
396 */
397static int8_t *nss_stats_str_wifi[NSS_STATS_WIFI_MAX] = {
398	"RX_PACKETS",
399	"RX_DROPPED",
400	"TX_PACKETS",
401	"TX_DROPPED",
402	"TX_TRANSMIT_COMPLETED",
403	"TX_MGMT_RECEIVED",
404	"TX_MGMT_TRANSMITTED",
405	"TX_MGMT_DROPPED",
406	"TX_MGMT_COMPLETED",
407	"TX_INV_PEER_ENQ_CNT",
408	"RX_INV_PEER_RCV_CNT",
409	"RX_PN_CHECK_FAILED",
410	"RX_PKTS_DELIVERD",
411};
412
413/*
414 * nss_stats_ipv4_read()
415 *	Read IPV4 stats
416 */
417static ssize_t nss_stats_ipv4_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
418{
419	int32_t i;
420	/*
421	 * max output lines = #stats + start tag line + end tag line + three blank lines
422	 */
423	uint32_t max_output_lines = (NSS_STATS_NODE_MAX + 2) + (NSS_STATS_IPV4_MAX + 3) + (NSS_EXCEPTION_EVENT_IPV4_MAX + 3) + 5;
424	size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
425	size_t size_wr = 0;
426	ssize_t bytes_read = 0;
427	uint64_t *stats_shadow;
428
429	char *lbuf = kzalloc(size_al, GFP_KERNEL);
430	if (unlikely(lbuf == NULL)) {
431		nss_warning("Could not allocate memory for local statistics buffer");
432		return 0;
433	}
434
435	/*
436	 * Note: The assumption here is that exception event count is larger than other statistics count for IPv4
437	 */
438	stats_shadow = kzalloc(NSS_EXCEPTION_EVENT_IPV4_MAX * 8, GFP_KERNEL);
439	if (unlikely(stats_shadow == NULL)) {
440		nss_warning("Could not allocate memory for local shadow buffer");
441		kfree(lbuf);
442		return 0;
443	}
444
445	size_wr = scnprintf(lbuf, size_al, "ipv4 stats start:\n\n");
446
447	/*
448	 * Common node stats
449	 */
450	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "common node stats:\n\n");
451	spin_lock_bh(&nss_top_main.stats_lock);
452	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
453		stats_shadow[i] = nss_top_main.stats_node[NSS_IPV4_RX_INTERFACE][i];
454	}
455
456	spin_unlock_bh(&nss_top_main.stats_lock);
457
458	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
459		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
460					"%s = %llu\n", nss_stats_str_node[i], stats_shadow[i]);
461	}
462
463	/*
464	 * IPv4 node stats
465	 */
466	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nipv4 node stats:\n\n");
467
468	spin_lock_bh(&nss_top_main.stats_lock);
469	for (i = 0; (i < NSS_STATS_IPV4_MAX); i++) {
470		stats_shadow[i] = nss_top_main.stats_ipv4[i];
471	}
472
473	spin_unlock_bh(&nss_top_main.stats_lock);
474
475	for (i = 0; (i < NSS_STATS_IPV4_MAX); i++) {
476		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
477					"%s = %llu\n", nss_stats_str_ipv4[i], stats_shadow[i]);
478	}
479
480	/*
481	 * Exception stats
482	 */
483	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nipv4 exception stats:\n\n");
484
485	spin_lock_bh(&nss_top_main.stats_lock);
486	for (i = 0; (i < NSS_EXCEPTION_EVENT_IPV4_MAX); i++) {
487		stats_shadow[i] = nss_top_main.stats_if_exception_ipv4[i];
488	}
489
490	spin_unlock_bh(&nss_top_main.stats_lock);
491
492	for (i = 0; (i < NSS_EXCEPTION_EVENT_IPV4_MAX); i++) {
493		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
494					"%s = %llu\n", nss_stats_str_if_exception_ipv4[i], stats_shadow[i]);
495	}
496
497	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nipv4 stats end\n\n");
498	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
499	kfree(lbuf);
500	kfree(stats_shadow);
501
502	return bytes_read;
503}
504
505/*
506 * nss_stats_ipv4_reasm_read()
507 *	Read IPV4 reassembly stats
508 */
509static ssize_t nss_stats_ipv4_reasm_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
510{
511	int32_t i;
512	/*
513	 * max output lines = #stats + start tag line + end tag line + three blank lines
514	 */
515	uint32_t max_output_lines = (NSS_STATS_NODE_MAX + 2) + (NSS_STATS_IPV4_REASM_MAX + 3) + 5;
516	size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
517	size_t size_wr = 0;
518	ssize_t bytes_read = 0;
519	uint64_t *stats_shadow;
520
521	char *lbuf = kzalloc(size_al, GFP_KERNEL);
522	if (unlikely(lbuf == NULL)) {
523		nss_warning("Could not allocate memory for local statistics buffer");
524		return 0;
525	}
526
527	stats_shadow = kzalloc(NSS_STATS_IPV4_REASM_MAX * 8, GFP_KERNEL);
528	if (unlikely(stats_shadow == NULL)) {
529		nss_warning("Could not allocate memory for local shadow buffer");
530		kfree(lbuf);
531		return 0;
532	}
533
534	size_wr = scnprintf(lbuf, size_al, "ipv4 reasm stats start:\n\n");
535
536	/*
537	 * Common node stats
538	 */
539	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "common node stats:\n\n");
540	spin_lock_bh(&nss_top_main.stats_lock);
541	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
542		stats_shadow[i] = nss_top_main.stats_node[NSS_IPV4_REASM_INTERFACE][i];
543	}
544
545	spin_unlock_bh(&nss_top_main.stats_lock);
546
547	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
548		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
549					"%s = %llu\n", nss_stats_str_node[i], stats_shadow[i]);
550	}
551
552	/*
553	 * IPv4 reasm node stats
554	 */
555	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nipv4 reasm node stats:\n\n");
556
557	spin_lock_bh(&nss_top_main.stats_lock);
558	for (i = 0; (i < NSS_STATS_IPV4_REASM_MAX); i++) {
559		stats_shadow[i] = nss_top_main.stats_ipv4_reasm[i];
560	}
561
562	spin_unlock_bh(&nss_top_main.stats_lock);
563
564	for (i = 0; (i < NSS_STATS_IPV4_REASM_MAX); i++) {
565		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
566					"%s = %llu\n", nss_stats_str_ipv4_reasm[i], stats_shadow[i]);
567	}
568
569	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nipv4 reasm stats end\n\n");
570	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
571	kfree(lbuf);
572	kfree(stats_shadow);
573
574	return bytes_read;
575}
576
577/*
578 * nss_stats_ipv6_read()
579 *	Read IPV6 stats
580 */
581static ssize_t nss_stats_ipv6_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
582{
583	int32_t i;
584
585	/*
586	 * max output lines = #stats + start tag line + end tag line + three blank lines
587	 */
588	uint32_t max_output_lines = (NSS_STATS_NODE_MAX + 2) + (NSS_STATS_IPV6_MAX + 3) + (NSS_EXCEPTION_EVENT_IPV6_MAX + 3) + 5;
589	size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
590	size_t size_wr = 0;
591	ssize_t bytes_read = 0;
592	uint64_t *stats_shadow;
593
594	char *lbuf = kzalloc(size_al, GFP_KERNEL);
595	if (unlikely(lbuf == NULL)) {
596		nss_warning("Could not allocate memory for local statistics buffer");
597		return 0;
598	}
599
600	/*
601	 * Note: The assumption here is that exception event count is larger than other statistics count for IPv4
602	 */
603	stats_shadow = kzalloc(NSS_EXCEPTION_EVENT_IPV6_MAX * 8, GFP_KERNEL);
604	if (unlikely(stats_shadow == NULL)) {
605		nss_warning("Could not allocate memory for local shadow buffer");
606		kfree(lbuf);
607		return 0;
608	}
609
610	size_wr = scnprintf(lbuf, size_al, "ipv6 stats start:\n\n");
611
612	/*
613	 * Common node stats
614	 */
615	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "common node stats:\n\n");
616	spin_lock_bh(&nss_top_main.stats_lock);
617	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
618		stats_shadow[i] = nss_top_main.stats_node[NSS_IPV6_RX_INTERFACE][i];
619	}
620
621	spin_unlock_bh(&nss_top_main.stats_lock);
622
623	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
624		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
625					"%s = %llu\n", nss_stats_str_node[i], stats_shadow[i]);
626	}
627
628	/*
629	 * IPv6 node stats
630	 */
631	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nipv6 node stats:\n\n");
632
633	spin_lock_bh(&nss_top_main.stats_lock);
634	for (i = 0; (i < NSS_STATS_IPV6_MAX); i++) {
635		stats_shadow[i] = nss_top_main.stats_ipv6[i];
636	}
637
638	spin_unlock_bh(&nss_top_main.stats_lock);
639
640	for (i = 0; (i < NSS_STATS_IPV6_MAX); i++) {
641		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
642					"%s = %llu\n", nss_stats_str_ipv6[i], stats_shadow[i]);
643	}
644
645	/*
646	 * Exception stats
647	 */
648	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nipv6 exception stats:\n\n");
649
650	spin_lock_bh(&nss_top_main.stats_lock);
651	for (i = 0; (i < NSS_EXCEPTION_EVENT_IPV6_MAX); i++) {
652		stats_shadow[i] = nss_top_main.stats_if_exception_ipv6[i];
653	}
654
655	spin_unlock_bh(&nss_top_main.stats_lock);
656
657	for (i = 0; (i < NSS_EXCEPTION_EVENT_IPV6_MAX); i++) {
658		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
659					"%s = %llu\n", nss_stats_str_if_exception_ipv6[i], stats_shadow[i]);
660	}
661
662	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,"\nipv6 stats end\n\n");
663	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
664	kfree(lbuf);
665	kfree(stats_shadow);
666
667	return bytes_read;
668}
669
670/*
671 * nss_stats_ipv6_reasm_read()
672 *	Read IPV6 reassembly stats
673 */
674static ssize_t nss_stats_ipv6_reasm_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
675{
676	int32_t i;
677	/*
678	 * max output lines = #stats + start tag line + end tag line + three blank lines
679	 */
680	uint32_t max_output_lines = (NSS_STATS_NODE_MAX + 2) + (NSS_STATS_IPV6_REASM_MAX + 3) + 5;
681	size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
682	size_t size_wr = 0;
683	ssize_t bytes_read = 0;
684	uint64_t *stats_shadow;
685
686	char *lbuf = kzalloc(size_al, GFP_KERNEL);
687	if (unlikely(lbuf == NULL)) {
688		nss_warning("Could not allocate memory for local statistics buffer");
689		return 0;
690	}
691
692	stats_shadow = kzalloc(NSS_STATS_IPV6_REASM_MAX * 8, GFP_KERNEL);
693	if (unlikely(stats_shadow == NULL)) {
694		nss_warning("Could not allocate memory for local shadow buffer");
695		kfree(lbuf);
696		return 0;
697	}
698
699	size_wr = scnprintf(lbuf, size_al, "ipv6 reasm stats start:\n\n");
700
701	/*
702	 * Common node stats
703	 */
704	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "common node stats:\n\n");
705	spin_lock_bh(&nss_top_main.stats_lock);
706	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
707		stats_shadow[i] = nss_top_main.stats_node[NSS_IPV6_REASM_INTERFACE][i];
708	}
709
710	spin_unlock_bh(&nss_top_main.stats_lock);
711
712	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
713		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
714					"%s = %llu\n", nss_stats_str_node[i], stats_shadow[i]);
715	}
716
717	/*
718	 * Ipv6 reasm node stats
719	 */
720	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nipv6 reasm node stats:\n\n");
721
722	spin_lock_bh(&nss_top_main.stats_lock);
723	for (i = 0; (i < NSS_STATS_IPV6_REASM_MAX); i++) {
724		stats_shadow[i] = nss_top_main.stats_ipv6_reasm[i];
725	}
726
727	spin_unlock_bh(&nss_top_main.stats_lock);
728
729	for (i = 0; (i < NSS_STATS_IPV6_REASM_MAX); i++) {
730		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
731					"%s = %llu\n", nss_stats_str_ipv6_reasm[i], stats_shadow[i]);
732	}
733
734	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nipv6 reasm stats end\n\n");
735	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
736	kfree(lbuf);
737	kfree(stats_shadow);
738
739	return bytes_read;
740}
741
742/*
743 * nss_stats_eth_rx_read()
744 *	Read ETH_RX stats
745 */
746static ssize_t nss_stats_eth_rx_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
747{
748	int32_t i;
749
750	/*
751	 * max output lines = #stats + start tag line + end tag line + three blank lines
752	 */
753	uint32_t max_output_lines = (NSS_STATS_NODE_MAX + 2) + (NSS_STATS_ETH_RX_MAX + 3) + (NSS_EXCEPTION_EVENT_ETH_RX_MAX + 3) + 5;
754	size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
755	size_t size_wr = 0;
756	ssize_t bytes_read = 0;
757	uint64_t *stats_shadow;
758
759	char *lbuf = kzalloc(size_al, GFP_KERNEL);
760	if (unlikely(lbuf == NULL)) {
761		nss_warning("Could not allocate memory for local statistics buffer");
762		return 0;
763	}
764
765	/*
766	 * Note: The assumption here is that we do not have more than 64 stats
767	 */
768	stats_shadow = kzalloc(64 * 8, GFP_KERNEL);
769	if (unlikely(stats_shadow == NULL)) {
770		nss_warning("Could not allocate memory for local shadow buffer");
771		kfree(lbuf);
772		return 0;
773	}
774
775	size_wr = scnprintf(lbuf, size_al,"eth_rx stats start:\n\n");
776
777	/*
778	 * Common node stats
779	 */
780	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "common node stats:\n\n");
781	spin_lock_bh(&nss_top_main.stats_lock);
782	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
783		stats_shadow[i] = nss_top_main.stats_node[NSS_ETH_RX_INTERFACE][i];
784	}
785
786	spin_unlock_bh(&nss_top_main.stats_lock);
787
788	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
789		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
790					"%s = %llu\n", nss_stats_str_node[i], stats_shadow[i]);
791	}
792
793	/*
794	 * eth_rx node stats
795	 */
796	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\neth_rx node stats:\n\n");
797	spin_lock_bh(&nss_top_main.stats_lock);
798	for (i = 0; (i < NSS_STATS_ETH_RX_MAX); i++) {
799		stats_shadow[i] = nss_top_main.stats_eth_rx[i];
800	}
801
802	spin_unlock_bh(&nss_top_main.stats_lock);
803
804	for (i = 0; (i < NSS_STATS_ETH_RX_MAX); i++) {
805		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
806					"%s = %llu\n", nss_stats_str_eth_rx[i], stats_shadow[i]);
807	}
808
809	/*
810	 * Exception stats
811	 */
812	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\neth_rx exception stats:\n\n");
813
814	spin_lock_bh(&nss_top_main.stats_lock);
815	for (i = 0; (i < NSS_EXCEPTION_EVENT_ETH_RX_MAX); i++) {
816		stats_shadow[i] = nss_top_main.stats_if_exception_eth_rx[i];
817	}
818
819	spin_unlock_bh(&nss_top_main.stats_lock);
820
821	for (i = 0; (i < NSS_EXCEPTION_EVENT_ETH_RX_MAX); i++) {
822		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
823					"%s = %llu\n", nss_stats_str_if_exception_eth_rx[i], stats_shadow[i]);
824	}
825
826	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,"\neth_rx stats end\n\n");
827	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
828	kfree(lbuf);
829	kfree(stats_shadow);
830
831	return bytes_read;
832}
833
834/*
835 * nss_stats_n2h_read()
836 *	Read N2H stats
837 */
838static ssize_t nss_stats_n2h_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
839{
840	int32_t i;
841
842	/*
843	 * max output lines = #stats + start tag line + end tag line + three blank lines
844	 */
845	uint32_t max_output_lines = (NSS_STATS_NODE_MAX + 2) + (NSS_STATS_N2H_MAX + 3) + 5;
846	size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
847	size_t size_wr = 0;
848	ssize_t bytes_read = 0;
849	uint64_t *stats_shadow;
850	int max = NSS_STATS_N2H_MAX - NSS_STATS_NODE_MAX;
851
852	char *lbuf = kzalloc(size_al, GFP_KERNEL);
853	if (unlikely(lbuf == NULL)) {
854		nss_warning("Could not allocate memory for local statistics buffer");
855		return 0;
856	}
857
858	stats_shadow = kzalloc(NSS_STATS_N2H_MAX * 8, GFP_KERNEL);
859	if (unlikely(stats_shadow == NULL)) {
860		nss_warning("Could not allocate memory for local shadow buffer");
861		kfree(lbuf);
862		return 0;
863	}
864
865	size_wr = scnprintf(lbuf, size_al, "n2h stats start:\n\n");
866
867	/*
868	 * Common node stats
869	 */
870	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "common node stats:\n\n");
871	spin_lock_bh(&nss_top_main.stats_lock);
872	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
873		stats_shadow[i] = nss_top_main.nss[0].stats_n2h[i];
874	}
875
876	spin_unlock_bh(&nss_top_main.stats_lock);
877
878	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
879		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
880					"%s = %llu\n", nss_stats_str_node[i], stats_shadow[i]);
881	}
882
883	/*
884	 * N2H node stats
885	 */
886	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nn2h node stats:\n\n");
887	spin_lock_bh(&nss_top_main.stats_lock);
888	for (i = NSS_STATS_NODE_MAX; (i < NSS_STATS_N2H_MAX); i++) {
889		stats_shadow[i] = nss_top_main.nss[0].stats_n2h[i];
890	}
891
892	spin_unlock_bh(&nss_top_main.stats_lock);
893
894	for (i = 0; i < max; i++) {
895		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
896					"%s = %llu\n", nss_stats_str_n2h[i], stats_shadow[i + NSS_STATS_NODE_MAX]);
897	}
898
899	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nn2h stats end\n\n");
900	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
901	kfree(lbuf);
902	kfree(stats_shadow);
903
904	return bytes_read;
905}
906
907/*
908 * nss_stats_lso_rx_read()
909 *	Read LSO_RX stats
910 */
911static ssize_t nss_stats_lso_rx_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
912{
913	int32_t i;
914
915	/*
916	 * max output lines = #stats + start tag line + end tag line + three blank lines
917	 */
918	uint32_t max_output_lines = (NSS_STATS_NODE_MAX + 2) + (NSS_STATS_LSO_RX_MAX + 3) + 5;
919	size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
920	size_t size_wr = 0;
921	ssize_t bytes_read = 0;
922	uint64_t *stats_shadow;
923
924	char *lbuf = kzalloc(size_al, GFP_KERNEL);
925	if (unlikely(lbuf == NULL)) {
926		nss_warning("Could not allocate memory for local statistics buffer");
927		return 0;
928	}
929
930	stats_shadow = kzalloc(NSS_STATS_LSO_RX_MAX * 8, GFP_KERNEL);
931	if (unlikely(stats_shadow == NULL)) {
932		nss_warning("Could not allocate memory for local shadow buffer");
933		kfree(lbuf);
934		return 0;
935	}
936
937	size_wr = scnprintf(lbuf, size_al, "lso_rx stats start:\n\n");
938
939	/*
940	 * Common node stats
941	 */
942	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "common node stats:\n\n");
943	spin_lock_bh(&nss_top_main.stats_lock);
944	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
945		stats_shadow[i] = nss_top_main.stats_node[NSS_LSO_RX_INTERFACE][i];
946	}
947
948	spin_unlock_bh(&nss_top_main.stats_lock);
949
950	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
951		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
952					"%s = %llu\n", nss_stats_str_node[i], stats_shadow[i]);
953	}
954
955	/*
956	 * lso_rx node stats
957	 */
958	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nlso_rx node stats:\n\n");
959	spin_lock_bh(&nss_top_main.stats_lock);
960	for (i = 0; (i < NSS_STATS_LSO_RX_MAX); i++) {
961		stats_shadow[i] = nss_top_main.stats_lso_rx[i];
962	}
963
964	spin_unlock_bh(&nss_top_main.stats_lock);
965
966	for (i = 0; i < NSS_STATS_LSO_RX_MAX; i++) {
967		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
968					"%s = %llu\n", nss_stats_str_lso_rx[i], stats_shadow[i]);
969	}
970
971	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nlso_rx stats end\n\n");
972	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
973	kfree(lbuf);
974	kfree(stats_shadow);
975
976	return bytes_read;
977}
978
979/*
980 * nss_stats_drv_read()
981 *	Read HLOS driver stats
982 */
983static ssize_t nss_stats_drv_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
984{
985	int32_t i;
986
987	/*
988	 * max output lines = #stats + start tag line + end tag line + three blank lines
989	 */
990	uint32_t max_output_lines = NSS_STATS_DRV_MAX + 5;
991	size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
992	size_t size_wr = 0;
993	ssize_t bytes_read = 0;
994	uint64_t *stats_shadow;
995
996	char *lbuf = kzalloc(size_al, GFP_KERNEL);
997	if (unlikely(lbuf == NULL)) {
998		nss_warning("Could not allocate memory for local statistics buffer");
999		return 0;
1000	}
1001
1002	stats_shadow = kzalloc(NSS_STATS_DRV_MAX * 8, GFP_KERNEL);
1003	if (unlikely(stats_shadow == NULL)) {
1004		nss_warning("Could not allocate memory for local shadow buffer");
1005		kfree(lbuf);
1006		return 0;
1007	}
1008
1009	size_wr = scnprintf(lbuf, size_al, "drv stats start:\n\n");
1010	for (i = 0; (i < NSS_STATS_DRV_MAX); i++) {
1011		stats_shadow[i] = NSS_PKT_STATS_READ(&nss_top_main.stats_drv[i]);
1012	}
1013
1014	for (i = 0; (i < NSS_STATS_DRV_MAX); i++) {
1015		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
1016					"%s = %llu\n", nss_stats_str_drv[i], stats_shadow[i]);
1017	}
1018
1019	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\ndrv stats end\n\n");
1020	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
1021	kfree(lbuf);
1022	kfree(stats_shadow);
1023
1024	return bytes_read;
1025}
1026
1027/*
1028 * nss_stats_pppoe_read()
1029 *	Read PPPoE stats
1030 */
1031static ssize_t nss_stats_pppoe_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
1032{
1033	int32_t i, j, k;
1034
1035	/*
1036	 * max output lines = #stats + start tag line + end tag line + three blank lines
1037	 */
1038	uint32_t max_output_lines = (NSS_STATS_NODE_MAX + 2) + (NSS_STATS_PPPOE_MAX + 3) +
1039					((NSS_MAX_PHYSICAL_INTERFACES * NSS_PPPOE_NUM_SESSION_PER_INTERFACE * (NSS_PPPOE_EXCEPTION_EVENT_MAX + 5)) + 3) + 5;
1040	size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
1041	size_t size_wr = 0;
1042	ssize_t bytes_read = 0;
1043	uint64_t *stats_shadow;
1044
1045	char *lbuf = kzalloc(size_al, GFP_KERNEL);
1046	if (unlikely(lbuf == NULL)) {
1047		nss_warning("Could not allocate memory for local statistics buffer");
1048		return 0;
1049	}
1050
1051	stats_shadow = kzalloc(64 * 8, GFP_KERNEL);
1052	if (unlikely(stats_shadow == NULL)) {
1053		nss_warning("Could not allocate memory for local shadow buffer");
1054		kfree(lbuf);
1055		return 0;
1056	}
1057
1058	size_wr = scnprintf(lbuf, size_al, "pppoe stats start:\n\n");
1059
1060	/*
1061	 * Common node stats
1062	 */
1063	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "common node stats:\n\n");
1064	spin_lock_bh(&nss_top_main.stats_lock);
1065	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
1066		stats_shadow[i] = nss_top_main.stats_node[NSS_PPPOE_RX_INTERFACE][i];
1067	}
1068
1069	spin_unlock_bh(&nss_top_main.stats_lock);
1070
1071	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
1072		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
1073				 "%s = %llu\n", nss_stats_str_node[i], stats_shadow[i]);
1074	}
1075
1076	/*
1077	 * PPPoE node stats
1078	 */
1079	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\npppoe node stats:\n\n");
1080	spin_lock_bh(&nss_top_main.stats_lock);
1081	for (i = 0; (i < NSS_STATS_PPPOE_MAX); i++) {
1082		stats_shadow[i] = nss_top_main.stats_pppoe[i];
1083	}
1084
1085	spin_unlock_bh(&nss_top_main.stats_lock);
1086
1087	for (i = 0; (i < NSS_STATS_PPPOE_MAX); i++) {
1088		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
1089					"%s = %llu\n", nss_stats_str_pppoe[i], stats_shadow[i]);
1090	}
1091
1092	/*
1093	 * Exception stats
1094	 */
1095	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nException PPPoE:\n\n");
1096
1097	for (j = 1; j <= NSS_MAX_PHYSICAL_INTERFACES; j++) {
1098		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nInterface %d:\n\n", j);
1099
1100		spin_lock_bh(&nss_top_main.stats_lock);
1101		for (k = 1; k <= NSS_PPPOE_NUM_SESSION_PER_INTERFACE; k++) {
1102			for (i = 0; (i < NSS_PPPOE_EXCEPTION_EVENT_MAX); i++) {
1103				stats_shadow_pppoe_except[k - 1][i] = nss_top_main.stats_if_exception_pppoe[j][k][i];
1104			}
1105		}
1106
1107		spin_unlock_bh(&nss_top_main.stats_lock);
1108
1109		for (k = 1; k <= NSS_PPPOE_NUM_SESSION_PER_INTERFACE; k++) {
1110			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "%d. Session\n", k);
1111			for (i = 0; (i < NSS_PPPOE_EXCEPTION_EVENT_MAX); i++) {
1112				size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
1113						"%s = %llu\n",
1114						nss_stats_str_if_exception_pppoe[i],
1115						stats_shadow_pppoe_except[k - 1][i]);
1116			}
1117		}
1118
1119	}
1120
1121	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\npppoe stats end\n\n");
1122	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
1123	kfree(lbuf);
1124	kfree(stats_shadow);
1125
1126	return bytes_read;
1127}
1128
1129/*
1130 * nss_stats_gmac_read()
1131 *	Read GMAC stats
1132 */
1133static ssize_t nss_stats_gmac_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
1134{
1135	uint32_t i, id;
1136
1137	/*
1138	 * max output lines = ((#stats + start tag + one blank) * #GMACs) + start/end tag + 3 blank
1139	 */
1140	uint32_t max_output_lines = ((NSS_STATS_GMAC_MAX + 2) * NSS_MAX_PHYSICAL_INTERFACES) + 5;
1141	size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
1142	size_t size_wr = 0;
1143	ssize_t bytes_read = 0;
1144	uint64_t *stats_shadow;
1145
1146	char *lbuf = kzalloc(size_al, GFP_KERNEL);
1147	if (unlikely(lbuf == NULL)) {
1148		nss_warning("Could not allocate memory for local statistics buffer");
1149		return 0;
1150	}
1151
1152	stats_shadow = kzalloc(NSS_STATS_GMAC_MAX * 8, GFP_KERNEL);
1153	if (unlikely(stats_shadow == NULL)) {
1154		nss_warning("Could not allocate memory for local shadow buffer");
1155		kfree(lbuf);
1156		return 0;
1157	}
1158
1159	size_wr = scnprintf(lbuf, size_al, "gmac stats start:\n\n");
1160
1161	for (id = 0; id < NSS_MAX_PHYSICAL_INTERFACES; id++) {
1162		spin_lock_bh(&nss_top_main.stats_lock);
1163		for (i = 0; (i < NSS_STATS_GMAC_MAX); i++) {
1164			stats_shadow[i] = nss_top_main.stats_gmac[id][i];
1165		}
1166
1167		spin_unlock_bh(&nss_top_main.stats_lock);
1168
1169		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "GMAC ID: %d\n", id);
1170		for (i = 0; (i < NSS_STATS_GMAC_MAX); i++) {
1171			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
1172					"%s = %llu\n", nss_stats_str_gmac[i], stats_shadow[i]);
1173		}
1174		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,"\n");
1175	}
1176
1177	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\ngmac stats end\n\n");
1178	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
1179	kfree(lbuf);
1180	kfree(stats_shadow);
1181
1182	return bytes_read;
1183}
1184
1185/*
1186 * nss_stats_wifi_read()
1187 * 	Read wifi statistics
1188 */
1189static ssize_t nss_stats_wifi_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
1190{
1191	uint32_t i, id;
1192
1193	/*
1194	 * max output lines = ((#stats + start tag + one blank) * #WIFI RADIOs) + start/end tag + 3 blank
1195	 */
1196	uint32_t max_output_lines = ((NSS_STATS_WIFI_MAX + 2) * NSS_MAX_WIFI_RADIO_INTERFACES) + 5;
1197	size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
1198	size_t size_wr = 0;
1199	ssize_t bytes_read = 0;
1200	uint64_t *stats_shadow;
1201
1202	char *lbuf = kzalloc(size_al, GFP_KERNEL);
1203	if (unlikely(lbuf == NULL)) {
1204		nss_warning("Could not allocate memory for local statistics buffer");
1205		return 0;
1206	}
1207
1208	stats_shadow = kzalloc(NSS_STATS_WIFI_MAX * 8, GFP_KERNEL);
1209	if (unlikely(stats_shadow == NULL)) {
1210		nss_warning("Could not allocate memory for local shadow buffer");
1211		kfree(lbuf);
1212		return 0;
1213	}
1214
1215	size_wr = scnprintf(lbuf, size_al, "wifi stats start:\n\n");
1216
1217	for (id = 0; id < NSS_MAX_WIFI_RADIO_INTERFACES; id++) {
1218		spin_lock_bh(&nss_top_main.stats_lock);
1219		for (i = 0; (i < NSS_STATS_WIFI_MAX); i++) {
1220			stats_shadow[i] = nss_top_main.stats_wifi[id][i];
1221		}
1222
1223		spin_unlock_bh(&nss_top_main.stats_lock);
1224
1225		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "WIFI ID: %d\n", id);
1226		for (i = 0; (i < NSS_STATS_WIFI_MAX); i++) {
1227			size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
1228					"%s = %llu\n", nss_stats_str_wifi[i], stats_shadow[i]);
1229		}
1230		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,"\n");
1231	}
1232
1233	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nwifi stats end\n\n");
1234	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
1235	kfree(lbuf);
1236	kfree(stats_shadow);
1237
1238	return bytes_read;
1239}
1240
1241/*
1242 * nss_stats_sjack_read()
1243 *	Read SJACK stats
1244 */
1245static ssize_t nss_stats_sjack_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
1246{
1247	int32_t i;
1248	/*
1249	 * max output lines = #stats + start tag line + end tag line + three blank lines
1250	 */
1251	uint32_t max_output_lines = NSS_STATS_NODE_MAX + 5;
1252	size_t size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
1253	size_t size_wr = 0;
1254	ssize_t bytes_read = 0;
1255	uint64_t *stats_shadow;
1256
1257	char *lbuf = kzalloc(size_al, GFP_KERNEL);
1258	if (unlikely(lbuf == NULL)) {
1259		nss_warning("Could not allocate memory for local statistics buffer");
1260		return 0;
1261	}
1262
1263	stats_shadow = kzalloc(NSS_STATS_NODE_MAX * 8, GFP_KERNEL);
1264	if (unlikely(stats_shadow == NULL)) {
1265		nss_warning("Could not allocate memory for local shadow buffer");
1266		kfree(lbuf);
1267		return 0;
1268	}
1269
1270	size_wr = scnprintf(lbuf, size_al, "sjack stats start:\n\n");
1271
1272	/*
1273	 * Common node stats
1274	 */
1275	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "common node stats:\n\n");
1276	spin_lock_bh(&nss_top_main.stats_lock);
1277	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
1278		stats_shadow[i] = nss_top_main.stats_node[NSS_SJACK_INTERFACE][i];
1279	}
1280
1281	spin_unlock_bh(&nss_top_main.stats_lock);
1282
1283	for (i = 0; (i < NSS_STATS_NODE_MAX); i++) {
1284		size_wr += scnprintf(lbuf + size_wr, size_al - size_wr,
1285					"%s = %llu\n", nss_stats_str_node[i], stats_shadow[i]);
1286	}
1287
1288	size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\nsjack stats end\n\n");
1289
1290	bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
1291	kfree(lbuf);
1292	kfree(stats_shadow);
1293
1294	return bytes_read;
1295}
1296
1297/*
1298 * Make a row for CAPWAP encap stats.
1299 */
1300static ssize_t nss_stats_capwap_encap(char *line, int len, int i, struct nss_capwap_tunnel_stats *s)
1301{
1302	char *header[] = { "packets", "bytes", "fragments", "drop_ref", "drop_ver", "drop_unalign",
1303			"drop_hroom", "drop_dtls", "drop_nwireless", "drop_qfull", "drop_memfail", "unknown" };
1304	uint64_t tcnt = 0;
1305
1306	switch (i) {
1307	case 0:
1308		tcnt = s->pnode_stats.tx_packets;
1309		break;
1310	case 1:
1311		tcnt = s->pnode_stats.tx_bytes;
1312		break;
1313	case 2:
1314		tcnt = s->tx_segments;
1315		break;
1316	case 3:
1317		tcnt = s->tx_dropped_sg_ref;
1318		break;
1319	case 4:
1320		tcnt = s->tx_dropped_ver_mis;
1321		break;
1322	case 5:
1323		tcnt = s->tx_dropped_unalign;
1324		break;
1325	case 6:
1326		tcnt = s->tx_dropped_hroom;
1327		break;
1328	case 7:
1329		tcnt = s->tx_dropped_dtls;
1330		break;
1331	case 8:
1332		tcnt = s->tx_dropped_nwireless;
1333		break;
1334	case 9:
1335		tcnt = s->tx_queue_full_drops;
1336		break;
1337	case 10:
1338		tcnt = s->tx_mem_failure_drops;
1339		break;
1340	default:
1341		return 0;
1342	}
1343
1344	return (snprintf(line, len, "%s = %llu\n", header[i], tcnt));
1345}
1346
1347/*
1348 * Make a row for CAPWAP decap stats.
1349 */
1350static ssize_t nss_stats_capwap_decap(char *line, int len, int i, struct nss_capwap_tunnel_stats *s)
1351{
1352	char *header[] = { "packets", "bytes", "DTLS_pkts", "fragments", "rx_dropped", "drop_oversize",
1353		"drop_frag_timeout", "drop_frag_dup", "drop_frag_gap", "drop_qfull", "drop_memfail",
1354		"drop_csum", "drop_malformed", "unknown" };
1355	uint64_t tcnt = 0;
1356
1357	switch(i) {
1358	case 0:
1359		tcnt = s->pnode_stats.rx_packets;
1360		break;
1361	case 1:
1362		tcnt = s->pnode_stats.rx_bytes;
1363		break;
1364	case 2:
1365		tcnt = s->dtls_pkts;
1366		break;
1367	case 3:
1368		tcnt = s->rx_segments;
1369		break;
1370	case 4:
1371		tcnt = s->pnode_stats.rx_dropped;
1372		break;
1373	case 5:
1374		tcnt = s->rx_oversize_drops;
1375		break;
1376	case 6:
1377		tcnt = s->rx_frag_timeout_drops;
1378		break;
1379	case 7:
1380		tcnt = s->rx_dup_frag;
1381		break;
1382	case 8:
1383		tcnt = s->rx_frag_gap_drops;
1384		break;
1385	case 9:
1386		tcnt = s->rx_queue_full_drops;
1387		return (snprintf(line, len, "%s = %llu (n2h = %llu)\n", header[i], tcnt, s->rx_n2h_queue_full_drops));
1388	case 10:
1389		tcnt = s->rx_mem_failure_drops;
1390		break;
1391	case 11:
1392		tcnt = s->rx_csum_drops;
1393		break;
1394	case 12:
1395		tcnt = s->rx_malformed;
1396		break;
1397	default:
1398		return 0;
1399	}
1400
1401	return (snprintf(line, len, "%s = %llu\n", header[i], tcnt));
1402}
1403
1404/*
1405 * nss_stats_capwap_read()
1406 *	Read CAPWAP stats
1407 */
1408static ssize_t nss_stats_capwap_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos, uint16_t type)
1409{
1410	struct nss_stats_data *data = fp->private_data;
1411	ssize_t bytes_read = 0;
1412	struct nss_capwap_tunnel_stats stats;
1413	size_t bytes;
1414	char line[80];
1415	int start;
1416	uint32_t if_num = NSS_DYNAMIC_IF_START;
1417	uint32_t max_if_num = NSS_DYNAMIC_IF_START + NSS_MAX_DYNAMIC_INTERFACES;
1418
1419	if (data) {
1420		if_num = data->if_num;
1421	}
1422
1423	/*
1424	 * If we are done accomodating all the CAPWAP tunnels.
1425	 */
1426	if (if_num > max_if_num) {
1427		return 0;
1428	}
1429
1430	for (; if_num <= max_if_num; if_num++) {
1431		bool isthere;
1432
1433		if (nss_is_dynamic_interface(if_num) == false) {
1434			continue;
1435		}
1436
1437		if (nss_dynamic_interface_get_type(if_num) != NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP) {
1438			continue;
1439		}
1440
1441		/*
1442		 * If CAPWAP tunnel does not exists, then isthere will be false.
1443		 */
1444		isthere = nss_capwap_get_stats(if_num, &stats);
1445		if (!isthere) {
1446			continue;
1447		}
1448
1449		bytes = snprintf(line, sizeof(line), "----if_num : %2d----\n", if_num);
1450		if ((bytes_read + bytes) > sz) {
1451			break;
1452		}
1453
1454		if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
1455			bytes_read = -EFAULT;
1456			goto fail;
1457		}
1458		bytes_read += bytes;
1459		start = 0;
1460		while (bytes_read < sz) {
1461			if (type == 1) {
1462				bytes = nss_stats_capwap_encap(line, sizeof(line), start, &stats);
1463			} else {
1464				bytes = nss_stats_capwap_decap(line, sizeof(line), start, &stats);
1465			}
1466
1467			/*
1468			 * If we don't have any more lines in decap/encap.
1469			 */
1470			if (bytes == 0) {
1471				break;
1472			}
1473
1474			if ((bytes_read + bytes) > sz)
1475				break;
1476
1477			if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
1478				bytes_read = -EFAULT;
1479				goto fail;
1480			}
1481
1482			bytes_read += bytes;
1483			start++;
1484		}
1485	}
1486
1487	if (bytes_read > 0) {
1488		*ppos = bytes_read;
1489	}
1490
1491	if (data) {
1492		data->if_num = if_num;
1493	}
1494fail:
1495	return bytes_read;
1496}
1497
1498/*
1499 * nss_stats_capwap_decap_read()
1500 *	Read CAPWAP decap stats
1501 */
1502static ssize_t nss_stats_capwap_decap_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
1503{
1504	return (nss_stats_capwap_read(fp, ubuf, sz, ppos, 0));
1505}
1506
1507/*
1508 * nss_stats_capwap_encap_read()
1509 *	Read CAPWAP encap stats
1510 */
1511static ssize_t nss_stats_capwap_encap_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
1512{
1513	return (nss_stats_capwap_read(fp, ubuf, sz, ppos, 1));
1514}
1515
1516/*
1517 * nss_stats_gre_redir()
1518 * 	Make a row for GRE_REDIR stats.
1519 */
1520static ssize_t nss_stats_gre_redir(char *line, int len, int i, struct nss_gre_redir_tunnel_stats *s)
1521{
1522	char *header[] = { "TX Packets", "TX Bytes", "TX Drops", "RX Packets", "RX Bytes", "Rx Drops" };
1523	uint64_t tcnt = 0;
1524
1525	switch (i) {
1526	case 0:
1527		tcnt = s->node_stats.tx_packets;
1528		break;
1529	case 1:
1530		tcnt = s->node_stats.tx_bytes;
1531		break;
1532	case 2:
1533		tcnt = s->tx_dropped;
1534		break;
1535	case 3:
1536		tcnt = s->node_stats.rx_packets;
1537		break;
1538	case 4:
1539		tcnt = s->node_stats.rx_bytes;
1540		break;
1541	case 5:
1542		tcnt = s->node_stats.rx_dropped;
1543		break;
1544	default:
1545		i = 6;
1546		break;
1547	}
1548
1549	return (snprintf(line, len, "%s = %llu\n", header[i], tcnt));
1550}
1551
1552/*
1553 * nss_stats_gre_redir_read()
1554 * 	READ gre_redir tunnel stats.
1555 */
1556static ssize_t nss_stats_gre_redir_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
1557{
1558	struct nss_stats_data *data = fp->private_data;
1559	ssize_t bytes_read = 0;
1560	struct nss_gre_redir_tunnel_stats stats;
1561	size_t bytes;
1562	char line[80];
1563	int start, end;
1564	int index = 0;
1565
1566	if (data) {
1567		index = data->index;
1568	}
1569
1570	/*
1571	 * If we are done accomodating all the GRE_REDIR tunnels.
1572	 */
1573	if (index >= NSS_GRE_REDIR_MAX_INTERFACES) {
1574		return 0;
1575	}
1576
1577	for (; index < NSS_GRE_REDIR_MAX_INTERFACES; index++) {
1578		bool isthere;
1579
1580		/*
1581		 * If gre_redir tunnel does not exists, then isthere will be false.
1582		 */
1583		isthere = nss_gre_redir_get_stats(index, &stats);
1584		if (!isthere) {
1585			continue;
1586		}
1587
1588		bytes = snprintf(line, sizeof(line), "\nTunnel if_num: %2d\n", stats.if_num);
1589		if ((bytes_read + bytes) > sz) {
1590			break;
1591		}
1592
1593		if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
1594			bytes_read = -EFAULT;
1595			goto fail;
1596		}
1597		bytes_read += bytes;
1598		start = 0;
1599		end = 6;
1600		while (bytes_read < sz && start < end) {
1601			bytes = nss_stats_gre_redir(line, sizeof(line), start, &stats);
1602
1603			if ((bytes_read + bytes) > sz)
1604				break;
1605
1606			if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
1607				bytes_read = -EFAULT;
1608				goto fail;
1609			}
1610
1611			bytes_read += bytes;
1612			start++;
1613		}
1614	}
1615
1616	if (bytes_read > 0) {
1617		*ppos = bytes_read;
1618	}
1619
1620	if (data) {
1621		data->index = index;
1622	}
1623
1624fail:
1625	return bytes_read;
1626}
1627
1628/*
1629 * nss_stats_wifi_if_read()
1630 *	Read wifi_if statistics
1631 */
1632static ssize_t nss_stats_wifi_if_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
1633{
1634	struct nss_stats_data *data = fp->private_data;
1635	int32_t if_num = NSS_DYNAMIC_IF_START;
1636	int32_t max_if_num = if_num + NSS_MAX_DYNAMIC_INTERFACES;
1637	size_t bytes = 0;
1638	ssize_t bytes_read = 0;
1639	char line[80];
1640	int start, end;
1641
1642	if (data) {
1643		if_num = data->if_num;
1644	}
1645
1646	if (if_num > max_if_num) {
1647		return 0;
1648	}
1649
1650	for (; if_num < max_if_num; if_num++) {
1651		if (nss_dynamic_interface_get_type(if_num) != NSS_DYNAMIC_INTERFACE_TYPE_WIFI)
1652			continue;
1653
1654		bytes = scnprintf(line, sizeof(line), "if_num %d stats start:\n\n", if_num);
1655		if ((bytes_read + bytes) > sz)
1656			break;
1657
1658		if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
1659			bytes_read = -EFAULT;
1660			goto end;
1661		}
1662
1663		bytes_read += bytes;
1664
1665		start = 0;
1666		end = 7;
1667		while (bytes_read < sz && start < end) {
1668			bytes = nss_wifi_if_copy_stats(if_num, start, line);
1669			if (!bytes)
1670				break;
1671
1672			if ((bytes_read + bytes) > sz)
1673				break;
1674
1675			if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
1676				bytes_read = -EFAULT;
1677				goto end;
1678			}
1679
1680			bytes_read += bytes;
1681			start++;
1682		}
1683
1684		bytes = scnprintf(line, sizeof(line), "if_num %d stats end:\n\n", if_num);
1685		if (bytes_read > (sz - bytes))
1686			break;
1687
1688		if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
1689			bytes_read = -EFAULT;
1690			goto end;
1691		}
1692
1693		bytes_read += bytes;
1694	}
1695
1696	if (bytes_read > 0) {
1697		*ppos = bytes_read;
1698	}
1699
1700	if (data) {
1701		data->if_num = if_num;
1702	}
1703
1704end:
1705	return bytes_read;
1706}
1707
1708/*
1709 * nss_stats_virt_if_read()
1710 *	Read virt_if statistics
1711 */
1712static ssize_t nss_stats_virt_if_read(struct file *fp, char __user *ubuf,
1713						size_t sz, loff_t *ppos)
1714{
1715	struct nss_stats_data *data = fp->private_data;
1716	int32_t if_num = NSS_DYNAMIC_IF_START;
1717	int32_t max_if_num = if_num + NSS_MAX_DYNAMIC_INTERFACES;
1718	size_t bytes = 0;
1719	ssize_t bytes_read = 0;
1720	char line[80];
1721	int start, end;
1722
1723	if (data) {
1724		if_num = data->if_num;
1725	}
1726
1727	if (if_num > max_if_num) {
1728		return 0;
1729	}
1730
1731	for (; if_num < max_if_num; if_num++) {
1732		if (nss_dynamic_interface_get_type(if_num) != NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR)
1733			continue;
1734
1735		bytes = scnprintf(line, sizeof(line), "if_num %d stats start:\n\n", if_num);
1736		if ((bytes_read + bytes) > sz)
1737			break;
1738
1739		if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
1740			bytes_read = -EFAULT;
1741			goto end;
1742		}
1743
1744		bytes_read += bytes;
1745
1746		start = 0;
1747		end = 7;
1748		while (bytes_read < sz && start < end) {
1749			bytes = nss_virt_if_copy_stats(if_num, start, line);
1750			if (!bytes)
1751				break;
1752
1753			if ((bytes_read + bytes) > sz)
1754				break;
1755
1756			if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
1757				bytes_read = -EFAULT;
1758				goto end;
1759			}
1760
1761			bytes_read += bytes;
1762			start++;
1763		}
1764
1765		bytes = scnprintf(line, sizeof(line), "if_num %d stats end:\n\n", if_num);
1766		if (bytes_read > (sz - bytes))
1767			break;
1768
1769		if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
1770			bytes_read = -EFAULT;
1771			goto end;
1772		}
1773
1774		bytes_read += bytes;
1775	}
1776
1777	if (bytes_read > 0) {
1778		*ppos = bytes_read;
1779	}
1780
1781	if (data) {
1782		data->if_num = if_num;
1783	}
1784
1785end:
1786	return bytes_read;
1787}
1788
1789/*
1790 * nss_stats_tx_rx_virt_if_read()
1791 *	Read tx_rx_virt_if statistics
1792 */
1793static ssize_t nss_stats_tx_rx_virt_if_read(struct file *fp, char __user *ubuf,
1794						size_t sz, loff_t *ppos)
1795{
1796	struct nss_stats_data *data = fp->private_data;
1797	int32_t if_num = NSS_DYNAMIC_IF_START;
1798	int32_t max_if_num = if_num + NSS_MAX_DYNAMIC_INTERFACES;
1799	size_t bytes = 0;
1800	ssize_t bytes_read = 0;
1801	char line[80];
1802	int start, end;
1803
1804	if (data) {
1805		if_num = data->if_num;
1806	}
1807
1808	if (if_num > max_if_num) {
1809		return 0;
1810	}
1811
1812	for (; if_num < max_if_num; if_num++) {
1813		if (nss_dynamic_interface_get_type(if_num) != NSS_DYNAMIC_INTERFACE_TYPE_VIRTIF_DEPRECATED)
1814			continue;
1815
1816		bytes = scnprintf(line, sizeof(line), "if_num %d stats start:\n\n", if_num);
1817		if ((bytes_read + bytes) > sz)
1818			break;
1819
1820		if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
1821			bytes_read = -EFAULT;
1822			goto end;
1823		}
1824
1825		bytes_read += bytes;
1826
1827		start = 0;
1828		end = 7;
1829		while (bytes_read < sz && start < end) {
1830			bytes = nss_tx_rx_virt_if_copy_stats(if_num, start, line);
1831			if (!bytes)
1832				break;
1833
1834			if ((bytes_read + bytes) > sz)
1835				break;
1836
1837			if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
1838				bytes_read = -EFAULT;
1839				goto end;
1840			}
1841
1842			bytes_read += bytes;
1843			start++;
1844		}
1845
1846		bytes = scnprintf(line, sizeof(line), "if_num %d stats end:\n\n", if_num);
1847		if (bytes_read > (sz - bytes))
1848			break;
1849
1850		if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
1851			bytes_read = -EFAULT;
1852			goto end;
1853		}
1854
1855		bytes_read += bytes;
1856	}
1857
1858	if (bytes_read > 0) {
1859		*ppos = bytes_read;
1860	}
1861
1862	if (data) {
1863		data->if_num = if_num;
1864	}
1865
1866end:
1867	return bytes_read;
1868}
1869
1870/*
1871 * nss_stats_open()
1872 */
1873static int nss_stats_open(struct inode *inode, struct file *filp)
1874{
1875	struct nss_stats_data *data = NULL;
1876
1877	data = kzalloc(sizeof(struct nss_stats_data), GFP_KERNEL);
1878	if (!data) {
1879		return -ENOMEM;
1880	}
1881	memset(data, 0, sizeof (struct nss_stats_data));
1882	data->if_num = NSS_DYNAMIC_IF_START;
1883	data->index = 0;
1884	filp->private_data = data;
1885
1886	return 0;
1887}
1888
1889/*
1890 * nss_stats_release()
1891 */
1892static int nss_stats_release(struct inode *inode, struct file *filp)
1893{
1894	struct nss_stats_data *data = filp->private_data;
1895
1896	if (data) {
1897		kfree(data);
1898	}
1899
1900	return 0;
1901}
1902
1903#define NSS_STATS_DECLARE_FILE_OPERATIONS(name) \
1904static const struct file_operations nss_stats_##name##_ops = { \
1905	.open = nss_stats_open, \
1906	.read = nss_stats_##name##_read, \
1907	.llseek = generic_file_llseek, \
1908	.release = nss_stats_release, \
1909};
1910
1911/*
1912 * nss_ipv4_stats_ops
1913 */
1914NSS_STATS_DECLARE_FILE_OPERATIONS(ipv4)
1915
1916/*
1917 * ipv4_reasm_stats_ops
1918 */
1919NSS_STATS_DECLARE_FILE_OPERATIONS(ipv4_reasm)
1920
1921/*
1922 * ipv6_stats_ops
1923 */
1924NSS_STATS_DECLARE_FILE_OPERATIONS(ipv6)
1925
1926/*
1927 * ipv6_reasm_stats_ops
1928 */
1929NSS_STATS_DECLARE_FILE_OPERATIONS(ipv6_reasm)
1930
1931/*
1932 * n2h_stats_ops
1933 */
1934NSS_STATS_DECLARE_FILE_OPERATIONS(n2h)
1935
1936/*
1937 * lso_rx_stats_ops
1938 */
1939NSS_STATS_DECLARE_FILE_OPERATIONS(lso_rx)
1940
1941/*
1942 * drv_stats_ops
1943 */
1944NSS_STATS_DECLARE_FILE_OPERATIONS(drv)
1945
1946/*
1947 * pppoe_stats_ops
1948 */
1949NSS_STATS_DECLARE_FILE_OPERATIONS(pppoe)
1950
1951/*
1952 * gmac_stats_ops
1953 */
1954NSS_STATS_DECLARE_FILE_OPERATIONS(gmac)
1955
1956/*
1957 * capwap_stats_ops
1958 */
1959NSS_STATS_DECLARE_FILE_OPERATIONS(capwap_encap)
1960NSS_STATS_DECLARE_FILE_OPERATIONS(capwap_decap)
1961
1962/*
1963 * eth_rx_stats_ops
1964 */
1965NSS_STATS_DECLARE_FILE_OPERATIONS(eth_rx)
1966
1967/*
1968 * gre_redir_ops
1969 */
1970NSS_STATS_DECLARE_FILE_OPERATIONS(gre_redir)
1971
1972/*
1973 * sjack_stats_ops
1974 */
1975NSS_STATS_DECLARE_FILE_OPERATIONS(sjack)
1976
1977NSS_STATS_DECLARE_FILE_OPERATIONS(wifi_if)
1978
1979NSS_STATS_DECLARE_FILE_OPERATIONS(virt_if)
1980
1981NSS_STATS_DECLARE_FILE_OPERATIONS(tx_rx_virt_if)
1982
1983/*
1984 * wifi_stats_ops
1985 */
1986NSS_STATS_DECLARE_FILE_OPERATIONS(wifi)
1987
1988/*
1989 * nss_stats_init()
1990 * 	Enable NSS statistics
1991 */
1992void nss_stats_init(void)
1993{
1994	/*
1995	 * NSS driver entry
1996	 */
1997	nss_top_main.top_dentry = debugfs_create_dir("qca-nss-drv", NULL);
1998	if (unlikely(nss_top_main.top_dentry == NULL)) {
1999		nss_warning("Failed to create qca-nss-drv directory in debugfs");
2000
2001		/*
2002		 * Non availability of debugfs directory is not a catastrophy
2003		 * We can still go ahead with other initialization
2004		 */
2005		return;
2006	}
2007
2008	nss_top_main.stats_dentry = debugfs_create_dir("stats", nss_top_main.top_dentry);
2009	if (unlikely(nss_top_main.stats_dentry == NULL)) {
2010		nss_warning("Failed to create qca-nss-drv directory in debugfs");
2011
2012		/*
2013		 * Non availability of debugfs directory is not a catastrophy
2014		 * We can still go ahead with rest of initialization
2015		 */
2016		return;
2017	}
2018
2019	/*
2020	 * Create files to obtain statistics
2021	 */
2022
2023	/*
2024	 * ipv4_stats
2025	 */
2026	nss_top_main.ipv4_dentry = debugfs_create_file("ipv4", 0400,
2027						nss_top_main.stats_dentry, &nss_top_main, &nss_stats_ipv4_ops);
2028	if (unlikely(nss_top_main.ipv4_dentry == NULL)) {
2029		nss_warning("Failed to create qca-nss-drv/stats/ipv4 file in debugfs");
2030		return;
2031	}
2032
2033	/*
2034	 * ipv4_reasm_stats
2035	 */
2036	nss_top_main.ipv4_reasm_dentry = debugfs_create_file("ipv4_reasm", 0400,
2037						nss_top_main.stats_dentry, &nss_top_main, &nss_stats_ipv4_reasm_ops);
2038	if (unlikely(nss_top_main.ipv4_reasm_dentry == NULL)) {
2039		nss_warning("Failed to create qca-nss-drv/stats/ipv4_reasm file in debugfs");
2040		return;
2041	}
2042
2043	/*
2044	 * ipv6_stats
2045	 */
2046	nss_top_main.ipv6_dentry = debugfs_create_file("ipv6", 0400,
2047						nss_top_main.stats_dentry, &nss_top_main, &nss_stats_ipv6_ops);
2048	if (unlikely(nss_top_main.ipv6_dentry == NULL)) {
2049		nss_warning("Failed to create qca-nss-drv/stats/ipv6 file in debugfs");
2050		return;
2051	}
2052
2053	/*
2054	 * ipv6_reasm_stats
2055	 */
2056	nss_top_main.ipv6_reasm_dentry = debugfs_create_file("ipv6_reasm", 0400,
2057						nss_top_main.stats_dentry, &nss_top_main, &nss_stats_ipv6_reasm_ops);
2058	if (unlikely(nss_top_main.ipv6_reasm_dentry == NULL)) {
2059		nss_warning("Failed to create qca-nss-drv/stats/ipv6_reasm file in debugfs");
2060		return;
2061	}
2062
2063	/*
2064	 * eth_rx__stats
2065	 */
2066	nss_top_main.eth_rx_dentry = debugfs_create_file("eth_rx", 0400,
2067						nss_top_main.stats_dentry, &nss_top_main, &nss_stats_eth_rx_ops);
2068	if (unlikely(nss_top_main.eth_rx_dentry == NULL)) {
2069		nss_warning("Failed to create qca-nss-drv/stats/eth_rx file in debugfs");
2070		return;
2071	}
2072
2073	/*
2074	 * n2h_stats
2075	 */
2076	nss_top_main.n2h_dentry = debugfs_create_file("n2h", 0400,
2077						nss_top_main.stats_dentry, &nss_top_main, &nss_stats_n2h_ops);
2078	if (unlikely(nss_top_main.n2h_dentry == NULL)) {
2079		nss_warning("Failed to create qca-nss-drv/stats/n2h directory in debugfs");
2080		return;
2081	}
2082
2083	/*
2084	 * lso_rx_stats
2085	 */
2086	nss_top_main.lso_rx_dentry = debugfs_create_file("lso_rx", 0400,
2087						nss_top_main.stats_dentry, &nss_top_main, &nss_stats_lso_rx_ops);
2088	if (unlikely(nss_top_main.lso_rx_dentry == NULL)) {
2089		nss_warning("Failed to create qca-nss-drv/stats/lso_rx file in debugfs");
2090		return;
2091	}
2092
2093	/*
2094	 * drv_stats
2095	 */
2096	nss_top_main.drv_dentry = debugfs_create_file("drv", 0400,
2097						nss_top_main.stats_dentry, &nss_top_main, &nss_stats_drv_ops);
2098	if (unlikely(nss_top_main.drv_dentry == NULL)) {
2099		nss_warning("Failed to create qca-nss-drv/stats/drv directory in debugfs");
2100		return;
2101	}
2102
2103	/*
2104	 * pppoe_stats
2105	 */
2106	nss_top_main.pppoe_dentry = debugfs_create_file("pppoe", 0400,
2107						nss_top_main.stats_dentry, &nss_top_main, &nss_stats_pppoe_ops);
2108	if (unlikely(nss_top_main.pppoe_dentry == NULL)) {
2109		nss_warning("Failed to create qca-nss-drv/stats/pppoe file in debugfs");
2110		return;
2111	}
2112
2113	/*
2114	 * gmac_stats
2115	 */
2116	nss_top_main.gmac_dentry = debugfs_create_file("gmac", 0400,
2117						nss_top_main.stats_dentry, &nss_top_main, &nss_stats_gmac_ops);
2118	if (unlikely(nss_top_main.gmac_dentry == NULL)) {
2119		nss_warning("Failed to create qca-nss-drv/stats/gmac file in debugfs");
2120		return;
2121	}
2122
2123	/*
2124	 * CAPWAP stats.
2125	 */
2126	nss_top_main.capwap_encap_dentry = debugfs_create_file("capwap_encap", 0400,
2127	nss_top_main.stats_dentry, &nss_top_main, &nss_stats_capwap_encap_ops);
2128	if (unlikely(nss_top_main.capwap_encap_dentry == NULL)) {
2129		nss_warning("Failed to create qca-nss-drv/stats/capwap_encap file in debugfs");
2130		return;
2131	}
2132
2133	nss_top_main.capwap_decap_dentry = debugfs_create_file("capwap_decap", 0400,
2134	nss_top_main.stats_dentry, &nss_top_main, &nss_stats_capwap_decap_ops);
2135	if (unlikely(nss_top_main.capwap_decap_dentry == NULL)) {
2136		nss_warning("Failed to create qca-nss-drv/stats/capwap_decap file in debugfs");
2137		return;
2138	}
2139
2140	/*
2141	 * GRE_REDIR stats
2142	 */
2143	nss_top_main.gre_redir_dentry = debugfs_create_file("gre_redir", 0400,
2144						nss_top_main.stats_dentry, &nss_top_main, &nss_stats_gre_redir_ops);
2145	if (unlikely(nss_top_main.gre_redir_dentry == NULL)) {
2146		nss_warning("Failed to create qca-nss-drv/stats/gre_redir file in debugfs");
2147		return;
2148	}
2149
2150	/*
2151	 * SJACK stats
2152	 */
2153	nss_top_main.sjack_dentry = debugfs_create_file("sjack", 0400,
2154						nss_top_main.stats_dentry, &nss_top_main, &nss_stats_sjack_ops);
2155	if (unlikely(nss_top_main.sjack_dentry == NULL)) {
2156		nss_warning("Failed to create qca-nss-drv/stats/sjack file in debugfs");
2157		return;
2158	}
2159
2160	/*
2161	 * WIFI stats
2162	 */
2163	nss_top_main.wifi_dentry = debugfs_create_file("wifi", 0400,
2164						nss_top_main.stats_dentry, &nss_top_main, &nss_stats_wifi_ops);
2165	if (unlikely(nss_top_main.wifi_dentry == NULL)) {
2166		nss_warning("Failed to create qca-nss-drv/stats/wifi file in debugfs");
2167		return;
2168	}
2169
2170	/*
2171	 * wifi_if stats
2172	 */
2173	nss_top_main.wifi_if_dentry = debugfs_create_file("wifi_if", 0400,
2174						nss_top_main.stats_dentry, &nss_top_main, &nss_stats_wifi_if_ops);
2175	if (unlikely(nss_top_main.wifi_if_dentry == NULL)) {
2176		nss_warning("Failed to create qca-nss-drv/stats/wifi_if file in debugfs");
2177		return;
2178	}
2179
2180	nss_top_main.virt_if_dentry = debugfs_create_file("virt_if", 0400,
2181						nss_top_main.stats_dentry, &nss_top_main, &nss_stats_virt_if_ops);
2182	if (unlikely(nss_top_main.virt_if_dentry == NULL)) {
2183		nss_warning("Failed to create qca-nss-drv/stats/virt_if file in debugfs");
2184		return;
2185	}
2186
2187	nss_top_main.tx_rx_virt_if_dentry = debugfs_create_file("tx_rx_virt_if", 0400,
2188						nss_top_main.stats_dentry, &nss_top_main, &nss_stats_tx_rx_virt_if_ops);
2189	if (unlikely(nss_top_main.virt_if_dentry == NULL)) {
2190		nss_warning("Failed to create qca-nss-drv/stats/tx_rx_virt_if file in debugfs");
2191		return;
2192	}
2193
2194	nss_log_init();
2195}
2196
2197
2198/*
2199 * nss_stats_clean()
2200 * 	Cleanup NSS statistics files
2201 */
2202void nss_stats_clean(void)
2203{
2204	/*
2205	 * Remove debugfs tree
2206	 */
2207	if (likely(nss_top_main.top_dentry != NULL)) {
2208		debugfs_remove_recursive(nss_top_main.top_dentry);
2209		nss_top_main.top_dentry = NULL;
2210	}
2211}
2212