Commit 673a68e6 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] Add watchdog timer to iseries_veth driver

From: David Gibson <david@gibson.dropbear.id.au>

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: default avatarDavid Gibson <david@gibson.dropbear.id.au>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent dbfd829d
......@@ -801,6 +801,48 @@ static int veth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
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<<i)))
continue;
/* If we're pending on it, we must be connected to it,
* so we should certainly have a structure for it. */
BUG_ON(! cnx);
/* Theoretically we could be kicking a connection
* which doesn't deserve it, but in practice if we've
* had a Tx timeout, the pending_lpmask will have
* exactly one bit set - the connection causing the
* problem. */
spin_lock(&cnx->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;
......@@ -848,6 +890,9 @@ struct net_device * __init veth_probe_one(int vlan)
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,
......
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