3 * linux/drivers/s390/net/qeth_fs.c ($Revision: 1.13 $)
5 * Linux on zSeries OSA Express and HiperSockets support
6 * This file contains code related to procfs.
8 * Copyright 2000,2003 IBM Corporation
10 * Author(s): Thomas Spatzier <tspat@de.ibm.com>
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>
24 const char *VERSION_QETH_PROC_C
= "$Revision: 1.13 $";
26 /***** /proc/qeth *****/
27 #define QETH_PROCFILE_NAME "qeth"
28 static struct proc_dir_entry
*qeth_procfile
;
31 qeth_procfile_seq_start(struct seq_file
*s
, loff_t
*offset
)
33 struct list_head
*next_card
= NULL
;
36 down_read(&qeth_ccwgroup_driver
.driver
.bus
->subsys
.rwsem
);
39 return SEQ_START_TOKEN
;
41 /* get card at pos *offset */
42 list_for_each(next_card
, &qeth_ccwgroup_driver
.driver
.devices
)
50 qeth_procfile_seq_stop(struct seq_file
*s
, void* it
)
52 up_read(&qeth_ccwgroup_driver
.driver
.bus
->subsys
.rwsem
);
56 qeth_procfile_seq_next(struct seq_file
*s
, void *it
, loff_t
*offset
)
58 struct list_head
*next_card
= NULL
;
59 struct list_head
*current_card
;
61 if (it
== SEQ_START_TOKEN
) {
62 next_card
= qeth_ccwgroup_driver
.driver
.devices
.next
;
63 if (next_card
->next
== next_card
) /* list empty */
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
;
77 static inline const char *
78 qeth_get_router_str(struct qeth_card
*card
, int ipv
)
83 routing_type
= card
->options
.route4
.type
;
85 #ifdef CONFIG_QETH_IPV6
86 routing_type
= card
->options
.route6
.type
;
89 #endif /* CONFIG_QETH_IPV6 */
92 if (routing_type
== PRIMARY_ROUTER
)
94 else if (routing_type
== SECONDARY_ROUTER
)
96 else if (routing_type
== MULTICAST_ROUTER
) {
97 if (card
->info
.broadcast_capable
== QETH_BROADCAST_WITHOUT_ECHO
)
100 } else if (routing_type
== PRIMARY_CONNECTOR
) {
101 if (card
->info
.broadcast_capable
== QETH_BROADCAST_WITHOUT_ECHO
)
104 } else if (routing_type
== SECONDARY_CONNECTOR
) {
105 if (card
->info
.broadcast_capable
== QETH_BROADCAST_WITHOUT_ECHO
)
108 } else if (routing_type
== NO_ROUTER
)
115 qeth_procfile_seq_show(struct seq_file
*s
, void *it
)
117 struct device
*device
;
118 struct qeth_card
*card
;
119 char tmp
[12]; /* for qeth_get_prioq_str */
121 if (it
== SEQ_START_TOKEN
){
122 seq_printf(s
, "devices CHPID interface "
123 "cardtype port chksum prio-q'ing rtr4 "
125 seq_printf(s
, "-------------------------- ----- ---------- "
126 "-------------- ---- ------ ---------- ---- "
127 "---- ----- -----\n");
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 ",
136 QETH_CARD_IFNAME(card
),
137 qeth_get_cardname_short(card
),
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
);
148 seq_printf(s
, " +++ LAN OFFLINE +++\n");
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
,
161 qeth_procfile_open(struct inode
*inode
, struct file
*file
)
163 return seq_open(file
, &qeth_procfile_seq_ops
);
166 static struct file_operations qeth_procfile_fops
= {
167 .owner
= THIS_MODULE
,
168 .open
= qeth_procfile_open
,
171 .release
= seq_release
,
174 /***** /proc/qeth_perf *****/
175 #define QETH_PERF_PROCFILE_NAME "qeth_perf"
176 static struct proc_dir_entry
*qeth_perf_procfile
;
178 #ifdef CONFIG_QETH_PERF_STATS
181 qeth_perf_procfile_seq_start(struct seq_file
*s
, loff_t
*offset
)
183 struct list_head
*next_card
= NULL
;
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
){
197 qeth_perf_procfile_seq_stop(struct seq_file
*s
, void* it
)
199 up_read(&qeth_ccwgroup_driver
.driver
.bus
->subsys
.rwsem
);
203 qeth_perf_procfile_seq_next(struct seq_file
*s
, void *it
, loff_t
*offset
)
205 struct list_head
*current_card
= (struct list_head
*)it
;
207 if (current_card
->next
== &qeth_ccwgroup_driver
.driver
.devices
)
208 return NULL
; /* end of list reached */
210 return current_card
->next
;
214 qeth_perf_procfile_seq_show(struct seq_file
*s
, void *it
)
216 struct device
*device
;
217 struct qeth_card
*card
;
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",
225 QETH_CARD_IFNAME(card
)
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
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
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) : "
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
)
257 (card
->qdio
.no_out_queues
> 2)?
258 atomic_read(&card
->qdio
.out_qs
[2]->used_buffers
)
260 (card
->qdio
.no_out_queues
> 3)?
261 atomic_read(&card
->qdio
.out_qs
[3]->used_buffers
)
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
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
,
296 qeth_perf_procfile_open(struct inode
*inode
, struct file
*file
)
298 return seq_open(file
, &qeth_perf_procfile_seq_ops
);
301 static struct file_operations qeth_perf_procfile_fops
= {
302 .owner
= THIS_MODULE
,
303 .open
= qeth_perf_procfile_open
,
306 .release
= seq_release
,
309 #define qeth_perf_procfile_created qeth_perf_procfile
311 #define qeth_perf_procfile_created 1
312 #endif /* CONFIG_QETH_PERF_STATS */
314 /***** /proc/qeth_ipa_takeover *****/
315 #define QETH_IPATO_PROCFILE_NAME "qeth_ipa_takeover"
316 static struct proc_dir_entry
*qeth_ipato_procfile
;
319 qeth_ipato_procfile_seq_start(struct seq_file
*s
, loff_t
*offset
)
321 struct list_head
*next_card
= NULL
;
324 down_read(&qeth_ccwgroup_driver
.driver
.bus
->subsys
.rwsem
);
325 /* TODO: finish this */
327 * maybe SEQ_SATRT_TOKEN can be returned for offset 0
328 * output driver settings then;
329 * else output setting for respective card
331 /* get card at pos *offset */
332 list_for_each(next_card
, &qeth_ccwgroup_driver
.driver
.devices
){
341 qeth_ipato_procfile_seq_stop(struct seq_file
*s
, void* it
)
343 up_read(&qeth_ccwgroup_driver
.driver
.bus
->subsys
.rwsem
);
347 qeth_ipato_procfile_seq_next(struct seq_file
*s
, void *it
, loff_t
*offset
)
349 struct list_head
*current_card
= (struct list_head
*)it
;
351 /* TODO: finish this */
353 * maybe SEQ_SATRT_TOKEN can be returned for offset 0
354 * output driver settings then;
355 * else output setting for respective card
357 if (current_card
->next
== &qeth_ccwgroup_driver
.driver
.devices
)
358 return NULL
; /* end of list reached */
360 return current_card
->next
;
364 qeth_ipato_procfile_seq_show(struct seq_file
*s
, void *it
)
366 struct device
*device
;
367 struct qeth_card
*card
;
369 /* TODO: finish this */
371 * maybe SEQ_SATRT_TOKEN can be returned for offset 0
372 * output driver settings then;
373 * else output setting for respective card
375 device
= list_entry(it
, struct device
, driver_list
);
376 card
= device
->driver_data
;
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
,
389 qeth_ipato_procfile_open(struct inode
*inode
, struct file
*file
)
391 return seq_open(file
, &qeth_ipato_procfile_seq_ops
);
394 static struct file_operations qeth_ipato_procfile_fops
= {
395 .owner
= THIS_MODULE
,
396 .open
= qeth_ipato_procfile_open
,
399 .release
= seq_release
,
403 qeth_create_procfs_entries(void)
405 qeth_procfile
= create_proc_entry(QETH_PROCFILE_NAME
,
406 S_IFREG
| 0444, NULL
);
408 qeth_procfile
->proc_fops
= &qeth_procfile_fops
;
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 */
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
;
423 qeth_ipato_procfile
&&
424 qeth_perf_procfile_created
)
431 qeth_remove_procfs_entries(void)
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
);
442 /* ONLY FOR DEVELOPMENT! -> make it as module */
445 qeth_create_sysfs_entries(void)
449 down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
451 list_for_each_entry(dev, &qeth_ccwgroup_driver.driver.devices,
453 qeth_create_device_attributes(dev);
455 up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
459 qeth_remove_sysfs_entries(void)
463 down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
465 list_for_each_entry(dev, &qeth_ccwgroup_driver.driver.devices,
467 qeth_remove_device_attributes(dev);
469 up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
475 printk(KERN_INFO "qeth_fs_init\n");
476 qeth_create_procfs_entries();
477 qeth_create_sysfs_entries();
485 printk(KERN_INFO "qeth_fs_exit\n");
486 qeth_remove_procfs_entries();
487 qeth_remove_sysfs_entries();
491 module_init(qeth_fs_init);
492 module_exit(qeth_fs_exit);
494 MODULE_LICENSE("GPL");