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