aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
authorEli Cohen <eli@dev.mellanox.co.il>2008-04-30 23:02:45 -0400
committerRoland Dreier <rolandd@cisco.com>2008-04-30 23:02:45 -0400
commit57ce41d1d18279cc90223f3deadca70c7de1cfca (patch)
tree39111403527e4744b4a6a15d5ffe3fd038751489 /drivers/infiniband
parent3ae15e1623b9d32eb410c2a23d90e47b16e6acd0 (diff)
IB/ipoib: Fix transmit queue stalling forever
Commit f56bcd80 ("IPoIB: Use separate CQ for UD send completions") introduced a bug where the transmit queue could get stopped and never woken up. The problem is that send completions are only polled at the end of the xmit function, so if the send queue fills up and the xmit path stops the queue, then there is no way for send completions to ever get polled, and so the transmit queue stays stopped forever. Fix this by arming the send CQ just before posting the last send request that fills the send queue. Then, when the completion event handler is called, drain the send CQ. Since it is possible that not enough send completions are in the CQ, verify that the the net queue has been woken up after draining the send CQ, and if not arm a timer and drain again at the timer function. Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h2
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c47
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_verbs.c3
3 files changed, 46 insertions, 6 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 9044f8803532..ca126fc2b853 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -334,6 +334,7 @@ struct ipoib_dev_priv {
334#endif 334#endif
335 int hca_caps; 335 int hca_caps;
336 struct ipoib_ethtool_st ethtool; 336 struct ipoib_ethtool_st ethtool;
337 struct timer_list poll_timer;
337}; 338};
338 339
339struct ipoib_ah { 340struct ipoib_ah {
@@ -404,6 +405,7 @@ extern struct workqueue_struct *ipoib_workqueue;
404 405
405int ipoib_poll(struct napi_struct *napi, int budget); 406int ipoib_poll(struct napi_struct *napi, int budget);
406void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr); 407void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr);
408void ipoib_send_comp_handler(struct ib_cq *cq, void *dev_ptr);
407 409
408struct ipoib_ah *ipoib_create_ah(struct net_device *dev, 410struct ipoib_ah *ipoib_create_ah(struct net_device *dev,
409 struct ib_pd *pd, struct ib_ah_attr *attr); 411 struct ib_pd *pd, struct ib_ah_attr *attr);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 97b815c1a3fc..f429bce24c20 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -461,6 +461,26 @@ void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr)
461 netif_rx_schedule(dev, &priv->napi); 461 netif_rx_schedule(dev, &priv->napi);
462} 462}
463 463
464static void drain_tx_cq(struct net_device *dev)
465{
466 struct ipoib_dev_priv *priv = netdev_priv(dev);
467 unsigned long flags;
468
469 spin_lock_irqsave(&priv->tx_lock, flags);
470 while (poll_tx(priv))
471 ; /* nothing */
472
473 if (netif_queue_stopped(dev))
474 mod_timer(&priv->poll_timer, jiffies + 1);
475
476 spin_unlock_irqrestore(&priv->tx_lock, flags);
477}
478
479void ipoib_send_comp_handler(struct ib_cq *cq, void *dev_ptr)
480{
481 drain_tx_cq((struct net_device *)dev_ptr);
482}
483
464static inline int post_send(struct ipoib_dev_priv *priv, 484static inline int post_send(struct ipoib_dev_priv *priv,
465 unsigned int wr_id, 485 unsigned int wr_id,
466 struct ib_ah *address, u32 qpn, 486 struct ib_ah *address, u32 qpn,
@@ -555,12 +575,22 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
555 else 575 else
556 priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM; 576 priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM;
557 577
578 if (++priv->tx_outstanding == ipoib_sendq_size) {
579 ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n");
580 if (ib_req_notify_cq(priv->send_cq, IB_CQ_NEXT_COMP))
581 ipoib_warn(priv, "request notify on send CQ failed\n");
582 netif_stop_queue(dev);
583 }
584
558 if (unlikely(post_send(priv, priv->tx_head & (ipoib_sendq_size - 1), 585 if (unlikely(post_send(priv, priv->tx_head & (ipoib_sendq_size - 1),
559 address->ah, qpn, tx_req, phead, hlen))) { 586 address->ah, qpn, tx_req, phead, hlen))) {
560 ipoib_warn(priv, "post_send failed\n"); 587 ipoib_warn(priv, "post_send failed\n");
561 ++dev->stats.tx_errors; 588 ++dev->stats.tx_errors;
589 --priv->tx_outstanding;
562 ipoib_dma_unmap_tx(priv->ca, tx_req); 590 ipoib_dma_unmap_tx(priv->ca, tx_req);
563 dev_kfree_skb_any(skb); 591 dev_kfree_skb_any(skb);
592 if (netif_queue_stopped(dev))
593 netif_wake_queue(dev);
564 } else { 594 } else {
565 dev->trans_start = jiffies; 595 dev->trans_start = jiffies;
566 596
@@ -568,14 +598,11 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
568 ++priv->tx_head; 598 ++priv->tx_head;
569 skb_orphan(skb); 599 skb_orphan(skb);
570 600
571 if (++priv->tx_outstanding == ipoib_sendq_size) {
572 ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n");
573 netif_stop_queue(dev);
574 }
575 } 601 }
576 602
577 if (unlikely(priv->tx_outstanding > MAX_SEND_CQE)) 603 if (unlikely(priv->tx_outstanding > MAX_SEND_CQE))
578 poll_tx(priv); 604 while (poll_tx(priv))
605 ; /* nothing */
579} 606}
580 607
581static void __ipoib_reap_ah(struct net_device *dev) 608static void __ipoib_reap_ah(struct net_device *dev)
@@ -609,6 +636,11 @@ void ipoib_reap_ah(struct work_struct *work)
609 round_jiffies_relative(HZ)); 636 round_jiffies_relative(HZ));
610} 637}
611 638
639static void ipoib_ib_tx_timer_func(unsigned long ctx)
640{
641 drain_tx_cq((struct net_device *)ctx);
642}
643
612int ipoib_ib_dev_open(struct net_device *dev) 644int ipoib_ib_dev_open(struct net_device *dev)
613{ 645{
614 struct ipoib_dev_priv *priv = netdev_priv(dev); 646 struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -645,6 +677,10 @@ int ipoib_ib_dev_open(struct net_device *dev)
645 queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task, 677 queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task,
646 round_jiffies_relative(HZ)); 678 round_jiffies_relative(HZ));
647 679
680 init_timer(&priv->poll_timer);
681 priv->poll_timer.function = ipoib_ib_tx_timer_func;
682 priv->poll_timer.data = (unsigned long)dev;
683
648 set_bit(IPOIB_FLAG_INITIALIZED, &priv->flags); 684 set_bit(IPOIB_FLAG_INITIALIZED, &priv->flags);
649 685
650 return 0; 686 return 0;
@@ -810,6 +846,7 @@ int ipoib_ib_dev_stop(struct net_device *dev, int flush)
810 ipoib_dbg(priv, "All sends and receives done.\n"); 846 ipoib_dbg(priv, "All sends and receives done.\n");
811 847
812timeout: 848timeout:
849 del_timer_sync(&priv->poll_timer);
813 qp_attr.qp_state = IB_QPS_RESET; 850 qp_attr.qp_state = IB_QPS_RESET;
814 if (ib_modify_qp(priv->qp, &qp_attr, IB_QP_STATE)) 851 if (ib_modify_qp(priv->qp, &qp_attr, IB_QP_STATE))
815 ipoib_warn(priv, "Failed to modify QP to RESET state\n"); 852 ipoib_warn(priv, "Failed to modify QP to RESET state\n");
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index c1e7ece1fd44..8766d29ce3b7 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -187,7 +187,8 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
187 goto out_free_mr; 187 goto out_free_mr;
188 } 188 }
189 189
190 priv->send_cq = ib_create_cq(priv->ca, NULL, NULL, dev, ipoib_sendq_size, 0); 190 priv->send_cq = ib_create_cq(priv->ca, ipoib_send_comp_handler, NULL,
191 dev, ipoib_sendq_size, 0);
191 if (IS_ERR(priv->send_cq)) { 192 if (IS_ERR(priv->send_cq)) {
192 printk(KERN_WARNING "%s: failed to create send CQ\n", ca->name); 193 printk(KERN_WARNING "%s: failed to create send CQ\n", ca->name);
193 goto out_free_recv_cq; 194 goto out_free_recv_cq;