blob: f2ccfea8fdb89cabe2bf65a7885c3fbcde3b4798 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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
24const char *VERSION_QETH_PROC_C = "$Revision: 1.13 $";
25
26/***** /proc/qeth *****/
27#define QETH_PROCFILE_NAME "qeth"
28static struct proc_dir_entry *qeth_procfile;
29
Cornelia Huck66aea232005-08-08 09:22:36 -070030static int
31qeth_procfile_seq_match(struct device *dev, void *data)
32{
33 return 1;
34}
35
Linus Torvalds1da177e2005-04-16 15:20:36 -070036static void *
37qeth_procfile_seq_start(struct seq_file *s, loff_t *offset)
38{
Cornelia Huck66aea232005-08-08 09:22:36 -070039 struct device *dev;
40 loff_t nr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42 down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
43
Cornelia Huck66aea232005-08-08 09:22:36 -070044 nr = *offset;
45 if (nr == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 return SEQ_START_TOKEN;
47
Cornelia Huck66aea232005-08-08 09:22:36 -070048 dev = driver_find_device(&qeth_ccwgroup_driver.driver, NULL,
49 NULL, qeth_procfile_seq_match);
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
Cornelia Huck66aea232005-08-08 09:22:36 -070051 /* 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -070057}
58
59static void
60qeth_procfile_seq_stop(struct seq_file *s, void* it)
61{
62 up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
63}
64
65static void *
66qeth_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
67{
Cornelia Huck66aea232005-08-08 09:22:36 -070068 struct device *prev, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
70 if (it == SEQ_START_TOKEN) {
Cornelia Huck66aea232005-08-08 09:22:36 -070071 next = driver_find_device(&qeth_ccwgroup_driver.driver,
72 NULL, NULL, qeth_procfile_seq_match);
73 if (next)
74 (*offset)++;
75 return (void *) next;
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 }
Cornelia Huck66aea232005-08-08 09:22:36 -070077 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083}
84
85static inline const char *
86qeth_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
122static int
123qeth_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 {
Cornelia Huck66aea232005-08-08 09:22:36 -0700137 device = (struct device *) it;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 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
161static 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
168static int
169qeth_procfile_open(struct inode *inode, struct file *file)
170{
171 return seq_open(file, &qeth_procfile_seq_ops);
172}
173
174static 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"
184static struct proc_dir_entry *qeth_perf_procfile;
185
186#ifdef CONFIG_QETH_PERF_STATS
187
188static void *
189qeth_perf_procfile_seq_start(struct seq_file *s, loff_t *offset)
190{
Cornelia Huck66aea232005-08-08 09:22:36 -0700191 struct device *dev = NULL;
192 int nr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
194 down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
195 /* get card at pos *offset */
Cornelia Huck66aea232005-08-08 09:22:36 -0700196 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205}
206
207static void
208qeth_perf_procfile_seq_stop(struct seq_file *s, void* it)
209{
210 up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
211}
212
213static void *
214qeth_perf_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
215{
Cornelia Huck66aea232005-08-08 09:22:36 -0700216 struct device *prev, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
Cornelia Huck66aea232005-08-08 09:22:36 -0700218 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224}
225
226static int
227qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
228{
229 struct device *device;
230 struct qeth_card *card;
231
Cornelia Huck66aea232005-08-08 09:22:36 -0700232 device = (struct device *) it;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 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
301static 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
308static int
309qeth_perf_procfile_open(struct inode *inode, struct file *file)
310{
311 return seq_open(file, &qeth_perf_procfile_seq_ops);
312}
313
314static 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"
329static struct proc_dir_entry *qeth_ipato_procfile;
330
331static void *
332qeth_ipato_procfile_seq_start(struct seq_file *s, loff_t *offset)
333{
Cornelia Huck66aea232005-08-08 09:22:36 -0700334 struct device *dev;
335 loff_t nr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
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 */
Cornelia Huck66aea232005-08-08 09:22:36 -0700344
345 dev = driver_find_device(&qeth_ccwgroup_driver.driver, NULL, NULL,
346 qeth_procfile_seq_match);
347
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 /* get card at pos *offset */
Cornelia Huck66aea232005-08-08 09:22:36 -0700349 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354}
355
356static void
357qeth_ipato_procfile_seq_stop(struct seq_file *s, void* it)
358{
359 up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
360}
361
362static void *
363qeth_ipato_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
364{
Cornelia Huck66aea232005-08-08 09:22:36 -0700365 struct device *prev, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
Cornelia Huck66aea232005-08-08 09:22:36 -0700367 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373}
374
375static int
376qeth_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 */
Cornelia Huck66aea232005-08-08 09:22:36 -0700387 device = (struct device *) it;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 card = device->driver_data;
389
390 return 0;
391}
392
393static 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
400static int
401qeth_ipato_procfile_open(struct inode *inode, struct file *file)
402{
403 return seq_open(file, &qeth_ipato_procfile_seq_ops);
404}
405
406static 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
414int __init
415qeth_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
442void __exit
443qeth_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/*
456static void
457qeth_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
470static void
471qeth_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
484static int __init
485qeth_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
494static void __exit
495qeth_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
503module_init(qeth_fs_init);
504module_exit(qeth_fs_exit);
505
506MODULE_LICENSE("GPL");
507*/