1/* 2 * 3 * linux/drivers/s390/net/qeth_fs.c 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/***** /proc/qeth *****/ 25#define QETH_PROCFILE_NAME "qeth" 26static struct proc_dir_entry *qeth_procfile; 27 28static int 29qeth_procfile_seq_match(struct device *dev, void *data) 30{ 31 return(dev ? 1 : 0); 32} 33 34static void * 35qeth_procfile_seq_start(struct seq_file *s, loff_t *offset) 36{ 37 struct device *dev = NULL; 38 loff_t nr = 0; 39 40 if (*offset == 0) 41 return SEQ_START_TOKEN; 42 while (1) { 43 dev = driver_find_device(&qeth_ccwgroup_driver.driver, dev, 44 NULL, qeth_procfile_seq_match); 45 if (++nr == *offset) 46 break; 47 put_device(dev); 48 } 49 return dev; 50} 51 52static void 53qeth_procfile_seq_stop(struct seq_file *s, void* it) 54{ 55} 56 57static void * 58qeth_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset) 59{ 60 struct device *prev, *next; 61 62 if (it == SEQ_START_TOKEN) 63 prev = NULL; 64 else 65 prev = (struct device *) it; 66 next = driver_find_device(&qeth_ccwgroup_driver.driver, 67 prev, NULL, qeth_procfile_seq_match); 68 (*offset)++; 69 return (void *) next; 70} 71 72static inline const char * 73qeth_get_router_str(struct qeth_card *card, int ipv) 74{ 75 enum qeth_routing_types routing_type = NO_ROUTER; 76 77 if (ipv == 4) { 78 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 87 switch (routing_type){ 88 case PRIMARY_ROUTER: 89 return "pri"; 90 case SECONDARY_ROUTER: 91 return "sec"; 92 case MULTICAST_ROUTER: 93 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO) 94 return "mc+"; 95 return "mc"; 96 case PRIMARY_CONNECTOR: 97 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO) 98 return "p+c"; 99 return "p.c"; 100 case SECONDARY_CONNECTOR: 101 if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO) 102 return "s+c"; 103 return "s.c"; 104 default: /* NO_ROUTER */ 105 return "no"; 106 } 107} 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 { 124 device = (struct device *) it; 125 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"); 144 put_device(device); 145 } 146 return 0; 147} 148 149static struct seq_operations qeth_procfile_seq_ops = { 150 .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 162static const struct file_operations qeth_procfile_fops = { 163 .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 174static int 175qeth_perf_procfile_seq_show(struct seq_file *s, void *it) 176{ 177 struct device *device; 178 struct qeth_card *card; 179 180 181 if (it == SEQ_START_TOKEN) 182 return 0; 183 184 device = (struct device *) it; 185 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 ); 192 if (!card->options.performance_stats) 193 seq_printf(s, "Performance statistics are deactivated.\n"); 194 seq_printf(s, " Skb's/buffers received : %lu/%u\n" 195 " Skb's/buffers sent : %lu/%u\n\n", 196 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 202 ); 203 seq_printf(s, " Skb's/buffers sent without packing : %lu/%u\n" 204 " Skb's/buffers sent with packing : %u/%u\n\n", 205 card->stats.tx_packets - card->perf_stats.initial_tx_packets 206 - card->perf_stats.skbs_sent_pack, 207 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 ); 211 seq_printf(s, " Skbs sent in SG mode : %u\n" 212 " Skb fragments sent in SG mode : %u\n\n", 213 card->perf_stats.sg_skbs_sent, 214 card->perf_stats.sg_frags_sent); 215 seq_printf(s, " large_send tx (in Kbytes) : %u\n" 216 " large_send count : %u\n\n", 217 card->perf_stats.large_send_bytes >> 10, 218 card->perf_stats.large_send_cnt); 219 seq_printf(s, " Packing state changes no pkg.->packing : %u/%u\n" 220 " Watermarks L/H : %i/%i\n" 221 " Current buffer usage (outbound q's) : " 222 "%i/%i/%i/%i\n\n", 223 card->perf_stats.sc_dp_p, card->perf_stats.sc_p_dp, 224 QETH_LOW_WATERMARK_PACK, QETH_HIGH_WATERMARK_PACK, 225 atomic_read(&card->qdio.out_qs[0]->used_buffers), 226 (card->qdio.no_out_queues > 1)? 227 atomic_read(&card->qdio.out_qs[1]->used_buffers) 228 : 0, 229 (card->qdio.no_out_queues > 2)? 230 atomic_read(&card->qdio.out_qs[2]->used_buffers) 231 : 0, 232 (card->qdio.no_out_queues > 3)? 233 atomic_read(&card->qdio.out_qs[3]->used_buffers) 234 : 0 235 ); 236 seq_printf(s, " Inbound handler time (in us) : %u\n" 237 " Inbound handler count : %u\n" 238 " Inbound do_QDIO time (in us) : %u\n" 239 " Inbound do_QDIO count : %u\n\n" 240 " Outbound handler time (in us) : %u\n" 241 " Outbound handler count : %u\n\n" 242 " Outbound time (in us, incl QDIO) : %u\n" 243 " Outbound count : %u\n" 244 " Outbound do_QDIO time (in us) : %u\n" 245 " Outbound do_QDIO count : %u\n\n", 246 card->perf_stats.inbound_time, 247 card->perf_stats.inbound_cnt, 248 card->perf_stats.inbound_do_qdio_time, 249 card->perf_stats.inbound_do_qdio_cnt, 250 card->perf_stats.outbound_handler_time, 251 card->perf_stats.outbound_handler_cnt, 252 card->perf_stats.outbound_time, 253 card->perf_stats.outbound_cnt, 254 card->perf_stats.outbound_do_qdio_time, 255 card->perf_stats.outbound_do_qdio_cnt 256 ); 257 put_device(device); 258 return 0; 259} 260 261static struct seq_operations qeth_perf_procfile_seq_ops = { 262 .start = qeth_procfile_seq_start, 263 .stop = qeth_procfile_seq_stop, 264 .next = qeth_procfile_seq_next, 265 .show = qeth_perf_procfile_seq_show, 266}; 267 268static int 269qeth_perf_procfile_open(struct inode *inode, struct file *file) 270{ 271 return seq_open(file, &qeth_perf_procfile_seq_ops); 272} 273 274static const struct file_operations qeth_perf_procfile_fops = { 275 .owner = THIS_MODULE, 276 .open = qeth_perf_procfile_open, 277 .read = seq_read, 278 .llseek = seq_lseek, 279 .release = seq_release, 280}; 281 282int __init 283qeth_create_procfs_entries(void) 284{ 285 qeth_procfile = create_proc_entry(QETH_PROCFILE_NAME, 286 S_IFREG | 0444, NULL); 287 if (qeth_procfile) 288 qeth_procfile->proc_fops = &qeth_procfile_fops; 289 290 qeth_perf_procfile = create_proc_entry(QETH_PERF_PROCFILE_NAME, 291 S_IFREG | 0444, NULL); 292 if (qeth_perf_procfile) 293 qeth_perf_procfile->proc_fops = &qeth_perf_procfile_fops; 294 295 if (qeth_procfile && 296 qeth_perf_procfile) 297 return 0; 298 else 299 return -ENOMEM; 300} 301 302void __exit 303qeth_remove_procfs_entries(void) 304{ 305 if (qeth_procfile) 306 remove_proc_entry(QETH_PROCFILE_NAME, NULL); 307 if (qeth_perf_procfile) 308 remove_proc_entry(QETH_PERF_PROCFILE_NAME, NULL); 309} 310