diff options
author | Eli Cohen <eli@dev.mellanox.co.il> | 2008-04-17 00:09:27 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2008-04-17 00:09:27 -0400 |
commit | 40ca1988e03c001747d0b4cc1b25cf38297c9f9e (patch) | |
tree | 5eb1d1e32b41409bd722df9c80deb326a227b09f /drivers/infiniband | |
parent | c93570f23a98c633570397aedc6d1808f5d5846a (diff) |
IPoIB: Add LSO support
For HCAs that support TCP segmentation offload (IB_DEVICE_UD_TSO), set
NETIF_F_TSO and use HW LSO to offload TCP segmentation.
Signed-off-by: Eli Cohen <eli@mellanox.co.il>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib.h | 1 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_cm.c | 7 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_ib.c | 107 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_main.c | 10 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_verbs.c | 3 |
5 files changed, 92 insertions, 36 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 08930ca41a30..19a41ff90d15 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h | |||
@@ -319,6 +319,7 @@ struct ipoib_dev_priv { | |||
319 | struct dentry *mcg_dentry; | 319 | struct dentry *mcg_dentry; |
320 | struct dentry *path_dentry; | 320 | struct dentry *path_dentry; |
321 | #endif | 321 | #endif |
322 | int hca_caps; | ||
322 | }; | 323 | }; |
323 | 324 | ||
324 | struct ipoib_ah { | 325 | struct ipoib_ah { |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index edf63dc0afe0..9d411f21460e 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c | |||
@@ -1384,7 +1384,7 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr, | |||
1384 | ipoib_warn(priv, "enabling connected mode " | 1384 | ipoib_warn(priv, "enabling connected mode " |
1385 | "will cause multicast packet drops\n"); | 1385 | "will cause multicast packet drops\n"); |
1386 | 1386 | ||
1387 | dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_SG); | 1387 | dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO); |
1388 | priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM; | 1388 | priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM; |
1389 | 1389 | ||
1390 | ipoib_flush_paths(dev); | 1390 | ipoib_flush_paths(dev); |
@@ -1396,8 +1396,11 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr, | |||
1396 | dev->mtu = min(priv->mcast_mtu, dev->mtu); | 1396 | dev->mtu = min(priv->mcast_mtu, dev->mtu); |
1397 | ipoib_flush_paths(dev); | 1397 | ipoib_flush_paths(dev); |
1398 | 1398 | ||
1399 | if (test_bit(IPOIB_FLAG_CSUM, &priv->flags)) | 1399 | if (test_bit(IPOIB_FLAG_CSUM, &priv->flags)) { |
1400 | dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; | 1400 | dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; |
1401 | if (priv->hca_caps & IB_DEVICE_UD_TSO) | ||
1402 | dev->features |= NETIF_F_TSO; | ||
1403 | } | ||
1401 | 1404 | ||
1402 | return count; | 1405 | return count; |
1403 | } | 1406 | } |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index d13f4fb3853f..8b4ff69ecb80 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c | |||
@@ -39,6 +39,8 @@ | |||
39 | #include <linux/dma-mapping.h> | 39 | #include <linux/dma-mapping.h> |
40 | 40 | ||
41 | #include <rdma/ib_cache.h> | 41 | #include <rdma/ib_cache.h> |
42 | #include <linux/ip.h> | ||
43 | #include <linux/tcp.h> | ||
42 | 44 | ||
43 | #include "ipoib.h" | 45 | #include "ipoib.h" |
44 | 46 | ||
@@ -249,29 +251,37 @@ static int ipoib_dma_map_tx(struct ib_device *ca, | |||
249 | struct sk_buff *skb = tx_req->skb; | 251 | struct sk_buff *skb = tx_req->skb; |
250 | u64 *mapping = tx_req->mapping; | 252 | u64 *mapping = tx_req->mapping; |
251 | int i; | 253 | int i; |
254 | int off; | ||
252 | 255 | ||
253 | mapping[0] = ib_dma_map_single(ca, skb->data, skb_headlen(skb), | 256 | if (skb_headlen(skb)) { |
254 | DMA_TO_DEVICE); | 257 | mapping[0] = ib_dma_map_single(ca, skb->data, skb_headlen(skb), |
255 | if (unlikely(ib_dma_mapping_error(ca, mapping[0]))) | 258 | DMA_TO_DEVICE); |
256 | return -EIO; | 259 | if (unlikely(ib_dma_mapping_error(ca, mapping[0]))) |
260 | return -EIO; | ||
261 | |||
262 | off = 1; | ||
263 | } else | ||
264 | off = 0; | ||
257 | 265 | ||
258 | for (i = 0; i < skb_shinfo(skb)->nr_frags; ++i) { | 266 | for (i = 0; i < skb_shinfo(skb)->nr_frags; ++i) { |
259 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; | 267 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; |
260 | mapping[i + 1] = ib_dma_map_page(ca, frag->page, | 268 | mapping[i + off] = ib_dma_map_page(ca, frag->page, |
261 | frag->page_offset, frag->size, | 269 | frag->page_offset, frag->size, |
262 | DMA_TO_DEVICE); | 270 | DMA_TO_DEVICE); |
263 | if (unlikely(ib_dma_mapping_error(ca, mapping[i + 1]))) | 271 | if (unlikely(ib_dma_mapping_error(ca, mapping[i + off]))) |
264 | goto partial_error; | 272 | goto partial_error; |
265 | } | 273 | } |
266 | return 0; | 274 | return 0; |
267 | 275 | ||
268 | partial_error: | 276 | partial_error: |
269 | ib_dma_unmap_single(ca, mapping[0], skb_headlen(skb), DMA_TO_DEVICE); | ||
270 | |||
271 | for (; i > 0; --i) { | 277 | for (; i > 0; --i) { |
272 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1]; | 278 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1]; |
273 | ib_dma_unmap_page(ca, mapping[i], frag->size, DMA_TO_DEVICE); | 279 | ib_dma_unmap_page(ca, mapping[i - !off], frag->size, DMA_TO_DEVICE); |
274 | } | 280 | } |
281 | |||
282 | if (off) | ||
283 | ib_dma_unmap_single(ca, mapping[0], skb_headlen(skb), DMA_TO_DEVICE); | ||
284 | |||
275 | return -EIO; | 285 | return -EIO; |
276 | } | 286 | } |
277 | 287 | ||
@@ -281,12 +291,17 @@ static void ipoib_dma_unmap_tx(struct ib_device *ca, | |||
281 | struct sk_buff *skb = tx_req->skb; | 291 | struct sk_buff *skb = tx_req->skb; |
282 | u64 *mapping = tx_req->mapping; | 292 | u64 *mapping = tx_req->mapping; |
283 | int i; | 293 | int i; |
294 | int off; | ||
284 | 295 | ||
285 | ib_dma_unmap_single(ca, mapping[0], skb_headlen(skb), DMA_TO_DEVICE); | 296 | if (skb_headlen(skb)) { |
297 | ib_dma_unmap_single(ca, mapping[0], skb_headlen(skb), DMA_TO_DEVICE); | ||
298 | off = 1; | ||
299 | } else | ||
300 | off = 0; | ||
286 | 301 | ||
287 | for (i = 0; i < skb_shinfo(skb)->nr_frags; ++i) { | 302 | for (i = 0; i < skb_shinfo(skb)->nr_frags; ++i) { |
288 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; | 303 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; |
289 | ib_dma_unmap_page(ca, mapping[i + 1], frag->size, | 304 | ib_dma_unmap_page(ca, mapping[i + off], frag->size, |
290 | DMA_TO_DEVICE); | 305 | DMA_TO_DEVICE); |
291 | } | 306 | } |
292 | } | 307 | } |
@@ -392,24 +407,40 @@ void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr) | |||
392 | static inline int post_send(struct ipoib_dev_priv *priv, | 407 | static inline int post_send(struct ipoib_dev_priv *priv, |
393 | unsigned int wr_id, | 408 | unsigned int wr_id, |
394 | struct ib_ah *address, u32 qpn, | 409 | struct ib_ah *address, u32 qpn, |
395 | u64 *mapping, int headlen, | 410 | struct ipoib_tx_buf *tx_req, |
396 | skb_frag_t *frags, | 411 | void *head, int hlen) |
397 | int nr_frags) | ||
398 | { | 412 | { |
399 | struct ib_send_wr *bad_wr; | 413 | struct ib_send_wr *bad_wr; |
400 | int i; | 414 | int i, off; |
415 | struct sk_buff *skb = tx_req->skb; | ||
416 | skb_frag_t *frags = skb_shinfo(skb)->frags; | ||
417 | int nr_frags = skb_shinfo(skb)->nr_frags; | ||
418 | u64 *mapping = tx_req->mapping; | ||
419 | |||
420 | if (skb_headlen(skb)) { | ||
421 | priv->tx_sge[0].addr = mapping[0]; | ||
422 | priv->tx_sge[0].length = skb_headlen(skb); | ||
423 | off = 1; | ||
424 | } else | ||
425 | off = 0; | ||
401 | 426 | ||
402 | priv->tx_sge[0].addr = mapping[0]; | ||
403 | priv->tx_sge[0].length = headlen; | ||
404 | for (i = 0; i < nr_frags; ++i) { | 427 | for (i = 0; i < nr_frags; ++i) { |
405 | priv->tx_sge[i + 1].addr = mapping[i + 1]; | 428 | priv->tx_sge[i + off].addr = mapping[i + off]; |
406 | priv->tx_sge[i + 1].length = frags[i].size; | 429 | priv->tx_sge[i + off].length = frags[i].size; |
407 | } | 430 | } |
408 | priv->tx_wr.num_sge = nr_frags + 1; | 431 | priv->tx_wr.num_sge = nr_frags + off; |
409 | priv->tx_wr.wr_id = wr_id; | 432 | priv->tx_wr.wr_id = wr_id; |
410 | priv->tx_wr.wr.ud.remote_qpn = qpn; | 433 | priv->tx_wr.wr.ud.remote_qpn = qpn; |
411 | priv->tx_wr.wr.ud.ah = address; | 434 | priv->tx_wr.wr.ud.ah = address; |
412 | 435 | ||
436 | if (head) { | ||
437 | priv->tx_wr.wr.ud.mss = skb_shinfo(skb)->gso_size; | ||
438 | priv->tx_wr.wr.ud.header = head; | ||
439 | priv->tx_wr.wr.ud.hlen = hlen; | ||
440 | priv->tx_wr.opcode = IB_WR_LSO; | ||
441 | } else | ||
442 | priv->tx_wr.opcode = IB_WR_SEND; | ||
443 | |||
413 | return ib_post_send(priv->qp, &priv->tx_wr, &bad_wr); | 444 | return ib_post_send(priv->qp, &priv->tx_wr, &bad_wr); |
414 | } | 445 | } |
415 | 446 | ||
@@ -418,14 +449,30 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, | |||
418 | { | 449 | { |
419 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 450 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
420 | struct ipoib_tx_buf *tx_req; | 451 | struct ipoib_tx_buf *tx_req; |
421 | 452 | int hlen; | |
422 | if (unlikely(skb->len > priv->mcast_mtu + IPOIB_ENCAP_LEN)) { | 453 | void *phead; |
423 | ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n", | 454 | |
424 | skb->len, priv->mcast_mtu + IPOIB_ENCAP_LEN); | 455 | if (skb_is_gso(skb)) { |
425 | ++dev->stats.tx_dropped; | 456 | hlen = skb_transport_offset(skb) + tcp_hdrlen(skb); |
426 | ++dev->stats.tx_errors; | 457 | phead = skb->data; |
427 | ipoib_cm_skb_too_long(dev, skb, priv->mcast_mtu); | 458 | if (unlikely(!skb_pull(skb, hlen))) { |
428 | return; | 459 | ipoib_warn(priv, "linear data too small\n"); |
460 | ++dev->stats.tx_dropped; | ||
461 | ++dev->stats.tx_errors; | ||
462 | dev_kfree_skb_any(skb); | ||
463 | return; | ||
464 | } | ||
465 | } else { | ||
466 | if (unlikely(skb->len > priv->mcast_mtu + IPOIB_ENCAP_LEN)) { | ||
467 | ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n", | ||
468 | skb->len, priv->mcast_mtu + IPOIB_ENCAP_LEN); | ||
469 | ++dev->stats.tx_dropped; | ||
470 | ++dev->stats.tx_errors; | ||
471 | ipoib_cm_skb_too_long(dev, skb, priv->mcast_mtu); | ||
472 | return; | ||
473 | } | ||
474 | phead = NULL; | ||
475 | hlen = 0; | ||
429 | } | 476 | } |
430 | 477 | ||
431 | ipoib_dbg_data(priv, "sending packet, length=%d address=%p qpn=0x%06x\n", | 478 | ipoib_dbg_data(priv, "sending packet, length=%d address=%p qpn=0x%06x\n", |
@@ -452,9 +499,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, | |||
452 | priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM; | 499 | priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM; |
453 | 500 | ||
454 | if (unlikely(post_send(priv, priv->tx_head & (ipoib_sendq_size - 1), | 501 | if (unlikely(post_send(priv, priv->tx_head & (ipoib_sendq_size - 1), |
455 | address->ah, qpn, | 502 | address->ah, qpn, tx_req, phead, hlen))) { |
456 | tx_req->mapping, skb_headlen(skb), | ||
457 | skb_shinfo(skb)->frags, skb_shinfo(skb)->nr_frags))) { | ||
458 | ipoib_warn(priv, "post_send failed\n"); | 503 | ipoib_warn(priv, "post_send failed\n"); |
459 | ++dev->stats.tx_errors; | 504 | ++dev->stats.tx_errors; |
460 | ipoib_dma_unmap_tx(priv->ca, tx_req); | 505 | ipoib_dma_unmap_tx(priv->ca, tx_req); |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index d87f53190a15..35a3643fb566 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c | |||
@@ -1134,14 +1134,15 @@ static struct net_device *ipoib_add_port(const char *format, | |||
1134 | kfree(device_attr); | 1134 | kfree(device_attr); |
1135 | goto device_init_failed; | 1135 | goto device_init_failed; |
1136 | } | 1136 | } |
1137 | priv->hca_caps = device_attr->device_cap_flags; | ||
1137 | 1138 | ||
1138 | if (device_attr->device_cap_flags & IB_DEVICE_UD_IP_CSUM) { | 1139 | kfree(device_attr); |
1140 | |||
1141 | if (priv->hca_caps & IB_DEVICE_UD_IP_CSUM) { | ||
1139 | set_bit(IPOIB_FLAG_CSUM, &priv->flags); | 1142 | set_bit(IPOIB_FLAG_CSUM, &priv->flags); |
1140 | priv->dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; | 1143 | priv->dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; |
1141 | } | 1144 | } |
1142 | 1145 | ||
1143 | kfree(device_attr); | ||
1144 | |||
1145 | /* | 1146 | /* |
1146 | * Set the full membership bit, so that we join the right | 1147 | * Set the full membership bit, so that we join the right |
1147 | * broadcast group, etc. | 1148 | * broadcast group, etc. |
@@ -1176,6 +1177,9 @@ static struct net_device *ipoib_add_port(const char *format, | |||
1176 | goto event_failed; | 1177 | goto event_failed; |
1177 | } | 1178 | } |
1178 | 1179 | ||
1180 | if (priv->dev->features & NETIF_F_SG && priv->hca_caps & IB_DEVICE_UD_TSO) | ||
1181 | priv->dev->features |= NETIF_F_TSO; | ||
1182 | |||
1179 | result = register_netdev(priv->dev); | 1183 | result = register_netdev(priv->dev); |
1180 | if (result) { | 1184 | if (result) { |
1181 | printk(KERN_WARNING "%s: couldn't register ipoib port %d; error %d\n", | 1185 | printk(KERN_WARNING "%s: couldn't register ipoib port %d; error %d\n", |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index a3aeb911f024..8a20e3742c43 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c | |||
@@ -192,6 +192,9 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) | |||
192 | init_attr.send_cq = priv->cq; | 192 | init_attr.send_cq = priv->cq; |
193 | init_attr.recv_cq = priv->cq; | 193 | init_attr.recv_cq = priv->cq; |
194 | 194 | ||
195 | if (priv->hca_caps & IB_DEVICE_UD_TSO) | ||
196 | init_attr.create_flags = IB_QP_CREATE_IPOIB_UD_LSO; | ||
197 | |||
195 | if (dev->features & NETIF_F_SG) | 198 | if (dev->features & NETIF_F_SG) |
196 | init_attr.cap.max_send_sge = MAX_SKB_FRAGS + 1; | 199 | init_attr.cap.max_send_sge = MAX_SKB_FRAGS + 1; |
197 | 200 | ||