Commit 678aa1f6 authored by Stephen Hemminger's avatar Stephen Hemminger Committed by Jeff Garzik

skge: add a debug interface

Add a debugfs interface to look at internal ring state.
Signed-off-by: default avatarStephen Hemminger <shemminger@linux-foundation.org>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent afa151b9
...@@ -2173,6 +2173,16 @@ config SKGE ...@@ -2173,6 +2173,16 @@ config SKGE
To compile this driver as a module, choose M here: the module To compile this driver as a module, choose M here: the module
will be called skge. This is recommended. will be called skge. This is recommended.
config SKGE_DEBUG
bool "Debugging interface"
depends on SKGE && DEBUG_FS
help
This option adds the ability to dump driver state for debugging.
The file debugfs/skge/ethX displays the state of the internal
transmit and receive rings.
If unsure, say N.
config SKY2 config SKY2
tristate "SysKonnect Yukon2 support" tristate "SysKonnect Yukon2 support"
depends on PCI depends on PCI
......
...@@ -36,6 +36,8 @@ ...@@ -36,6 +36,8 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/mii.h> #include <linux/mii.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -3676,6 +3678,145 @@ static int skge_reset(struct skge_hw *hw) ...@@ -3676,6 +3678,145 @@ static int skge_reset(struct skge_hw *hw)
return 0; return 0;
} }
#ifdef CONFIG_SKGE_DEBUG
static struct dentry *skge_debug;
static int skge_debug_show(struct seq_file *seq, void *v)
{
struct net_device *dev = seq->private;
const struct skge_port *skge = netdev_priv(dev);
const struct skge_hw *hw = skge->hw;
const struct skge_element *e;
if (!netif_running(dev))
return -ENETDOWN;
seq_printf(seq, "IRQ src=%x mask=%x\n", skge_read32(hw, B0_ISRC),
skge_read32(hw, B0_IMSK));
seq_printf(seq, "Tx Ring: (%d)\n", skge_avail(&skge->tx_ring));
for (e = skge->tx_ring.to_clean; e != skge->tx_ring.to_use; e = e->next) {
const struct skge_tx_desc *t = e->desc;
seq_printf(seq, "%#x dma=%#x%08x %#x csum=%#x/%x/%x\n",
t->control, t->dma_hi, t->dma_lo, t->status,
t->csum_offs, t->csum_write, t->csum_start);
}
seq_printf(seq, "\nRx Ring: \n");
for (e = skge->rx_ring.to_clean; ; e = e->next) {
const struct skge_rx_desc *r = e->desc;
if (r->control & BMU_OWN)
break;
seq_printf(seq, "%#x dma=%#x%08x %#x %#x csum=%#x/%x\n",
r->control, r->dma_hi, r->dma_lo, r->status,
r->timestamp, r->csum1, r->csum1_start);
}
return 0;
}
static int skge_debug_open(struct inode *inode, struct file *file)
{
return single_open(file, skge_debug_show, inode->i_private);
}
static const struct file_operations skge_debug_fops = {
.owner = THIS_MODULE,
.open = skge_debug_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/*
* Use network device events to create/remove/rename
* debugfs file entries
*/
static int skge_device_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
struct net_device *dev = ptr;
struct skge_port *skge;
struct dentry *d;
if (dev->open != &skge_up || !skge_debug)
goto done;
skge = netdev_priv(dev);
switch(event) {
case NETDEV_CHANGENAME:
if (skge->debugfs) {
d = debugfs_rename(skge_debug, skge->debugfs,
skge_debug, dev->name);
if (d)
skge->debugfs = d;
else {
pr_info(PFX "%s: rename failed\n", dev->name);
debugfs_remove(skge->debugfs);
}
}
break;
case NETDEV_GOING_DOWN:
if (skge->debugfs) {
debugfs_remove(skge->debugfs);
skge->debugfs = NULL;
}
break;
case NETDEV_UP:
d = debugfs_create_file(dev->name, S_IRUGO,
skge_debug, dev,
&skge_debug_fops);
if (!d || IS_ERR(d))
pr_info(PFX "%s: debugfs create failed\n",
dev->name);
else
skge->debugfs = d;
break;
}
done:
return NOTIFY_DONE;
}
static struct notifier_block skge_notifier = {
.notifier_call = skge_device_event,
};
static __init void skge_debug_init(void)
{
struct dentry *ent;
ent = debugfs_create_dir("skge", NULL);
if (!ent || IS_ERR(ent)) {
pr_info(PFX "debugfs create directory failed\n");
return;
}
skge_debug = ent;
register_netdevice_notifier(&skge_notifier);
}
static __exit void skge_debug_cleanup(void)
{
if (skge_debug) {
unregister_netdevice_notifier(&skge_notifier);
debugfs_remove(skge_debug);
skge_debug = NULL;
}
}
#else
#define skge_debug_init()
#define skge_debug_cleanup()
#endif
/* Initialize network device */ /* Initialize network device */
static struct net_device *skge_devinit(struct skge_hw *hw, int port, static struct net_device *skge_devinit(struct skge_hw *hw, int port,
int highmem) int highmem)
...@@ -4040,12 +4181,14 @@ static struct pci_driver skge_driver = { ...@@ -4040,12 +4181,14 @@ static struct pci_driver skge_driver = {
static int __init skge_init_module(void) static int __init skge_init_module(void)
{ {
skge_debug_init();
return pci_register_driver(&skge_driver); return pci_register_driver(&skge_driver);
} }
static void __exit skge_cleanup_module(void) static void __exit skge_cleanup_module(void)
{ {
pci_unregister_driver(&skge_driver); pci_unregister_driver(&skge_driver);
skge_debug_cleanup();
} }
module_init(skge_init_module); module_init(skge_init_module);
......
...@@ -2469,6 +2469,9 @@ struct skge_port { ...@@ -2469,6 +2469,9 @@ struct skge_port {
void *mem; /* PCI memory for rings */ void *mem; /* PCI memory for rings */
dma_addr_t dma; dma_addr_t dma;
unsigned long mem_size; unsigned long mem_size;
#ifdef CONFIG_SKGE_DEBUG
struct dentry *debugfs;
#endif
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment