net: usb: Add debug support to the driver
Add debugfs file to rmnet usb data driver to dynamically
display driver statistics
Change-Id: I9a20df04414002e4e44529fff321ce39ae1a2be1
Signed-off-by: Hemant Kumar <hemantk@codeaurora.org>
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
index ae3f934..d4c2823 100644
--- a/drivers/net/usb/rmnet_usb_data.c
+++ b/drivers/net/usb/rmnet_usb_data.c
@@ -13,6 +13,8 @@
#include <linux/mii.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#include <linux/usb.h>
#include <linux/usb/usbnet.h>
#include <linux/msm_rmnet.h>
@@ -416,6 +418,86 @@
dev->watchdog_timeo = 1000; /* 10 seconds? */
}
+static int rmnet_usb_data_status(struct seq_file *s, void *unused)
+{
+ struct usbnet *unet = s->private;
+
+ seq_printf(s, "RMNET_MODE_LLP_IP: %d\n",
+ test_bit(RMNET_MODE_LLP_IP, &unet->data[0]));
+ seq_printf(s, "RMNET_MODE_LLP_ETH: %d\n",
+ test_bit(RMNET_MODE_LLP_ETH, &unet->data[0]));
+ seq_printf(s, "RMNET_MODE_QOS: %d\n",
+ test_bit(RMNET_MODE_QOS, &unet->data[0]));
+ seq_printf(s, "Net MTU: %u\n", unet->net->mtu);
+ seq_printf(s, "rx_urb_size: %u\n", unet->rx_urb_size);
+ seq_printf(s, "rx skb q len: %u\n", unet->rxq.qlen);
+ seq_printf(s, "rx skb done q len: %u\n", unet->done.qlen);
+ seq_printf(s, "rx errors: %lu\n", unet->net->stats.rx_errors);
+ seq_printf(s, "rx over errors: %lu\n",
+ unet->net->stats.rx_over_errors);
+ seq_printf(s, "rx length errors: %lu\n",
+ unet->net->stats.rx_length_errors);
+ seq_printf(s, "rx packets: %lu\n", unet->net->stats.rx_packets);
+ seq_printf(s, "rx bytes: %lu\n", unet->net->stats.rx_bytes);
+ seq_printf(s, "tx skb q len: %u\n", unet->txq.qlen);
+ seq_printf(s, "tx errors: %lu\n", unet->net->stats.tx_errors);
+ seq_printf(s, "tx packets: %lu\n", unet->net->stats.tx_packets);
+ seq_printf(s, "tx bytes: %lu\n", unet->net->stats.tx_bytes);
+ seq_printf(s, "suspend count: %d\n", unet->suspend_count);
+ seq_printf(s, "EVENT_DEV_OPEN: %d\n",
+ test_bit(EVENT_DEV_OPEN, &unet->flags));
+ seq_printf(s, "EVENT_TX_HALT: %d\n",
+ test_bit(EVENT_TX_HALT, &unet->flags));
+ seq_printf(s, "EVENT_RX_HALT: %d\n",
+ test_bit(EVENT_RX_HALT, &unet->flags));
+ seq_printf(s, "EVENT_RX_MEMORY: %d\n",
+ test_bit(EVENT_RX_MEMORY, &unet->flags));
+ seq_printf(s, "EVENT_DEV_ASLEEP: %d\n",
+ test_bit(EVENT_DEV_ASLEEP, &unet->flags));
+
+ return 0;
+}
+
+static int rmnet_usb_data_status_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, rmnet_usb_data_status, inode->i_private);
+}
+
+const struct file_operations rmnet_usb_data_fops = {
+ .open = rmnet_usb_data_status_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct dentry *rmnet_usb_data_dbg_root;
+static int rmnet_usb_data_debugfs_init(struct usbnet *unet)
+{
+ struct dentry *rmnet_usb_data_dentry;
+
+ rmnet_usb_data_dbg_root = debugfs_create_dir(unet->net->name, NULL);
+
+ if (!rmnet_usb_data_dbg_root || IS_ERR(rmnet_usb_data_dbg_root))
+ return -ENODEV;
+
+ rmnet_usb_data_dentry = debugfs_create_file("status",
+ S_IRUGO | S_IWUSR,
+ rmnet_usb_data_dbg_root, unet,
+ &rmnet_usb_data_fops);
+
+ if (!rmnet_usb_data_dentry) {
+ debugfs_remove_recursive(rmnet_usb_data_dbg_root);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void rmnet_usb_data_debugfs_cleanup(void)
+{
+ debugfs_remove_recursive(rmnet_usb_data_dbg_root);
+}
+
static int rmnet_usb_probe(struct usb_interface *iface,
const struct usb_device_id *prod)
{
@@ -469,6 +551,10 @@
if (status)
goto out;
+ status = rmnet_usb_data_debugfs_init(unet);
+ if (status)
+ dev_dbg(&udev->dev, "mode debugfs file is not available\n");
+
/* allow modem to wake up suspended system */
device_set_wakeup_enable(&udev->dev, 1);
out:
@@ -484,6 +570,8 @@
udev = interface_to_usbdev(intf);
device_set_wakeup_enable(&udev->dev, 0);
+ rmnet_usb_data_debugfs_cleanup();
+
unet = usb_get_intfdata(intf);
if (!unet) {
dev_err(&udev->dev, "%s:data device not found\n", __func__);