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