diff options
author | Roland Dreier <rolandd@cisco.com> | 2008-09-30 13:36:21 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2008-09-30 13:36:21 -0400 |
commit | 943c246e9ba9078a61b6bcc5b4a8131ce8befb64 (patch) | |
tree | 5be6015188c06d14ff39ac85f28f58834d001d05 /drivers/infiniband/ulp/ipoib/ipoib_ib.c | |
parent | c9da4bad5b80c3d9884e2c6ad8d2091252c32d5e (diff) |
IPoIB: Use netif_tx_lock() and get rid of private tx_lock, LLTX
Currently, IPoIB is an LLTX driver that uses its own IRQ-disabling
tx_lock. Not only do we want to get rid of LLTX, this actually causes
problems because of the skb_orphan() done with this tx_lock held: some
skb destructors expect to be run with interrupts enabled.
The simplest fix for this is to get rid of the driver-private tx_lock
and stop using LLTX. We kill off priv->tx_lock and use
netif_tx_lock[_bh]() instead; the patch to do this is a tiny bit
tricky because we need to update places that take priv->lock inside
the tx_lock to disable IRQs, rather than relying on tx_lock having
already disabled IRQs.
Also, there are a couple of places where we need to disable BHs to
make sure we have a consistent context to call netif_tx_lock() (since
we no longer can use _irqsave() variants), and we also have to change
ipoib_send_comp_handler() to call drain_tx_cq() through a timer rather
than directly, because ipoib_send_comp_handler() runs in interrupt
context and drain_tx_cq() must run in BH context so it can call
netif_tx_lock().
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/ulp/ipoib/ipoib_ib.c')
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_ib.c | 30 |
1 files changed, 22 insertions, 8 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 66cafa20c246..0e748aeeae99 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c | |||
@@ -468,21 +468,22 @@ void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr) | |||
468 | static void drain_tx_cq(struct net_device *dev) | 468 | static void drain_tx_cq(struct net_device *dev) |
469 | { | 469 | { |
470 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 470 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
471 | unsigned long flags; | ||
472 | 471 | ||
473 | spin_lock_irqsave(&priv->tx_lock, flags); | 472 | netif_tx_lock(dev); |
474 | while (poll_tx(priv)) | 473 | while (poll_tx(priv)) |
475 | ; /* nothing */ | 474 | ; /* nothing */ |
476 | 475 | ||
477 | if (netif_queue_stopped(dev)) | 476 | if (netif_queue_stopped(dev)) |
478 | mod_timer(&priv->poll_timer, jiffies + 1); | 477 | mod_timer(&priv->poll_timer, jiffies + 1); |
479 | 478 | ||
480 | spin_unlock_irqrestore(&priv->tx_lock, flags); | 479 | netif_tx_unlock(dev); |
481 | } | 480 | } |
482 | 481 | ||
483 | void ipoib_send_comp_handler(struct ib_cq *cq, void *dev_ptr) | 482 | void ipoib_send_comp_handler(struct ib_cq *cq, void *dev_ptr) |
484 | { | 483 | { |
485 | drain_tx_cq((struct net_device *)dev_ptr); | 484 | struct ipoib_dev_priv *priv = netdev_priv(dev_ptr); |
485 | |||
486 | mod_timer(&priv->poll_timer, jiffies); | ||
486 | } | 487 | } |
487 | 488 | ||
488 | static inline int post_send(struct ipoib_dev_priv *priv, | 489 | static inline int post_send(struct ipoib_dev_priv *priv, |
@@ -614,17 +615,20 @@ static void __ipoib_reap_ah(struct net_device *dev) | |||
614 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 615 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
615 | struct ipoib_ah *ah, *tah; | 616 | struct ipoib_ah *ah, *tah; |
616 | LIST_HEAD(remove_list); | 617 | LIST_HEAD(remove_list); |
618 | unsigned long flags; | ||
619 | |||
620 | netif_tx_lock_bh(dev); | ||
621 | spin_lock_irqsave(&priv->lock, flags); | ||
617 | 622 | ||
618 | spin_lock_irq(&priv->tx_lock); | ||
619 | spin_lock(&priv->lock); | ||
620 | list_for_each_entry_safe(ah, tah, &priv->dead_ahs, list) | 623 | list_for_each_entry_safe(ah, tah, &priv->dead_ahs, list) |
621 | if ((int) priv->tx_tail - (int) ah->last_send >= 0) { | 624 | if ((int) priv->tx_tail - (int) ah->last_send >= 0) { |
622 | list_del(&ah->list); | 625 | list_del(&ah->list); |
623 | ib_destroy_ah(ah->ah); | 626 | ib_destroy_ah(ah->ah); |
624 | kfree(ah); | 627 | kfree(ah); |
625 | } | 628 | } |
626 | spin_unlock(&priv->lock); | 629 | |
627 | spin_unlock_irq(&priv->tx_lock); | 630 | spin_unlock_irqrestore(&priv->lock, flags); |
631 | netif_tx_unlock_bh(dev); | ||
628 | } | 632 | } |
629 | 633 | ||
630 | void ipoib_reap_ah(struct work_struct *work) | 634 | void ipoib_reap_ah(struct work_struct *work) |
@@ -761,6 +765,14 @@ void ipoib_drain_cq(struct net_device *dev) | |||
761 | { | 765 | { |
762 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 766 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
763 | int i, n; | 767 | int i, n; |
768 | |||
769 | /* | ||
770 | * We call completion handling routines that expect to be | ||
771 | * called from the BH-disabled NAPI poll context, so disable | ||
772 | * BHs here too. | ||
773 | */ | ||
774 | local_bh_disable(); | ||
775 | |||
764 | do { | 776 | do { |
765 | n = ib_poll_cq(priv->recv_cq, IPOIB_NUM_WC, priv->ibwc); | 777 | n = ib_poll_cq(priv->recv_cq, IPOIB_NUM_WC, priv->ibwc); |
766 | for (i = 0; i < n; ++i) { | 778 | for (i = 0; i < n; ++i) { |
@@ -784,6 +796,8 @@ void ipoib_drain_cq(struct net_device *dev) | |||
784 | 796 | ||
785 | while (poll_tx(priv)) | 797 | while (poll_tx(priv)) |
786 | ; /* nothing */ | 798 | ; /* nothing */ |
799 | |||
800 | local_bh_enable(); | ||
787 | } | 801 | } |
788 | 802 | ||
789 | int ipoib_ib_dev_stop(struct net_device *dev, int flush) | 803 | int ipoib_ib_dev_stop(struct net_device *dev, int flush) |