aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorSowmini Varadhan <sowmini.varadhan@oracle.com>2014-08-12 10:33:10 -0400
committerDavid S. Miller <davem@davemloft.net>2014-08-13 23:04:46 -0400
commitadddc32d6fde82156c779997f928865100542e55 (patch)
treeb7605e8c600203c43768f48256c4382f30e5c390 /drivers/net
parent1f6394e382f137f07136182c591ca8a7eeba6a06 (diff)
sunvnet: Do not spin in an infinite loop when vio_ldc_send() returns EAGAIN
ldc_rx -> vnet_rx -> .. -> vnet_walk_rx->vnet_send_ack should not spin into an infinite loop waiting EAGAIN to lift. The sender could have sent us a burst, and gone to lunch without doing any more ldc_read()'s. That should not cause the receiver to loop infinitely till soft-lockup kicks in. Similarly __vnet_tx_trigger should only loop on EAGAIN a finite number of times. The caller (vnet_start_xmit()) already has code to reset the dring state and bail on errors from __vnet_tx_trigger Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com> Acked-by: Raghuram Kothakota <raghuram.kothakota@oracle.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ethernet/sun/sunvnet.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c
index 238434dcfe02..a5871791e452 100644
--- a/drivers/net/ethernet/sun/sunvnet.c
+++ b/drivers/net/ethernet/sun/sunvnet.c
@@ -32,6 +32,11 @@ MODULE_DESCRIPTION("Sun LDOM virtual network driver");
32MODULE_LICENSE("GPL"); 32MODULE_LICENSE("GPL");
33MODULE_VERSION(DRV_MODULE_VERSION); 33MODULE_VERSION(DRV_MODULE_VERSION);
34 34
35/* Heuristic for the number of times to exponentially backoff and
36 * retry sending an LDC trigger when EAGAIN is encountered
37 */
38#define VNET_MAX_RETRIES 10
39
35/* Ordered from largest major to lowest */ 40/* Ordered from largest major to lowest */
36static struct vio_version vnet_versions[] = { 41static struct vio_version vnet_versions[] = {
37 { .major = 1, .minor = 0 }, 42 { .major = 1, .minor = 0 },
@@ -260,6 +265,7 @@ static int vnet_send_ack(struct vnet_port *port, struct vio_dring_state *dr,
260 .state = vio_dring_state, 265 .state = vio_dring_state,
261 }; 266 };
262 int err, delay; 267 int err, delay;
268 int retries = 0;
263 269
264 hdr.seq = dr->snd_nxt; 270 hdr.seq = dr->snd_nxt;
265 delay = 1; 271 delay = 1;
@@ -272,6 +278,13 @@ static int vnet_send_ack(struct vnet_port *port, struct vio_dring_state *dr,
272 udelay(delay); 278 udelay(delay);
273 if ((delay <<= 1) > 128) 279 if ((delay <<= 1) > 128)
274 delay = 128; 280 delay = 128;
281 if (retries++ > VNET_MAX_RETRIES) {
282 pr_info("ECONNRESET %x:%x:%x:%x:%x:%x\n",
283 port->raddr[0], port->raddr[1],
284 port->raddr[2], port->raddr[3],
285 port->raddr[4], port->raddr[5]);
286 err = -ECONNRESET;
287 }
275 } while (err == -EAGAIN); 288 } while (err == -EAGAIN);
276 289
277 return err; 290 return err;
@@ -593,6 +606,7 @@ static int __vnet_tx_trigger(struct vnet_port *port)
593 .end_idx = (u32) -1, 606 .end_idx = (u32) -1,
594 }; 607 };
595 int err, delay; 608 int err, delay;
609 int retries = 0;
596 610
597 hdr.seq = dr->snd_nxt; 611 hdr.seq = dr->snd_nxt;
598 delay = 1; 612 delay = 1;
@@ -605,6 +619,8 @@ static int __vnet_tx_trigger(struct vnet_port *port)
605 udelay(delay); 619 udelay(delay);
606 if ((delay <<= 1) > 128) 620 if ((delay <<= 1) > 128)
607 delay = 128; 621 delay = 128;
622 if (retries++ > VNET_MAX_RETRIES)
623 break;
608 } while (err == -EAGAIN); 624 } while (err == -EAGAIN);
609 625
610 return err; 626 return err;