aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@linux-foundation.org>2007-07-09 18:33:35 -0400
committerJeff Garzik <jeff@garzik.org>2007-07-10 12:22:28 -0400
commit3cf267539f1f133eb6ba63d074da18cb58cdf89a (patch)
treec35a52a717702fdade349c1af0d7013bb7c51115
parent55d7b4e6ed6ad3ec5e5e30b3b4515a0a6a53e344 (diff)
sky2: debug interface
Add an optional debug interface for displaying state of transmit/receive rings. Creates a file debugfs/sky2/ethX for each device that is up. Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org> Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r--drivers/net/Kconfig10
-rw-r--r--drivers/net/sky2.c196
-rw-r--r--drivers/net/sky2.h4
3 files changed, 208 insertions, 2 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 5cc3d517e39b..58c6aa28baff 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2133,6 +2133,16 @@ config SKY2
2133 To compile this driver as a module, choose M here: the module 2133 To compile this driver as a module, choose M here: the module
2134 will be called sky2. This is recommended. 2134 will be called sky2. This is recommended.
2135 2135
2136config SKY2_DEBUG
2137 bool "Debugging interface"
2138 depends on SKY2 && DEBUG_FS
2139 help
2140 This option adds the ability to dump driver state for debugging.
2141 The file debugfs/sky2/ethX displays the state of the internal
2142 transmit and receive rings.
2143
2144 If unsure, say N.
2145
2136config SK98LIN 2146config SK98LIN
2137 tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support (DEPRECATED)" 2147 tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support (DEPRECATED)"
2138 depends on PCI 2148 depends on PCI
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index f6fe2861cc4c..90b1b9708178 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -39,6 +39,7 @@
39#include <linux/workqueue.h> 39#include <linux/workqueue.h>
40#include <linux/if_vlan.h> 40#include <linux/if_vlan.h>
41#include <linux/prefetch.h> 41#include <linux/prefetch.h>
42#include <linux/debugfs.h>
42#include <linux/mii.h> 43#include <linux/mii.h>
43 44
44#include <asm/irq.h> 45#include <asm/irq.h>
@@ -1574,13 +1575,13 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
1574 if (unlikely(netif_msg_tx_done(sky2))) 1575 if (unlikely(netif_msg_tx_done(sky2)))
1575 printk(KERN_DEBUG "%s: tx done %u\n", 1576 printk(KERN_DEBUG "%s: tx done %u\n",
1576 dev->name, idx); 1577 dev->name, idx);
1578
1577 sky2->net_stats.tx_packets++; 1579 sky2->net_stats.tx_packets++;
1578 sky2->net_stats.tx_bytes += re->skb->len; 1580 sky2->net_stats.tx_bytes += re->skb->len;
1579 1581
1580 dev_kfree_skb_any(re->skb); 1582 dev_kfree_skb_any(re->skb);
1583 sky2->tx_next = RING_NEXT(idx, TX_RING_SIZE);
1581 } 1584 }
1582
1583 le->opcode = 0; /* paranoia */
1584 } 1585 }
1585 1586
1586 sky2->tx_cons = idx; 1587 sky2->tx_cons = idx;
@@ -3470,6 +3471,195 @@ static const struct ethtool_ops sky2_ethtool_ops = {
3470 .get_perm_addr = ethtool_op_get_perm_addr, 3471 .get_perm_addr = ethtool_op_get_perm_addr,
3471}; 3472};
3472 3473
3474#ifdef CONFIG_SKY2_DEBUG
3475
3476static struct dentry *sky2_debug;
3477
3478static int sky2_debug_show(struct seq_file *seq, void *v)
3479{
3480 struct net_device *dev = seq->private;
3481 const struct sky2_port *sky2 = netdev_priv(dev);
3482 const struct sky2_hw *hw = sky2->hw;
3483 unsigned port = sky2->port;
3484 unsigned idx, last;
3485 int sop;
3486
3487 if (!netif_running(dev))
3488 return -ENETDOWN;
3489
3490 seq_printf(seq, "IRQ src=%x mask=%x control=%x\n",
3491 sky2_read32(hw, B0_ISRC),
3492 sky2_read32(hw, B0_IMSK),
3493 sky2_read32(hw, B0_Y2_SP_ICR));
3494
3495 netif_poll_disable(hw->dev[0]);
3496 last = sky2_read16(hw, STAT_PUT_IDX);
3497
3498 if (hw->st_idx == last)
3499 seq_puts(seq, "Status ring (empty)\n");
3500 else {
3501 seq_puts(seq, "Status ring\n");
3502 for (idx = hw->st_idx; idx != last && idx < STATUS_RING_SIZE;
3503 idx = RING_NEXT(idx, STATUS_RING_SIZE)) {
3504 const struct sky2_status_le *le = hw->st_le + idx;
3505 seq_printf(seq, "[%d] %#x %d %#x\n",
3506 idx, le->opcode, le->length, le->status);
3507 }
3508 seq_puts(seq, "\n");
3509 }
3510
3511 seq_printf(seq, "Tx ring pending=%u...%u report=%d done=%d\n",
3512 sky2->tx_cons, sky2->tx_prod,
3513 sky2_read16(hw, port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX),
3514 sky2_read16(hw, Q_ADDR(txqaddr[port], Q_DONE)));
3515
3516 /* Dump contents of tx ring */
3517 sop = 1;
3518 for (idx = sky2->tx_next; idx != sky2->tx_prod && idx < TX_RING_SIZE;
3519 idx = RING_NEXT(idx, TX_RING_SIZE)) {
3520 const struct sky2_tx_le *le = sky2->tx_le + idx;
3521 u32 a = le32_to_cpu(le->addr);
3522
3523 if (sop)
3524 seq_printf(seq, "%u:", idx);
3525 sop = 0;
3526
3527 switch(le->opcode & ~HW_OWNER) {
3528 case OP_ADDR64:
3529 seq_printf(seq, " %#x:", a);
3530 break;
3531 case OP_LRGLEN:
3532 seq_printf(seq, " mtu=%d", a);
3533 break;
3534 case OP_VLAN:
3535 seq_printf(seq, " vlan=%d", be16_to_cpu(le->length));
3536 break;
3537 case OP_TCPLISW:
3538 seq_printf(seq, " csum=%#x", a);
3539 break;
3540 case OP_LARGESEND:
3541 seq_printf(seq, " tso=%#x(%d)", a, le16_to_cpu(le->length));
3542 break;
3543 case OP_PACKET:
3544 seq_printf(seq, " %#x(%d)", a, le16_to_cpu(le->length));
3545 break;
3546 case OP_BUFFER:
3547 seq_printf(seq, " frag=%#x(%d)", a, le16_to_cpu(le->length));
3548 break;
3549 default:
3550 seq_printf(seq, " op=%#x,%#x(%d)", le->opcode,
3551 a, le16_to_cpu(le->length));
3552 }
3553
3554 if (le->ctrl & EOP) {
3555 seq_putc(seq, '\n');
3556 sop = 1;
3557 }
3558 }
3559
3560 seq_printf(seq, "\nRx ring hw get=%d put=%d last=%d\n",
3561 sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_GET_IDX)),
3562 last = sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_PUT_IDX)),
3563 sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_LAST_IDX)));
3564
3565 netif_poll_enable(hw->dev[0]);
3566 return 0;
3567}
3568
3569static int sky2_debug_open(struct inode *inode, struct file *file)
3570{
3571 return single_open(file, sky2_debug_show, inode->i_private);
3572}
3573
3574static const struct file_operations sky2_debug_fops = {
3575 .owner = THIS_MODULE,
3576 .open = sky2_debug_open,
3577 .read = seq_read,
3578 .llseek = seq_lseek,
3579 .release = single_release,
3580};
3581
3582/*
3583 * Use network device events to create/remove/rename
3584 * debugfs file entries
3585 */
3586static int sky2_device_event(struct notifier_block *unused,
3587 unsigned long event, void *ptr)
3588{
3589 struct net_device *dev = ptr;
3590
3591 if (dev->open == sky2_up) {
3592 struct sky2_port *sky2 = netdev_priv(dev);
3593
3594 switch(event) {
3595 case NETDEV_CHANGENAME:
3596 if (!netif_running(dev))
3597 break;
3598 /* fallthrough */
3599 case NETDEV_DOWN:
3600 case NETDEV_GOING_DOWN:
3601 if (sky2->debugfs) {
3602 printk(KERN_DEBUG PFX "%s: remove debugfs\n",
3603 dev->name);
3604 debugfs_remove(sky2->debugfs);
3605 sky2->debugfs = NULL;
3606 }
3607
3608 if (event != NETDEV_CHANGENAME)
3609 break;
3610 /* fallthrough for changename */
3611 case NETDEV_UP:
3612 if (sky2_debug) {
3613 struct dentry *d;
3614 d = debugfs_create_file(dev->name, S_IRUGO,
3615 sky2_debug, dev,
3616 &sky2_debug_fops);
3617 if (d == NULL || IS_ERR(d))
3618 printk(KERN_INFO PFX
3619 "%s: debugfs create failed\n",
3620 dev->name);
3621 else
3622 sky2->debugfs = d;
3623 }
3624 break;
3625 }
3626 }
3627
3628 return NOTIFY_DONE;
3629}
3630
3631static struct notifier_block sky2_notifier = {
3632 .notifier_call = sky2_device_event,
3633};
3634
3635
3636static __init void sky2_debug_init(void)
3637{
3638 struct dentry *ent;
3639
3640 ent = debugfs_create_dir("sky2", NULL);
3641 if (!ent || IS_ERR(ent))
3642 return;
3643
3644 sky2_debug = ent;
3645 register_netdevice_notifier(&sky2_notifier);
3646}
3647
3648static __exit void sky2_debug_cleanup(void)
3649{
3650 if (sky2_debug) {
3651 unregister_netdevice_notifier(&sky2_notifier);
3652 debugfs_remove(sky2_debug);
3653 sky2_debug = NULL;
3654 }
3655}
3656
3657#else
3658#define sky2_debug_init()
3659#define sky2_debug_cleanup()
3660#endif
3661
3662
3473/* Initialize network device */ 3663/* Initialize network device */
3474static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, 3664static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
3475 unsigned port, 3665 unsigned port,
@@ -3960,12 +4150,14 @@ static struct pci_driver sky2_driver = {
3960 4150
3961static int __init sky2_init_module(void) 4151static int __init sky2_init_module(void)
3962{ 4152{
4153 sky2_debug_init();
3963 return pci_register_driver(&sky2_driver); 4154 return pci_register_driver(&sky2_driver);
3964} 4155}
3965 4156
3966static void __exit sky2_cleanup_module(void) 4157static void __exit sky2_cleanup_module(void)
3967{ 4158{
3968 pci_unregister_driver(&sky2_driver); 4159 pci_unregister_driver(&sky2_driver);
4160 sky2_debug_cleanup();
3969} 4161}
3970 4162
3971module_init(sky2_init_module); 4163module_init(sky2_init_module);
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 8df4643493d1..dce4d276d443 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -1998,6 +1998,7 @@ struct sky2_port {
1998 struct sky2_tx_le *tx_le; 1998 struct sky2_tx_le *tx_le;
1999 u16 tx_cons; /* next le to check */ 1999 u16 tx_cons; /* next le to check */
2000 u16 tx_prod; /* next le to use */ 2000 u16 tx_prod; /* next le to use */
2001 u16 tx_next; /* debug only */
2001 u32 tx_addr64; 2002 u32 tx_addr64;
2002 u16 tx_pending; 2003 u16 tx_pending;
2003 u16 tx_last_mss; 2004 u16 tx_last_mss;
@@ -2028,6 +2029,9 @@ struct sky2_port {
2028 enum flow_control flow_mode; 2029 enum flow_control flow_mode;
2029 enum flow_control flow_status; 2030 enum flow_control flow_status;
2030 2031
2032#ifdef CONFIG_SKY2_DEBUG
2033 struct dentry *debugfs;
2034#endif
2031 struct net_device_stats net_stats; 2035 struct net_device_stats net_stats;
2032 2036
2033}; 2037};