===== net/sched/sch_generic.c 1.32 vs edited =====
--- 1.32/net/sched/sch_generic.c	2004-12-28 05:51:20 +01:00
+++ edited/net/sched/sch_generic.c	2005-01-02 23:55:18 +01:00
@@ -104,9 +104,17 @@
 		 * locking again. These checks are worth it because
 		 * even uncongested locks can be quite expensive.
 		 * The driver can do trylock like here too, in case
-		 * of lock congestion it should return -1 and the packet
-		 * will be requeued.
+		 * of lock congestion it should return NETDEV_TX_LOCKED
+		 * and the packet will be requeued.
+		 * 
+		 * Note: when the driver has LLTX set queue_lock cannot
+		 * be dropped in here if we want to avoid having packets
+		 * passing eachover during transmit. queue_lock can only
+		 * be dropped in hard_start_xmit() after private tx lock 
+		 * has been grabbed. If hard_start_xmit() does release 
+		 * queue_lock it must grab it again before it returns.
 		 */
+
 		if (!nolock) {
 			if (!spin_trylock(&dev->xmit_lock)) {
 			collision:
@@ -128,12 +136,12 @@
 			}
 			/* Remember that the driver is grabbed by us. */
 			dev->xmit_lock_owner = smp_processor_id();
+
+			/* And release queue */
+			spin_unlock(&dev->queue_lock);
 		}
 		
 		{
-			/* And release queue */
-			spin_unlock(&dev->queue_lock);
-
 			if (!netif_queue_stopped(dev)) {
 				int ret;
 				if (netdev_nit)
@@ -144,14 +152,12 @@
 					if (!nolock) {
 						dev->xmit_lock_owner = -1;
 						spin_unlock(&dev->xmit_lock);
+						spin_lock(&dev->queue_lock);
 					}
-					spin_lock(&dev->queue_lock);
 					return -1;
 				}
-				if (ret == NETDEV_TX_LOCKED && nolock) {
-					spin_lock(&dev->queue_lock);
+				if (ret == NETDEV_TX_LOCKED && nolock)
 					goto collision; 
-				}
 			}
 
 			/* NETDEV_TX_BUSY - we need to requeue */
@@ -159,8 +165,8 @@
 			if (!nolock) { 
 				dev->xmit_lock_owner = -1;
 				spin_unlock(&dev->xmit_lock);
+				spin_lock(&dev->queue_lock);
 			} 
-			spin_lock(&dev->queue_lock);
 			q = dev->qdisc;
 		}
 
