};
 
 /*
- * Device private locking: tx_lock protects members used in TX fast
- * path (and we use LLTX so upper layers don't do extra locking).
- * lock protects everything else.  lock nests inside of tx_lock (ie
- * tx_lock must be acquired first if needed).
+ * Device private locking: network stack tx_lock protects members used
+ * in TX fast path, lock protects everything else.  lock nests inside
+ * of tx_lock (ie tx_lock must be acquired first if needed).
  */
 struct ipoib_dev_priv {
        spinlock_t lock;
 
        struct ipoib_rx_buf *rx_ring;
 
-       spinlock_t           tx_lock;
        struct ipoib_tx_buf *tx_ring;
        unsigned             tx_head;
        unsigned             tx_tail;
 
 
        dev_kfree_skb_any(tx_req->skb);
 
-       spin_lock_irqsave(&priv->tx_lock, flags);
+       netif_tx_lock(dev);
+
        ++tx->tx_tail;
        if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) &&
            netif_queue_stopped(dev) &&
                           "(status=%d, wrid=%d vend_err %x)\n",
                           wc->status, wr_id, wc->vendor_err);
 
-               spin_lock(&priv->lock);
+               spin_lock_irqsave(&priv->lock, flags);
                neigh = tx->neigh;
 
                if (neigh) {
 
                clear_bit(IPOIB_FLAG_OPER_UP, &tx->flags);
 
-               spin_unlock(&priv->lock);
+               spin_unlock_irqrestore(&priv->lock, flags);
        }
 
-       spin_unlock_irqrestore(&priv->tx_lock, flags);
+       netif_tx_unlock(dev);
 }
 
 int ipoib_cm_dev_open(struct net_device *dev)
 {
        struct ipoib_dev_priv *priv = netdev_priv(p->dev);
        struct ipoib_cm_tx_buf *tx_req;
-       unsigned long flags;
        unsigned long begin;
 
        ipoib_dbg(priv, "Destroy active connection 0x%x head 0x%x tail 0x%x\n",
                                    DMA_TO_DEVICE);
                dev_kfree_skb_any(tx_req->skb);
                ++p->tx_tail;
-               spin_lock_irqsave(&priv->tx_lock, flags);
+               netif_tx_lock_bh(p->dev);
                if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) &&
                    netif_queue_stopped(p->dev) &&
                    test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
                        netif_wake_queue(p->dev);
-               spin_unlock_irqrestore(&priv->tx_lock, flags);
+               netif_tx_unlock_bh(p->dev);
        }
 
        if (p->qp)
        struct ipoib_dev_priv *priv = netdev_priv(tx->dev);
        struct net_device *dev = priv->dev;
        struct ipoib_neigh *neigh;
+       unsigned long flags;
        int ret;
 
        switch (event->event) {
        case IB_CM_REJ_RECEIVED:
        case IB_CM_TIMEWAIT_EXIT:
                ipoib_dbg(priv, "CM error %d.\n", event->event);
-               spin_lock_irq(&priv->tx_lock);
-               spin_lock(&priv->lock);
+               netif_tx_lock_bh(dev);
+               spin_lock_irqsave(&priv->lock, flags);
                neigh = tx->neigh;
 
                if (neigh) {
                        queue_work(ipoib_workqueue, &priv->cm.reap_task);
                }
 
-               spin_unlock(&priv->lock);
-               spin_unlock_irq(&priv->tx_lock);
+               spin_unlock_irqrestore(&priv->lock, flags);
+               netif_tx_unlock_bh(dev);
                break;
        default:
                break;
        struct ib_sa_path_rec pathrec;
        u32 qpn;
 
-       spin_lock_irqsave(&priv->tx_lock, flags);
-       spin_lock(&priv->lock);
+       netif_tx_lock_bh(dev);
+       spin_lock_irqsave(&priv->lock, flags);
+
        while (!list_empty(&priv->cm.start_list)) {
                p = list_entry(priv->cm.start_list.next, typeof(*p), list);
                list_del_init(&p->list);
                neigh = p->neigh;
                qpn = IPOIB_QPN(neigh->neighbour->ha);
                memcpy(&pathrec, &p->path->pathrec, sizeof pathrec);
-               spin_unlock(&priv->lock);
-               spin_unlock_irqrestore(&priv->tx_lock, flags);
+
+               spin_unlock_irqrestore(&priv->lock, flags);
+               netif_tx_unlock_bh(dev);
+
                ret = ipoib_cm_tx_init(p, qpn, &pathrec);
-               spin_lock_irqsave(&priv->tx_lock, flags);
-               spin_lock(&priv->lock);
+
+               netif_tx_lock_bh(dev);
+               spin_lock_irqsave(&priv->lock, flags);
+
                if (ret) {
                        neigh = p->neigh;
                        if (neigh) {
                        kfree(p);
                }
        }
-       spin_unlock(&priv->lock);
-       spin_unlock_irqrestore(&priv->tx_lock, flags);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+       netif_tx_unlock_bh(dev);
 }
 
 static void ipoib_cm_tx_reap(struct work_struct *work)
 {
        struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
                                                   cm.reap_task);
+       struct net_device *dev = priv->dev;
        struct ipoib_cm_tx *p;
+       unsigned long flags;
+
+       netif_tx_lock_bh(dev);
+       spin_lock_irqsave(&priv->lock, flags);
 
-       spin_lock_irq(&priv->tx_lock);
-       spin_lock(&priv->lock);
        while (!list_empty(&priv->cm.reap_list)) {
                p = list_entry(priv->cm.reap_list.next, typeof(*p), list);
                list_del(&p->list);
-               spin_unlock(&priv->lock);
-               spin_unlock_irq(&priv->tx_lock);
+               spin_unlock_irqrestore(&priv->lock, flags);
+               netif_tx_unlock_bh(dev);
                ipoib_cm_tx_destroy(p);
-               spin_lock_irq(&priv->tx_lock);
-               spin_lock(&priv->lock);
+               netif_tx_lock_bh(dev);
+               spin_lock_irqsave(&priv->lock, flags);
        }
-       spin_unlock(&priv->lock);
-       spin_unlock_irq(&priv->tx_lock);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+       netif_tx_unlock_bh(dev);
 }
 
 static void ipoib_cm_skb_reap(struct work_struct *work)
 {
        struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
                                                   cm.skb_task);
+       struct net_device *dev = priv->dev;
        struct sk_buff *skb;
-
+       unsigned long flags;
        unsigned mtu = priv->mcast_mtu;
 
-       spin_lock_irq(&priv->tx_lock);
-       spin_lock(&priv->lock);
+       netif_tx_lock_bh(dev);
+       spin_lock_irqsave(&priv->lock, flags);
+
        while ((skb = skb_dequeue(&priv->cm.skb_queue))) {
-               spin_unlock(&priv->lock);
-               spin_unlock_irq(&priv->tx_lock);
+               spin_unlock_irqrestore(&priv->lock, flags);
+               netif_tx_unlock_bh(dev);
+
                if (skb->protocol == htons(ETH_P_IP))
                        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
                        icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, priv->dev);
 #endif
                dev_kfree_skb_any(skb);
-               spin_lock_irq(&priv->tx_lock);
-               spin_lock(&priv->lock);
+
+               netif_tx_lock_bh(dev);
+               spin_lock_irqsave(&priv->lock, flags);
        }
-       spin_unlock(&priv->lock);
-       spin_unlock_irq(&priv->tx_lock);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+       netif_tx_unlock_bh(dev);
 }
 
 void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb,
 
 static void drain_tx_cq(struct net_device *dev)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
-       unsigned long flags;
 
-       spin_lock_irqsave(&priv->tx_lock, flags);
+       netif_tx_lock(dev);
        while (poll_tx(priv))
                ; /* nothing */
 
        if (netif_queue_stopped(dev))
                mod_timer(&priv->poll_timer, jiffies + 1);
 
-       spin_unlock_irqrestore(&priv->tx_lock, flags);
+       netif_tx_unlock(dev);
 }
 
 void ipoib_send_comp_handler(struct ib_cq *cq, void *dev_ptr)
 {
-       drain_tx_cq((struct net_device *)dev_ptr);
+       struct ipoib_dev_priv *priv = netdev_priv(dev_ptr);
+
+       mod_timer(&priv->poll_timer, jiffies);
 }
 
 static inline int post_send(struct ipoib_dev_priv *priv,
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ipoib_ah *ah, *tah;
        LIST_HEAD(remove_list);
+       unsigned long flags;
+
+       netif_tx_lock_bh(dev);
+       spin_lock_irqsave(&priv->lock, flags);
 
-       spin_lock_irq(&priv->tx_lock);
-       spin_lock(&priv->lock);
        list_for_each_entry_safe(ah, tah, &priv->dead_ahs, list)
                if ((int) priv->tx_tail - (int) ah->last_send >= 0) {
                        list_del(&ah->list);
                        ib_destroy_ah(ah->ah);
                        kfree(ah);
                }
-       spin_unlock(&priv->lock);
-       spin_unlock_irq(&priv->tx_lock);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+       netif_tx_unlock_bh(dev);
 }
 
 void ipoib_reap_ah(struct work_struct *work)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        int i, n;
+
+       /*
+        * We call completion handling routines that expect to be
+        * called from the BH-disabled NAPI poll context, so disable
+        * BHs here too.
+        */
+       local_bh_disable();
+
        do {
                n = ib_poll_cq(priv->recv_cq, IPOIB_NUM_WC, priv->ibwc);
                for (i = 0; i < n; ++i) {
 
        while (poll_tx(priv))
                ; /* nothing */
+
+       local_bh_enable();
 }
 
 int ipoib_ib_dev_stop(struct net_device *dev, int flush)
 
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ipoib_path *path, *tp;
        LIST_HEAD(remove_list);
+       unsigned long flags;
 
-       spin_lock_irq(&priv->tx_lock);
-       spin_lock(&priv->lock);
+       netif_tx_lock_bh(dev);
+       spin_lock_irqsave(&priv->lock, flags);
 
        list_splice_init(&priv->path_list, &remove_list);
 
        list_for_each_entry_safe(path, tp, &remove_list, list) {
                if (path->query)
                        ib_sa_cancel_query(path->query_id, path->query);
-               spin_unlock(&priv->lock);
-               spin_unlock_irq(&priv->tx_lock);
+               spin_unlock_irqrestore(&priv->lock, flags);
+               netif_tx_unlock_bh(dev);
                wait_for_completion(&path->done);
                path_free(dev, path);
-               spin_lock_irq(&priv->tx_lock);
-               spin_lock(&priv->lock);
+               netif_tx_lock_bh(dev);
+               spin_lock_irqsave(&priv->lock, flags);
        }
-       spin_unlock(&priv->lock);
-       spin_unlock_irq(&priv->tx_lock);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+       netif_tx_unlock_bh(dev);
 }
 
 static void path_rec_completion(int status,
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ipoib_path *path;
        struct ipoib_neigh *neigh;
+       unsigned long flags;
 
        neigh = ipoib_neigh_alloc(skb->dst->neighbour, skb->dev);
        if (!neigh) {
                return;
        }
 
-       /*
-        * We can only be called from ipoib_start_xmit, so we're
-        * inside tx_lock -- no need to save/restore flags.
-        */
-       spin_lock(&priv->lock);
+       spin_lock_irqsave(&priv->lock, flags);
 
        path = __path_find(dev, skb->dst->neighbour->ha + 4);
        if (!path) {
                __skb_queue_tail(&neigh->queue, skb);
        }
 
-       spin_unlock(&priv->lock);
+       spin_unlock_irqrestore(&priv->lock, flags);
        return;
 
 err_list:
        ++dev->stats.tx_dropped;
        dev_kfree_skb_any(skb);
 
-       spin_unlock(&priv->lock);
+       spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ipoib_path *path;
+       unsigned long flags;
 
-       /*
-        * We can only be called from ipoib_start_xmit, so we're
-        * inside tx_lock -- no need to save/restore flags.
-        */
-       spin_lock(&priv->lock);
+       spin_lock_irqsave(&priv->lock, flags);
 
        path = __path_find(dev, phdr->hwaddr + 4);
        if (!path || !path->valid) {
                        __skb_queue_tail(&path->queue, skb);
 
                        if (path_rec_start(dev, path)) {
-                               spin_unlock(&priv->lock);
+                               spin_unlock_irqrestore(&priv->lock, flags);
                                path_free(dev, path);
                                return;
                        } else
                        dev_kfree_skb_any(skb);
                }
 
-               spin_unlock(&priv->lock);
+               spin_unlock_irqrestore(&priv->lock, flags);
                return;
        }
 
                dev_kfree_skb_any(skb);
        }
 
-       spin_unlock(&priv->lock);
+       spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct ipoib_neigh *neigh;
        unsigned long flags;
 
-       if (unlikely(!spin_trylock_irqsave(&priv->tx_lock, flags)))
-               return NETDEV_TX_LOCKED;
-
        if (likely(skb->dst && skb->dst->neighbour)) {
                if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) {
                        ipoib_path_lookup(skb, dev);
-                       goto out;
+                       return NETDEV_TX_OK;
                }
 
                neigh = *to_ipoib_neigh(skb->dst->neighbour);
                                            skb->dst->neighbour->ha + 4,
                                            sizeof(union ib_gid))) ||
                                         (neigh->dev != dev))) {
-                               spin_lock(&priv->lock);
+                               spin_lock_irqsave(&priv->lock, flags);
                                /*
                                 * It's safe to call ipoib_put_ah() inside
                                 * priv->lock here, because we know that
                                ipoib_put_ah(neigh->ah);
                                list_del(&neigh->list);
                                ipoib_neigh_free(dev, neigh);
-                               spin_unlock(&priv->lock);
+                               spin_unlock_irqrestore(&priv->lock, flags);
                                ipoib_path_lookup(skb, dev);
-                               goto out;
+                               return NETDEV_TX_OK;
                        }
 
                if (ipoib_cm_get(neigh)) {
                        if (ipoib_cm_up(neigh)) {
                                ipoib_cm_send(dev, skb, ipoib_cm_get(neigh));
-                               goto out;
+                               return NETDEV_TX_OK;
                        }
                } else if (neigh->ah) {
                        ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb->dst->neighbour->ha));
-                       goto out;
+                       return NETDEV_TX_OK;
                }
 
                if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
-                       spin_lock(&priv->lock);
+                       spin_lock_irqsave(&priv->lock, flags);
                        __skb_queue_tail(&neigh->queue, skb);
-                       spin_unlock(&priv->lock);
+                       spin_unlock_irqrestore(&priv->lock, flags);
                } else {
                        ++dev->stats.tx_dropped;
                        dev_kfree_skb_any(skb);
                                           IPOIB_GID_RAW_ARG(phdr->hwaddr + 4));
                                dev_kfree_skb_any(skb);
                                ++dev->stats.tx_dropped;
-                               goto out;
+                               return NETDEV_TX_OK;
                        }
 
                        unicast_arp_send(skb, dev, phdr);
                }
        }
 
-out:
-       spin_unlock_irqrestore(&priv->tx_lock, flags);
-
        return NETDEV_TX_OK;
 }
 
        dev->type                = ARPHRD_INFINIBAND;
        dev->tx_queue_len        = ipoib_sendq_size * 2;
        dev->features            = (NETIF_F_VLAN_CHALLENGED     |
-                                   NETIF_F_LLTX                |
                                    NETIF_F_HIGHDMA);
 
        memcpy(dev->broadcast, ipv4_bcast_addr, INFINIBAND_ALEN);
        ipoib_lro_setup(priv);
 
        spin_lock_init(&priv->lock);
-       spin_lock_init(&priv->tx_lock);
 
        mutex_init(&priv->vlan_mutex);
 
 
        struct net_device *dev = mcast->dev;
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ipoib_neigh *neigh, *tmp;
-       unsigned long flags;
        int tx_dropped = 0;
 
        ipoib_dbg_mcast(netdev_priv(dev),
                        "deleting multicast group " IPOIB_GID_FMT "\n",
                        IPOIB_GID_ARG(mcast->mcmember.mgid));
 
-       spin_lock_irqsave(&priv->lock, flags);
+       spin_lock_irq(&priv->lock);
 
        list_for_each_entry_safe(neigh, tmp, &mcast->neigh_list, list) {
                /*
                ipoib_neigh_free(dev, neigh);
        }
 
-       spin_unlock_irqrestore(&priv->lock, flags);
+       spin_unlock_irq(&priv->lock);
 
        if (mcast->ah)
                ipoib_put_ah(mcast->ah);
                dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
        }
 
-       spin_lock_irqsave(&priv->tx_lock, flags);
+       netif_tx_lock_bh(dev);
        dev->stats.tx_dropped += tx_dropped;
-       spin_unlock_irqrestore(&priv->tx_lock, flags);
+       netif_tx_unlock_bh(dev);
 
        kfree(mcast);
 }
        }
 
        /* actually send any queued packets */
-       spin_lock_irq(&priv->tx_lock);
+       netif_tx_lock_bh(dev);
        while (!skb_queue_empty(&mcast->pkt_queue)) {
                struct sk_buff *skb = skb_dequeue(&mcast->pkt_queue);
-               spin_unlock_irq(&priv->tx_lock);
+               netif_tx_unlock_bh(dev);
 
                skb->dev = dev;
 
 
                if (dev_queue_xmit(skb))
                        ipoib_warn(priv, "dev_queue_xmit failed to requeue packet\n");
-               spin_lock_irq(&priv->tx_lock);
+               netif_tx_lock_bh(dev);
        }
-       spin_unlock_irq(&priv->tx_lock);
+       netif_tx_unlock_bh(dev);
 
        return 0;
 }
 {
        struct ipoib_mcast *mcast = multicast->context;
        struct net_device *dev = mcast->dev;
-       struct ipoib_dev_priv *priv = netdev_priv(dev);
 
        /* We trap for port events ourselves. */
        if (status == -ENETRESET)
                                        IPOIB_GID_ARG(mcast->mcmember.mgid), status);
 
                /* Flush out any queued packets */
-               spin_lock_irq(&priv->tx_lock);
+               netif_tx_lock_bh(dev);
                while (!skb_queue_empty(&mcast->pkt_queue)) {
                        ++dev->stats.tx_dropped;
                        dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
                }
-               spin_unlock_irq(&priv->tx_lock);
+               netif_tx_unlock_bh(dev);
 
                /* Clear the busy flag so we try again */
                status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY,
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ipoib_mcast *mcast;
+       unsigned long flags;
 
-       /*
-        * We can only be called from ipoib_start_xmit, so we're
-        * inside tx_lock -- no need to save/restore flags.
-        */
-       spin_lock(&priv->lock);
+       spin_lock_irqsave(&priv->lock, flags);
 
        if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)         ||
            !priv->broadcast                                    ||
        }
 
 unlock:
-       spin_unlock(&priv->lock);
+       spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 void ipoib_mcast_dev_flush(struct net_device *dev)