ia64/linux-2.6.18-xen.hg

changeset 849:3a4410c4504e

sfc_netfront: Only clear tx_skb when ready for netif_wake_queue
(doing otherwise could result in a lost packet) and document use of
locks to protect tx_skb

Signed-off-by: Kieran Mansley <kmansley@solarflare.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Mar 31 12:00:53 2009 +0100 (2009-03-31)
parents ab1d4fbbe4bf
children b358ebf1c416
files drivers/xen/sfc_netfront/accel.h drivers/xen/sfc_netfront/accel_netfront.c drivers/xen/sfc_netfront/accel_vi.c
line diff
     1.1 --- a/drivers/xen/sfc_netfront/accel.h	Tue Mar 31 12:00:03 2009 +0100
     1.2 +++ b/drivers/xen/sfc_netfront/accel.h	Tue Mar 31 12:00:53 2009 +0100
     1.3 @@ -277,8 +277,10 @@ typedef struct netfront_accel_vnic {
     1.4  
     1.5  	int poll_enabled;
     1.6  
     1.7 -	/** A spare slot for a TX packet.  This is treated as an extension
     1.8 -	 * of the DMA queue. */
     1.9 +	/** A spare slot for a TX packet.  This is treated as an
    1.10 +	 * extension of the DMA queue.  Reads require either
    1.11 +	 * netfront's tx_lock or the vnic tx_lock; writes require both
    1.12 +	 * locks */
    1.13  	struct sk_buff *tx_skb;
    1.14  
    1.15  	/** Keep track of fragments of SSR packets */
     2.1 --- a/drivers/xen/sfc_netfront/accel_netfront.c	Tue Mar 31 12:00:03 2009 +0100
     2.2 +++ b/drivers/xen/sfc_netfront/accel_netfront.c	Tue Mar 31 12:00:53 2009 +0100
     2.3 @@ -65,7 +65,7 @@ static int netfront_accel_netdev_start_x
     2.4  		BUG_ON(vnic->net_dev != net_dev);
     2.5  		DPRINTK("%s stopping queue\n", __FUNCTION__);
     2.6  
     2.7 -		/* Netfront's lock protects tx_skb */
     2.8 +		/* Need netfront's tx_lock and vnic tx_lock to write tx_skb */
     2.9  		spin_lock_irqsave(&np->tx_lock, flags2);
    2.10  		BUG_ON(vnic->tx_skb != NULL);
    2.11  		vnic->tx_skb = skb;
    2.12 @@ -183,7 +183,7 @@ static int netfront_accel_check_ready(st
    2.13  
    2.14  	BUG_ON(vnic == NULL);
    2.15  
    2.16 -	/* This is protected by netfront's lock */ 
    2.17 +	/* Read of tx_skb is protected by netfront's tx_lock */ 
    2.18  	return vnic->tx_skb == NULL;
    2.19  }
    2.20  
     3.1 --- a/drivers/xen/sfc_netfront/accel_vi.c	Tue Mar 31 12:00:03 2009 +0100
     3.2 +++ b/drivers/xen/sfc_netfront/accel_vi.c	Tue Mar 31 12:00:53 2009 +0100
     3.3 @@ -991,39 +991,35 @@ static void netfront_accel_vi_not_busy(n
     3.4  {
     3.5  	struct netfront_info *np = ((struct netfront_info *)
     3.6  				    netdev_priv(vnic->net_dev));
     3.7 -	struct sk_buff *skb;
     3.8  	int handled;
     3.9  	unsigned long flags;
    3.10 -	
    3.11 +
    3.12  	/*
    3.13 -	 * TODO if we could safely check tx_skb == NULL and return
    3.14 -	 * early without taking the lock, that would obviously help
    3.15 -	 * performance
    3.16 +	 * We hold the vnic tx_lock which is sufficient to exclude
    3.17 +	 * writes to tx_skb
    3.18  	 */
    3.19  
    3.20 -	/* Take the netfront lock which protects tx_skb. */
    3.21 -	spin_lock_irqsave(&np->tx_lock, flags);
    3.22  	if (vnic->tx_skb != NULL) {
    3.23  		DPRINTK("%s trying to send spare buffer\n", __FUNCTION__);
    3.24  		
    3.25 -		skb = vnic->tx_skb;
    3.26 -		vnic->tx_skb = NULL;
    3.27 -
    3.28 -		spin_unlock_irqrestore(&np->tx_lock, flags);
    3.29 -
    3.30 -		handled = netfront_accel_vi_tx_post(vnic, skb);
    3.31 +		handled = netfront_accel_vi_tx_post(vnic, vnic->tx_skb);
    3.32  		
    3.33 -		spin_lock_irqsave(&np->tx_lock, flags);
    3.34 -
    3.35  		if (handled != NETFRONT_ACCEL_STATUS_BUSY) {
    3.36  			DPRINTK("%s restarting tx\n", __FUNCTION__);
    3.37 +
    3.38 +			/* Need netfront tx_lock and vnic tx_lock to
    3.39 +			 * write tx_skb */
    3.40 +			spin_lock_irqsave(&np->tx_lock, flags);
    3.41 +
    3.42 +			vnic->tx_skb = NULL;
    3.43 +
    3.44  			if (netfront_check_queue_ready(vnic->net_dev)) {
    3.45  				netif_wake_queue(vnic->net_dev);
    3.46  				NETFRONT_ACCEL_STATS_OP
    3.47  					(vnic->stats.queue_wakes++);
    3.48  			}
    3.49 -		} else {
    3.50 -			vnic->tx_skb = skb;
    3.51 +			spin_unlock_irqrestore(&np->tx_lock, flags);
    3.52 +
    3.53  		}
    3.54  		
    3.55  		/*
    3.56 @@ -1032,7 +1028,6 @@ static void netfront_accel_vi_not_busy(n
    3.57  		 */
    3.58  		BUG_ON(handled == NETFRONT_ACCEL_STATUS_CANT);
    3.59  	}
    3.60 -	spin_unlock_irqrestore(&np->tx_lock, flags);
    3.61  }
    3.62  
    3.63