xref: /freebsd/sys/ofed/drivers/infiniband/ulp/sdp/sdp_proc.c (revision fe267a559009cbf34f9341666fe4d88a92c02d5e)
1*fe267a55SPedro F. Giffuni /*-
2*fe267a55SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0
3*fe267a55SPedro F. Giffuni  *
4aa0a1e58SJeff Roberson  * Copyright (c) 2008 Mellanox Technologies Ltd.  All rights reserved.
5aa0a1e58SJeff Roberson  *
6aa0a1e58SJeff Roberson  * This software is available to you under a choice of one of two
7aa0a1e58SJeff Roberson  * licenses.  You may choose to be licensed under the terms of the GNU
8aa0a1e58SJeff Roberson  * General Public License (GPL) Version 2, available from the file
9aa0a1e58SJeff Roberson  * COPYING in the main directory of this source tree, or the
10aa0a1e58SJeff Roberson  * OpenIB.org BSD license below:
11aa0a1e58SJeff Roberson  *
12aa0a1e58SJeff Roberson  *     Redistribution and use in source and binary forms, with or
13aa0a1e58SJeff Roberson  *     without modification, are permitted provided that the following
14aa0a1e58SJeff Roberson  *     conditions are met:
15aa0a1e58SJeff Roberson  *
16aa0a1e58SJeff Roberson  *      - Redistributions of source code must retain the above
17aa0a1e58SJeff Roberson  *        copyright notice, this list of conditions and the following
18aa0a1e58SJeff Roberson  *        disclaimer.
19aa0a1e58SJeff Roberson  *
20aa0a1e58SJeff Roberson  *      - Redistributions in binary form must reproduce the above
21aa0a1e58SJeff Roberson  *        copyright notice, this list of conditions and the following
22aa0a1e58SJeff Roberson  *        disclaimer in the documentation and/or other materials
23aa0a1e58SJeff Roberson  *        provided with the distribution.
24aa0a1e58SJeff Roberson  *
25aa0a1e58SJeff Roberson  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26aa0a1e58SJeff Roberson  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27aa0a1e58SJeff Roberson  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28aa0a1e58SJeff Roberson  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29aa0a1e58SJeff Roberson  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30aa0a1e58SJeff Roberson  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31aa0a1e58SJeff Roberson  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32aa0a1e58SJeff Roberson  * SOFTWARE.
33aa0a1e58SJeff Roberson  */
34aa0a1e58SJeff Roberson 
35aa0a1e58SJeff Roberson #include <linux/proc_fs.h>
36aa0a1e58SJeff Roberson #include "sdp.h"
37aa0a1e58SJeff Roberson 
38aa0a1e58SJeff Roberson #ifdef CONFIG_PROC_FS
39aa0a1e58SJeff Roberson 
40aa0a1e58SJeff Roberson #define PROC_SDP_STATS "sdpstats"
41aa0a1e58SJeff Roberson #define PROC_SDP_PERF "sdpprf"
42aa0a1e58SJeff Roberson 
43aa0a1e58SJeff Roberson /* just like TCP fs */
44aa0a1e58SJeff Roberson struct sdp_seq_afinfo {
45aa0a1e58SJeff Roberson 	struct module           *owner;
46aa0a1e58SJeff Roberson 	char                    *name;
47aa0a1e58SJeff Roberson 	sa_family_t             family;
48aa0a1e58SJeff Roberson 	int                     (*seq_show) (struct seq_file *m, void *v);
49aa0a1e58SJeff Roberson 	struct file_operations  *seq_fops;
50aa0a1e58SJeff Roberson };
51aa0a1e58SJeff Roberson 
52aa0a1e58SJeff Roberson struct sdp_iter_state {
53aa0a1e58SJeff Roberson 	sa_family_t             family;
54aa0a1e58SJeff Roberson 	int                     num;
55aa0a1e58SJeff Roberson 	struct seq_operations   seq_ops;
56aa0a1e58SJeff Roberson };
57aa0a1e58SJeff Roberson 
sdp_get_idx(struct seq_file * seq,loff_t pos)58aa0a1e58SJeff Roberson static void *sdp_get_idx(struct seq_file *seq, loff_t pos)
59aa0a1e58SJeff Roberson {
60aa0a1e58SJeff Roberson 	int i = 0;
61aa0a1e58SJeff Roberson 	struct sdp_sock *ssk;
62aa0a1e58SJeff Roberson 
63aa0a1e58SJeff Roberson 	if (!list_empty(&sock_list))
64aa0a1e58SJeff Roberson 		list_for_each_entry(ssk, &sock_list, sock_list) {
65aa0a1e58SJeff Roberson 			if (i == pos)
66aa0a1e58SJeff Roberson 				return ssk;
67aa0a1e58SJeff Roberson 			i++;
68aa0a1e58SJeff Roberson 		}
69aa0a1e58SJeff Roberson 
70aa0a1e58SJeff Roberson 	return NULL;
71aa0a1e58SJeff Roberson }
72aa0a1e58SJeff Roberson 
sdp_seq_start(struct seq_file * seq,loff_t * pos)73aa0a1e58SJeff Roberson static void *sdp_seq_start(struct seq_file *seq, loff_t *pos)
74aa0a1e58SJeff Roberson {
75aa0a1e58SJeff Roberson 	void *start = NULL;
76aa0a1e58SJeff Roberson 	struct sdp_iter_state *st = seq->private;
77aa0a1e58SJeff Roberson 
78aa0a1e58SJeff Roberson 	st->num = 0;
79aa0a1e58SJeff Roberson 
80aa0a1e58SJeff Roberson 	if (!*pos)
81aa0a1e58SJeff Roberson 		return SEQ_START_TOKEN;
82aa0a1e58SJeff Roberson 
83aa0a1e58SJeff Roberson 	spin_lock_irq(&sock_list_lock);
84aa0a1e58SJeff Roberson 	start = sdp_get_idx(seq, *pos - 1);
85aa0a1e58SJeff Roberson 	if (start)
86aa0a1e58SJeff Roberson 		sock_hold((struct socket *)start, SOCK_REF_SEQ);
87aa0a1e58SJeff Roberson 	spin_unlock_irq(&sock_list_lock);
88aa0a1e58SJeff Roberson 
89aa0a1e58SJeff Roberson 	return start;
90aa0a1e58SJeff Roberson }
91aa0a1e58SJeff Roberson 
sdp_seq_next(struct seq_file * seq,void * v,loff_t * pos)92aa0a1e58SJeff Roberson static void *sdp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
93aa0a1e58SJeff Roberson {
94aa0a1e58SJeff Roberson 	struct sdp_iter_state *st = seq->private;
95aa0a1e58SJeff Roberson 	void *next = NULL;
96aa0a1e58SJeff Roberson 
97aa0a1e58SJeff Roberson 	spin_lock_irq(&sock_list_lock);
98aa0a1e58SJeff Roberson 	if (v == SEQ_START_TOKEN)
99aa0a1e58SJeff Roberson 		next = sdp_get_idx(seq, 0);
100aa0a1e58SJeff Roberson 	else
101aa0a1e58SJeff Roberson 		next = sdp_get_idx(seq, *pos);
102aa0a1e58SJeff Roberson 	if (next)
103aa0a1e58SJeff Roberson 		sock_hold((struct socket *)next, SOCK_REF_SEQ);
104aa0a1e58SJeff Roberson 	spin_unlock_irq(&sock_list_lock);
105aa0a1e58SJeff Roberson 
106aa0a1e58SJeff Roberson 	*pos += 1;
107aa0a1e58SJeff Roberson 	st->num++;
108aa0a1e58SJeff Roberson 
109aa0a1e58SJeff Roberson 	return next;
110aa0a1e58SJeff Roberson }
111aa0a1e58SJeff Roberson 
sdp_seq_stop(struct seq_file * seq,void * v)112aa0a1e58SJeff Roberson static void sdp_seq_stop(struct seq_file *seq, void *v)
113aa0a1e58SJeff Roberson {
114aa0a1e58SJeff Roberson }
115aa0a1e58SJeff Roberson 
116aa0a1e58SJeff Roberson #define TMPSZ 150
117aa0a1e58SJeff Roberson 
sdp_seq_show(struct seq_file * seq,void * v)118aa0a1e58SJeff Roberson static int sdp_seq_show(struct seq_file *seq, void *v)
119aa0a1e58SJeff Roberson {
120aa0a1e58SJeff Roberson 	struct sdp_iter_state *st;
121aa0a1e58SJeff Roberson 	struct socket *sk = v;
122aa0a1e58SJeff Roberson 	char tmpbuf[TMPSZ + 1];
123aa0a1e58SJeff Roberson 	unsigned int dest;
124aa0a1e58SJeff Roberson 	unsigned int src;
125aa0a1e58SJeff Roberson 	int uid;
126aa0a1e58SJeff Roberson 	unsigned long inode;
127aa0a1e58SJeff Roberson 	__u16 destp;
128aa0a1e58SJeff Roberson 	__u16 srcp;
129aa0a1e58SJeff Roberson 	__u32 rx_queue, tx_queue;
130aa0a1e58SJeff Roberson 
131aa0a1e58SJeff Roberson 	if (v == SEQ_START_TOKEN) {
132aa0a1e58SJeff Roberson 		seq_printf(seq, "%-*s\n", TMPSZ - 1,
133aa0a1e58SJeff Roberson 				"  sl  local_address rem_address        "
134aa0a1e58SJeff Roberson 				"uid inode   rx_queue tx_queue state");
135aa0a1e58SJeff Roberson 		goto out;
136aa0a1e58SJeff Roberson 	}
137aa0a1e58SJeff Roberson 
138aa0a1e58SJeff Roberson 	st = seq->private;
139aa0a1e58SJeff Roberson 
140aa0a1e58SJeff Roberson 	dest = inet_sk(sk)->daddr;
141aa0a1e58SJeff Roberson 	src = inet_sk(sk)->rcv_saddr;
142aa0a1e58SJeff Roberson 	destp = ntohs(inet_sk(sk)->dport);
143aa0a1e58SJeff Roberson 	srcp = ntohs(inet_sk(sk)->sport);
144aa0a1e58SJeff Roberson 	uid = sock_i_uid(sk);
145aa0a1e58SJeff Roberson 	inode = sock_i_ino(sk);
146aa0a1e58SJeff Roberson 	rx_queue = rcv_nxt(sdp_sk(sk)) - sdp_sk(sk)->copied_seq;
147aa0a1e58SJeff Roberson 	tx_queue = sdp_sk(sk)->write_seq - sdp_sk(sk)->tx_ring.una_seq;
148aa0a1e58SJeff Roberson 
149aa0a1e58SJeff Roberson 	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X %5d %lu	%08X:%08X %X",
150aa0a1e58SJeff Roberson 		st->num, src, srcp, dest, destp, uid, inode,
151aa0a1e58SJeff Roberson 		rx_queue, tx_queue, sk->sk_state);
152aa0a1e58SJeff Roberson 
153aa0a1e58SJeff Roberson 	seq_printf(seq, "%-*s\n", TMPSZ - 1, tmpbuf);
154aa0a1e58SJeff Roberson 
155aa0a1e58SJeff Roberson 	sock_put(sk, SOCK_REF_SEQ);
156aa0a1e58SJeff Roberson out:
157aa0a1e58SJeff Roberson 	return 0;
158aa0a1e58SJeff Roberson }
159aa0a1e58SJeff Roberson 
sdp_seq_open(struct inode * inode,struct file * file)160aa0a1e58SJeff Roberson static int sdp_seq_open(struct inode *inode, struct file *file)
161aa0a1e58SJeff Roberson {
162aa0a1e58SJeff Roberson 	struct sdp_seq_afinfo *afinfo = PDE(inode)->data;
163aa0a1e58SJeff Roberson 	struct seq_file *seq;
164aa0a1e58SJeff Roberson 	struct sdp_iter_state *s;
165aa0a1e58SJeff Roberson 	int rc;
166aa0a1e58SJeff Roberson 
167aa0a1e58SJeff Roberson 	if (unlikely(afinfo == NULL))
168aa0a1e58SJeff Roberson 		return -EINVAL;
169aa0a1e58SJeff Roberson 
170aa0a1e58SJeff Roberson /* Workaround bogus warning by memtrack */
171aa0a1e58SJeff Roberson #define _kzalloc(size,flags) kzalloc(size,flags)
172aa0a1e58SJeff Roberson #undef kzalloc
173aa0a1e58SJeff Roberson 	s = kzalloc(sizeof(*s), GFP_KERNEL);
174aa0a1e58SJeff Roberson #define kzalloc(s,f) _kzalloc(s,f)
175aa0a1e58SJeff Roberson 	if (!s)
176aa0a1e58SJeff Roberson 		return -ENOMEM;
177aa0a1e58SJeff Roberson 	s->family               = afinfo->family;
178aa0a1e58SJeff Roberson 	s->seq_ops.start        = sdp_seq_start;
179aa0a1e58SJeff Roberson 	s->seq_ops.next         = sdp_seq_next;
180aa0a1e58SJeff Roberson 	s->seq_ops.show         = afinfo->seq_show;
181aa0a1e58SJeff Roberson 	s->seq_ops.stop         = sdp_seq_stop;
182aa0a1e58SJeff Roberson 
183aa0a1e58SJeff Roberson 	rc = seq_open(file, &s->seq_ops);
184aa0a1e58SJeff Roberson 	if (rc)
185aa0a1e58SJeff Roberson 		goto out_kfree;
186aa0a1e58SJeff Roberson 	seq          = file->private_data;
187aa0a1e58SJeff Roberson 	seq->private = s;
188aa0a1e58SJeff Roberson out:
189aa0a1e58SJeff Roberson 	return rc;
190aa0a1e58SJeff Roberson out_kfree:
191aa0a1e58SJeff Roberson 	kfree(s);
192aa0a1e58SJeff Roberson 	goto out;
193aa0a1e58SJeff Roberson }
194aa0a1e58SJeff Roberson 
195aa0a1e58SJeff Roberson 
196aa0a1e58SJeff Roberson static struct file_operations sdp_seq_fops;
197aa0a1e58SJeff Roberson static struct sdp_seq_afinfo sdp_seq_afinfo = {
198aa0a1e58SJeff Roberson 	.owner          = THIS_MODULE,
199aa0a1e58SJeff Roberson 	.name           = "sdp",
200aa0a1e58SJeff Roberson 	.family         = AF_INET_SDP,
201aa0a1e58SJeff Roberson 	.seq_show       = sdp_seq_show,
202aa0a1e58SJeff Roberson 	.seq_fops       = &sdp_seq_fops,
203aa0a1e58SJeff Roberson };
204aa0a1e58SJeff Roberson 
205aa0a1e58SJeff Roberson #ifdef SDPSTATS_ON
206aa0a1e58SJeff Roberson DEFINE_PER_CPU(struct sdpstats, sdpstats);
207aa0a1e58SJeff Roberson 
sdpstats_seq_hist(struct seq_file * seq,char * str,u32 * h,int n,int is_log)208aa0a1e58SJeff Roberson static void sdpstats_seq_hist(struct seq_file *seq, char *str, u32 *h, int n,
209aa0a1e58SJeff Roberson 		int is_log)
210aa0a1e58SJeff Roberson {
211aa0a1e58SJeff Roberson 	int i;
212aa0a1e58SJeff Roberson 	u32 max = 0;
213aa0a1e58SJeff Roberson 
214aa0a1e58SJeff Roberson 	seq_printf(seq, "%s:\n", str);
215aa0a1e58SJeff Roberson 
216aa0a1e58SJeff Roberson 	for (i = 0; i < n; i++) {
217aa0a1e58SJeff Roberson 		if (h[i] > max)
218aa0a1e58SJeff Roberson 			max = h[i];
219aa0a1e58SJeff Roberson 	}
220aa0a1e58SJeff Roberson 
221aa0a1e58SJeff Roberson 	if (max == 0) {
222aa0a1e58SJeff Roberson 		seq_printf(seq, " - all values are 0\n");
223aa0a1e58SJeff Roberson 		return;
224aa0a1e58SJeff Roberson 	}
225aa0a1e58SJeff Roberson 
226aa0a1e58SJeff Roberson 	for (i = 0; i < n; i++) {
227aa0a1e58SJeff Roberson 		char s[51];
228aa0a1e58SJeff Roberson 		int j = 50 * h[i] / max;
229aa0a1e58SJeff Roberson 		int val = is_log ? (i == n-1 ? 0 : 1<<i) : i;
230aa0a1e58SJeff Roberson 		memset(s, '*', j);
231aa0a1e58SJeff Roberson 		s[j] = '\0';
232aa0a1e58SJeff Roberson 
233aa0a1e58SJeff Roberson 		seq_printf(seq, "%10d | %-50s - %d\n", val, s, h[i]);
234aa0a1e58SJeff Roberson 	}
235aa0a1e58SJeff Roberson }
236aa0a1e58SJeff Roberson 
237aa0a1e58SJeff Roberson #define SDPSTATS_COUNTER_GET(var) ({ \
238aa0a1e58SJeff Roberson 	u32 __val = 0;						\
239aa0a1e58SJeff Roberson 	unsigned int __i;                                       \
240aa0a1e58SJeff Roberson 	for_each_possible_cpu(__i)                              \
241aa0a1e58SJeff Roberson 		__val += per_cpu(sdpstats, __i).var;		\
242aa0a1e58SJeff Roberson 	__val;							\
243aa0a1e58SJeff Roberson })
244aa0a1e58SJeff Roberson 
245aa0a1e58SJeff Roberson #define SDPSTATS_HIST_GET(hist, hist_len, sum) ({ \
246aa0a1e58SJeff Roberson 	unsigned int __i;                                       \
247aa0a1e58SJeff Roberson 	for_each_possible_cpu(__i) {                            \
248aa0a1e58SJeff Roberson 		unsigned int __j;				\
249aa0a1e58SJeff Roberson 		u32 *h = per_cpu(sdpstats, __i).hist;		\
250aa0a1e58SJeff Roberson 		for (__j = 0; __j < hist_len; __j++) { 		\
251aa0a1e58SJeff Roberson 			sum[__j] += h[__j];			\
252aa0a1e58SJeff Roberson 		} \
253aa0a1e58SJeff Roberson 	} 							\
254aa0a1e58SJeff Roberson })
255aa0a1e58SJeff Roberson 
256aa0a1e58SJeff Roberson #define __sdpstats_seq_hist(seq, msg, hist, is_log) ({		\
257aa0a1e58SJeff Roberson 	u32 tmp_hist[SDPSTATS_MAX_HIST_SIZE];			\
258aa0a1e58SJeff Roberson 	int hist_len = ARRAY_SIZE(__get_cpu_var(sdpstats).hist);\
259aa0a1e58SJeff Roberson 	memset(tmp_hist, 0, sizeof(tmp_hist));			\
260aa0a1e58SJeff Roberson 	SDPSTATS_HIST_GET(hist, hist_len, tmp_hist);	\
261aa0a1e58SJeff Roberson 	sdpstats_seq_hist(seq, msg, tmp_hist, hist_len, is_log);\
262aa0a1e58SJeff Roberson })
263aa0a1e58SJeff Roberson 
sdpstats_seq_show(struct seq_file * seq,void * v)264aa0a1e58SJeff Roberson static int sdpstats_seq_show(struct seq_file *seq, void *v)
265aa0a1e58SJeff Roberson {
266aa0a1e58SJeff Roberson 	int i;
267aa0a1e58SJeff Roberson 
268aa0a1e58SJeff Roberson 	seq_printf(seq, "SDP statistics:\n");
269aa0a1e58SJeff Roberson 
270aa0a1e58SJeff Roberson 	__sdpstats_seq_hist(seq, "sendmsg_seglen", sendmsg_seglen, 1);
271aa0a1e58SJeff Roberson 	__sdpstats_seq_hist(seq, "send_size", send_size, 1);
272aa0a1e58SJeff Roberson 	__sdpstats_seq_hist(seq, "credits_before_update",
273aa0a1e58SJeff Roberson 		credits_before_update, 0);
274aa0a1e58SJeff Roberson 
275aa0a1e58SJeff Roberson 	seq_printf(seq, "sdp_sendmsg() calls\t\t: %d\n",
276aa0a1e58SJeff Roberson 		SDPSTATS_COUNTER_GET(sendmsg));
277aa0a1e58SJeff Roberson 	seq_printf(seq, "bcopy segments     \t\t: %d\n",
278aa0a1e58SJeff Roberson 		SDPSTATS_COUNTER_GET(sendmsg_bcopy_segment));
279aa0a1e58SJeff Roberson 	seq_printf(seq, "bzcopy segments    \t\t: %d\n",
280aa0a1e58SJeff Roberson 		SDPSTATS_COUNTER_GET(sendmsg_bzcopy_segment));
281aa0a1e58SJeff Roberson 	seq_printf(seq, "zcopy segments    \t\t: %d\n",
282aa0a1e58SJeff Roberson 		SDPSTATS_COUNTER_GET(sendmsg_zcopy_segment));
283aa0a1e58SJeff Roberson 	seq_printf(seq, "post_send_credits  \t\t: %d\n",
284aa0a1e58SJeff Roberson 		SDPSTATS_COUNTER_GET(post_send_credits));
285aa0a1e58SJeff Roberson 	seq_printf(seq, "memcpy_count       \t\t: %u\n",
286aa0a1e58SJeff Roberson 		SDPSTATS_COUNTER_GET(memcpy_count));
287aa0a1e58SJeff Roberson 
288aa0a1e58SJeff Roberson         for (i = 0; i < ARRAY_SIZE(__get_cpu_var(sdpstats).post_send); i++) {
289aa0a1e58SJeff Roberson                 if (mid2str(i)) {
290aa0a1e58SJeff Roberson                         seq_printf(seq, "post_send %-20s\t: %d\n",
291aa0a1e58SJeff Roberson                                         mid2str(i),
292aa0a1e58SJeff Roberson 					SDPSTATS_COUNTER_GET(post_send[i]));
293aa0a1e58SJeff Roberson                 }
294aa0a1e58SJeff Roberson         }
295aa0a1e58SJeff Roberson 
296aa0a1e58SJeff Roberson 	seq_printf(seq, "\n");
297aa0a1e58SJeff Roberson 	seq_printf(seq, "post_recv         \t\t: %d\n",
298aa0a1e58SJeff Roberson 		SDPSTATS_COUNTER_GET(post_recv));
299aa0a1e58SJeff Roberson 	seq_printf(seq, "BZCopy poll miss  \t\t: %d\n",
300aa0a1e58SJeff Roberson 		SDPSTATS_COUNTER_GET(bzcopy_poll_miss));
301aa0a1e58SJeff Roberson 	seq_printf(seq, "send_wait_for_mem \t\t: %d\n",
302aa0a1e58SJeff Roberson 		SDPSTATS_COUNTER_GET(send_wait_for_mem));
303aa0a1e58SJeff Roberson 	seq_printf(seq, "send_miss_no_credits\t\t: %d\n",
304aa0a1e58SJeff Roberson 		SDPSTATS_COUNTER_GET(send_miss_no_credits));
305aa0a1e58SJeff Roberson 
306aa0a1e58SJeff Roberson 	seq_printf(seq, "rx_poll_miss      \t\t: %d\n", SDPSTATS_COUNTER_GET(rx_poll_miss));
307aa0a1e58SJeff Roberson 	seq_printf(seq, "tx_poll_miss      \t\t: %d\n", SDPSTATS_COUNTER_GET(tx_poll_miss));
308aa0a1e58SJeff Roberson 	seq_printf(seq, "tx_poll_busy      \t\t: %d\n", SDPSTATS_COUNTER_GET(tx_poll_busy));
309aa0a1e58SJeff Roberson 	seq_printf(seq, "tx_poll_hit       \t\t: %d\n", SDPSTATS_COUNTER_GET(tx_poll_hit));
310aa0a1e58SJeff Roberson 
311aa0a1e58SJeff Roberson 	seq_printf(seq, "CQ stats:\n");
312aa0a1e58SJeff Roberson 	seq_printf(seq, "- RX interrupts\t\t: %d\n", SDPSTATS_COUNTER_GET(rx_int_count));
313aa0a1e58SJeff Roberson 	seq_printf(seq, "- TX interrupts\t\t: %d\n", SDPSTATS_COUNTER_GET(tx_int_count));
314aa0a1e58SJeff Roberson 
315aa0a1e58SJeff Roberson 	seq_printf(seq, "ZCopy stats:\n");
316aa0a1e58SJeff Roberson 	seq_printf(seq, "- TX timeout\t\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_tx_timeout));
317aa0a1e58SJeff Roberson 	seq_printf(seq, "- TX cross send\t\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_cross_send));
318aa0a1e58SJeff Roberson 	seq_printf(seq, "- TX aborted by peer\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_tx_aborted));
319aa0a1e58SJeff Roberson 	seq_printf(seq, "- TX error\t\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_tx_error));
320aa0a1e58SJeff Roberson 	return 0;
321aa0a1e58SJeff Roberson }
322aa0a1e58SJeff Roberson 
sdpstats_write(struct file * file,const char __user * buf,size_t count,loff_t * offs)323aa0a1e58SJeff Roberson static ssize_t sdpstats_write(struct file *file, const char __user *buf,
324aa0a1e58SJeff Roberson 			    size_t count, loff_t *offs)
325aa0a1e58SJeff Roberson {
326aa0a1e58SJeff Roberson 	int i;
327aa0a1e58SJeff Roberson 
328aa0a1e58SJeff Roberson 	for_each_possible_cpu(i)
329aa0a1e58SJeff Roberson 		memset(&per_cpu(sdpstats, i), 0, sizeof(struct sdpstats));
330aa0a1e58SJeff Roberson 	printk(KERN_WARNING "Cleared sdp statistics\n");
331aa0a1e58SJeff Roberson 
332aa0a1e58SJeff Roberson 	return count;
333aa0a1e58SJeff Roberson }
334aa0a1e58SJeff Roberson 
sdpstats_seq_open(struct inode * inode,struct file * file)335aa0a1e58SJeff Roberson static int sdpstats_seq_open(struct inode *inode, struct file *file)
336aa0a1e58SJeff Roberson {
337aa0a1e58SJeff Roberson 	return single_open(file, sdpstats_seq_show, NULL);
338aa0a1e58SJeff Roberson }
339aa0a1e58SJeff Roberson 
340aa0a1e58SJeff Roberson static struct file_operations sdpstats_fops = {
341aa0a1e58SJeff Roberson 	.owner		= THIS_MODULE,
342aa0a1e58SJeff Roberson 	.open		= sdpstats_seq_open,
343aa0a1e58SJeff Roberson 	.read		= seq_read,
344aa0a1e58SJeff Roberson 	.write		= sdpstats_write,
345aa0a1e58SJeff Roberson 	.llseek		= seq_lseek,
346aa0a1e58SJeff Roberson 	.release	= single_release,
347aa0a1e58SJeff Roberson };
348aa0a1e58SJeff Roberson 
349aa0a1e58SJeff Roberson #endif
350aa0a1e58SJeff Roberson 
351aa0a1e58SJeff Roberson #ifdef SDP_PROFILING
352aa0a1e58SJeff Roberson struct sdpprf_log sdpprf_log[SDPPRF_LOG_SIZE];
353aa0a1e58SJeff Roberson int sdpprf_log_count;
354aa0a1e58SJeff Roberson 
355aa0a1e58SJeff Roberson static unsigned long long start_t;
356aa0a1e58SJeff Roberson 
sdpprf_show(struct seq_file * m,void * v)357aa0a1e58SJeff Roberson static int sdpprf_show(struct seq_file *m, void *v)
358aa0a1e58SJeff Roberson {
359aa0a1e58SJeff Roberson 	struct sdpprf_log *l = v;
360aa0a1e58SJeff Roberson 	unsigned long nsec_rem, t;
361aa0a1e58SJeff Roberson 
362aa0a1e58SJeff Roberson 	if (!sdpprf_log_count) {
363aa0a1e58SJeff Roberson 		seq_printf(m, "No performance logs\n");
364aa0a1e58SJeff Roberson 		goto out;
365aa0a1e58SJeff Roberson 	}
366aa0a1e58SJeff Roberson 
367aa0a1e58SJeff Roberson 	t = l->time - start_t;
368aa0a1e58SJeff Roberson 	nsec_rem = do_div(t, 1000000000);
369aa0a1e58SJeff Roberson 
370aa0a1e58SJeff Roberson 	seq_printf(m, "%-6d: [%5lu.%06lu] %-50s - [%d{%d} %d:%d] "
371aa0a1e58SJeff Roberson 			"mb: %p %s:%d\n",
372aa0a1e58SJeff Roberson 			l->idx, (unsigned long)t, nsec_rem/1000,
373aa0a1e58SJeff Roberson 			l->msg, l->pid, l->cpu, l->sk_num, l->sk_dport,
374aa0a1e58SJeff Roberson 			l->mb, l->func, l->line);
375aa0a1e58SJeff Roberson out:
376aa0a1e58SJeff Roberson 	return 0;
377aa0a1e58SJeff Roberson }
378aa0a1e58SJeff Roberson 
sdpprf_start(struct seq_file * p,loff_t * pos)379aa0a1e58SJeff Roberson static void *sdpprf_start(struct seq_file *p, loff_t *pos)
380aa0a1e58SJeff Roberson {
381aa0a1e58SJeff Roberson 	int idx = *pos;
382aa0a1e58SJeff Roberson 
383aa0a1e58SJeff Roberson 	if (!*pos) {
384aa0a1e58SJeff Roberson 		if (!sdpprf_log_count)
385aa0a1e58SJeff Roberson 			return SEQ_START_TOKEN;
386aa0a1e58SJeff Roberson 	}
387aa0a1e58SJeff Roberson 
388aa0a1e58SJeff Roberson 	if (*pos >= MIN(sdpprf_log_count, SDPPRF_LOG_SIZE - 1))
389aa0a1e58SJeff Roberson 		return NULL;
390aa0a1e58SJeff Roberson 
391aa0a1e58SJeff Roberson 	if (sdpprf_log_count >= SDPPRF_LOG_SIZE - 1) {
392aa0a1e58SJeff Roberson 		int off = sdpprf_log_count & (SDPPRF_LOG_SIZE - 1);
393aa0a1e58SJeff Roberson 		idx = (idx + off) & (SDPPRF_LOG_SIZE - 1);
394aa0a1e58SJeff Roberson 
395aa0a1e58SJeff Roberson 	}
396aa0a1e58SJeff Roberson 
397aa0a1e58SJeff Roberson 	if (!start_t)
398aa0a1e58SJeff Roberson 		start_t = sdpprf_log[idx].time;
399aa0a1e58SJeff Roberson 	return &sdpprf_log[idx];
400aa0a1e58SJeff Roberson }
401aa0a1e58SJeff Roberson 
sdpprf_next(struct seq_file * p,void * v,loff_t * pos)402aa0a1e58SJeff Roberson static void *sdpprf_next(struct seq_file *p, void *v, loff_t *pos)
403aa0a1e58SJeff Roberson {
404aa0a1e58SJeff Roberson 	struct sdpprf_log *l = v;
405aa0a1e58SJeff Roberson 
406aa0a1e58SJeff Roberson 	if (++*pos >= MIN(sdpprf_log_count, SDPPRF_LOG_SIZE - 1))
407aa0a1e58SJeff Roberson 		return NULL;
408aa0a1e58SJeff Roberson 
409aa0a1e58SJeff Roberson 	++l;
410aa0a1e58SJeff Roberson 	if (l - &sdpprf_log[0] >= SDPPRF_LOG_SIZE - 1)
411aa0a1e58SJeff Roberson 		return &sdpprf_log[0];
412aa0a1e58SJeff Roberson 
413aa0a1e58SJeff Roberson 	return l;
414aa0a1e58SJeff Roberson }
415aa0a1e58SJeff Roberson 
sdpprf_stop(struct seq_file * p,void * v)416aa0a1e58SJeff Roberson static void sdpprf_stop(struct seq_file *p, void *v)
417aa0a1e58SJeff Roberson {
418aa0a1e58SJeff Roberson }
419aa0a1e58SJeff Roberson 
420aa0a1e58SJeff Roberson static struct seq_operations sdpprf_ops = {
421aa0a1e58SJeff Roberson 	.start = sdpprf_start,
422aa0a1e58SJeff Roberson 	.stop = sdpprf_stop,
423aa0a1e58SJeff Roberson 	.next = sdpprf_next,
424aa0a1e58SJeff Roberson 	.show = sdpprf_show,
425aa0a1e58SJeff Roberson };
426aa0a1e58SJeff Roberson 
sdpprf_open(struct inode * inode,struct file * file)427aa0a1e58SJeff Roberson static int sdpprf_open(struct inode *inode, struct file *file)
428aa0a1e58SJeff Roberson {
429aa0a1e58SJeff Roberson 	int res;
430aa0a1e58SJeff Roberson 
431aa0a1e58SJeff Roberson 	res = seq_open(file, &sdpprf_ops);
432aa0a1e58SJeff Roberson 
433aa0a1e58SJeff Roberson 	return res;
434aa0a1e58SJeff Roberson }
435aa0a1e58SJeff Roberson 
sdpprf_write(struct file * file,const char __user * buf,size_t count,loff_t * offs)436aa0a1e58SJeff Roberson static ssize_t sdpprf_write(struct file *file, const char __user *buf,
437aa0a1e58SJeff Roberson 			    size_t count, loff_t *offs)
438aa0a1e58SJeff Roberson {
439aa0a1e58SJeff Roberson 	sdpprf_log_count = 0;
440aa0a1e58SJeff Roberson 	printk(KERN_INFO "Cleared sdpprf statistics\n");
441aa0a1e58SJeff Roberson 
442aa0a1e58SJeff Roberson 	return count;
443aa0a1e58SJeff Roberson }
444aa0a1e58SJeff Roberson 
445aa0a1e58SJeff Roberson static struct file_operations sdpprf_fops = {
446aa0a1e58SJeff Roberson 	.open           = sdpprf_open,
447aa0a1e58SJeff Roberson 	.read           = seq_read,
448aa0a1e58SJeff Roberson 	.llseek         = seq_lseek,
449aa0a1e58SJeff Roberson 	.release        = seq_release,
450aa0a1e58SJeff Roberson 	.write		= sdpprf_write,
451aa0a1e58SJeff Roberson };
452aa0a1e58SJeff Roberson #endif /* SDP_PROFILING */
453aa0a1e58SJeff Roberson 
sdp_proc_init(void)454aa0a1e58SJeff Roberson int __init sdp_proc_init(void)
455aa0a1e58SJeff Roberson {
456aa0a1e58SJeff Roberson 	struct proc_dir_entry *p = NULL;
457aa0a1e58SJeff Roberson #ifdef SDPSTATS_ON
458aa0a1e58SJeff Roberson 	struct proc_dir_entry *stats = NULL;
459aa0a1e58SJeff Roberson #endif
460aa0a1e58SJeff Roberson #ifdef SDP_PROFILING
461aa0a1e58SJeff Roberson 	struct proc_dir_entry *prof = NULL;
462aa0a1e58SJeff Roberson #endif
463aa0a1e58SJeff Roberson 
464aa0a1e58SJeff Roberson 	sdp_seq_afinfo.seq_fops->owner         = sdp_seq_afinfo.owner;
465aa0a1e58SJeff Roberson 	sdp_seq_afinfo.seq_fops->open          = sdp_seq_open;
466aa0a1e58SJeff Roberson 	sdp_seq_afinfo.seq_fops->read          = seq_read;
467aa0a1e58SJeff Roberson 	sdp_seq_afinfo.seq_fops->llseek        = seq_lseek;
468aa0a1e58SJeff Roberson 	sdp_seq_afinfo.seq_fops->release       = seq_release_private;
469aa0a1e58SJeff Roberson 
470aa0a1e58SJeff Roberson 	p = proc_net_fops_create(&init_net, sdp_seq_afinfo.name, S_IRUGO,
471aa0a1e58SJeff Roberson 				 sdp_seq_afinfo.seq_fops);
472aa0a1e58SJeff Roberson 	if (p)
473aa0a1e58SJeff Roberson 		p->data = &sdp_seq_afinfo;
474aa0a1e58SJeff Roberson 	else
475aa0a1e58SJeff Roberson 		goto no_mem;
476aa0a1e58SJeff Roberson 
477aa0a1e58SJeff Roberson #ifdef SDPSTATS_ON
478aa0a1e58SJeff Roberson 
479aa0a1e58SJeff Roberson 	stats = proc_net_fops_create(&init_net, PROC_SDP_STATS,
480aa0a1e58SJeff Roberson 			S_IRUGO | S_IWUGO, &sdpstats_fops);
481aa0a1e58SJeff Roberson 	if (!stats)
482aa0a1e58SJeff Roberson 		goto no_mem_stats;
483aa0a1e58SJeff Roberson 
484aa0a1e58SJeff Roberson #endif
485aa0a1e58SJeff Roberson 
486aa0a1e58SJeff Roberson #ifdef SDP_PROFILING
487aa0a1e58SJeff Roberson 	prof = proc_net_fops_create(&init_net, PROC_SDP_PERF,
488aa0a1e58SJeff Roberson 			S_IRUGO | S_IWUGO, &sdpprf_fops);
489aa0a1e58SJeff Roberson 	if (!prof)
490aa0a1e58SJeff Roberson 		goto no_mem_prof;
491aa0a1e58SJeff Roberson #endif
492aa0a1e58SJeff Roberson 
493aa0a1e58SJeff Roberson 	return 0;
494aa0a1e58SJeff Roberson 
495aa0a1e58SJeff Roberson #ifdef SDP_PROFILING
496aa0a1e58SJeff Roberson no_mem_prof:
497aa0a1e58SJeff Roberson #endif
498aa0a1e58SJeff Roberson 
499aa0a1e58SJeff Roberson #ifdef SDPSTATS_ON
500aa0a1e58SJeff Roberson 	proc_net_remove(&init_net, PROC_SDP_STATS);
501aa0a1e58SJeff Roberson 
502aa0a1e58SJeff Roberson no_mem_stats:
503aa0a1e58SJeff Roberson #endif
504aa0a1e58SJeff Roberson 	proc_net_remove(&init_net, sdp_seq_afinfo.name);
505aa0a1e58SJeff Roberson 
506aa0a1e58SJeff Roberson no_mem:
507aa0a1e58SJeff Roberson 	return -ENOMEM;
508aa0a1e58SJeff Roberson }
509aa0a1e58SJeff Roberson 
sdp_proc_unregister(void)510aa0a1e58SJeff Roberson void sdp_proc_unregister(void)
511aa0a1e58SJeff Roberson {
512aa0a1e58SJeff Roberson 	proc_net_remove(&init_net, sdp_seq_afinfo.name);
513aa0a1e58SJeff Roberson 	memset(sdp_seq_afinfo.seq_fops, 0, sizeof(*sdp_seq_afinfo.seq_fops));
514aa0a1e58SJeff Roberson 
515aa0a1e58SJeff Roberson #ifdef SDPSTATS_ON
516aa0a1e58SJeff Roberson 	proc_net_remove(&init_net, PROC_SDP_STATS);
517aa0a1e58SJeff Roberson #endif
518aa0a1e58SJeff Roberson #ifdef SDP_PROFILING
519aa0a1e58SJeff Roberson 	proc_net_remove(&init_net, PROC_SDP_PERF);
520aa0a1e58SJeff Roberson #endif
521aa0a1e58SJeff Roberson }
522aa0a1e58SJeff Roberson 
523aa0a1e58SJeff Roberson #else /* CONFIG_PROC_FS */
524aa0a1e58SJeff Roberson 
sdp_proc_init(void)525aa0a1e58SJeff Roberson int __init sdp_proc_init(void)
526aa0a1e58SJeff Roberson {
527aa0a1e58SJeff Roberson 	return 0;
528aa0a1e58SJeff Roberson }
529aa0a1e58SJeff Roberson 
sdp_proc_unregister(void)530aa0a1e58SJeff Roberson void sdp_proc_unregister(void)
531aa0a1e58SJeff Roberson {
532aa0a1e58SJeff Roberson 
533aa0a1e58SJeff Roberson }
534aa0a1e58SJeff Roberson #endif /* CONFIG_PROC_FS */
535