From: David Gibson Currently the iSeries virtual ethernet driver has no Tx watchdog timer. This makes it vulnerable to clagging up if the other end of connection is misbehaving - in particular if it is not giving timely hypervisor level acks to our data frams. This patch adds a watchdog timer which resets the connection to any lpar we seem to be having trouble sending to. With any luck the other end might behave better after the reset. If not, this will at least unclag the queue for a while so we can keep talking to the lpars which are behaving correctly. Signed-off-by: David Gibson Signed-off-by: Andrew Morton --- 25-akpm/drivers/net/iseries_veth.c | 45 +++++++++++++++++++++++++++++++++++++ 1 files changed, 45 insertions(+) diff -puN drivers/net/iseries_veth.c~add-watchdog-timer-to-iseries_veth-driver drivers/net/iseries_veth.c --- 25/drivers/net/iseries_veth.c~add-watchdog-timer-to-iseries_veth-driver 2004-05-31 16:50:29.549479288 -0700 +++ 25-akpm/drivers/net/iseries_veth.c 2004-05-31 16:50:29.554478528 -0700 @@ -796,6 +796,48 @@ static int veth_ioctl(struct net_device return -EOPNOTSUPP; } +static void veth_tx_timeout(struct net_device *dev) +{ + struct veth_port *port = (struct veth_port *)dev->priv; + struct net_device_stats *stats = &port->stats; + unsigned long flags; + int i; + + stats->tx_errors++; + + spin_lock_irqsave(&port->pending_gate, flags); + + printk(KERN_WARNING "%s: Tx timeout! Resetting lp connections: %08x\n", + dev->name, port->pending_lpmask); + + /* If we've timed out the queue must be stopped, which should + * only ever happen when there is a pending packet. */ + WARN_ON(! port->pending_lpmask); + + for (i = 0; i < HVMAXARCHITECTEDLPS; i++) { + struct veth_lpar_connection *cnx = veth_cnx[i]; + + if (! (port->pending_lpmask & (1<lock); + cnx->state |= VETH_STATE_RESET; + veth_kick_statemachine(cnx); + spin_unlock(&cnx->lock); + } + + spin_unlock_irqrestore(&port->pending_gate, flags); +} + struct net_device * __init veth_probe_one(int vlan) { struct net_device *dev; @@ -843,6 +885,9 @@ struct net_device * __init veth_probe_on dev->set_multicast_list = veth_set_multicast_list; dev->do_ioctl = veth_ioctl; + dev->watchdog_timeo = 2 * (VETH_ACKTIMEOUT * HZ / 1000000); + dev->tx_timeout = veth_tx_timeout; + rc = register_netdev(dev); if (rc != 0) { veth_printk(KERN_ERR, _