Please reproduce problem with this patch, then do:
cat /proc/sys/net/sky2/lan0
This patch (which shouldn't go into the mainline driver), adds a debug
interface to sky2 driver to dump the receive and transmit rings.
The file /proc/net/sky2/ethX will show the status of transmits in process,
status responses not handled, and receives pending.
---
drivers/net/sky2.c | 158 +++--
drivers/net/sky2.h |4 +
2 files changed, 157 insertions(+), 5 deletions(-)
--- sky2-2.6.orig/drivers/net/sky2.c2007-01-11 10:05:09.0 -0800
+++ sky2-2.6/drivers/net/sky2.c 2007-01-11 10:23:01.0 -0800
@@ -38,6 +38,7 @@
#include linux/workqueue.h
#include linux/if_vlan.h
#include linux/prefetch.h
+#include linux/proc_fs.h
#include linux/mii.h
#include asm/irq.h
@@ -866,10 +867,11 @@
/* Build description to hardware for one possibly fragmented skb */
static void sky2_rx_submit(struct sky2_port *sky2,
- const struct rx_ring_info *re)
+ struct rx_ring_info *re)
{
int i;
+ re-idx = sky2-rx_put;
sky2_rx_add(sky2, OP_PACKET, re-data_addr, sky2-rx_data_size);
for (i = 0; i skb_shinfo(re-skb)-nr_frags; i++)
@@ -1462,6 +1464,7 @@
}
le-ctrl |= EOP;
+ re-idx = le - sky2-tx_le; /* debug */
if (tx_avail(sky2) = MAX_SKB_TX_LE)
netif_stop_queue(dev);
@@ -3296,6 +3299,139 @@
.get_perm_addr = ethtool_op_get_perm_addr,
};
+
+static struct proc_dir_entry *sky2_proc;
+
+static int sky2_seq_show(struct seq_file *seq, void *v)
+{
+ struct net_device *dev = seq-private;
+ const struct sky2_port *sky2 = netdev_priv(dev);
+ const struct sky2_hw *hw = sky2-hw;
+ unsigned port = sky2-port;
+ unsigned idx, ridx, rend, last;
+
+ last = sky2_read16(hw, STAT_PUT_IDX);
+
+ if (hw-st_idx == last)
+ seq_puts(seq, Status ring (empty)\n);
+ else {
+ seq_puts(seq, Status ring\n);
+ for (idx = hw-st_idx; idx != last;
+idx = RING_NEXT(idx, STATUS_RING_SIZE)) {
+ const struct sky2_status_le *le = hw-st_le + idx;
+ seq_printf(seq, [%d] %#x %d %#x\n,
+ idx, le-opcode, le-length, le-status);
+ }
+ }
+
+ if (sky2-tx_cons == sky2-tx_prod)
+ seq_puts(seq, \nTx ring (empty)\n);
+ else {
+ seq_puts(seq, \nTx ring\n);
+ idx = sky2-tx_cons;
+ while (idx != sky2-tx_prod) {
+ const struct tx_ring_info *re = sky2-tx_ring + idx;
+
+ seq_printf(seq, [%d] %p\n, idx, re-skb);
+ do {
+ const struct sky2_tx_le *le = sky2-tx_le + idx;
+ seq_printf(seq, \t%#x %d, le-opcode,
le-addr);
+ idx = RING_NEXT(idx, TX_RING_SIZE);
+ } while (idx != re-idx || idx != sky2-tx_prod);
+ seq_putc(seq, '\n');
+ }
+ }
+
+ seq_printf(seq, \nRx pending hw get=%d put=%d last=%d\n,
+ sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_GET_IDX)),
+ last = sky2_read16(hw, Y2_QADDR(rxqaddr[port],
PREF_UNIT_PUT_IDX)),
+ sky2_read16(hw, Y2_QADDR(rxqaddr[port],
PREF_UNIT_LAST_IDX)));
+
+ ridx = sky2-rx_next;
+ do {
+ const struct rx_ring_info *re = sky2-rx_ring + ridx;
+ seq_printf(seq, [%d] %p |, ridx, re-skb);
+
+ idx = re-idx;
+ ridx = (ridx + 1) % sky2-rx_pending;
+
+ if (ridx == sky2-rx_next)
+ rend = last;
+ else
+ rend = sky2-rx_ring[ridx].idx;
+
+ do {
+ const struct sky2_rx_le *le = sky2-rx_le + idx;
+
+ switch (le-opcode ~HW_OWNER) {
+ case OP_PACKET:
+ case OP_BUFFER:
+ seq_printf(seq, %#x(%d), le-addr,
le-length);
+ break;
+ case OP_ADDR64:
+ seq_printf(seq, %#x:, le-addr);
+ break;
+ default:
+ seq_printf(seq, {%x} %#x(%d),
+ le-opcode, le-addr, le-length);
+ }
+
+ } while ((idx = RING_NEXT(idx, RX_LE_SIZE)) != rend);
+
+ seq_puts(seq, \n);
+ } while (ridx != sky2-rx_next);
+
+ return 0;
+}
+
+static int sky2_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, sky2_seq_show, PDE(inode)-data);
+}
+
+static const struct file_operations sky2_proc_fops = {
+