diff options
Diffstat (limited to 'drivers/net/mlx4/en_rx.c')
-rw-r--r-- | drivers/net/mlx4/en_rx.c | 123 |
1 files changed, 49 insertions, 74 deletions
diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 8e2fcb7103c3..277215fb9d72 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c | |||
@@ -42,18 +42,6 @@ | |||
42 | #include "mlx4_en.h" | 42 | #include "mlx4_en.h" |
43 | 43 | ||
44 | 44 | ||
45 | static int mlx4_en_get_frag_header(struct skb_frag_struct *frags, void **mac_hdr, | ||
46 | void **ip_hdr, void **tcpudp_hdr, | ||
47 | u64 *hdr_flags, void *priv) | ||
48 | { | ||
49 | *mac_hdr = page_address(frags->page) + frags->page_offset; | ||
50 | *ip_hdr = *mac_hdr + ETH_HLEN; | ||
51 | *tcpudp_hdr = (struct tcphdr *)(*ip_hdr + sizeof(struct iphdr)); | ||
52 | *hdr_flags = LRO_IPV4 | LRO_TCP; | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static int mlx4_en_alloc_frag(struct mlx4_en_priv *priv, | 45 | static int mlx4_en_alloc_frag(struct mlx4_en_priv *priv, |
58 | struct mlx4_en_rx_desc *rx_desc, | 46 | struct mlx4_en_rx_desc *rx_desc, |
59 | struct skb_frag_struct *skb_frags, | 47 | struct skb_frag_struct *skb_frags, |
@@ -251,7 +239,6 @@ reduce_rings: | |||
251 | ring->prod--; | 239 | ring->prod--; |
252 | mlx4_en_free_rx_desc(priv, ring, ring->actual_size); | 240 | mlx4_en_free_rx_desc(priv, ring, ring->actual_size); |
253 | } | 241 | } |
254 | ring->size_mask = ring->actual_size - 1; | ||
255 | } | 242 | } |
256 | 243 | ||
257 | return 0; | 244 | return 0; |
@@ -313,28 +300,8 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, | |||
313 | } | 300 | } |
314 | ring->buf = ring->wqres.buf.direct.buf; | 301 | ring->buf = ring->wqres.buf.direct.buf; |
315 | 302 | ||
316 | /* Configure lro mngr */ | ||
317 | memset(&ring->lro, 0, sizeof(struct net_lro_mgr)); | ||
318 | ring->lro.dev = priv->dev; | ||
319 | ring->lro.features = LRO_F_NAPI; | ||
320 | ring->lro.frag_align_pad = NET_IP_ALIGN; | ||
321 | ring->lro.ip_summed = CHECKSUM_UNNECESSARY; | ||
322 | ring->lro.ip_summed_aggr = CHECKSUM_UNNECESSARY; | ||
323 | ring->lro.max_desc = mdev->profile.num_lro; | ||
324 | ring->lro.max_aggr = MAX_SKB_FRAGS; | ||
325 | ring->lro.lro_arr = kzalloc(mdev->profile.num_lro * | ||
326 | sizeof(struct net_lro_desc), | ||
327 | GFP_KERNEL); | ||
328 | if (!ring->lro.lro_arr) { | ||
329 | en_err(priv, "Failed to allocate lro array\n"); | ||
330 | goto err_map; | ||
331 | } | ||
332 | ring->lro.get_frag_header = mlx4_en_get_frag_header; | ||
333 | |||
334 | return 0; | 303 | return 0; |
335 | 304 | ||
336 | err_map: | ||
337 | mlx4_en_unmap_buffer(&ring->wqres.buf); | ||
338 | err_hwq: | 305 | err_hwq: |
339 | mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size); | 306 | mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size); |
340 | err_ring: | 307 | err_ring: |
@@ -378,6 +345,8 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) | |||
378 | err = mlx4_en_init_allocator(priv, ring); | 345 | err = mlx4_en_init_allocator(priv, ring); |
379 | if (err) { | 346 | if (err) { |
380 | en_err(priv, "Failed initializing ring allocator\n"); | 347 | en_err(priv, "Failed initializing ring allocator\n"); |
348 | if (ring->stride <= TXBB_SIZE) | ||
349 | ring->buf -= TXBB_SIZE; | ||
381 | ring_ind--; | 350 | ring_ind--; |
382 | goto err_allocator; | 351 | goto err_allocator; |
383 | } | 352 | } |
@@ -389,6 +358,7 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) | |||
389 | for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { | 358 | for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { |
390 | ring = &priv->rx_ring[ring_ind]; | 359 | ring = &priv->rx_ring[ring_ind]; |
391 | 360 | ||
361 | ring->size_mask = ring->actual_size - 1; | ||
392 | mlx4_en_update_rx_prod_db(ring); | 362 | mlx4_en_update_rx_prod_db(ring); |
393 | } | 363 | } |
394 | 364 | ||
@@ -401,6 +371,8 @@ err_buffers: | |||
401 | ring_ind = priv->rx_ring_num - 1; | 371 | ring_ind = priv->rx_ring_num - 1; |
402 | err_allocator: | 372 | err_allocator: |
403 | while (ring_ind >= 0) { | 373 | while (ring_ind >= 0) { |
374 | if (priv->rx_ring[ring_ind].stride <= TXBB_SIZE) | ||
375 | priv->rx_ring[ring_ind].buf -= TXBB_SIZE; | ||
404 | mlx4_en_destroy_allocator(priv, &priv->rx_ring[ring_ind]); | 376 | mlx4_en_destroy_allocator(priv, &priv->rx_ring[ring_ind]); |
405 | ring_ind--; | 377 | ring_ind--; |
406 | } | 378 | } |
@@ -412,7 +384,6 @@ void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv, | |||
412 | { | 384 | { |
413 | struct mlx4_en_dev *mdev = priv->mdev; | 385 | struct mlx4_en_dev *mdev = priv->mdev; |
414 | 386 | ||
415 | kfree(ring->lro.lro_arr); | ||
416 | mlx4_en_unmap_buffer(&ring->wqres.buf); | 387 | mlx4_en_unmap_buffer(&ring->wqres.buf); |
417 | mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size + TXBB_SIZE); | 388 | mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size + TXBB_SIZE); |
418 | vfree(ring->rx_info); | 389 | vfree(ring->rx_info); |
@@ -459,7 +430,7 @@ static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv, | |||
459 | goto fail; | 430 | goto fail; |
460 | 431 | ||
461 | /* Unmap buffer */ | 432 | /* Unmap buffer */ |
462 | pci_unmap_single(mdev->pdev, dma, skb_frags[nr].size, | 433 | pci_unmap_single(mdev->pdev, dma, skb_frags_rx[nr].size, |
463 | PCI_DMA_FROMDEVICE); | 434 | PCI_DMA_FROMDEVICE); |
464 | } | 435 | } |
465 | /* Adjust size of last fragment to match actual length */ | 436 | /* Adjust size of last fragment to match actual length */ |
@@ -541,6 +512,21 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv, | |||
541 | return skb; | 512 | return skb; |
542 | } | 513 | } |
543 | 514 | ||
515 | static void validate_loopback(struct mlx4_en_priv *priv, struct sk_buff *skb) | ||
516 | { | ||
517 | int i; | ||
518 | int offset = ETH_HLEN; | ||
519 | |||
520 | for (i = 0; i < MLX4_LOOPBACK_TEST_PAYLOAD; i++, offset++) { | ||
521 | if (*(skb->data + offset) != (unsigned char) (i & 0xff)) | ||
522 | goto out_loopback; | ||
523 | } | ||
524 | /* Loopback found */ | ||
525 | priv->loopback_ok = 1; | ||
526 | |||
527 | out_loopback: | ||
528 | dev_kfree_skb_any(skb); | ||
529 | } | ||
544 | 530 | ||
545 | int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget) | 531 | int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget) |
546 | { | 532 | { |
@@ -548,7 +534,6 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud | |||
548 | struct mlx4_cqe *cqe; | 534 | struct mlx4_cqe *cqe; |
549 | struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring]; | 535 | struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring]; |
550 | struct skb_frag_struct *skb_frags; | 536 | struct skb_frag_struct *skb_frags; |
551 | struct skb_frag_struct lro_frags[MLX4_EN_MAX_RX_FRAGS]; | ||
552 | struct mlx4_en_rx_desc *rx_desc; | 537 | struct mlx4_en_rx_desc *rx_desc; |
553 | struct sk_buff *skb; | 538 | struct sk_buff *skb; |
554 | int index; | 539 | int index; |
@@ -599,7 +584,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud | |||
599 | ring->bytes += length; | 584 | ring->bytes += length; |
600 | ring->packets++; | 585 | ring->packets++; |
601 | 586 | ||
602 | if (likely(priv->rx_csum)) { | 587 | if (likely(dev->features & NETIF_F_RXCSUM)) { |
603 | if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) && | 588 | if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) && |
604 | (cqe->checksum == cpu_to_be16(0xffff))) { | 589 | (cqe->checksum == cpu_to_be16(0xffff))) { |
605 | priv->port_stats.rx_chksum_good++; | 590 | priv->port_stats.rx_chksum_good++; |
@@ -608,37 +593,35 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud | |||
608 | * - TCP/IP (v4) | 593 | * - TCP/IP (v4) |
609 | * - without IP options | 594 | * - without IP options |
610 | * - not an IP fragment */ | 595 | * - not an IP fragment */ |
611 | if (mlx4_en_can_lro(cqe->status) && | 596 | if (dev->features & NETIF_F_GRO) { |
612 | dev->features & NETIF_F_LRO) { | 597 | struct sk_buff *gro_skb = napi_get_frags(&cq->napi); |
598 | if (!gro_skb) | ||
599 | goto next; | ||
613 | 600 | ||
614 | nr = mlx4_en_complete_rx_desc( | 601 | nr = mlx4_en_complete_rx_desc( |
615 | priv, rx_desc, | 602 | priv, rx_desc, |
616 | skb_frags, lro_frags, | 603 | skb_frags, skb_shinfo(gro_skb)->frags, |
617 | ring->page_alloc, length); | 604 | ring->page_alloc, length); |
618 | if (!nr) | 605 | if (!nr) |
619 | goto next; | 606 | goto next; |
620 | 607 | ||
608 | skb_shinfo(gro_skb)->nr_frags = nr; | ||
609 | gro_skb->len = length; | ||
610 | gro_skb->data_len = length; | ||
611 | gro_skb->truesize += length; | ||
612 | gro_skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
613 | |||
621 | if (priv->vlgrp && (cqe->vlan_my_qpn & | 614 | if (priv->vlgrp && (cqe->vlan_my_qpn & |
622 | cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK))) { | 615 | cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK))) |
623 | lro_vlan_hwaccel_receive_frags( | 616 | vlan_gro_frags(&cq->napi, priv->vlgrp, be16_to_cpu(cqe->sl_vid)); |
624 | &ring->lro, lro_frags, | 617 | else |
625 | length, length, | 618 | napi_gro_frags(&cq->napi); |
626 | priv->vlgrp, | ||
627 | be16_to_cpu(cqe->sl_vid), | ||
628 | NULL, 0); | ||
629 | } else | ||
630 | lro_receive_frags(&ring->lro, | ||
631 | lro_frags, | ||
632 | length, | ||
633 | length, | ||
634 | NULL, 0); | ||
635 | 619 | ||
636 | goto next; | 620 | goto next; |
637 | } | 621 | } |
638 | 622 | ||
639 | /* LRO not possible, complete processing here */ | 623 | /* LRO not possible, complete processing here */ |
640 | ip_summed = CHECKSUM_UNNECESSARY; | 624 | ip_summed = CHECKSUM_UNNECESSARY; |
641 | INC_PERF_COUNTER(priv->pstats.lro_misses); | ||
642 | } else { | 625 | } else { |
643 | ip_summed = CHECKSUM_NONE; | 626 | ip_summed = CHECKSUM_NONE; |
644 | priv->port_stats.rx_chksum_none++; | 627 | priv->port_stats.rx_chksum_none++; |
@@ -655,6 +638,11 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud | |||
655 | goto next; | 638 | goto next; |
656 | } | 639 | } |
657 | 640 | ||
641 | if (unlikely(priv->validate_loopback)) { | ||
642 | validate_loopback(priv, skb); | ||
643 | goto next; | ||
644 | } | ||
645 | |||
658 | skb->ip_summed = ip_summed; | 646 | skb->ip_summed = ip_summed; |
659 | skb->protocol = eth_type_trans(skb, dev); | 647 | skb->protocol = eth_type_trans(skb, dev); |
660 | skb_record_rx_queue(skb, cq->ring); | 648 | skb_record_rx_queue(skb, cq->ring); |
@@ -674,14 +662,10 @@ next: | |||
674 | if (++polled == budget) { | 662 | if (++polled == budget) { |
675 | /* We are here because we reached the NAPI budget - | 663 | /* We are here because we reached the NAPI budget - |
676 | * flush only pending LRO sessions */ | 664 | * flush only pending LRO sessions */ |
677 | lro_flush_all(&ring->lro); | ||
678 | goto out; | 665 | goto out; |
679 | } | 666 | } |
680 | } | 667 | } |
681 | 668 | ||
682 | /* If CQ is empty flush all LRO sessions unconditionally */ | ||
683 | lro_flush_all(&ring->lro); | ||
684 | |||
685 | out: | 669 | out: |
686 | AVG_PERF_COUNTER(priv->pstats.rx_coal_avg, polled); | 670 | AVG_PERF_COUNTER(priv->pstats.rx_coal_avg, polled); |
687 | mlx4_cq_set_ci(&cq->mcq); | 671 | mlx4_cq_set_ci(&cq->mcq); |
@@ -726,7 +710,7 @@ int mlx4_en_poll_rx_cq(struct napi_struct *napi, int budget) | |||
726 | } | 710 | } |
727 | 711 | ||
728 | 712 | ||
729 | /* Calculate the last offset position that accomodates a full fragment | 713 | /* Calculate the last offset position that accommodates a full fragment |
730 | * (assuming fagment size = stride-align) */ | 714 | * (assuming fagment size = stride-align) */ |
731 | static int mlx4_en_last_alloc_offset(struct mlx4_en_priv *priv, u16 stride, u16 align) | 715 | static int mlx4_en_last_alloc_offset(struct mlx4_en_priv *priv, u16 stride, u16 align) |
732 | { | 716 | { |
@@ -816,7 +800,7 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn, | |||
816 | qp->event = mlx4_en_sqp_event; | 800 | qp->event = mlx4_en_sqp_event; |
817 | 801 | ||
818 | memset(context, 0, sizeof *context); | 802 | memset(context, 0, sizeof *context); |
819 | mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 0, 0, | 803 | mlx4_en_fill_qp_context(priv, ring->actual_size, ring->stride, 0, 0, |
820 | qpn, ring->cqn, context); | 804 | qpn, ring->cqn, context); |
821 | context->db_rec_addr = cpu_to_be64(ring->wqres.db.dma); | 805 | context->db_rec_addr = cpu_to_be64(ring->wqres.db.dma); |
822 | 806 | ||
@@ -839,8 +823,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) | |||
839 | struct mlx4_qp_context context; | 823 | struct mlx4_qp_context context; |
840 | struct mlx4_en_rss_context *rss_context; | 824 | struct mlx4_en_rss_context *rss_context; |
841 | void *ptr; | 825 | void *ptr; |
842 | int rss_xor = mdev->profile.rss_xor; | 826 | u8 rss_mask = 0x3f; |
843 | u8 rss_mask = mdev->profile.rss_mask; | ||
844 | int i, qpn; | 827 | int i, qpn; |
845 | int err = 0; | 828 | int err = 0; |
846 | int good_qps = 0; | 829 | int good_qps = 0; |
@@ -866,16 +849,10 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) | |||
866 | } | 849 | } |
867 | 850 | ||
868 | /* Configure RSS indirection qp */ | 851 | /* Configure RSS indirection qp */ |
869 | err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &priv->base_qpn); | ||
870 | if (err) { | ||
871 | en_err(priv, "Failed to reserve range for RSS " | ||
872 | "indirection qp\n"); | ||
873 | goto rss_err; | ||
874 | } | ||
875 | err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, &rss_map->indir_qp); | 852 | err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, &rss_map->indir_qp); |
876 | if (err) { | 853 | if (err) { |
877 | en_err(priv, "Failed to allocate RSS indirection QP\n"); | 854 | en_err(priv, "Failed to allocate RSS indirection QP\n"); |
878 | goto reserve_err; | 855 | goto rss_err; |
879 | } | 856 | } |
880 | rss_map->indir_qp.event = mlx4_en_sqp_event; | 857 | rss_map->indir_qp.event = mlx4_en_sqp_event; |
881 | mlx4_en_fill_qp_context(priv, 0, 0, 0, 1, priv->base_qpn, | 858 | mlx4_en_fill_qp_context(priv, 0, 0, 0, 1, priv->base_qpn, |
@@ -886,9 +863,10 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) | |||
886 | rss_context->base_qpn = cpu_to_be32(ilog2(priv->rx_ring_num) << 24 | | 863 | rss_context->base_qpn = cpu_to_be32(ilog2(priv->rx_ring_num) << 24 | |
887 | (rss_map->base_qpn)); | 864 | (rss_map->base_qpn)); |
888 | rss_context->default_qpn = cpu_to_be32(rss_map->base_qpn); | 865 | rss_context->default_qpn = cpu_to_be32(rss_map->base_qpn); |
889 | rss_context->hash_fn = rss_xor & 0x3; | 866 | rss_context->flags = rss_mask; |
890 | rss_context->flags = rss_mask << 2; | ||
891 | 867 | ||
868 | if (priv->mdev->profile.udp_rss) | ||
869 | rss_context->base_qpn_udp = rss_context->default_qpn; | ||
892 | err = mlx4_qp_to_ready(mdev->dev, &priv->res.mtt, &context, | 870 | err = mlx4_qp_to_ready(mdev->dev, &priv->res.mtt, &context, |
893 | &rss_map->indir_qp, &rss_map->indir_state); | 871 | &rss_map->indir_qp, &rss_map->indir_state); |
894 | if (err) | 872 | if (err) |
@@ -901,8 +879,6 @@ indir_err: | |||
901 | MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp); | 879 | MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp); |
902 | mlx4_qp_remove(mdev->dev, &rss_map->indir_qp); | 880 | mlx4_qp_remove(mdev->dev, &rss_map->indir_qp); |
903 | mlx4_qp_free(mdev->dev, &rss_map->indir_qp); | 881 | mlx4_qp_free(mdev->dev, &rss_map->indir_qp); |
904 | reserve_err: | ||
905 | mlx4_qp_release_range(mdev->dev, priv->base_qpn, 1); | ||
906 | rss_err: | 882 | rss_err: |
907 | for (i = 0; i < good_qps; i++) { | 883 | for (i = 0; i < good_qps; i++) { |
908 | mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], | 884 | mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], |
@@ -924,7 +900,6 @@ void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv) | |||
924 | MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp); | 900 | MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp); |
925 | mlx4_qp_remove(mdev->dev, &rss_map->indir_qp); | 901 | mlx4_qp_remove(mdev->dev, &rss_map->indir_qp); |
926 | mlx4_qp_free(mdev->dev, &rss_map->indir_qp); | 902 | mlx4_qp_free(mdev->dev, &rss_map->indir_qp); |
927 | mlx4_qp_release_range(mdev->dev, priv->base_qpn, 1); | ||
928 | 903 | ||
929 | for (i = 0; i < priv->rx_ring_num; i++) { | 904 | for (i = 0; i < priv->rx_ring_num; i++) { |
930 | mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], | 905 | mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], |