Thread (9 messages) 9 messages, 3 authors, 2006-08-23

Re: sky2 driver - large files upload problem

From: Stephen Hemminger <hidden>
Date: 2006-08-21 16:51:27

On Mon, 21 Aug 2006 16:21:07 +0200
Jon Wikne [off-list ref] wrote:
Daniel Drake wrote:
quoted
Jon Wikne wrote:
quoted
What happens is typically this: After transeferring some
data, ranging from less than 100kB to 10MB, the upload freezes,
i.e. gets no further. Use of ping shows the connection is
effectively dead. If I do a sequence /sbin/ifdown eth0
/sbin/ifup eth0 the upload might resume, but stops again
shortly. The phenomenon seems to occur sooner if the path
to the remote system is _fast_ (low ping times).
You can try applying this patch:
http://developer.osdl.org/shemminger/prototypes/sky2-proc-debug.patch

It will add a /proc/net/sky2/ethX file, which lists the status of the TX 
and status rings. You should compare the contents of this file during 
normal operation to when the interface has hung.
Thanks, Daniel. I applied the patch.

The output of 'cat /proc/net/sky2/eth0' under normal circumstances
is here:

http://puma.uio.no/sky2/sky2-status-normal.txt

After the interface hangs, 'cat /proc/net/sky2/eth0' causes the
whole computer to hang completely. No kernel oops or other
messages in the console window. Power down is the only
solution.... :-[ No log entries after reboot.
It could be the code in the debug patch is walking off into space.
The smaller version of the same patch, doesn't walk but just reports
the index values.
--- sky2.orig/drivers/net/sky2.c	2006-08-16 15:17:53.000000000 -0700
+++ sky2/drivers/net/sky2.c	2006-08-16 15:19:42.000000000 -0700
@@ -38,6 +38,7 @@
 #include <linux/delay.h>
 #include <linux/workqueue.h>
 #include <linux/if_vlan.h>
+#include <linux/proc_fs.h>
 #include <linux/prefetch.h>
 #include <linux/mii.h>
 
@@ -1005,6 +1006,7 @@
 
 		re->mapaddr = pci_map_single(hw->pdev, re->skb->data,
 					     sky2->rx_bufsize, PCI_DMA_FROMDEVICE);
+		re->ridx = sky2->rx_put;
 		sky2_rx_add(sky2, re->mapaddr);
 	}
 
@@ -1890,6 +1892,7 @@
 	skb_put(skb, length);
 resubmit:
 	re->skb->ip_summed = CHECKSUM_NONE;
+	re->ridx = sky2->rx_put;
 	sky2_rx_add(sky2, re->mapaddr);
 
 	return skb;
@@ -3088,6 +3091,49 @@
 	.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 last;
+
+	last = sky2_read16(hw, STAT_PUT_IDX);
+
+	if (hw->st_idx == last)
+		seq_puts(seq, "Status ring (empty)\n");
+	else
+		seq_printf(seq, "Status ring %d...%d\n", last, hw->st_idx);
+
+	if (sky2->tx_cons == sky2->tx_prod)
+		seq_puts(seq, "Tx ring (empty)\n");
+	else
+		seq_printf(seq, "Tx ring %d..%d\n", sky2->tx_cons, sky2->tx_prod);
+
+	seq_printf(seq, "Rx pending hw get=%d put=%d last=%d\n",
+		   sky2_read16(hw, Y2_QADDR(rxqaddr[sky2->port], PREF_UNIT_GET_IDX)),
+		   sky2_read16(hw, Y2_QADDR(rxqaddr[sky2->port], PREF_UNIT_PUT_IDX)),
+		   sky2_read16(hw, Y2_QADDR(rxqaddr[sky2->port], PREF_UNIT_LAST_IDX)));
+
+	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 = {
+	.owner		= THIS_MODULE,
+	.open		= sky2_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
 /* Initialize network device */
 static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
 						     unsigned port, int highmem)
@@ -3178,6 +3224,15 @@
 		       dev->name,
 		       dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
 		       dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+
+	if (sky2_proc) {
+		struct proc_dir_entry *res;
+		res = create_proc_entry(dev->name, S_IRUGO, sky2_proc);
+		if (res) {
+			res->proc_fops = &sky2_proc_fops;
+			res->data = dev;
+		}
+	}
 }
 
 /* Handle software interrupt used during MSI test */
@@ -3417,8 +3472,11 @@
 
 	dev0 = hw->dev[0];
 	dev1 = hw->dev[1];
-	if (dev1)
+	if (dev1) {
+		remove_proc_entry(dev1->name, sky2_proc);
 		unregister_netdev(dev1);
+	}
+	remove_proc_entry(dev0->name, sky2_proc);
 	unregister_netdev(dev0);
 
 	sky2_set_power_state(hw, PCI_D3hot);
@@ -3519,12 +3577,14 @@
 
 static int __init sky2_init_module(void)
 {
+	sky2_proc = proc_mkdir("sky2", proc_net);
 	return pci_register_driver(&sky2_driver);
 }
 
 static void __exit sky2_cleanup_module(void)
 {
 	pci_unregister_driver(&sky2_driver);
+	proc_net_remove("sky2");
 }
 
 module_init(sky2_init_module);
--- sky2.orig/drivers/net/sky2.h	2006-08-16 15:19:29.000000000 -0700
+++ sky2/drivers/net/sky2.h	2006-08-16 15:19:42.000000000 -0700
@@ -1827,6 +1827,7 @@
 struct ring_info {
 	struct sk_buff	*skb;
 	dma_addr_t	mapaddr;
+	u16		ridx;
 };
 
 struct sky2_port {
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help