blob: 46ecd03a597ef2828a9ecbbd1b3077ce0aa0aefa [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 *
Heiko Carstense018ba12006-02-01 03:06:31 -08003 * linux/drivers/s390/net/qeth_fs.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
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
Linus Torvalds1da177e2005-04-16 15:20:36 -070024/***** /proc/qeth *****/
25#define QETH_PROCFILE_NAME "qeth"
26static struct proc_dir_entry *qeth_procfile;
27
Cornelia Huck66aea232005-08-08 09:22:36 -070028static int
29qeth_procfile_seq_match(struct device *dev, void *data)
30{
Frank Pavlic3df3cc62005-12-13 08:23:26 +010031 return(dev ? 1 : 0);
Cornelia Huck66aea232005-08-08 09:22:36 -070032}
33
Linus Torvalds1da177e2005-04-16 15:20:36 -070034static void *
35qeth_procfile_seq_start(struct seq_file *s, loff_t *offset)
36{
Frank Pavlic3df3cc62005-12-13 08:23:26 +010037 struct device *dev = NULL;
38 loff_t nr = 0;
Jeff Garzike82b0f22006-05-26 21:58:38 -040039
Frank Pavlic3df3cc62005-12-13 08:23:26 +010040 if (*offset == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 return SEQ_START_TOKEN;
Frank Pavlic3df3cc62005-12-13 08:23:26 +010042 while (1) {
Cornelia Huck66aea232005-08-08 09:22:36 -070043 dev = driver_find_device(&qeth_ccwgroup_driver.driver, dev,
44 NULL, qeth_procfile_seq_match);
Frank Pavlic3df3cc62005-12-13 08:23:26 +010045 if (++nr == *offset)
46 break;
47 put_device(dev);
48 }
49 return dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070050}
51
52static void
53qeth_procfile_seq_stop(struct seq_file *s, void* it)
54{
Linus Torvalds1da177e2005-04-16 15:20:36 -070055}
56
57static void *
58qeth_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
59{
Cornelia Huck66aea232005-08-08 09:22:36 -070060 struct device *prev, *next;
Jeff Garzike82b0f22006-05-26 21:58:38 -040061
62 if (it == SEQ_START_TOKEN)
Frank Pavlic3df3cc62005-12-13 08:23:26 +010063 prev = NULL;
64 else
65 prev = (struct device *) it;
Cornelia Huck66aea232005-08-08 09:22:36 -070066 next = driver_find_device(&qeth_ccwgroup_driver.driver,
67 prev, NULL, qeth_procfile_seq_match);
Frank Pavlic3df3cc62005-12-13 08:23:26 +010068 (*offset)++;
Cornelia Huck66aea232005-08-08 09:22:36 -070069 return (void *) next;
Linus Torvalds1da177e2005-04-16 15:20:36 -070070}
71
72static inline const char *
73qeth_get_router_str(struct qeth_card *card, int ipv)
74{
Frank Pavlic1380fee2006-03-22 16:03:41 +010075 enum qeth_routing_types routing_type = NO_ROUTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
Frank Pavlic3df3cc62005-12-13 08:23:26 +010077 if (ipv == 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 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
Frank Pavlic1380fee2006-03-22 16:03:41 +010087 switch (routing_type){
88 case PRIMARY_ROUTER:
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 return "pri";
Frank Pavlic1380fee2006-03-22 16:03:41 +010090 case SECONDARY_ROUTER:
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 return "sec";
Frank Pavlic1380fee2006-03-22 16:03:41 +010092 case MULTICAST_ROUTER:
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
94 return "mc+";
95 return "mc";
Frank Pavlic1380fee2006-03-22 16:03:41 +010096 case PRIMARY_CONNECTOR:
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
98 return "p+c";
99 return "p.c";
Frank Pavlic1380fee2006-03-22 16:03:41 +0100100 case SECONDARY_CONNECTOR:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
102 return "s+c";
103 return "s.c";
Frank Pavlic1380fee2006-03-22 16:03:41 +0100104 default: /* NO_ROUTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 return "no";
Frank Pavlic1380fee2006-03-22 16:03:41 +0100106 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107}
108
109static int
110qeth_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 {
Cornelia Huck66aea232005-08-08 09:22:36 -0700124 device = (struct device *) it;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 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");
Frank Pavlic3df3cc62005-12-13 08:23:26 +0100144 put_device(device);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 }
146 return 0;
147}
148
Jan Engelhardt5c81cdb2008-01-26 14:11:29 +0100149static const struct seq_operations qeth_procfile_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 .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
156static int
157qeth_procfile_open(struct inode *inode, struct file *file)
158{
159 return seq_open(file, &qeth_procfile_seq_ops);
160}
161
Arjan van de Vend54b1fd2007-02-12 00:55:34 -0800162static const struct file_operations qeth_procfile_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 .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"
172static struct proc_dir_entry *qeth_perf_procfile;
173
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174static int
175qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
176{
177 struct device *device;
178 struct qeth_card *card;
179
Jeff Garzike82b0f22006-05-26 21:58:38 -0400180
Frank Pavlic3df3cc62005-12-13 08:23:26 +0100181 if (it == SEQ_START_TOKEN)
182 return 0;
183
Cornelia Huck66aea232005-08-08 09:22:36 -0700184 device = (struct device *) it;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 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 );
Frank Pavlic09d2d382006-09-15 16:26:34 +0200192 if (!card->options.performance_stats)
193 seq_printf(s, "Performance statistics are deactivated.\n");
Frank Pavlic95f6b5a2006-03-22 16:03:39 +0100194 seq_printf(s, " Skb's/buffers received : %lu/%u\n"
195 " Skb's/buffers sent : %lu/%u\n\n",
Frank Pavlic09d2d382006-09-15 16:26:34 +0200196 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 );
Frank Pavlic95f6b5a2006-03-22 16:03:39 +0100203 seq_printf(s, " Skb's/buffers sent without packing : %lu/%u\n"
204 " Skb's/buffers sent with packing : %u/%u\n\n",
Frank Pavlic09d2d382006-09-15 16:26:34 +0200205 card->stats.tx_packets - card->perf_stats.initial_tx_packets
206 - card->perf_stats.skbs_sent_pack,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 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 );
Frank Pavlic95f6b5a2006-03-22 16:03:39 +0100211 seq_printf(s, " Skbs sent in SG mode : %u\n"
212 " Skb fragments sent in SG mode : %u\n\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 card->perf_stats.sg_skbs_sent,
214 card->perf_stats.sg_frags_sent);
Frank Blaschkaaa617aa2007-07-12 12:51:34 +0200215 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);
Frank Pavlic95f6b5a2006-03-22 16:03:39 +0100221 seq_printf(s, " large_send tx (in Kbytes) : %u\n"
222 " large_send count : %u\n\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 card->perf_stats.large_send_bytes >> 10,
224 card->perf_stats.large_send_cnt);
Frank Pavlic95f6b5a2006-03-22 16:03:39 +0100225 seq_printf(s, " Packing state changes no pkg.->packing : %u/%u\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 " 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 );
Frank Pavlic95f6b5a2006-03-22 16:03:39 +0100242 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",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 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 );
Frank Pavlic3df3cc62005-12-13 08:23:26 +0100263 put_device(device);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 return 0;
265}
266
Jan Engelhardt5c81cdb2008-01-26 14:11:29 +0100267static const struct seq_operations qeth_perf_procfile_seq_ops = {
Frank Pavlic3df3cc62005-12-13 08:23:26 +0100268 .start = qeth_procfile_seq_start,
269 .stop = qeth_procfile_seq_stop,
270 .next = qeth_procfile_seq_next,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 .show = qeth_perf_procfile_seq_show,
272};
273
274static int
275qeth_perf_procfile_open(struct inode *inode, struct file *file)
276{
277 return seq_open(file, &qeth_perf_procfile_seq_ops);
278}
279
Arjan van de Vend54b1fd2007-02-12 00:55:34 -0800280static const struct file_operations qeth_perf_procfile_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 .owner = THIS_MODULE,
282 .open = qeth_perf_procfile_open,
283 .read = seq_read,
284 .llseek = seq_lseek,
285 .release = seq_release,
286};
287
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288int __init
289qeth_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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 if (qeth_procfile &&
Frank Pavlic09d2d382006-09-15 16:26:34 +0200302 qeth_perf_procfile)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 return 0;
304 else
305 return -ENOMEM;
306}
307
308void __exit
309qeth_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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315}
316