[PATCH] uml spinlock breakage
[linux-2.6] / drivers / s390 / net / qeth_proc.c
1 /*
2  *
3  * linux/drivers/s390/net/qeth_fs.c ($Revision: 1.13 $)
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.13 $";
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 1;
34 }
35
36 static void *
37 qeth_procfile_seq_start(struct seq_file *s, loff_t *offset)
38 {
39         struct device *dev;
40         loff_t nr;
41
42         down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
43
44         nr = *offset;
45         if (nr == 0)
46                 return SEQ_START_TOKEN;
47
48         dev = driver_find_device(&qeth_ccwgroup_driver.driver, NULL,
49                                  NULL, qeth_procfile_seq_match);
50
51         /* get card at pos *offset */
52         nr = *offset;
53         while (nr-- > 1 && dev)
54                 dev = driver_find_device(&qeth_ccwgroup_driver.driver, dev,
55                                          NULL, qeth_procfile_seq_match);
56         return (void *) dev;
57 }
58
59 static void
60 qeth_procfile_seq_stop(struct seq_file *s, void* it)
61 {
62         up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
63 }
64
65 static void *
66 qeth_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
67 {
68         struct device *prev, *next;
69
70         if (it == SEQ_START_TOKEN) {
71                 next = driver_find_device(&qeth_ccwgroup_driver.driver,
72                                           NULL, NULL, qeth_procfile_seq_match);
73                 if (next)
74                         (*offset)++;
75                 return (void *) next;
76         }
77         prev = (struct device *) it;
78         next = driver_find_device(&qeth_ccwgroup_driver.driver,
79                                   prev, NULL, qeth_procfile_seq_match);
80         if (next)
81                 (*offset)++;
82         return (void *) next;
83 }
84
85 static inline const char *
86 qeth_get_router_str(struct qeth_card *card, int ipv)
87 {
88         int routing_type = 0;
89
90         if (ipv == 4){
91                 routing_type = card->options.route4.type;
92         } else {
93 #ifdef CONFIG_QETH_IPV6
94                 routing_type = card->options.route6.type;
95 #else
96                 return "n/a";
97 #endif /* CONFIG_QETH_IPV6 */
98         }
99
100         if (routing_type == PRIMARY_ROUTER)
101                 return "pri";
102         else if (routing_type == SECONDARY_ROUTER)
103                 return "sec";
104         else if (routing_type == MULTICAST_ROUTER) {
105                 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
106                         return "mc+";
107                 return "mc";
108         } else if (routing_type == PRIMARY_CONNECTOR) {
109                 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
110                         return "p+c";
111                 return "p.c";
112         } else if (routing_type == SECONDARY_CONNECTOR) {
113                 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
114                         return "s+c";
115                 return "s.c";
116         } else if (routing_type == NO_ROUTER)
117                 return "no";
118         else
119                 return "unk";
120 }
121
122 static int
123 qeth_procfile_seq_show(struct seq_file *s, void *it)
124 {
125         struct device *device;
126         struct qeth_card *card;
127         char tmp[12]; /* for qeth_get_prioq_str */
128
129         if (it == SEQ_START_TOKEN){
130                 seq_printf(s, "devices                    CHPID interface  "
131                               "cardtype       port chksum prio-q'ing rtr4 "
132                               "rtr6 fsz   cnt\n");
133                 seq_printf(s, "-------------------------- ----- ---------- "
134                               "-------------- ---- ------ ---------- ---- "
135                               "---- ----- -----\n");
136         } else {
137                 device = (struct device *) it;
138                 card = device->driver_data;
139                 seq_printf(s, "%s/%s/%s x%02X   %-10s %-14s %-4i ",
140                                 CARD_RDEV_ID(card),
141                                 CARD_WDEV_ID(card),
142                                 CARD_DDEV_ID(card),
143                                 card->info.chpid,
144                                 QETH_CARD_IFNAME(card),
145                                 qeth_get_cardname_short(card),
146                                 card->info.portno);
147                 if (card->lan_online)
148                         seq_printf(s, "%-6s %-10s %-4s %-4s %-5s %-5i\n",
149                                         qeth_get_checksum_str(card),
150                                         qeth_get_prioq_str(card, tmp),
151                                         qeth_get_router_str(card, 4),
152                                         qeth_get_router_str(card, 6),
153                                         qeth_get_bufsize_str(card),
154                                         card->qdio.in_buf_pool.buf_count);
155                 else
156                         seq_printf(s, "  +++ LAN OFFLINE +++\n");
157         }
158         return 0;
159 }
160
161 static struct seq_operations qeth_procfile_seq_ops = {
162         .start = qeth_procfile_seq_start,
163         .stop  = qeth_procfile_seq_stop,
164         .next  = qeth_procfile_seq_next,
165         .show  = qeth_procfile_seq_show,
166 };
167
168 static int
169 qeth_procfile_open(struct inode *inode, struct file *file)
170 {
171         return seq_open(file, &qeth_procfile_seq_ops);
172 }
173
174 static struct file_operations qeth_procfile_fops = {
175         .owner   = THIS_MODULE,
176         .open    = qeth_procfile_open,
177         .read    = seq_read,
178         .llseek  = seq_lseek,
179         .release = seq_release,
180 };
181
182 /***** /proc/qeth_perf *****/
183 #define QETH_PERF_PROCFILE_NAME "qeth_perf"
184 static struct proc_dir_entry *qeth_perf_procfile;
185
186 #ifdef CONFIG_QETH_PERF_STATS
187
188 static void *
189 qeth_perf_procfile_seq_start(struct seq_file *s, loff_t *offset)
190 {
191         struct device *dev = NULL;
192         int nr;
193
194         down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
195         /* get card at pos *offset */
196         dev = driver_find_device(&qeth_ccwgroup_driver.driver, NULL, NULL,
197                                  qeth_procfile_seq_match);
198
199         /* get card at pos *offset */
200         nr = *offset;
201         while (nr-- > 1 && dev)
202                 dev = driver_find_device(&qeth_ccwgroup_driver.driver, dev,
203                                          NULL, qeth_procfile_seq_match);
204         return (void *) dev;
205 }
206
207 static void
208 qeth_perf_procfile_seq_stop(struct seq_file *s, void* it)
209 {
210         up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
211 }
212
213 static void *
214 qeth_perf_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
215 {
216         struct device *prev, *next;
217
218         prev = (struct device *) it;
219         next = driver_find_device(&qeth_ccwgroup_driver.driver, prev,
220                                   NULL, qeth_procfile_seq_match);
221         if (next)
222                 (*offset)++;
223         return (void *) next;
224 }
225
226 static int
227 qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
228 {
229         struct device *device;
230         struct qeth_card *card;
231
232         device = (struct device *) it;
233         card = device->driver_data;
234         seq_printf(s, "For card with devnos %s/%s/%s (%s):\n",
235                         CARD_RDEV_ID(card),
236                         CARD_WDEV_ID(card),
237                         CARD_DDEV_ID(card),
238                         QETH_CARD_IFNAME(card)
239                   );
240         seq_printf(s, "  Skb's/buffers received                 : %li/%i\n"
241                       "  Skb's/buffers sent                     : %li/%i\n\n",
242                         card->stats.rx_packets, card->perf_stats.bufs_rec,
243                         card->stats.tx_packets, card->perf_stats.bufs_sent
244                   );
245         seq_printf(s, "  Skb's/buffers sent without packing     : %li/%i\n"
246                       "  Skb's/buffers sent with packing        : %i/%i\n\n",
247                    card->stats.tx_packets - card->perf_stats.skbs_sent_pack,
248                    card->perf_stats.bufs_sent - card->perf_stats.bufs_sent_pack,
249                    card->perf_stats.skbs_sent_pack,
250                    card->perf_stats.bufs_sent_pack
251                   );
252         seq_printf(s, "  Skbs sent in SG mode                   : %i\n"
253                       "  Skb fragments sent in SG mode          : %i\n\n",
254                       card->perf_stats.sg_skbs_sent,
255                       card->perf_stats.sg_frags_sent);
256         seq_printf(s, "  large_send tx (in Kbytes)              : %i\n"
257                       "  large_send count                       : %i\n\n",
258                       card->perf_stats.large_send_bytes >> 10,
259                       card->perf_stats.large_send_cnt);
260         seq_printf(s, "  Packing state changes no pkg.->packing : %i/%i\n"
261                       "  Watermarks L/H                         : %i/%i\n"
262                       "  Current buffer usage (outbound q's)    : "
263                       "%i/%i/%i/%i\n\n",
264                         card->perf_stats.sc_dp_p, card->perf_stats.sc_p_dp,
265                         QETH_LOW_WATERMARK_PACK, QETH_HIGH_WATERMARK_PACK,
266                         atomic_read(&card->qdio.out_qs[0]->used_buffers),
267                         (card->qdio.no_out_queues > 1)?
268                                 atomic_read(&card->qdio.out_qs[1]->used_buffers)
269                                 : 0,
270                         (card->qdio.no_out_queues > 2)?
271                                 atomic_read(&card->qdio.out_qs[2]->used_buffers)
272                                 : 0,
273                         (card->qdio.no_out_queues > 3)?
274                                 atomic_read(&card->qdio.out_qs[3]->used_buffers)
275                                 : 0
276                   );
277         seq_printf(s, "  Inbound handler time (in us)           : %i\n"
278                       "  Inbound handler count                  : %i\n"
279                       "  Inbound do_QDIO time (in us)           : %i\n"
280                       "  Inbound do_QDIO count                  : %i\n\n"
281                       "  Outbound handler time (in us)          : %i\n"
282                       "  Outbound handler count                 : %i\n\n"
283                       "  Outbound time (in us, incl QDIO)       : %i\n"
284                       "  Outbound count                         : %i\n"
285                       "  Outbound do_QDIO time (in us)          : %i\n"
286                       "  Outbound do_QDIO count                 : %i\n\n",
287                         card->perf_stats.inbound_time,
288                         card->perf_stats.inbound_cnt,
289                         card->perf_stats.inbound_do_qdio_time,
290                         card->perf_stats.inbound_do_qdio_cnt,
291                         card->perf_stats.outbound_handler_time,
292                         card->perf_stats.outbound_handler_cnt,
293                         card->perf_stats.outbound_time,
294                         card->perf_stats.outbound_cnt,
295                         card->perf_stats.outbound_do_qdio_time,
296                         card->perf_stats.outbound_do_qdio_cnt
297                   );
298         return 0;
299 }
300
301 static struct seq_operations qeth_perf_procfile_seq_ops = {
302         .start = qeth_perf_procfile_seq_start,
303         .stop  = qeth_perf_procfile_seq_stop,
304         .next  = qeth_perf_procfile_seq_next,
305         .show  = qeth_perf_procfile_seq_show,
306 };
307
308 static int
309 qeth_perf_procfile_open(struct inode *inode, struct file *file)
310 {
311         return seq_open(file, &qeth_perf_procfile_seq_ops);
312 }
313
314 static struct file_operations qeth_perf_procfile_fops = {
315         .owner   = THIS_MODULE,
316         .open    = qeth_perf_procfile_open,
317         .read    = seq_read,
318         .llseek  = seq_lseek,
319         .release = seq_release,
320 };
321
322 #define qeth_perf_procfile_created qeth_perf_procfile
323 #else
324 #define qeth_perf_procfile_created 1
325 #endif /* CONFIG_QETH_PERF_STATS */
326
327 /***** /proc/qeth_ipa_takeover *****/
328 #define QETH_IPATO_PROCFILE_NAME "qeth_ipa_takeover"
329 static struct proc_dir_entry *qeth_ipato_procfile;
330
331 static void *
332 qeth_ipato_procfile_seq_start(struct seq_file *s, loff_t *offset)
333 {
334         struct device *dev;
335         loff_t nr;
336
337         down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
338         /* TODO: finish this */
339         /*
340          * maybe SEQ_SATRT_TOKEN can be returned for offset 0
341          * output driver settings then;
342          * else output setting for respective card
343          */
344
345         dev = driver_find_device(&qeth_ccwgroup_driver.driver, NULL, NULL,
346                                  qeth_procfile_seq_match);
347
348         /* get card at pos *offset */
349         nr = *offset;
350         while (nr-- > 1 && dev)
351                 dev = driver_find_device(&qeth_ccwgroup_driver.driver, dev,
352                                          NULL, qeth_procfile_seq_match);
353         return (void *) dev;
354 }
355
356 static void
357 qeth_ipato_procfile_seq_stop(struct seq_file *s, void* it)
358 {
359         up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
360 }
361
362 static void *
363 qeth_ipato_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
364 {
365         struct device *prev, *next;
366
367         prev = (struct device *) it;
368         next = driver_find_device(&qeth_ccwgroup_driver.driver, prev,
369                                   NULL, qeth_procfile_seq_match);
370         if (next)
371                 (*offset)++;
372         return (void *) next;
373 }
374
375 static int
376 qeth_ipato_procfile_seq_show(struct seq_file *s, void *it)
377 {
378         struct device *device;
379         struct qeth_card *card;
380
381         /* TODO: finish this */
382         /*
383          * maybe SEQ_SATRT_TOKEN can be returned for offset 0
384          * output driver settings then;
385          * else output setting for respective card
386          */
387         device = (struct device *) it;
388         card = device->driver_data;
389
390         return 0;
391 }
392
393 static struct seq_operations qeth_ipato_procfile_seq_ops = {
394         .start = qeth_ipato_procfile_seq_start,
395         .stop  = qeth_ipato_procfile_seq_stop,
396         .next  = qeth_ipato_procfile_seq_next,
397         .show  = qeth_ipato_procfile_seq_show,
398 };
399
400 static int
401 qeth_ipato_procfile_open(struct inode *inode, struct file *file)
402 {
403         return seq_open(file, &qeth_ipato_procfile_seq_ops);
404 }
405
406 static struct file_operations qeth_ipato_procfile_fops = {
407         .owner   = THIS_MODULE,
408         .open    = qeth_ipato_procfile_open,
409         .read    = seq_read,
410         .llseek  = seq_lseek,
411         .release = seq_release,
412 };
413
414 int __init
415 qeth_create_procfs_entries(void)
416 {
417         qeth_procfile = create_proc_entry(QETH_PROCFILE_NAME,
418                                            S_IFREG | 0444, NULL);
419         if (qeth_procfile)
420                 qeth_procfile->proc_fops = &qeth_procfile_fops;
421
422 #ifdef CONFIG_QETH_PERF_STATS
423         qeth_perf_procfile = create_proc_entry(QETH_PERF_PROCFILE_NAME,
424                                            S_IFREG | 0444, NULL);
425         if (qeth_perf_procfile)
426                 qeth_perf_procfile->proc_fops = &qeth_perf_procfile_fops;
427 #endif /* CONFIG_QETH_PERF_STATS */
428
429         qeth_ipato_procfile = create_proc_entry(QETH_IPATO_PROCFILE_NAME,
430                                            S_IFREG | 0444, NULL);
431         if (qeth_ipato_procfile)
432                 qeth_ipato_procfile->proc_fops = &qeth_ipato_procfile_fops;
433
434         if (qeth_procfile &&
435             qeth_ipato_procfile &&
436             qeth_perf_procfile_created)
437                 return 0;
438         else
439                 return -ENOMEM;
440 }
441
442 void __exit
443 qeth_remove_procfs_entries(void)
444 {
445         if (qeth_procfile)
446                 remove_proc_entry(QETH_PROCFILE_NAME, NULL);
447         if (qeth_perf_procfile)
448                 remove_proc_entry(QETH_PERF_PROCFILE_NAME, NULL);
449         if (qeth_ipato_procfile)
450                 remove_proc_entry(QETH_IPATO_PROCFILE_NAME, NULL);
451 }
452
453
454 /* ONLY FOR DEVELOPMENT! -> make it as module */
455 /*
456 static void
457 qeth_create_sysfs_entries(void)
458 {
459         struct device *dev;
460
461         down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
462
463         list_for_each_entry(dev, &qeth_ccwgroup_driver.driver.devices,
464                         driver_list)
465                 qeth_create_device_attributes(dev);
466
467         up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
468 }
469
470 static void
471 qeth_remove_sysfs_entries(void)
472 {
473         struct device *dev;
474
475         down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
476
477         list_for_each_entry(dev, &qeth_ccwgroup_driver.driver.devices,
478                         driver_list)
479                 qeth_remove_device_attributes(dev);
480
481         up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
482 }
483
484 static int __init
485 qeth_fs_init(void)
486 {
487         printk(KERN_INFO "qeth_fs_init\n");
488         qeth_create_procfs_entries();
489         qeth_create_sysfs_entries();
490
491         return 0;
492 }
493
494 static void __exit
495 qeth_fs_exit(void)
496 {
497         printk(KERN_INFO "qeth_fs_exit\n");
498         qeth_remove_procfs_entries();
499         qeth_remove_sysfs_entries();
500 }
501
502
503 module_init(qeth_fs_init);
504 module_exit(qeth_fs_exit);
505
506 MODULE_LICENSE("GPL");
507 */