]> rtime.felk.cvut.cz Git - socketcan-devel.git/blob - kernel/2.6/net/can/proc.c
* Rearrange 2.6 subtree for a better compatibility with the vanilla kernel.
[socketcan-devel.git] / kernel / 2.6 / net / can / proc.c
1 /*
2  * af_can_proc.c
3  *
4  * Copyright (c) 2002-2005 Volkswagen Group Electronic Research
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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.
19  *
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.
24  *
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.
27  *
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
39  * DAMAGE.
40  *
41  * Send feedback to <llcf@volkswagen.de>
42  *
43  */
44
45 #include <linux/module.h>
46 #include <linux/proc_fs.h>
47
48 #include <net/can/af_can.h>
49 #include <net/can/version.h>
50
51 RCSID("$Id: proc.c,v 2.0 2006/04/13 10:37:19 ethuerm Exp $");
52
53 /* proc filenames */
54
55 #define CAN_PROC_VERSION     "version"
56 #define CAN_PROC_STATS       "stats"
57 #define CAN_PROC_RESET_STATS "reset_stats"
58 #define CAN_PROC_RCVLIST_ALL "rcvlist_all"
59 #define CAN_PROC_RCVLIST_FIL "rcvlist_fil"
60 #define CAN_PROC_RCVLIST_INV "rcvlist_inv"
61 #define CAN_PROC_RCVLIST_SFF "rcvlist_sff"
62 #define CAN_PROC_RCVLIST_EFF "rcvlist_eff"
63
64 static void can_init_stats(int caller);
65 static void can_stat_update(unsigned long data);
66
67 static struct proc_dir_entry *can_create_proc_read_entry(const char *name, mode_t mode, read_proc_t* read_proc, void *data);
68 static void can_remove_proc_entry(const char *name);
69 static unsigned long calc_rate(unsigned long oldjif, unsigned long newjif, unsigned long count);
70
71 static int can_proc_read_version(char *page, char **start, off_t off, int count, int *eof, void *data);
72 static int can_proc_read_stats(char *page, char **start, off_t off, int count, int *eof, void *data);
73 static int can_proc_read_reset_stats(char *page, char **start, off_t off, int count, int *eof, void *data);
74 static int can_proc_read_rcvlist_all(char *page, char **start, off_t off, int count, int *eof, void *data);
75 static int can_proc_read_rcvlist_fil(char *page, char **start, off_t off, int count, int *eof, void *data);
76 static int can_proc_read_rcvlist_inv(char *page, char **start, off_t off, int count, int *eof, void *data);
77 static int can_proc_read_rcvlist_sff(char *page, char **start, off_t off, int count, int *eof, void *data);
78 static int can_proc_read_rcvlist_eff(char *page, char **start, off_t off, int count, int *eof, void *data);
79
80 static struct proc_dir_entry *can_dir         = NULL;
81 static struct proc_dir_entry *pde_version     = NULL;
82 static struct proc_dir_entry *pde_stats       = NULL;
83 static struct proc_dir_entry *pde_reset_stats = NULL;
84 static struct proc_dir_entry *pde_rcvlist_all = NULL;
85 static struct proc_dir_entry *pde_rcvlist_fil = NULL;
86 static struct proc_dir_entry *pde_rcvlist_inv = NULL;
87 static struct proc_dir_entry *pde_rcvlist_sff = NULL;
88 static struct proc_dir_entry *pde_rcvlist_eff = NULL;
89
90 struct timer_list stattimer; /* timer for statistics update */
91
92 struct s_stats  stats; /* statistics */
93 struct s_pstats pstats;
94
95 extern struct rcv_dev_list *rx_dev_list; /* rx dispatcher structures */
96 extern int stats_timer;                  /* module parameter. default: on */
97
98 /**************************************************/
99 /* procfs init / remove                           */
100 /**************************************************/
101
102 void can_init_proc(void)
103 {
104
105     /* procfs init */
106
107     /* create /proc/can directory */
108     can_dir = proc_mkdir(CAN_PROC_DIR, NULL);
109
110     if (can_dir) {
111
112         can_dir->owner = THIS_MODULE;
113
114         /* own procfs entries from the AF_CAN core */
115         pde_version     = can_create_proc_read_entry(CAN_PROC_VERSION, 0644, can_proc_read_version, NULL);
116         pde_stats       = can_create_proc_read_entry(CAN_PROC_STATS, 0644, can_proc_read_stats, NULL);
117         pde_reset_stats = can_create_proc_read_entry(CAN_PROC_RESET_STATS, 0644, can_proc_read_reset_stats, NULL);
118         pde_rcvlist_all = can_create_proc_read_entry(CAN_PROC_RCVLIST_ALL, 0644, can_proc_read_rcvlist_all, NULL);
119         pde_rcvlist_fil = can_create_proc_read_entry(CAN_PROC_RCVLIST_FIL, 0644, can_proc_read_rcvlist_fil, NULL);
120         pde_rcvlist_inv = can_create_proc_read_entry(CAN_PROC_RCVLIST_INV, 0644, can_proc_read_rcvlist_inv, NULL);
121         pde_rcvlist_sff = can_create_proc_read_entry(CAN_PROC_RCVLIST_SFF, 0644, can_proc_read_rcvlist_sff, NULL);
122         pde_rcvlist_eff = can_create_proc_read_entry(CAN_PROC_RCVLIST_EFF, 0644, can_proc_read_rcvlist_eff, NULL);
123
124         if (stats_timer) {
125             /* the statistics are updated every second (timer triggered) */
126             stattimer.function = can_stat_update;
127             stattimer.data = 0;
128             stattimer.expires = jiffies + HZ; /* every second */
129             add_timer(&stattimer); /* start statistics timer */
130         }
131     } else
132         printk(KERN_INFO "af_can: failed to create CAN_PROC_DIR. CONFIG_PROC_FS missing?\n");
133 }
134
135 void can_remove_proc(void)
136 {
137     /* procfs remove */
138     if (pde_version) {
139         can_remove_proc_entry(CAN_PROC_VERSION);
140     }
141
142     if (pde_stats) {
143         can_remove_proc_entry(CAN_PROC_STATS);
144     }
145
146     if (pde_reset_stats) {
147         can_remove_proc_entry(CAN_PROC_RESET_STATS);
148     }
149
150     if (pde_rcvlist_all) {
151         can_remove_proc_entry(CAN_PROC_RCVLIST_ALL);
152     }
153
154     if (pde_rcvlist_fil) {
155         can_remove_proc_entry(CAN_PROC_RCVLIST_FIL);
156     }
157
158     if (pde_rcvlist_inv) {
159         can_remove_proc_entry(CAN_PROC_RCVLIST_INV);
160     }
161
162     if (pde_rcvlist_sff) {
163         can_remove_proc_entry(CAN_PROC_RCVLIST_SFF);
164     }
165
166     if (pde_rcvlist_eff) {
167         can_remove_proc_entry(CAN_PROC_RCVLIST_EFF);
168     }
169
170     if (can_dir) {
171         remove_proc_entry(CAN_PROC_DIR, NULL);
172     }
173 }
174
175 /**************************************************/
176 /* proc read functions                            */
177 /**************************************************/
178
179 int can_print_recv_list(char *page, int len, struct rcv_list *rx_list, struct net_device *dev)
180 {
181     struct rcv_list *p;
182
183     if (rx_list) {
184         for (p = rx_list; p; p = p->next) {
185
186             /*                             can1.  00000000  00000000  00000000  .......0  tp20 */
187             if (p->can_id & CAN_EFF_FLAG) /* EFF & CAN_ID_ALL */
188                 len += snprintf(page + len, PAGE_SIZE - len, "   %-5s  %08X  %08x  %08x  %08x  %8ld  %s\n",
189                                dev->name, p->can_id, p->mask, (unsigned int)p->func,
190                                (unsigned int)p->data, p->matches, p->ident);
191             else
192                 len += snprintf(page + len, PAGE_SIZE - len, "   %-5s     %03X    %08x  %08x  %08x  %8ld  %s\n",
193                                dev->name, p->can_id, p->mask, (unsigned int)p->func,
194                                (unsigned int)p->data, p->matches, p->ident);
195
196             /* does a typical line fit into the current buffer? */
197             if (len > PAGE_SIZE - 100) { /* 100 Bytes before end of buffer */
198                 len += snprintf(page + len, PAGE_SIZE - len, "   (..)\n"); /* mark output cutted off */
199                 return len;
200             }
201         }
202     }
203
204     return len;
205 }
206
207 static int can_print_recv_banner(char *page, int len)
208 {
209     /*                  can1.  00000000  00000000  00000000  .......0  tp20 */
210     len += snprintf(page + len, PAGE_SIZE - len,
211                     "  device   can_id   can_mask  function  userdata   matches  ident\n");
212
213     return len;
214 }
215
216 int can_proc_read_stats(char *page, char **start, off_t off, int count, int *eof, void *data)
217 {
218     int len = 0;
219
220     len += snprintf(page + len, PAGE_SIZE - len, "\n");
221     len += snprintf(page + len, PAGE_SIZE - len, " %8ld transmitted frames (TXF)\n",
222                     stats.tx_frames);
223     len += snprintf(page + len, PAGE_SIZE - len, " %8ld received frames (RXF)\n",
224                     stats.rx_frames);
225     len += snprintf(page + len, PAGE_SIZE - len, " %8ld matched frames (RXMF)\n",
226                     stats.matches);
227
228     len += snprintf(page + len, PAGE_SIZE - len, "\n");
229
230     len += snprintf(page + len, PAGE_SIZE - len, " %8ld %% total match ratio (RXMR)\n",
231                     stats.total_rx_match_ratio);
232
233     len += snprintf(page + len, PAGE_SIZE - len, " %8ld frames/s total tx rate (TXR)\n",
234                     stats.total_tx_rate);
235     len += snprintf(page + len, PAGE_SIZE - len, " %8ld frames/s total rx rate (RXR)\n",
236                     stats.total_rx_rate);
237
238     len += snprintf(page + len, PAGE_SIZE - len, "\n");
239
240     len += snprintf(page + len, PAGE_SIZE - len, " %8ld %% current match ratio (CRXMR)\n",
241                     stats.current_rx_match_ratio);
242
243     len += snprintf(page + len, PAGE_SIZE - len, " %8ld frames/s current tx rate (CTXR)\n",
244                     stats.current_tx_rate);
245     len += snprintf(page + len, PAGE_SIZE - len, " %8ld frames/s current rx rate (CRXR)\n",
246                     stats.current_rx_rate);
247
248     len += snprintf(page + len, PAGE_SIZE - len, "\n");
249
250     len += snprintf(page + len, PAGE_SIZE - len, " %8ld %% max match ratio (MRXMR)\n",
251                     stats.max_rx_match_ratio);
252
253     len += snprintf(page + len, PAGE_SIZE - len, " %8ld frames/s max tx rate (MTXR)\n",
254                     stats.max_tx_rate);
255     len += snprintf(page + len, PAGE_SIZE - len, " %8ld frames/s max rx rate (MRXR)\n",
256                     stats.max_rx_rate);
257
258     len += snprintf(page + len, PAGE_SIZE - len, "\n");
259
260     len += snprintf(page + len, PAGE_SIZE - len, " %8ld current receive list entries (CRCV)\n", pstats.rcv_entries);
261     len += snprintf(page + len, PAGE_SIZE - len, " %8ld maximum receive list entries (MRCV)\n", pstats.rcv_entries_max);
262
263     if (pstats.stats_reset)
264         len += snprintf(page + len, PAGE_SIZE - len, "\n %8ld statistic resets (STR)\n", pstats.stats_reset);
265
266     len += snprintf(page + len, PAGE_SIZE - len, "\n");
267
268     *eof = 1;
269     return len;
270 }
271
272 int can_proc_read_reset_stats(char *page, char **start, off_t off, int count, int *eof, void *data)
273 {
274     int len = 0;
275
276     can_init_stats(1);
277
278     len += snprintf(page + len, PAGE_SIZE - len, "CAN statistic reset #%ld done.\n", pstats.stats_reset);
279
280     *eof = 1;
281     return len;
282 }
283
284 int can_proc_read_version(char *page, char **start, off_t off, int count, int *eof, void *data)
285 {
286     int len = 0;
287
288     len += snprintf(page + len, PAGE_SIZE - len,
289                     "%06X [ Volkswagen AG - Low Level CAN Framework (LLCF) v%s ]\n",
290                     LLCF_VERSION_CODE, VERSION);
291
292     *eof = 1;
293     return len;
294 }
295
296 int can_proc_read_rcvlist_all(char *page, char **start, off_t off, int count, int *eof, void *data)
297 {
298     int len = 0;
299     struct rcv_dev_list *p;
300
301     /* RX_ALL */
302     len += snprintf(page + len, PAGE_SIZE - len, "\nreceive list 'rx_all':\n");
303
304     /* find receive list for this device */
305     for (p = rx_dev_list; p; p = p->next) {
306
307         if (p->rx_all) {
308             len = can_print_recv_banner(page, len);
309             len = can_print_recv_list(page, len, p->rx_all, p->dev);
310         } else
311             if (p->dev)
312                 len += snprintf(page + len, PAGE_SIZE - len, "  (%s: no entry)\n", p->dev->name);
313     }
314
315     len += snprintf(page + len, PAGE_SIZE - len, "\n");
316
317     *eof = 1;
318     return len;
319 }
320
321 int can_proc_read_rcvlist_fil(char *page, char **start, off_t off, int count, int *eof, void *data)
322 {
323     int len = 0;
324     struct rcv_dev_list *p;
325
326     /* RX_FIL */
327     len += snprintf(page + len, PAGE_SIZE - len, "\nreceive list 'rx_fil':\n");
328
329     /* find receive list for this device */
330     for (p = rx_dev_list; p; p = p->next) {
331
332         if (p->rx_fil) {
333             len = can_print_recv_banner(page, len);
334             len = can_print_recv_list(page, len, p->rx_fil, p->dev);
335         } else
336             if (p->dev)
337                 len += snprintf(page + len, PAGE_SIZE - len, "  (%s: no entry)\n", p->dev->name);
338     }
339
340     len += snprintf(page + len, PAGE_SIZE - len, "\n");
341
342     *eof = 1;
343     return len;
344 }
345
346 int can_proc_read_rcvlist_inv(char *page, char **start, off_t off, int count, int *eof, void *data)
347 {
348     int len = 0;
349     struct rcv_dev_list *p;
350
351     /* RX_INV */
352     len += snprintf(page + len, PAGE_SIZE - len, "\nreceive list 'rx_inv':\n");
353
354     /* find receive list for this device */
355     for (p = rx_dev_list; p; p = p->next) {
356
357         if (p->rx_inv) {
358             len = can_print_recv_banner(page, len);
359             len = can_print_recv_list(page, len, p->rx_inv, p->dev);
360         } else
361             if (p->dev)
362                 len += snprintf(page + len, PAGE_SIZE - len, "  (%s: no entry)\n", p->dev->name);
363     }
364
365     len += snprintf(page + len, PAGE_SIZE - len, "\n");
366
367     *eof = 1;
368     return len;
369 }
370
371 int can_proc_read_rcvlist_sff(char *page, char **start, off_t off, int count, int *eof, void *data)
372 {
373     int len = 0;
374     unsigned long id = 0;
375     int i;
376     struct rcv_dev_list *p;
377
378     /* RX_SFF */
379     len += snprintf(page + len, PAGE_SIZE - len, "\nreceive list 'rx_sff':\n");
380
381     /* find receive list for this device */
382     for (p = rx_dev_list; p; p = p->next) {
383
384         for(i=0; i<0x800; i++)
385             id |= (unsigned long) p->rx_sff[i]; /* check if any entry available */
386
387         if (id) {
388             len = can_print_recv_banner(page, len);
389             for(i=0; i<0x800; i++) {
390                 if ((p->rx_sff[i]) && (len < PAGE_SIZE - 100))
391                     len = can_print_recv_list(page, len, p->rx_sff[i], p->dev);
392             }
393         } else
394             if (p->dev)
395                 len += snprintf(page + len, PAGE_SIZE - len, "  (%s: no entry)\n", p->dev->name);
396     }
397
398     len += snprintf(page + len, PAGE_SIZE - len, "\n");
399
400     *eof = 1;
401     return len;
402 }
403
404 int can_proc_read_rcvlist_eff(char *page, char **start, off_t off, int count, int *eof, void *data)
405 {
406     int len = 0;
407     struct rcv_dev_list *p;
408
409     /* RX_EFF */
410     len += snprintf(page + len, PAGE_SIZE - len, "\nreceive list 'rx_eff':\n");
411
412     /* find receive list for this device */
413     for (p = rx_dev_list; p; p = p->next) {
414
415         if (p->rx_eff) {
416             len = can_print_recv_banner(page, len);
417             len = can_print_recv_list(page, len, p->rx_eff, p->dev);
418         } else
419             if (p->dev)
420                 len += snprintf(page + len, PAGE_SIZE - len, "  (%s: no entry)\n", p->dev->name);
421     }
422
423     len += snprintf(page + len, PAGE_SIZE - len, "\n");
424
425     *eof = 1;
426     return len;
427 }
428
429 /**************************************************/
430 /* proc utility functions                         */
431 /**************************************************/
432
433 static struct proc_dir_entry *can_create_proc_read_entry(const char *name, mode_t mode, read_proc_t* read_proc, void *data)
434 {
435     if (can_dir)
436         return create_proc_read_entry(name, mode, can_dir, read_proc, data);
437     else
438         return NULL;
439 }
440
441 static void can_remove_proc_entry(const char *name)
442 {
443     if (can_dir)
444         remove_proc_entry(name, can_dir);
445 }
446
447 static unsigned long calc_rate(unsigned long oldjif, unsigned long newjif, unsigned long count){
448
449     unsigned long ret = 0;
450
451     if (oldjif == newjif)
452         return 0;
453
454     if (count > (ULONG_MAX / HZ)) { /* see can_rcv() - this should NEVER happen! */
455         printk(KERN_ERR "af_can: calc_rate: count exceeded! %ld\n", count);
456         return 99999999;
457     }
458
459     ret = ((count * HZ) / (newjif - oldjif));
460
461     return ret;
462 };
463
464 /**************************************************/
465 /* af_can statistics stuff                        */
466 /**************************************************/
467
468 static void can_init_stats(int caller){
469
470     memset(&stats, 0, sizeof(stats));
471     stats.jiffies_init  = jiffies;
472     pstats.stats_reset++;
473 };
474
475 static void can_stat_update(unsigned long data){
476
477     unsigned long j = jiffies; /* snapshot */
478
479     //DBG("af_can: can_stat_update() jiffies = %ld\n", j);
480
481     if (j < stats.jiffies_init) /* jiffies overflow */
482         can_init_stats(2);
483
484     /* stats.rx_frames is the definitively max. statistic value */
485     if (stats.rx_frames > (ULONG_MAX / HZ)) /* prevent overflow in calc_rate() */
486         can_init_stats(3); /* restart */
487
488     if (stats.matches > (ULONG_MAX / 100)) /* matches overflow - very improbable */
489         can_init_stats(4);
490
491     /* calc total values */
492     if (stats.rx_frames)
493          stats.total_rx_match_ratio = (stats.matches * 100) / stats.rx_frames;
494
495     stats.total_tx_rate = calc_rate(stats.jiffies_init, j, stats.tx_frames);
496     stats.total_rx_rate = calc_rate(stats.jiffies_init, j, stats.rx_frames);
497
498     /* calc current values */
499     if (stats.rx_frames_delta)
500         stats.current_rx_match_ratio = (stats.matches_delta * 100) / stats.rx_frames_delta;
501
502     stats.current_tx_rate = calc_rate(0, HZ, stats.tx_frames_delta);
503     stats.current_rx_rate = calc_rate(0, HZ, stats.rx_frames_delta);
504
505     /* check / update maximum values */
506     if (stats.max_tx_rate < stats.current_tx_rate)
507         stats.max_tx_rate = stats.current_tx_rate;
508
509     if (stats.max_rx_rate < stats.current_rx_rate)
510         stats.max_rx_rate = stats.current_rx_rate;
511
512     if (stats.max_rx_match_ratio < stats.current_rx_match_ratio)
513         stats.max_rx_match_ratio = stats.current_rx_match_ratio;
514
515     /* clear values for 'current rate' calculation */
516     stats.tx_frames_delta = 0;
517     stats.rx_frames_delta = 0;
518     stats.matches_delta   = 0;
519
520     /* restart timer */
521     stattimer.expires = jiffies + HZ; /* every second */
522     add_timer(&stattimer);
523 };
524
525 /**************************************************/
526 /* EOF                                            */
527 /**************************************************/