2 * proc.c - procfs support for Protocol family CAN core module
4 * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions, the following disclaimer and
12 * the referenced file 'COPYING'.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of Volkswagen nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * Alternatively, provided that this notice is retained in full, this
21 * software may be distributed under the terms of the GNU General
22 * Public License ("GPL") version 2 as distributed in the 'COPYING'
23 * file from the main directory of the linux kernel source.
25 * The provided data structures and external interfaces from this code
26 * are not restricted to be used by modules with a GPL compatible license.
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
41 * Send feedback to <socketcan-users@lists.berlios.de>
45 #include <linux/module.h>
46 #include <linux/proc_fs.h>
47 #include <linux/list.h>
48 #include <linux/rcupdate.h>
50 #include <linux/can/core.h>
51 #include <linux/can/version.h>
59 #define CAN_PROC_VERSION "version"
60 #define CAN_PROC_STATS "stats"
61 #define CAN_PROC_RESET_STATS "reset_stats"
62 #define CAN_PROC_RCVLIST_ALL "rcvlist_all"
63 #define CAN_PROC_RCVLIST_FIL "rcvlist_fil"
64 #define CAN_PROC_RCVLIST_INV "rcvlist_inv"
65 #define CAN_PROC_RCVLIST_SFF "rcvlist_sff"
66 #define CAN_PROC_RCVLIST_EFF "rcvlist_eff"
67 #define CAN_PROC_RCVLIST_ERR "rcvlist_err"
69 static void can_init_stats(int caller);
70 static void can_stat_update(unsigned long data);
72 static struct proc_dir_entry *can_create_proc_readentry(const char *name,
73 mode_t mode, read_proc_t* read_proc, void *data);
74 static void can_remove_proc_readentry(const char *name);
75 static unsigned long calc_rate(unsigned long oldjif, unsigned long newjif,
78 static int can_proc_read_version(char *page, char **start, off_t off,
79 int count, int *eof, void *data);
80 static int can_proc_read_stats(char *page, char **start, off_t off,
81 int count, int *eof, void *data);
82 static int can_proc_read_reset_stats(char *page, char **start, off_t off,
83 int count, int *eof, void *data);
84 static int can_proc_read_rcvlist_all(char *page, char **start, off_t off,
85 int count, int *eof, void *data);
86 static int can_proc_read_rcvlist_fil(char *page, char **start, off_t off,
87 int count, int *eof, void *data);
88 static int can_proc_read_rcvlist_inv(char *page, char **start, off_t off,
89 int count, int *eof, void *data);
90 static int can_proc_read_rcvlist_sff(char *page, char **start, off_t off,
91 int count, int *eof, void *data);
92 static int can_proc_read_rcvlist_eff(char *page, char **start, off_t off,
93 int count, int *eof, void *data);
94 static int can_proc_read_rcvlist_err(char *page, char **start, off_t off,
95 int count, int *eof, void *data);
97 static struct proc_dir_entry *can_dir = NULL;
98 static struct proc_dir_entry *pde_version = NULL;
99 static struct proc_dir_entry *pde_stats = NULL;
100 static struct proc_dir_entry *pde_reset_stats = NULL;
101 static struct proc_dir_entry *pde_rcvlist_all = NULL;
102 static struct proc_dir_entry *pde_rcvlist_fil = NULL;
103 static struct proc_dir_entry *pde_rcvlist_inv = NULL;
104 static struct proc_dir_entry *pde_rcvlist_sff = NULL;
105 static struct proc_dir_entry *pde_rcvlist_eff = NULL;
106 static struct proc_dir_entry *pde_rcvlist_err = NULL;
108 struct timer_list stattimer; /* timer for statistics update */
110 struct s_stats stats; /* statistics */
111 struct s_pstats pstats;
113 extern struct hlist_head rx_dev_list; /* rx dispatcher structures */
114 extern int stats_timer; /* module parameter. default: on */
116 /**************************************************/
117 /* procfs init / remove */
118 /**************************************************/
120 void can_init_proc(void)
125 /* create /proc/can directory */
126 can_dir = proc_mkdir(CAN_PROC_DIR, NULL);
129 printk(KERN_INFO "CAN: failed to create CAN_PROC_DIR. "
130 "CONFIG_PROC_FS missing?\n");
134 can_dir->owner = THIS_MODULE;
136 /* own procfs entries from the AF_CAN core */
137 pde_version = can_create_proc_readentry(
138 CAN_PROC_VERSION, 0644, can_proc_read_version, NULL);
139 pde_stats = can_create_proc_readentry(
140 CAN_PROC_STATS, 0644, can_proc_read_stats, NULL);
141 pde_reset_stats = can_create_proc_readentry(
142 CAN_PROC_RESET_STATS, 0644, can_proc_read_reset_stats, NULL);
143 pde_rcvlist_all = can_create_proc_readentry(
144 CAN_PROC_RCVLIST_ALL, 0644, can_proc_read_rcvlist_all, NULL);
145 pde_rcvlist_fil = can_create_proc_readentry(
146 CAN_PROC_RCVLIST_FIL, 0644, can_proc_read_rcvlist_fil, NULL);
147 pde_rcvlist_inv = can_create_proc_readentry(
148 CAN_PROC_RCVLIST_INV, 0644, can_proc_read_rcvlist_inv, NULL);
149 pde_rcvlist_sff = can_create_proc_readentry(
150 CAN_PROC_RCVLIST_SFF, 0644, can_proc_read_rcvlist_sff, NULL);
151 pde_rcvlist_eff = can_create_proc_readentry(
152 CAN_PROC_RCVLIST_EFF, 0644, can_proc_read_rcvlist_eff, NULL);
153 pde_rcvlist_err = can_create_proc_readentry(
154 CAN_PROC_RCVLIST_ERR, 0644, can_proc_read_rcvlist_err, NULL);
157 /* the statistics are updated every second (timer triggered) */
158 stattimer.function = can_stat_update;
160 /* update every second */
161 stattimer.expires = jiffies + HZ;
162 /* start statistics timer */
163 add_timer(&stattimer);
167 void can_remove_proc(void)
171 can_remove_proc_readentry(CAN_PROC_VERSION);
174 can_remove_proc_readentry(CAN_PROC_STATS);
177 can_remove_proc_readentry(CAN_PROC_RESET_STATS);
180 can_remove_proc_readentry(CAN_PROC_RCVLIST_ALL);
183 can_remove_proc_readentry(CAN_PROC_RCVLIST_FIL);
186 can_remove_proc_readentry(CAN_PROC_RCVLIST_INV);
189 can_remove_proc_readentry(CAN_PROC_RCVLIST_SFF);
192 can_remove_proc_readentry(CAN_PROC_RCVLIST_EFF);
195 can_remove_proc_readentry(CAN_PROC_RCVLIST_ERR);
198 remove_proc_entry(CAN_PROC_DIR, NULL);
201 /**************************************************/
202 /* proc read functions */
203 /**************************************************/
205 static int can_print_rcvlist(char *page, int len, struct hlist_head *rx_list,
206 struct net_device *dev)
209 struct hlist_node *n;
212 hlist_for_each_entry_rcu(r, n, rx_list, list) {
213 char *fmt = (r->can_id & CAN_EFF_FLAG)?
214 " %-5s %08X %08x %08x %08x %8ld %s\n" :
215 " %-5s %03X %08x %08x %08x %8ld %s\n";
217 len += snprintf(page + len, PAGE_SIZE - len, fmt,
218 DNAME(dev), r->can_id, r->mask,
219 (unsigned int)r->func, (unsigned int)r->data,
220 r->matches, r->ident);
222 /* does a typical line fit into the current buffer? */
224 /* 100 Bytes before end of buffer */
225 if (len > PAGE_SIZE - 100) {
226 /* mark output cut off */
227 len += snprintf(page + len, PAGE_SIZE - len,
237 static int can_print_recv_banner(char *page, int len)
240 * can1. 00000000 00000000 00000000
243 len += snprintf(page + len, PAGE_SIZE - len,
244 " device can_id can_mask function"
245 " userdata matches ident\n");
250 static int can_proc_read_stats(char *page, char **start, off_t off,
251 int count, int *eof, void *data)
255 len += snprintf(page + len, PAGE_SIZE - len, "\n");
256 len += snprintf(page + len, PAGE_SIZE - len,
257 " %8ld transmitted frames (TXF)\n", stats.tx_frames);
258 len += snprintf(page + len, PAGE_SIZE - len,
259 " %8ld received frames (RXF)\n", stats.rx_frames);
260 len += snprintf(page + len, PAGE_SIZE - len,
261 " %8ld matched frames (RXMF)\n", stats.matches);
263 len += snprintf(page + len, PAGE_SIZE - len, "\n");
265 len += snprintf(page + len, PAGE_SIZE - len,
266 " %8ld %% total match ratio (RXMR)\n",
267 stats.total_rx_match_ratio);
269 len += snprintf(page + len, PAGE_SIZE - len,
270 " %8ld frames/s total tx rate (TXR)\n",
271 stats.total_tx_rate);
272 len += snprintf(page + len, PAGE_SIZE - len,
273 " %8ld frames/s total rx rate (RXR)\n",
274 stats.total_rx_rate);
276 len += snprintf(page + len, PAGE_SIZE - len, "\n");
278 len += snprintf(page + len, PAGE_SIZE - len,
279 " %8ld %% current match ratio (CRXMR)\n",
280 stats.current_rx_match_ratio);
282 len += snprintf(page + len, PAGE_SIZE - len,
283 " %8ld frames/s current tx rate (CTXR)\n",
284 stats.current_tx_rate);
285 len += snprintf(page + len, PAGE_SIZE - len,
286 " %8ld frames/s current rx rate (CRXR)\n",
287 stats.current_rx_rate);
289 len += snprintf(page + len, PAGE_SIZE - len, "\n");
291 len += snprintf(page + len, PAGE_SIZE - len,
292 " %8ld %% max match ratio (MRXMR)\n",
293 stats.max_rx_match_ratio);
295 len += snprintf(page + len, PAGE_SIZE - len,
296 " %8ld frames/s max tx rate (MTXR)\n",
298 len += snprintf(page + len, PAGE_SIZE - len,
299 " %8ld frames/s max rx rate (MRXR)\n",
302 len += snprintf(page + len, PAGE_SIZE - len, "\n");
304 len += snprintf(page + len, PAGE_SIZE - len,
305 " %8ld current receive list entries (CRCV)\n",
307 len += snprintf(page + len, PAGE_SIZE - len,
308 " %8ld maximum receive list entries (MRCV)\n",
309 pstats.rcv_entries_max);
311 if (pstats.stats_reset)
312 len += snprintf(page + len, PAGE_SIZE - len,
313 "\n %8ld statistic resets (STR)\n",
316 len += snprintf(page + len, PAGE_SIZE - len, "\n");
322 static int can_proc_read_reset_stats(char *page, char **start, off_t off,
323 int count, int *eof, void *data)
329 len += snprintf(page + len, PAGE_SIZE - len,
330 "CAN statistic reset #%ld done.\n",
337 static int can_proc_read_version(char *page, char **start, off_t off,
338 int count, int *eof, void *data)
342 len += snprintf(page + len, PAGE_SIZE - len,
343 "%06X [ Volkswagen Group - Low Level CAN Framework"
344 " (LLCF) v%s ]\n", LLCF_VERSION_CODE, VERSION);
349 static int can_proc_read_rcvlist_all(char *page, char **start, off_t off,
350 int count, int *eof, void *data)
353 struct dev_rcv_lists *d;
354 struct hlist_node *n;
357 len += snprintf(page + len, PAGE_SIZE - len,
358 "\nreceive list 'rx_all':\n");
360 /* find receive list for this device */
362 hlist_for_each_entry_rcu(d, n, &rx_dev_list, list) {
364 if (!hlist_empty(&d->rx_all)) {
365 len = can_print_recv_banner(page, len);
366 len = can_print_rcvlist(page, len, &d->rx_all, d->dev);
368 len += snprintf(page + len, PAGE_SIZE - len,
369 " (%s: no entry)\n", DNAME(d->dev));
371 /* exit on end of buffer? */
372 if (len > PAGE_SIZE - 100)
377 len += snprintf(page + len, PAGE_SIZE - len, "\n");
383 static int can_proc_read_rcvlist_fil(char *page, char **start, off_t off,
384 int count, int *eof, void *data)
387 struct dev_rcv_lists *d;
388 struct hlist_node *n;
391 len += snprintf(page + len, PAGE_SIZE - len,
392 "\nreceive list 'rx_fil':\n");
394 /* find receive list for this device */
396 hlist_for_each_entry_rcu(d, n, &rx_dev_list, list) {
398 if (!hlist_empty(&d->rx_fil)) {
399 len = can_print_recv_banner(page, len);
400 len = can_print_rcvlist(page, len, &d->rx_fil, d->dev);
402 len += snprintf(page + len, PAGE_SIZE - len,
403 " (%s: no entry)\n", DNAME(d->dev));
405 /* exit on end of buffer? */
406 if (len > PAGE_SIZE - 100)
411 len += snprintf(page + len, PAGE_SIZE - len, "\n");
417 static int can_proc_read_rcvlist_inv(char *page, char **start, off_t off,
418 int count, int *eof, void *data)
421 struct dev_rcv_lists *d;
422 struct hlist_node *n;
425 len += snprintf(page + len, PAGE_SIZE - len,
426 "\nreceive list 'rx_inv':\n");
428 /* find receive list for this device */
430 hlist_for_each_entry_rcu(d, n, &rx_dev_list, list) {
432 if (!hlist_empty(&d->rx_inv)) {
433 len = can_print_recv_banner(page, len);
434 len = can_print_rcvlist(page, len, &d->rx_inv, d->dev);
436 len += snprintf(page + len, PAGE_SIZE - len,
437 " (%s: no entry)\n", DNAME(d->dev));
439 /* exit on end of buffer? */
440 if (len > PAGE_SIZE - 100)
445 len += snprintf(page + len, PAGE_SIZE - len, "\n");
451 static int can_proc_read_rcvlist_sff(char *page, char **start, off_t off,
452 int count, int *eof, void *data)
455 struct dev_rcv_lists *d;
456 struct hlist_node *n;
459 len += snprintf(page + len, PAGE_SIZE - len,
460 "\nreceive list 'rx_sff':\n");
462 /* find receive list for this device */
464 hlist_for_each_entry_rcu(d, n, &rx_dev_list, list) {
465 int i, all_empty = 1;
466 /* check wether at least one list is non-empty */
467 for (i = 0; i < 0x800; i++)
468 if (!hlist_empty(&d->rx_sff[i])) {
474 len = can_print_recv_banner(page, len);
475 for (i = 0; i < 0x800; i++) {
476 if (!hlist_empty(&d->rx_sff[i]) &&
477 len < PAGE_SIZE - 100)
478 len = can_print_rcvlist(page, len,
483 len += snprintf(page + len, PAGE_SIZE - len,
484 " (%s: no entry)\n", DNAME(d->dev));
486 /* exit on end of buffer? */
487 if (len > PAGE_SIZE - 100)
492 len += snprintf(page + len, PAGE_SIZE - len, "\n");
498 static int can_proc_read_rcvlist_eff(char *page, char **start, off_t off,
499 int count, int *eof, void *data)
502 struct dev_rcv_lists *d;
503 struct hlist_node *n;
506 len += snprintf(page + len, PAGE_SIZE - len,
507 "\nreceive list 'rx_eff':\n");
509 /* find receive list for this device */
511 hlist_for_each_entry_rcu(d, n, &rx_dev_list, list) {
513 if (!hlist_empty(&d->rx_eff)) {
514 len = can_print_recv_banner(page, len);
515 len = can_print_rcvlist(page, len, &d->rx_eff, d->dev);
517 len += snprintf(page + len, PAGE_SIZE - len,
518 " (%s: no entry)\n", DNAME(d->dev));
520 /* exit on end of buffer? */
521 if (len > PAGE_SIZE - 100)
526 len += snprintf(page + len, PAGE_SIZE - len, "\n");
532 static int can_proc_read_rcvlist_err(char *page, char **start, off_t off,
533 int count, int *eof, void *data)
536 struct dev_rcv_lists *d;
537 struct hlist_node *n;
540 len += snprintf(page + len, PAGE_SIZE - len,
541 "\nreceive list 'rx_err':\n");
543 /* find receive list for this device */
545 hlist_for_each_entry_rcu(d, n, &rx_dev_list, list) {
547 if (!hlist_empty(&d->rx_err)) {
548 len = can_print_recv_banner(page, len);
549 len = can_print_rcvlist(page, len, &d->rx_err, d->dev);
551 len += snprintf(page + len, PAGE_SIZE - len,
552 " (%s: no entry)\n", DNAME(d->dev));
554 /* exit on end of buffer? */
555 if (len > PAGE_SIZE - 100)
560 len += snprintf(page + len, PAGE_SIZE - len, "\n");
566 /**************************************************/
567 /* proc utility functions */
568 /**************************************************/
570 static struct proc_dir_entry *can_create_proc_readentry(const char *name,
572 read_proc_t* read_proc,
576 return create_proc_read_entry(name, mode, can_dir, read_proc,
582 static void can_remove_proc_readentry(const char *name)
585 remove_proc_entry(name, can_dir);
588 static unsigned long calc_rate(unsigned long oldjif, unsigned long newjif,
591 unsigned long ret = 0;
593 if (oldjif == newjif)
596 /* see can_rcv() - this should NEVER happen! */
597 if (count > (ULONG_MAX / HZ)) {
598 printk(KERN_ERR "CAN: calc_rate: count exceeded! %ld\n",
603 ret = (count * HZ) / (newjif - oldjif);
608 /**************************************************/
609 /* af_can statistics stuff */
610 /**************************************************/
612 static void can_init_stats(int caller)
614 memset(&stats, 0, sizeof(stats));
615 stats.jiffies_init = jiffies;
616 pstats.stats_reset++;
619 static void can_stat_update(unsigned long data)
621 unsigned long j = jiffies; /* snapshot */
623 if (j < stats.jiffies_init) /* jiffies overflow */
626 /* stats.rx_frames is the definitively max. statistic value */
628 /* prevent overflow in calc_rate() */
629 if (stats.rx_frames > (ULONG_MAX / HZ))
632 /* matches overflow - very improbable */
633 if (stats.matches > (ULONG_MAX / 100))
636 /* calc total values */
638 stats.total_rx_match_ratio = (stats.matches * 100) /
641 stats.total_tx_rate = calc_rate(stats.jiffies_init, j,
643 stats.total_rx_rate = calc_rate(stats.jiffies_init, j,
646 /* calc current values */
647 if (stats.rx_frames_delta)
648 stats.current_rx_match_ratio =
649 (stats.matches_delta * 100) / stats.rx_frames_delta;
651 stats.current_tx_rate = calc_rate(0, HZ, stats.tx_frames_delta);
652 stats.current_rx_rate = calc_rate(0, HZ, stats.rx_frames_delta);
654 /* check / update maximum values */
655 if (stats.max_tx_rate < stats.current_tx_rate)
656 stats.max_tx_rate = stats.current_tx_rate;
658 if (stats.max_rx_rate < stats.current_rx_rate)
659 stats.max_rx_rate = stats.current_rx_rate;
661 if (stats.max_rx_match_ratio < stats.current_rx_match_ratio)
662 stats.max_rx_match_ratio = stats.current_rx_match_ratio;
664 /* clear values for 'current rate' calculation */
665 stats.tx_frames_delta = 0;
666 stats.rx_frames_delta = 0;
667 stats.matches_delta = 0;
670 stattimer.expires = jiffies + HZ; /* every second */
671 add_timer(&stattimer);