summaryrefslogtreecommitdiffstats
path: root/drivers/s390/net/qeth_proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/net/qeth_proc.c')
-rw-r--r--drivers/s390/net/qeth_proc.c495
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");
+*/