aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Westgaard Ry <hans.westgaard.ry@oracle.com>2016-03-02 07:44:28 -0500
committerDoug Ledford <dledford@redhat.com>2016-03-03 09:49:44 -0500
commit78a50a5e6068955494117b37b03379dacaf830b7 (patch)
treef3d16185b8e004c08c63aa37ff78fb0ddefe1457
parentfc77dbd34c5c99bce46d40a2491937c3bcbd10af (diff)
IB/ipoib: Add handling for sending of skb with many frags
IPoIB converts skb-fragments to sge adding 1 extra sge when SG is enabled. Current codepath assumes that the max number of sge a device support is at least MAX_SKB_FRAGS+1, there is no interaction with upper layers to limit number of fragments in an skb if a device suports fewer sges. The assumptions also lead to requesting a fixed number of sge when IPoIB creates queue-pairs with SG enabled. A fallback/slowpath is implemented using skb_linearize to handle cases where the conversion would result in more sges than supported. Signed-off-by: Hans Westgaard Ry <hans.westgaard.ry@oracle.com> Reviewed-by: HÃ¥kon Bugge <haakon.bugge@oracle.com> Reviewed-by: Wei Lin Guay <wei.lin.guay@oracle.com> Reviewed-by: Yuval Shaia <yuval.shaia@oracle.com> Signed-off-by: Doug Ledford <dledford@redhat.com>
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h2
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c23
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c18
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_verbs.c5
4 files changed, 45 insertions, 3 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index a6f3eab0f350..85be0de3ab26 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -244,6 +244,7 @@ struct ipoib_cm_tx {
244 unsigned tx_tail; 244 unsigned tx_tail;
245 unsigned long flags; 245 unsigned long flags;
246 u32 mtu; 246 u32 mtu;
247 unsigned max_send_sge;
247}; 248};
248 249
249struct ipoib_cm_rx_buf { 250struct ipoib_cm_rx_buf {
@@ -390,6 +391,7 @@ struct ipoib_dev_priv {
390 int hca_caps; 391 int hca_caps;
391 struct ipoib_ethtool_st ethtool; 392 struct ipoib_ethtool_st ethtool;
392 struct timer_list poll_timer; 393 struct timer_list poll_timer;
394 unsigned max_send_sge;
393}; 395};
394 396
395struct ipoib_ah { 397struct ipoib_ah {
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 917e46ea3bf6..c8ed53562c9b 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -710,6 +710,7 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
710 struct ipoib_dev_priv *priv = netdev_priv(dev); 710 struct ipoib_dev_priv *priv = netdev_priv(dev);
711 struct ipoib_tx_buf *tx_req; 711 struct ipoib_tx_buf *tx_req;
712 int rc; 712 int rc;
713 unsigned usable_sge = tx->max_send_sge - !!skb_headlen(skb);
713 714
714 if (unlikely(skb->len > tx->mtu)) { 715 if (unlikely(skb->len > tx->mtu)) {
715 ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n", 716 ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n",
@@ -719,7 +720,23 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
719 ipoib_cm_skb_too_long(dev, skb, tx->mtu - IPOIB_ENCAP_LEN); 720 ipoib_cm_skb_too_long(dev, skb, tx->mtu - IPOIB_ENCAP_LEN);
720 return; 721 return;
721 } 722 }
722 723 if (skb_shinfo(skb)->nr_frags > usable_sge) {
724 if (skb_linearize(skb) < 0) {
725 ipoib_warn(priv, "skb could not be linearized\n");
726 ++dev->stats.tx_dropped;
727 ++dev->stats.tx_errors;
728 dev_kfree_skb_any(skb);
729 return;
730 }
731 /* Does skb_linearize return ok without reducing nr_frags? */
732 if (skb_shinfo(skb)->nr_frags > usable_sge) {
733 ipoib_warn(priv, "too many frags after skb linearize\n");
734 ++dev->stats.tx_dropped;
735 ++dev->stats.tx_errors;
736 dev_kfree_skb_any(skb);
737 return;
738 }
739 }
723 ipoib_dbg_data(priv, "sending packet: head 0x%x length %d connection 0x%x\n", 740 ipoib_dbg_data(priv, "sending packet: head 0x%x length %d connection 0x%x\n",
724 tx->tx_head, skb->len, tx->qp->qp_num); 741 tx->tx_head, skb->len, tx->qp->qp_num);
725 742
@@ -1031,7 +1048,8 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_
1031 struct ib_qp *tx_qp; 1048 struct ib_qp *tx_qp;
1032 1049
1033 if (dev->features & NETIF_F_SG) 1050 if (dev->features & NETIF_F_SG)
1034 attr.cap.max_send_sge = MAX_SKB_FRAGS + 1; 1051 attr.cap.max_send_sge =
1052 min_t(u32, priv->ca->attrs.max_sge, MAX_SKB_FRAGS + 1);
1035 1053
1036 tx_qp = ib_create_qp(priv->pd, &attr); 1054 tx_qp = ib_create_qp(priv->pd, &attr);
1037 if (PTR_ERR(tx_qp) == -EINVAL) { 1055 if (PTR_ERR(tx_qp) == -EINVAL) {
@@ -1040,6 +1058,7 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_
1040 attr.create_flags &= ~IB_QP_CREATE_USE_GFP_NOIO; 1058 attr.create_flags &= ~IB_QP_CREATE_USE_GFP_NOIO;
1041 tx_qp = ib_create_qp(priv->pd, &attr); 1059 tx_qp = ib_create_qp(priv->pd, &attr);
1042 } 1060 }
1061 tx->max_send_sge = attr.cap.max_send_sge;
1043 return tx_qp; 1062 return tx_qp;
1044} 1063}
1045 1064
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index fa9c42ff1fb0..899e6b7fb8a5 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -538,6 +538,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
538 struct ipoib_tx_buf *tx_req; 538 struct ipoib_tx_buf *tx_req;
539 int hlen, rc; 539 int hlen, rc;
540 void *phead; 540 void *phead;
541 unsigned usable_sge = priv->max_send_sge - !!skb_headlen(skb);
541 542
542 if (skb_is_gso(skb)) { 543 if (skb_is_gso(skb)) {
543 hlen = skb_transport_offset(skb) + tcp_hdrlen(skb); 544 hlen = skb_transport_offset(skb) + tcp_hdrlen(skb);
@@ -561,6 +562,23 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
561 phead = NULL; 562 phead = NULL;
562 hlen = 0; 563 hlen = 0;
563 } 564 }
565 if (skb_shinfo(skb)->nr_frags > usable_sge) {
566 if (skb_linearize(skb) < 0) {
567 ipoib_warn(priv, "skb could not be linearized\n");
568 ++dev->stats.tx_dropped;
569 ++dev->stats.tx_errors;
570 dev_kfree_skb_any(skb);
571 return;
572 }
573 /* Does skb_linearize return ok without reducing nr_frags? */
574 if (skb_shinfo(skb)->nr_frags > usable_sge) {
575 ipoib_warn(priv, "too many frags after skb linearize\n");
576 ++dev->stats.tx_dropped;
577 ++dev->stats.tx_errors;
578 dev_kfree_skb_any(skb);
579 return;
580 }
581 }
564 582
565 ipoib_dbg_data(priv, "sending packet, length=%d address=%p qpn=0x%06x\n", 583 ipoib_dbg_data(priv, "sending packet, length=%d address=%p qpn=0x%06x\n",
566 skb->len, address, qpn); 584 skb->len, address, qpn);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index d48c5bae7877..b809c373e40e 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -206,7 +206,8 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
206 init_attr.create_flags |= IB_QP_CREATE_NETIF_QP; 206 init_attr.create_flags |= IB_QP_CREATE_NETIF_QP;
207 207
208 if (dev->features & NETIF_F_SG) 208 if (dev->features & NETIF_F_SG)
209 init_attr.cap.max_send_sge = MAX_SKB_FRAGS + 1; 209 init_attr.cap.max_send_sge =
210 min_t(u32, priv->ca->attrs.max_sge, MAX_SKB_FRAGS + 1);
210 211
211 priv->qp = ib_create_qp(priv->pd, &init_attr); 212 priv->qp = ib_create_qp(priv->pd, &init_attr);
212 if (IS_ERR(priv->qp)) { 213 if (IS_ERR(priv->qp)) {
@@ -233,6 +234,8 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
233 priv->rx_wr.next = NULL; 234 priv->rx_wr.next = NULL;
234 priv->rx_wr.sg_list = priv->rx_sge; 235 priv->rx_wr.sg_list = priv->rx_sge;
235 236
237 priv->max_send_sge = init_attr.cap.max_send_sge;
238
236 return 0; 239 return 0;
237 240
238out_free_send_cq: 241out_free_send_cq: