blob: 7bf35098831e50603107d74befd95314d4062893 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 *
Frank Pavlic3df3cc62005-12-13 08:23:26 +01003 * linux/drivers/s390/net/qeth_fs.c ($Revision: 1.16 $)
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
Frank Pavlic3df3cc62005-12-13 08:23:26 +010024const char *VERSION_QETH_PROC_C = "$Revision: 1.16 $";
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
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{
Frank Pavlic3df3cc62005-12-13 08:23:26 +010033 return(dev ? 1 : 0);
Cornelia Huck66aea232005-08-08 09:22:36 -070034}
35
Linus Torvalds1da177e2005-04-16 15:20:36 -070036static void *
37qeth_procfile_seq_start(struct seq_file *s, loff_t *offset)
38{
Frank Pavlic3df3cc62005-12-13 08:23:26 +010039 struct device *dev = NULL;
40 loff_t nr = 0;
41
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
Frank Pavlic3df3cc62005-12-13 08:23:26 +010043 if (*offset == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070044 return SEQ_START_TOKEN;
Frank Pavlic3df3cc62005-12-13 08:23:26 +010045 while (1) {
Cornelia Huck66aea232005-08-08 09:22:36 -070046 dev = driver_find_device(&qeth_ccwgroup_driver.driver, dev,
47 NULL, qeth_procfile_seq_match);
Frank Pavlic3df3cc62005-12-13 08:23:26 +010048 if (++nr == *offset)
49 break;
50 put_device(dev);
51 }
52 return dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070053}
54
55static void
56qeth_procfile_seq_stop(struct seq_file *s, void* it)
57{
58 up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
59}
60
61static void *
62qeth_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
63{
Cornelia Huck66aea232005-08-08 09:22:36 -070064 struct device *prev, *next;
Frank Pavlic3df3cc62005-12-13 08:23:26 +010065
66 if (it == SEQ_START_TOKEN)
67 prev = NULL;
68 else
69 prev = (struct device *) it;
Cornelia Huck66aea232005-08-08 09:22:36 -070070 next = driver_find_device(&qeth_ccwgroup_driver.driver,
71 prev, NULL, qeth_procfile_seq_match);
Frank Pavlic3df3cc62005-12-13 08:23:26 +010072 (*offset)++;
Cornelia Huck66aea232005-08-08 09:22:36 -070073 return (void *) next;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074}
75
76static inline const char *
77qeth_get_router_str(struct qeth_card *card, int ipv)
78{
79 int routing_type = 0;
80
Frank Pavlic3df3cc62005-12-13 08:23:26 +010081 if (ipv == 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070082 routing_type = card->options.route4.type;
83 } else {
84#ifdef CONFIG_QETH_IPV6
85 routing_type = card->options.route6.type;
86#else
87 return "n/a";
88#endif /* CONFIG_QETH_IPV6 */
89 }
90
91 if (routing_type == PRIMARY_ROUTER)
92 return "pri";
93 else if (routing_type == SECONDARY_ROUTER)
94 return "sec";
95 else if (routing_type == MULTICAST_ROUTER) {
96 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
97 return "mc+";
98 return "mc";
99 } else if (routing_type == PRIMARY_CONNECTOR) {
100 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
101 return "p+c";
102 return "p.c";
103 } else if (routing_type == SECONDARY_CONNECTOR) {
104 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
105 return "s+c";
106 return "s.c";
107 } else if (routing_type == NO_ROUTER)
108 return "no";
109 else
110 return "unk";
111}
112
113static int
114qeth_procfile_seq_show(struct seq_file *s, void *it)
115{
116 struct device *device;
117 struct qeth_card *card;
118 char tmp[12]; /* for qeth_get_prioq_str */
119
120 if (it == SEQ_START_TOKEN){
121 seq_printf(s, "devices CHPID interface "
122 "cardtype port chksum prio-q'ing rtr4 "
123 "rtr6 fsz cnt\n");
124 seq_printf(s, "-------------------------- ----- ---------- "
125 "-------------- ---- ------ ---------- ---- "
126 "---- ----- -----\n");
127 } else {
Cornelia Huck66aea232005-08-08 09:22:36 -0700128 device = (struct device *) it;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 card = device->driver_data;
130 seq_printf(s, "%s/%s/%s x%02X %-10s %-14s %-4i ",
131 CARD_RDEV_ID(card),
132 CARD_WDEV_ID(card),
133 CARD_DDEV_ID(card),
134 card->info.chpid,
135 QETH_CARD_IFNAME(card),
136 qeth_get_cardname_short(card),
137 card->info.portno);
138 if (card->lan_online)
139 seq_printf(s, "%-6s %-10s %-4s %-4s %-5s %-5i\n",
140 qeth_get_checksum_str(card),
141 qeth_get_prioq_str(card, tmp),
142 qeth_get_router_str(card, 4),
143 qeth_get_router_str(card, 6),
144 qeth_get_bufsize_str(card),
145 card->qdio.in_buf_pool.buf_count);
146 else
147 seq_printf(s, " +++ LAN OFFLINE +++\n");
Frank Pavlic3df3cc62005-12-13 08:23:26 +0100148 put_device(device);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 }
150 return 0;
151}
152
153static 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
160static int
161qeth_procfile_open(struct inode *inode, struct file *file)
162{
163 return seq_open(file, &qeth_procfile_seq_ops);
164}
165
166static 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"
176static struct proc_dir_entry *qeth_perf_procfile;
177
178#ifdef CONFIG_QETH_PERF_STATS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179static int
180qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
181{
182 struct device *device;
183 struct qeth_card *card;
184
Frank Pavlic3df3cc62005-12-13 08:23:26 +0100185
186 if (it == SEQ_START_TOKEN)
187 return 0;
188
Cornelia Huck66aea232005-08-08 09:22:36 -0700189 device = (struct device *) it;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 card = device->driver_data;
191 seq_printf(s, "For card with devnos %s/%s/%s (%s):\n",
192 CARD_RDEV_ID(card),
193 CARD_WDEV_ID(card),
194 CARD_DDEV_ID(card),
195 QETH_CARD_IFNAME(card)
196 );
197 seq_printf(s, " Skb's/buffers received : %li/%i\n"
198 " Skb's/buffers sent : %li/%i\n\n",
199 card->stats.rx_packets, card->perf_stats.bufs_rec,
200 card->stats.tx_packets, card->perf_stats.bufs_sent
201 );
202 seq_printf(s, " Skb's/buffers sent without packing : %li/%i\n"
203 " Skb's/buffers sent with packing : %i/%i\n\n",
204 card->stats.tx_packets - card->perf_stats.skbs_sent_pack,
205 card->perf_stats.bufs_sent - card->perf_stats.bufs_sent_pack,
206 card->perf_stats.skbs_sent_pack,
207 card->perf_stats.bufs_sent_pack
208 );
209 seq_printf(s, " Skbs sent in SG mode : %i\n"
210 " Skb fragments sent in SG mode : %i\n\n",
211 card->perf_stats.sg_skbs_sent,
212 card->perf_stats.sg_frags_sent);
213 seq_printf(s, " large_send tx (in Kbytes) : %i\n"
214 " large_send count : %i\n\n",
215 card->perf_stats.large_send_bytes >> 10,
216 card->perf_stats.large_send_cnt);
217 seq_printf(s, " Packing state changes no pkg.->packing : %i/%i\n"
218 " Watermarks L/H : %i/%i\n"
219 " Current buffer usage (outbound q's) : "
220 "%i/%i/%i/%i\n\n",
221 card->perf_stats.sc_dp_p, card->perf_stats.sc_p_dp,
222 QETH_LOW_WATERMARK_PACK, QETH_HIGH_WATERMARK_PACK,
223 atomic_read(&card->qdio.out_qs[0]->used_buffers),
224 (card->qdio.no_out_queues > 1)?
225 atomic_read(&card->qdio.out_qs[1]->used_buffers)
226 : 0,
227 (card->qdio.no_out_queues > 2)?
228 atomic_read(&card->qdio.out_qs[2]->used_buffers)
229 : 0,
230 (card->qdio.no_out_queues > 3)?
231 atomic_read(&card->qdio.out_qs[3]->used_buffers)
232 : 0
233 );
234 seq_printf(s, " Inbound handler time (in us) : %i\n"
235 " Inbound handler count : %i\n"
236 " Inbound do_QDIO time (in us) : %i\n"
237 " Inbound do_QDIO count : %i\n\n"
238 " Outbound handler time (in us) : %i\n"
239 " Outbound handler count : %i\n\n"
240 " Outbound time (in us, incl QDIO) : %i\n"
241 " Outbound count : %i\n"
242 " Outbound do_QDIO time (in us) : %i\n"
243 " Outbound do_QDIO count : %i\n\n",
244 card->perf_stats.inbound_time,
245 card->perf_stats.inbound_cnt,
246 card->perf_stats.inbound_do_qdio_time,
247 card->perf_stats.inbound_do_qdio_cnt,
248 card->perf_stats.outbound_handler_time,
249 card->perf_stats.outbound_handler_cnt,
250 card->perf_stats.outbound_time,
251 card->perf_stats.outbound_cnt,
252 card->perf_stats.outbound_do_qdio_time,
253 card->perf_stats.outbound_do_qdio_cnt
254 );
Frank Pavlic3df3cc62005-12-13 08:23:26 +0100255 put_device(device);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 return 0;
257}
258
259static struct seq_operations qeth_perf_procfile_seq_ops = {
Frank Pavlic3df3cc62005-12-13 08:23:26 +0100260 .start = qeth_procfile_seq_start,
261 .stop = qeth_procfile_seq_stop,
262 .next = qeth_procfile_seq_next,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 .show = qeth_perf_procfile_seq_show,
264};
265
266static int
267qeth_perf_procfile_open(struct inode *inode, struct file *file)
268{
269 return seq_open(file, &qeth_perf_procfile_seq_ops);
270}
271
272static struct file_operations qeth_perf_procfile_fops = {
273 .owner = THIS_MODULE,
274 .open = qeth_perf_procfile_open,
275 .read = seq_read,
276 .llseek = seq_lseek,
277 .release = seq_release,
278};
279
280#define qeth_perf_procfile_created qeth_perf_procfile
281#else
282#define qeth_perf_procfile_created 1
283#endif /* CONFIG_QETH_PERF_STATS */
284
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285int __init
286qeth_create_procfs_entries(void)
287{
288 qeth_procfile = create_proc_entry(QETH_PROCFILE_NAME,
289 S_IFREG | 0444, NULL);
290 if (qeth_procfile)
291 qeth_procfile->proc_fops = &qeth_procfile_fops;
292
293#ifdef CONFIG_QETH_PERF_STATS
294 qeth_perf_procfile = create_proc_entry(QETH_PERF_PROCFILE_NAME,
295 S_IFREG | 0444, NULL);
296 if (qeth_perf_procfile)
297 qeth_perf_procfile->proc_fops = &qeth_perf_procfile_fops;
298#endif /* CONFIG_QETH_PERF_STATS */
299
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 if (qeth_procfile &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 qeth_perf_procfile_created)
302 return 0;
303 else
304 return -ENOMEM;
305}
306
307void __exit
308qeth_remove_procfs_entries(void)
309{
310 if (qeth_procfile)
311 remove_proc_entry(QETH_PROCFILE_NAME, NULL);
312 if (qeth_perf_procfile)
313 remove_proc_entry(QETH_PERF_PROCFILE_NAME, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314}
315