diff options
Diffstat (limited to 'drivers/s390/net/qeth_proc.c')
-rw-r--r-- | drivers/s390/net/qeth_proc.c | 495 |
1 files changed, 495 insertions, 0 deletions
diff --git a/drivers/s390/net/qeth_proc.c b/drivers/s390/net/qeth_proc.c new file mode 100644 index 00000000000..04719196fd2 --- /dev/null +++ b/drivers/s390/net/qeth_proc.c @@ -0,0 +1,495 @@ +/* + * + * linux/drivers/s390/net/qeth_fs.c ($Revision: 1.13 $) + * + * Linux on zSeries OSA Express and HiperSockets support + * This file contains code related to procfs. + * + * Copyright 2000,2003 IBM Corporation + * + * Author(s): Thomas Spatzier <tspat@de.ibm.com> + * + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <linux/list.h> +#include <linux/rwsem.h> + +#include "qeth.h" +#include "qeth_mpc.h" +#include "qeth_fs.h" + +const char *VERSION_QETH_PROC_C = "$Revision: 1.13 $"; + +/***** /proc/qeth *****/ +#define QETH_PROCFILE_NAME "qeth" +static struct proc_dir_entry *qeth_procfile; + +static void * +qeth_procfile_seq_start(struct seq_file *s, loff_t *offset) +{ + struct list_head *next_card = NULL; + int i = 0; + + down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem); + + if (*offset == 0) + return SEQ_START_TOKEN; + + /* get card at pos *offset */ + list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices) + if (++i == *offset) + return next_card; + + return NULL; +} + +static void +qeth_procfile_seq_stop(struct seq_file *s, void* it) +{ + up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem); +} + +static void * +qeth_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset) +{ + struct list_head *next_card = NULL; + struct list_head *current_card; + + if (it == SEQ_START_TOKEN) { + next_card = qeth_ccwgroup_driver.driver.devices.next; + if (next_card->next == next_card) /* list empty */ + return NULL; + (*offset)++; + } else { + current_card = (struct list_head *)it; + if (current_card->next == &qeth_ccwgroup_driver.driver.devices) + return NULL; /* end of list reached */ + next_card = current_card->next; + (*offset)++; + } + + return next_card; +} + +static inline const char * +qeth_get_router_str(struct qeth_card *card, int ipv) +{ + int routing_type = 0; + + if (ipv == 4){ + routing_type = card->options.route4.type; + } else { +#ifdef CONFIG_QETH_IPV6 + routing_type = card->options.route6.type; +#else + return "n/a"; +#endif /* CONFIG_QETH_IPV6 */ + } + + if (routing_type == PRIMARY_ROUTER) + return "pri"; + else if (routing_type == SECONDARY_ROUTER) + return "sec"; + else if (routing_type == MULTICAST_ROUTER) { + if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO) + return "mc+"; + return "mc"; + } else if (routing_type == PRIMARY_CONNECTOR) { + if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO) + return "p+c"; + return "p.c"; + } else if (routing_type == SECONDARY_CONNECTOR) { + if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO) + return "s+c"; + return "s.c"; + } else if (routing_type == NO_ROUTER) + return "no"; + else + return "unk"; +} + +static int +qeth_procfile_seq_show(struct seq_file *s, void *it) +{ + struct device *device; + struct qeth_card *card; + char tmp[12]; /* for qeth_get_prioq_str */ + + if (it == SEQ_START_TOKEN){ + seq_printf(s, "devices CHPID interface " + "cardtype port chksum prio-q'ing rtr4 " + "rtr6 fsz cnt\n"); + seq_printf(s, "-------------------------- ----- ---------- " + "-------------- ---- ------ ---------- ---- " + "---- ----- -----\n"); + } else { + device = list_entry(it, struct device, driver_list); + card = device->driver_data; + seq_printf(s, "%s/%s/%s x%02X %-10s %-14s %-4i ", + CARD_RDEV_ID(card), + CARD_WDEV_ID(card), + CARD_DDEV_ID(card), + card->info.chpid, + QETH_CARD_IFNAME(card), + qeth_get_cardname_short(card), + card->info.portno); + if (card->lan_online) + seq_printf(s, "%-6s %-10s %-4s %-4s %-5s %-5i\n", + qeth_get_checksum_str(card), + qeth_get_prioq_str(card, tmp), + qeth_get_router_str(card, 4), + qeth_get_router_str(card, 6), + qeth_get_bufsize_str(card), + card->qdio.in_buf_pool.buf_count); + else + seq_printf(s, " +++ LAN OFFLINE +++\n"); + } + return 0; +} + +static struct seq_operations qeth_procfile_seq_ops = { + .start = qeth_procfile_seq_start, + .stop = qeth_procfile_seq_stop, + .next = qeth_procfile_seq_next, + .show = qeth_procfile_seq_show, +}; + +static int +qeth_procfile_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &qeth_procfile_seq_ops); +} + +static struct file_operations qeth_procfile_fops = { + .owner = THIS_MODULE, + .open = qeth_procfile_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/***** /proc/qeth_perf *****/ +#define QETH_PERF_PROCFILE_NAME "qeth_perf" +static struct proc_dir_entry *qeth_perf_procfile; + +#ifdef CONFIG_QETH_PERF_STATS + +static void * +qeth_perf_procfile_seq_start(struct seq_file *s, loff_t *offset) +{ + struct list_head *next_card = NULL; + int i = 0; + + down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem); + /* get card at pos *offset */ + list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices){ + if (i == *offset) + return next_card; + i++; + } + return NULL; +} + +static void +qeth_perf_procfile_seq_stop(struct seq_file *s, void* it) +{ + up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem); +} + +static void * +qeth_perf_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset) +{ + struct list_head *current_card = (struct list_head *)it; + + if (current_card->next == &qeth_ccwgroup_driver.driver.devices) + return NULL; /* end of list reached */ + (*offset)++; + return current_card->next; +} + +static int +qeth_perf_procfile_seq_show(struct seq_file *s, void *it) +{ + struct device *device; + struct qeth_card *card; + + device = list_entry(it, struct device, driver_list); + card = device->driver_data; + seq_printf(s, "For card with devnos %s/%s/%s (%s):\n", + CARD_RDEV_ID(card), + CARD_WDEV_ID(card), + CARD_DDEV_ID(card), + QETH_CARD_IFNAME(card) + ); + seq_printf(s, " Skb's/buffers received : %li/%i\n" + " Skb's/buffers sent : %li/%i\n\n", + card->stats.rx_packets, card->perf_stats.bufs_rec, + card->stats.tx_packets, card->perf_stats.bufs_sent + ); + seq_printf(s, " Skb's/buffers sent without packing : %li/%i\n" + " Skb's/buffers sent with packing : %i/%i\n\n", + card->stats.tx_packets - card->perf_stats.skbs_sent_pack, + card->perf_stats.bufs_sent - card->perf_stats.bufs_sent_pack, + card->perf_stats.skbs_sent_pack, + card->perf_stats.bufs_sent_pack + ); + seq_printf(s, " Skbs sent in SG mode : %i\n" + " Skb fragments sent in SG mode : %i\n\n", + card->perf_stats.sg_skbs_sent, + card->perf_stats.sg_frags_sent); + seq_printf(s, " large_send tx (in Kbytes) : %i\n" + " large_send count : %i\n\n", + card->perf_stats.large_send_bytes >> 10, + card->perf_stats.large_send_cnt); + seq_printf(s, " Packing state changes no pkg.->packing : %i/%i\n" + " Watermarks L/H : %i/%i\n" + " Current buffer usage (outbound q's) : " + "%i/%i/%i/%i\n\n", + card->perf_stats.sc_dp_p, card->perf_stats.sc_p_dp, + QETH_LOW_WATERMARK_PACK, QETH_HIGH_WATERMARK_PACK, + atomic_read(&card->qdio.out_qs[0]->used_buffers), + (card->qdio.no_out_queues > 1)? + atomic_read(&card->qdio.out_qs[1]->used_buffers) + : 0, + (card->qdio.no_out_queues > 2)? + atomic_read(&card->qdio.out_qs[2]->used_buffers) + : 0, + (card->qdio.no_out_queues > 3)? + atomic_read(&card->qdio.out_qs[3]->used_buffers) + : 0 + ); + seq_printf(s, " Inbound handler time (in us) : %i\n" + " Inbound handler count : %i\n" + " Inbound do_QDIO time (in us) : %i\n" + " Inbound do_QDIO count : %i\n\n" + " Outbound handler time (in us) : %i\n" + " Outbound handler count : %i\n\n" + " Outbound time (in us, incl QDIO) : %i\n" + " Outbound count : %i\n" + " Outbound do_QDIO time (in us) : %i\n" + " Outbound do_QDIO count : %i\n\n", + card->perf_stats.inbound_time, + card->perf_stats.inbound_cnt, + card->perf_stats.inbound_do_qdio_time, + card->perf_stats.inbound_do_qdio_cnt, + card->perf_stats.outbound_handler_time, + card->perf_stats.outbound_handler_cnt, + card->perf_stats.outbound_time, + card->perf_stats.outbound_cnt, + card->perf_stats.outbound_do_qdio_time, + card->perf_stats.outbound_do_qdio_cnt + ); + return 0; +} + +static struct seq_operations qeth_perf_procfile_seq_ops = { + .start = qeth_perf_procfile_seq_start, + .stop = qeth_perf_procfile_seq_stop, + .next = qeth_perf_procfile_seq_next, + .show = qeth_perf_procfile_seq_show, +}; + +static int +qeth_perf_procfile_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &qeth_perf_procfile_seq_ops); +} + +static struct file_operations qeth_perf_procfile_fops = { + .owner = THIS_MODULE, + .open = qeth_perf_procfile_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +#define qeth_perf_procfile_created qeth_perf_procfile +#else +#define qeth_perf_procfile_created 1 +#endif /* CONFIG_QETH_PERF_STATS */ + +/***** /proc/qeth_ipa_takeover *****/ +#define QETH_IPATO_PROCFILE_NAME "qeth_ipa_takeover" +static struct proc_dir_entry *qeth_ipato_procfile; + +static void * +qeth_ipato_procfile_seq_start(struct seq_file *s, loff_t *offset) +{ + struct list_head *next_card = NULL; + int i = 0; + + down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem); + /* TODO: finish this */ + /* + * maybe SEQ_SATRT_TOKEN can be returned for offset 0 + * output driver settings then; + * else output setting for respective card + */ + /* get card at pos *offset */ + list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices){ + if (i == *offset) + return next_card; + i++; + } + return NULL; +} + +static void +qeth_ipato_procfile_seq_stop(struct seq_file *s, void* it) +{ + up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem); +} + +static void * +qeth_ipato_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset) +{ + struct list_head *current_card = (struct list_head *)it; + + /* TODO: finish this */ + /* + * maybe SEQ_SATRT_TOKEN can be returned for offset 0 + * output driver settings then; + * else output setting for respective card + */ + if (current_card->next == &qeth_ccwgroup_driver.driver.devices) + return NULL; /* end of list reached */ + (*offset)++; + return current_card->next; +} + +static int +qeth_ipato_procfile_seq_show(struct seq_file *s, void *it) +{ + struct device *device; + struct qeth_card *card; + + /* TODO: finish this */ + /* + * maybe SEQ_SATRT_TOKEN can be returned for offset 0 + * output driver settings then; + * else output setting for respective card + */ + device = list_entry(it, struct device, driver_list); + card = device->driver_data; + + return 0; +} + +static struct seq_operations qeth_ipato_procfile_seq_ops = { + .start = qeth_ipato_procfile_seq_start, + .stop = qeth_ipato_procfile_seq_stop, + .next = qeth_ipato_procfile_seq_next, + .show = qeth_ipato_procfile_seq_show, +}; + +static int +qeth_ipato_procfile_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &qeth_ipato_procfile_seq_ops); +} + +static struct file_operations qeth_ipato_procfile_fops = { + .owner = THIS_MODULE, + .open = qeth_ipato_procfile_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +int __init +qeth_create_procfs_entries(void) +{ + qeth_procfile = create_proc_entry(QETH_PROCFILE_NAME, + S_IFREG | 0444, NULL); + if (qeth_procfile) + qeth_procfile->proc_fops = &qeth_procfile_fops; + +#ifdef CONFIG_QETH_PERF_STATS + qeth_perf_procfile = create_proc_entry(QETH_PERF_PROCFILE_NAME, + S_IFREG | 0444, NULL); + if (qeth_perf_procfile) + qeth_perf_procfile->proc_fops = &qeth_perf_procfile_fops; +#endif /* CONFIG_QETH_PERF_STATS */ + + qeth_ipato_procfile = create_proc_entry(QETH_IPATO_PROCFILE_NAME, + S_IFREG | 0444, NULL); + if (qeth_ipato_procfile) + qeth_ipato_procfile->proc_fops = &qeth_ipato_procfile_fops; + + if (qeth_procfile && + qeth_ipato_procfile && + qeth_perf_procfile_created) + return 0; + else + return -ENOMEM; +} + +void __exit +qeth_remove_procfs_entries(void) +{ + if (qeth_procfile) + remove_proc_entry(QETH_PROCFILE_NAME, NULL); + if (qeth_perf_procfile) + remove_proc_entry(QETH_PERF_PROCFILE_NAME, NULL); + if (qeth_ipato_procfile) + remove_proc_entry(QETH_IPATO_PROCFILE_NAME, NULL); +} + + +/* ONLY FOR DEVELOPMENT! -> make it as module */ +/* +static void +qeth_create_sysfs_entries(void) +{ + struct device *dev; + + down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem); + + list_for_each_entry(dev, &qeth_ccwgroup_driver.driver.devices, + driver_list) + qeth_create_device_attributes(dev); + + up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem); +} + +static void +qeth_remove_sysfs_entries(void) +{ + struct device *dev; + + down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem); + + list_for_each_entry(dev, &qeth_ccwgroup_driver.driver.devices, + driver_list) + qeth_remove_device_attributes(dev); + + up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem); +} + +static int __init +qeth_fs_init(void) +{ + printk(KERN_INFO "qeth_fs_init\n"); + qeth_create_procfs_entries(); + qeth_create_sysfs_entries(); + + return 0; +} + +static void __exit +qeth_fs_exit(void) +{ + printk(KERN_INFO "qeth_fs_exit\n"); + qeth_remove_procfs_entries(); + qeth_remove_sysfs_entries(); +} + + +module_init(qeth_fs_init); +module_exit(qeth_fs_exit); + +MODULE_LICENSE("GPL"); +*/ |