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