Merge branch 'origin'
[pandora-kernel.git] / drivers / s390 / net / qeth_proc.c
1 /*
2  *
3  * linux/drivers/s390/net/qeth_fs.c
4  *
5  * Linux on zSeries OSA Express and HiperSockets support
6  * This file contains code related to procfs.
7  *
8  * Copyright 2000,2003 IBM Corporation
9  *
10  * Author(s): Thomas Spatzier <tspat@de.ibm.com>
11  *
12  */
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/proc_fs.h>
16 #include <linux/seq_file.h>
17 #include <linux/list.h>
18 #include <linux/rwsem.h>
19
20 #include "qeth.h"
21 #include "qeth_mpc.h"
22 #include "qeth_fs.h"
23
24 /***** /proc/qeth *****/
25 #define QETH_PROCFILE_NAME "qeth"
26 static struct proc_dir_entry *qeth_procfile;
27
28 static int
29 qeth_procfile_seq_match(struct device *dev, void *data)
30 {
31         return(dev ? 1 : 0);
32 }
33
34 static void *
35 qeth_procfile_seq_start(struct seq_file *s, loff_t *offset)
36 {
37         struct device *dev = NULL;
38         loff_t nr = 0;
39         
40         down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
41         if (*offset == 0)
42                 return SEQ_START_TOKEN;
43         while (1) {
44                 dev = driver_find_device(&qeth_ccwgroup_driver.driver, dev,
45                                          NULL, qeth_procfile_seq_match);
46                 if (++nr == *offset)
47                         break;
48                 put_device(dev);
49         }
50         return dev;
51 }
52
53 static void
54 qeth_procfile_seq_stop(struct seq_file *s, void* it)
55 {
56         up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
57 }
58
59 static void *
60 qeth_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
61 {
62         struct device *prev, *next;
63         
64         if (it == SEQ_START_TOKEN) 
65                 prev = NULL;
66         else
67                 prev = (struct device *) it;
68         next = driver_find_device(&qeth_ccwgroup_driver.driver,
69                                   prev, NULL, qeth_procfile_seq_match);
70         (*offset)++;
71         return (void *) next;
72 }
73
74 static inline const char *
75 qeth_get_router_str(struct qeth_card *card, int ipv)
76 {
77         int routing_type = 0;
78
79         if (ipv == 4) {
80                 routing_type = card->options.route4.type;
81         } else {
82 #ifdef CONFIG_QETH_IPV6
83                 routing_type = card->options.route6.type;
84 #else
85                 return "n/a";
86 #endif /* CONFIG_QETH_IPV6 */
87         }
88
89         if (routing_type == PRIMARY_ROUTER)
90                 return "pri";
91         else if (routing_type == SECONDARY_ROUTER)
92                 return "sec";
93         else if (routing_type == MULTICAST_ROUTER) {
94                 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
95                         return "mc+";
96                 return "mc";
97         } else if (routing_type == PRIMARY_CONNECTOR) {
98                 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
99                         return "p+c";
100                 return "p.c";
101         } else if (routing_type == SECONDARY_CONNECTOR) {
102                 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
103                         return "s+c";
104                 return "s.c";
105         } else if (routing_type == NO_ROUTER)
106                 return "no";
107         else
108                 return "unk";
109 }
110
111 static int
112 qeth_procfile_seq_show(struct seq_file *s, void *it)
113 {
114         struct device *device;
115         struct qeth_card *card;
116         char tmp[12]; /* for qeth_get_prioq_str */
117
118         if (it == SEQ_START_TOKEN){
119                 seq_printf(s, "devices                    CHPID interface  "
120                               "cardtype       port chksum prio-q'ing rtr4 "
121                               "rtr6 fsz   cnt\n");
122                 seq_printf(s, "-------------------------- ----- ---------- "
123                               "-------------- ---- ------ ---------- ---- "
124                               "---- ----- -----\n");
125         } else {
126                 device = (struct device *) it;
127                 card = device->driver_data;
128                 seq_printf(s, "%s/%s/%s x%02X   %-10s %-14s %-4i ",
129                                 CARD_RDEV_ID(card),
130                                 CARD_WDEV_ID(card),
131                                 CARD_DDEV_ID(card),
132                                 card->info.chpid,
133                                 QETH_CARD_IFNAME(card),
134                                 qeth_get_cardname_short(card),
135                                 card->info.portno);
136                 if (card->lan_online)
137                         seq_printf(s, "%-6s %-10s %-4s %-4s %-5s %-5i\n",
138                                         qeth_get_checksum_str(card),
139                                         qeth_get_prioq_str(card, tmp),
140                                         qeth_get_router_str(card, 4),
141                                         qeth_get_router_str(card, 6),
142                                         qeth_get_bufsize_str(card),
143                                         card->qdio.in_buf_pool.buf_count);
144                 else
145                         seq_printf(s, "  +++ LAN OFFLINE +++\n");
146                 put_device(device);
147         }
148         return 0;
149 }
150
151 static struct seq_operations qeth_procfile_seq_ops = {
152         .start = qeth_procfile_seq_start,
153         .stop  = qeth_procfile_seq_stop,
154         .next  = qeth_procfile_seq_next,
155         .show  = qeth_procfile_seq_show,
156 };
157
158 static int
159 qeth_procfile_open(struct inode *inode, struct file *file)
160 {
161         return seq_open(file, &qeth_procfile_seq_ops);
162 }
163
164 static struct file_operations qeth_procfile_fops = {
165         .owner   = THIS_MODULE,
166         .open    = qeth_procfile_open,
167         .read    = seq_read,
168         .llseek  = seq_lseek,
169         .release = seq_release,
170 };
171
172 /***** /proc/qeth_perf *****/
173 #define QETH_PERF_PROCFILE_NAME "qeth_perf"
174 static struct proc_dir_entry *qeth_perf_procfile;
175
176 #ifdef CONFIG_QETH_PERF_STATS
177 static int
178 qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
179 {
180         struct device *device;
181         struct qeth_card *card;
182
183         
184         if (it == SEQ_START_TOKEN)
185                 return 0;
186
187         device = (struct device *) it;
188         card = device->driver_data;
189         seq_printf(s, "For card with devnos %s/%s/%s (%s):\n",
190                         CARD_RDEV_ID(card),
191                         CARD_WDEV_ID(card),
192                         CARD_DDEV_ID(card),
193                         QETH_CARD_IFNAME(card)
194                   );
195         seq_printf(s, "  Skb's/buffers received                 : %li/%i\n"
196                       "  Skb's/buffers sent                     : %li/%i\n\n",
197                         card->stats.rx_packets, card->perf_stats.bufs_rec,
198                         card->stats.tx_packets, card->perf_stats.bufs_sent
199                   );
200         seq_printf(s, "  Skb's/buffers sent without packing     : %li/%i\n"
201                       "  Skb's/buffers sent with packing        : %i/%i\n\n",
202                    card->stats.tx_packets - card->perf_stats.skbs_sent_pack,
203                    card->perf_stats.bufs_sent - card->perf_stats.bufs_sent_pack,
204                    card->perf_stats.skbs_sent_pack,
205                    card->perf_stats.bufs_sent_pack
206                   );
207         seq_printf(s, "  Skbs sent in SG mode                   : %i\n"
208                       "  Skb fragments sent in SG mode          : %i\n\n",
209                       card->perf_stats.sg_skbs_sent,
210                       card->perf_stats.sg_frags_sent);
211         seq_printf(s, "  large_send tx (in Kbytes)              : %i\n"
212                       "  large_send count                       : %i\n\n",
213                       card->perf_stats.large_send_bytes >> 10,
214                       card->perf_stats.large_send_cnt);
215         seq_printf(s, "  Packing state changes no pkg.->packing : %i/%i\n"
216                       "  Watermarks L/H                         : %i/%i\n"
217                       "  Current buffer usage (outbound q's)    : "
218                       "%i/%i/%i/%i\n\n",
219                         card->perf_stats.sc_dp_p, card->perf_stats.sc_p_dp,
220                         QETH_LOW_WATERMARK_PACK, QETH_HIGH_WATERMARK_PACK,
221                         atomic_read(&card->qdio.out_qs[0]->used_buffers),
222                         (card->qdio.no_out_queues > 1)?
223                                 atomic_read(&card->qdio.out_qs[1]->used_buffers)
224                                 : 0,
225                         (card->qdio.no_out_queues > 2)?
226                                 atomic_read(&card->qdio.out_qs[2]->used_buffers)
227                                 : 0,
228                         (card->qdio.no_out_queues > 3)?
229                                 atomic_read(&card->qdio.out_qs[3]->used_buffers)
230                                 : 0
231                   );
232         seq_printf(s, "  Inbound handler time (in us)           : %i\n"
233                       "  Inbound handler count                  : %i\n"
234                       "  Inbound do_QDIO time (in us)           : %i\n"
235                       "  Inbound do_QDIO count                  : %i\n\n"
236                       "  Outbound handler time (in us)          : %i\n"
237                       "  Outbound handler count                 : %i\n\n"
238                       "  Outbound time (in us, incl QDIO)       : %i\n"
239                       "  Outbound count                         : %i\n"
240                       "  Outbound do_QDIO time (in us)          : %i\n"
241                       "  Outbound do_QDIO count                 : %i\n\n",
242                         card->perf_stats.inbound_time,
243                         card->perf_stats.inbound_cnt,
244                         card->perf_stats.inbound_do_qdio_time,
245                         card->perf_stats.inbound_do_qdio_cnt,
246                         card->perf_stats.outbound_handler_time,
247                         card->perf_stats.outbound_handler_cnt,
248                         card->perf_stats.outbound_time,
249                         card->perf_stats.outbound_cnt,
250                         card->perf_stats.outbound_do_qdio_time,
251                         card->perf_stats.outbound_do_qdio_cnt
252                   );
253         put_device(device);
254         return 0;
255 }
256
257 static struct seq_operations qeth_perf_procfile_seq_ops = {
258         .start = qeth_procfile_seq_start,
259         .stop  = qeth_procfile_seq_stop,
260         .next  = qeth_procfile_seq_next,
261         .show  = qeth_perf_procfile_seq_show,
262 };
263
264 static int
265 qeth_perf_procfile_open(struct inode *inode, struct file *file)
266 {
267         return seq_open(file, &qeth_perf_procfile_seq_ops);
268 }
269
270 static struct file_operations qeth_perf_procfile_fops = {
271         .owner   = THIS_MODULE,
272         .open    = qeth_perf_procfile_open,
273         .read    = seq_read,
274         .llseek  = seq_lseek,
275         .release = seq_release,
276 };
277
278 #define qeth_perf_procfile_created qeth_perf_procfile
279 #else
280 #define qeth_perf_procfile_created 1
281 #endif /* CONFIG_QETH_PERF_STATS */
282
283 int __init
284 qeth_create_procfs_entries(void)
285 {
286         qeth_procfile = create_proc_entry(QETH_PROCFILE_NAME,
287                                            S_IFREG | 0444, NULL);
288         if (qeth_procfile)
289                 qeth_procfile->proc_fops = &qeth_procfile_fops;
290
291 #ifdef CONFIG_QETH_PERF_STATS
292         qeth_perf_procfile = create_proc_entry(QETH_PERF_PROCFILE_NAME,
293                                            S_IFREG | 0444, NULL);
294         if (qeth_perf_procfile)
295                 qeth_perf_procfile->proc_fops = &qeth_perf_procfile_fops;
296 #endif /* CONFIG_QETH_PERF_STATS */
297
298         if (qeth_procfile &&
299             qeth_perf_procfile_created)
300                 return 0;
301         else
302                 return -ENOMEM;
303 }
304
305 void __exit
306 qeth_remove_procfs_entries(void)
307 {
308         if (qeth_procfile)
309                 remove_proc_entry(QETH_PROCFILE_NAME, NULL);
310         if (qeth_perf_procfile)
311                 remove_proc_entry(QETH_PERF_PROCFILE_NAME, NULL);
312 }
313