blob: 1304641545dfadd0bc13829863be2d040bf70e7c [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;
39
Linus Torvalds1da177e2005-04-16 15:20:36 -070040 down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
Frank Pavlic3df3cc62005-12-13 08:23:26 +010041 if (*offset == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 return SEQ_START_TOKEN;
Frank Pavlic3df3cc62005-12-13 08:23:26 +010043 while (1) {
Cornelia Huck66aea232005-08-08 09:22:36 -070044 dev = driver_find_device(&qeth_ccwgroup_driver.driver, dev,
45 NULL, qeth_procfile_seq_match);
Frank Pavlic3df3cc62005-12-13 08:23:26 +010046 if (++nr == *offset)
47 break;
48 put_device(dev);
49 }
50 return dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070051}
52
53static void
54qeth_procfile_seq_stop(struct seq_file *s, void* it)
55{
56 up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
57}
58
59static void *
60qeth_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
61{
Cornelia Huck66aea232005-08-08 09:22:36 -070062 struct device *prev, *next;
Frank Pavlic3df3cc62005-12-13 08:23:26 +010063
64 if (it == SEQ_START_TOKEN)
65 prev = NULL;
66 else
67 prev = (struct device *) it;
Cornelia Huck66aea232005-08-08 09:22:36 -070068 next = driver_find_device(&qeth_ccwgroup_driver.driver,
69 prev, NULL, qeth_procfile_seq_match);
Frank Pavlic3df3cc62005-12-13 08:23:26 +010070 (*offset)++;
Cornelia Huck66aea232005-08-08 09:22:36 -070071 return (void *) next;
Linus Torvalds1da177e2005-04-16 15:20:36 -070072}
73
74static inline const char *
75qeth_get_router_str(struct qeth_card *card, int ipv)
76{
77 int routing_type = 0;
78
Frank Pavlic3df3cc62005-12-13 08:23:26 +010079 if (ipv == 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 routing_type = card->options.route4.type;
81 } else {
82#ifdef CONFIG_QETH_IPV6
83 routing_type = card->options.route6.type;
84#else
85 return "n/a";
86#endif /* CONFIG_QETH_IPV6 */
87 }
88
89 if (routing_type == PRIMARY_ROUTER)
90 return "pri";
91 else if (routing_type == SECONDARY_ROUTER)
92 return "sec";
93 else if (routing_type == MULTICAST_ROUTER) {
94 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
95 return "mc+";
96 return "mc";
97 } else if (routing_type == PRIMARY_CONNECTOR) {
98 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
99 return "p+c";
100 return "p.c";
101 } else if (routing_type == SECONDARY_CONNECTOR) {
102 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
103 return "s+c";
104 return "s.c";
105 } else if (routing_type == NO_ROUTER)
106 return "no";
107 else
108 return "unk";
109}
110
111static int
112qeth_procfile_seq_show(struct seq_file *s, void *it)
113{
114 struct device *device;
115 struct qeth_card *card;
116 char tmp[12]; /* for qeth_get_prioq_str */
117
118 if (it == SEQ_START_TOKEN){
119 seq_printf(s, "devices CHPID interface "
120 "cardtype port chksum prio-q'ing rtr4 "
121 "rtr6 fsz cnt\n");
122 seq_printf(s, "-------------------------- ----- ---------- "
123 "-------------- ---- ------ ---------- ---- "
124 "---- ----- -----\n");
125 } else {
Cornelia Huck66aea232005-08-08 09:22:36 -0700126 device = (struct device *) it;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 card = device->driver_data;
128 seq_printf(s, "%s/%s/%s x%02X %-10s %-14s %-4i ",
129 CARD_RDEV_ID(card),
130 CARD_WDEV_ID(card),
131 CARD_DDEV_ID(card),
132 card->info.chpid,
133 QETH_CARD_IFNAME(card),
134 qeth_get_cardname_short(card),
135 card->info.portno);
136 if (card->lan_online)
137 seq_printf(s, "%-6s %-10s %-4s %-4s %-5s %-5i\n",
138 qeth_get_checksum_str(card),
139 qeth_get_prioq_str(card, tmp),
140 qeth_get_router_str(card, 4),
141 qeth_get_router_str(card, 6),
142 qeth_get_bufsize_str(card),
143 card->qdio.in_buf_pool.buf_count);
144 else
145 seq_printf(s, " +++ LAN OFFLINE +++\n");
Frank Pavlic3df3cc62005-12-13 08:23:26 +0100146 put_device(device);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 }
148 return 0;
149}
150
151static struct seq_operations qeth_procfile_seq_ops = {
152 .start = qeth_procfile_seq_start,
153 .stop = qeth_procfile_seq_stop,
154 .next = qeth_procfile_seq_next,
155 .show = qeth_procfile_seq_show,
156};
157
158static int
159qeth_procfile_open(struct inode *inode, struct file *file)
160{
161 return seq_open(file, &qeth_procfile_seq_ops);
162}
163
164static struct file_operations qeth_procfile_fops = {
165 .owner = THIS_MODULE,
166 .open = qeth_procfile_open,
167 .read = seq_read,
168 .llseek = seq_lseek,
169 .release = seq_release,
170};
171
172/***** /proc/qeth_perf *****/
173#define QETH_PERF_PROCFILE_NAME "qeth_perf"
174static struct proc_dir_entry *qeth_perf_procfile;
175
176#ifdef CONFIG_QETH_PERF_STATS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177static int
178qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
179{
180 struct device *device;
181 struct qeth_card *card;
182
Frank Pavlic3df3cc62005-12-13 08:23:26 +0100183
184 if (it == SEQ_START_TOKEN)
185 return 0;
186
Cornelia Huck66aea232005-08-08 09:22:36 -0700187 device = (struct device *) it;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 card = device->driver_data;
189 seq_printf(s, "For card with devnos %s/%s/%s (%s):\n",
190 CARD_RDEV_ID(card),
191 CARD_WDEV_ID(card),
192 CARD_DDEV_ID(card),
193 QETH_CARD_IFNAME(card)
194 );
Frank Pavlic95f6b5a2006-03-22 16:03:39 +0100195 seq_printf(s, " Skb's/buffers received : %lu/%u\n"
196 " Skb's/buffers sent : %lu/%u\n\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 card->stats.rx_packets, card->perf_stats.bufs_rec,
198 card->stats.tx_packets, card->perf_stats.bufs_sent
199 );
Frank Pavlic95f6b5a2006-03-22 16:03:39 +0100200 seq_printf(s, " Skb's/buffers sent without packing : %lu/%u\n"
201 " Skb's/buffers sent with packing : %u/%u\n\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 card->stats.tx_packets - card->perf_stats.skbs_sent_pack,
203 card->perf_stats.bufs_sent - card->perf_stats.bufs_sent_pack,
204 card->perf_stats.skbs_sent_pack,
205 card->perf_stats.bufs_sent_pack
206 );
Frank Pavlic95f6b5a2006-03-22 16:03:39 +0100207 seq_printf(s, " Skbs sent in SG mode : %u\n"
208 " Skb fragments sent in SG mode : %u\n\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 card->perf_stats.sg_skbs_sent,
210 card->perf_stats.sg_frags_sent);
Frank Pavlic95f6b5a2006-03-22 16:03:39 +0100211 seq_printf(s, " large_send tx (in Kbytes) : %u\n"
212 " large_send count : %u\n\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 card->perf_stats.large_send_bytes >> 10,
214 card->perf_stats.large_send_cnt);
Frank Pavlic95f6b5a2006-03-22 16:03:39 +0100215 seq_printf(s, " Packing state changes no pkg.->packing : %u/%u\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 " Watermarks L/H : %i/%i\n"
217 " Current buffer usage (outbound q's) : "
218 "%i/%i/%i/%i\n\n",
219 card->perf_stats.sc_dp_p, card->perf_stats.sc_p_dp,
220 QETH_LOW_WATERMARK_PACK, QETH_HIGH_WATERMARK_PACK,
221 atomic_read(&card->qdio.out_qs[0]->used_buffers),
222 (card->qdio.no_out_queues > 1)?
223 atomic_read(&card->qdio.out_qs[1]->used_buffers)
224 : 0,
225 (card->qdio.no_out_queues > 2)?
226 atomic_read(&card->qdio.out_qs[2]->used_buffers)
227 : 0,
228 (card->qdio.no_out_queues > 3)?
229 atomic_read(&card->qdio.out_qs[3]->used_buffers)
230 : 0
231 );
Frank Pavlic95f6b5a2006-03-22 16:03:39 +0100232 seq_printf(s, " Inbound handler time (in us) : %u\n"
233 " Inbound handler count : %u\n"
234 " Inbound do_QDIO time (in us) : %u\n"
235 " Inbound do_QDIO count : %u\n\n"
236 " Outbound handler time (in us) : %u\n"
237 " Outbound handler count : %u\n\n"
238 " Outbound time (in us, incl QDIO) : %u\n"
239 " Outbound count : %u\n"
240 " Outbound do_QDIO time (in us) : %u\n"
241 " Outbound do_QDIO count : %u\n\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 card->perf_stats.inbound_time,
243 card->perf_stats.inbound_cnt,
244 card->perf_stats.inbound_do_qdio_time,
245 card->perf_stats.inbound_do_qdio_cnt,
246 card->perf_stats.outbound_handler_time,
247 card->perf_stats.outbound_handler_cnt,
248 card->perf_stats.outbound_time,
249 card->perf_stats.outbound_cnt,
250 card->perf_stats.outbound_do_qdio_time,
251 card->perf_stats.outbound_do_qdio_cnt
252 );
Frank Pavlic3df3cc62005-12-13 08:23:26 +0100253 put_device(device);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 return 0;
255}
256
257static struct seq_operations qeth_perf_procfile_seq_ops = {
Frank Pavlic3df3cc62005-12-13 08:23:26 +0100258 .start = qeth_procfile_seq_start,
259 .stop = qeth_procfile_seq_stop,
260 .next = qeth_procfile_seq_next,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 .show = qeth_perf_procfile_seq_show,
262};
263
264static int
265qeth_perf_procfile_open(struct inode *inode, struct file *file)
266{
267 return seq_open(file, &qeth_perf_procfile_seq_ops);
268}
269
270static struct file_operations qeth_perf_procfile_fops = {
271 .owner = THIS_MODULE,
272 .open = qeth_perf_procfile_open,
273 .read = seq_read,
274 .llseek = seq_lseek,
275 .release = seq_release,
276};
277
278#define qeth_perf_procfile_created qeth_perf_procfile
279#else
280#define qeth_perf_procfile_created 1
281#endif /* CONFIG_QETH_PERF_STATS */
282
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283int __init
284qeth_create_procfs_entries(void)
285{
286 qeth_procfile = create_proc_entry(QETH_PROCFILE_NAME,
287 S_IFREG | 0444, NULL);
288 if (qeth_procfile)
289 qeth_procfile->proc_fops = &qeth_procfile_fops;
290
291#ifdef CONFIG_QETH_PERF_STATS
292 qeth_perf_procfile = create_proc_entry(QETH_PERF_PROCFILE_NAME,
293 S_IFREG | 0444, NULL);
294 if (qeth_perf_procfile)
295 qeth_perf_procfile->proc_fops = &qeth_perf_procfile_fops;
296#endif /* CONFIG_QETH_PERF_STATS */
297
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 if (qeth_procfile &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 qeth_perf_procfile_created)
300 return 0;
301 else
302 return -ENOMEM;
303}
304
305void __exit
306qeth_remove_procfs_entries(void)
307{
308 if (qeth_procfile)
309 remove_proc_entry(QETH_PROCFILE_NAME, NULL);
310 if (qeth_perf_procfile)
311 remove_proc_entry(QETH_PERF_PROCFILE_NAME, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312}
313