aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-11-11 13:20:07 -0500
committerDavid S. Miller <davem@davemloft.net>2014-11-11 13:20:07 -0500
commit008e81656c32e34c0b248bd203872d15be8770b7 (patch)
tree9f4f031bb3a33ea164aa2014294c027c478e1d7e
parentb00394c007269183d9f539fa87e65892ac2006e2 (diff)
parentf8c6455bb04b944edb69e9b074e28efee2c56bdd (diff)
Merge branch 'mlx4-next'
Or Gerlitz says: ==================== mlx4: Add CHECKSUM_COMPLETE support These patches from Shani, Matan and myself add support for CHECKSUM_COMPLETE reporting on non TCP/UDP packets such as GRE and ICMP. I'd like to deeply thank Jerry Chu for his innovation and support in that effort. Based on the feedback from Eric and Ido Shamay, in V2 we dropped the patch which removed the calls to napi_gro_frags() and added a patch which makes the RX code to go through that path regardless of the checksum status. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_ethtool.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_port.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_rx.c228
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c9
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h5
-rw-r--r--include/linux/mlx4/device.h1
7 files changed, 193 insertions, 59 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index 8ea4d5be7376..6c643230a5ed 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -115,7 +115,7 @@ static const char main_strings[][ETH_GSTRING_LEN] = {
115 "tso_packets", 115 "tso_packets",
116 "xmit_more", 116 "xmit_more",
117 "queue_stopped", "wake_queue", "tx_timeout", "rx_alloc_failed", 117 "queue_stopped", "wake_queue", "tx_timeout", "rx_alloc_failed",
118 "rx_csum_good", "rx_csum_none", "tx_chksum_offload", 118 "rx_csum_good", "rx_csum_none", "rx_csum_complete", "tx_chksum_offload",
119 119
120 /* packet statistics */ 120 /* packet statistics */
121 "broadcast", "rx_prio_0", "rx_prio_1", "rx_prio_2", "rx_prio_3", 121 "broadcast", "rx_prio_0", "rx_prio_1", "rx_prio_2", "rx_prio_3",
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 0efbae90f1ba..d1eb25dbff56 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -1893,6 +1893,7 @@ static void mlx4_en_clear_stats(struct net_device *dev)
1893 priv->rx_ring[i]->packets = 0; 1893 priv->rx_ring[i]->packets = 0;
1894 priv->rx_ring[i]->csum_ok = 0; 1894 priv->rx_ring[i]->csum_ok = 0;
1895 priv->rx_ring[i]->csum_none = 0; 1895 priv->rx_ring[i]->csum_none = 0;
1896 priv->rx_ring[i]->csum_complete = 0;
1896 } 1897 }
1897} 1898}
1898 1899
@@ -2503,6 +2504,10 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
2503 /* Query for default mac and max mtu */ 2504 /* Query for default mac and max mtu */
2504 priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port]; 2505 priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port];
2505 2506
2507 if (mdev->dev->caps.rx_checksum_flags_port[priv->port] &
2508 MLX4_RX_CSUM_MODE_VAL_NON_TCP_UDP)
2509 priv->flags |= MLX4_EN_FLAG_RX_CSUM_NON_TCP_UDP;
2510
2506 /* Set default MAC */ 2511 /* Set default MAC */
2507 dev->addr_len = ETH_ALEN; 2512 dev->addr_len = ETH_ALEN;
2508 mlx4_en_u64_to_mac(dev->dev_addr, mdev->dev->caps.def_mac[priv->port]); 2513 mlx4_en_u64_to_mac(dev->dev_addr, mdev->dev->caps.def_mac[priv->port]);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_port.c b/drivers/net/ethernet/mellanox/mlx4/en_port.c
index 134b12e17da5..6cb80072af6c 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_port.c
@@ -155,11 +155,13 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
155 stats->rx_bytes = 0; 155 stats->rx_bytes = 0;
156 priv->port_stats.rx_chksum_good = 0; 156 priv->port_stats.rx_chksum_good = 0;
157 priv->port_stats.rx_chksum_none = 0; 157 priv->port_stats.rx_chksum_none = 0;
158 priv->port_stats.rx_chksum_complete = 0;
158 for (i = 0; i < priv->rx_ring_num; i++) { 159 for (i = 0; i < priv->rx_ring_num; i++) {
159 stats->rx_packets += priv->rx_ring[i]->packets; 160 stats->rx_packets += priv->rx_ring[i]->packets;
160 stats->rx_bytes += priv->rx_ring[i]->bytes; 161 stats->rx_bytes += priv->rx_ring[i]->bytes;
161 priv->port_stats.rx_chksum_good += priv->rx_ring[i]->csum_ok; 162 priv->port_stats.rx_chksum_good += priv->rx_ring[i]->csum_ok;
162 priv->port_stats.rx_chksum_none += priv->rx_ring[i]->csum_none; 163 priv->port_stats.rx_chksum_none += priv->rx_ring[i]->csum_none;
164 priv->port_stats.rx_chksum_complete += priv->rx_ring[i]->csum_complete;
163 } 165 }
164 stats->tx_packets = 0; 166 stats->tx_packets = 0;
165 stats->tx_bytes = 0; 167 stats->tx_bytes = 0;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index 5a193f40a14c..ccd95177ea7c 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -42,6 +42,10 @@
42#include <linux/vmalloc.h> 42#include <linux/vmalloc.h>
43#include <linux/irq.h> 43#include <linux/irq.h>
44 44
45#if IS_ENABLED(CONFIG_IPV6)
46#include <net/ip6_checksum.h>
47#endif
48
45#include "mlx4_en.h" 49#include "mlx4_en.h"
46 50
47static int mlx4_alloc_pages(struct mlx4_en_priv *priv, 51static int mlx4_alloc_pages(struct mlx4_en_priv *priv,
@@ -643,6 +647,86 @@ static void mlx4_en_refill_rx_buffers(struct mlx4_en_priv *priv,
643 } 647 }
644} 648}
645 649
650/* When hardware doesn't strip the vlan, we need to calculate the checksum
651 * over it and add it to the hardware's checksum calculation
652 */
653static inline __wsum get_fixed_vlan_csum(__wsum hw_checksum,
654 struct vlan_hdr *vlanh)
655{
656 return csum_add(hw_checksum, *(__wsum *)vlanh);
657}
658
659/* Although the stack expects checksum which doesn't include the pseudo
660 * header, the HW adds it. To address that, we are subtracting the pseudo
661 * header checksum from the checksum value provided by the HW.
662 */
663static void get_fixed_ipv4_csum(__wsum hw_checksum, struct sk_buff *skb,
664 struct iphdr *iph)
665{
666 __u16 length_for_csum = 0;
667 __wsum csum_pseudo_header = 0;
668
669 length_for_csum = (be16_to_cpu(iph->tot_len) - (iph->ihl << 2));
670 csum_pseudo_header = csum_tcpudp_nofold(iph->saddr, iph->daddr,
671 length_for_csum, iph->protocol, 0);
672 skb->csum = csum_sub(hw_checksum, csum_pseudo_header);
673}
674
675#if IS_ENABLED(CONFIG_IPV6)
676/* In IPv6 packets, besides subtracting the pseudo header checksum,
677 * we also compute/add the IP header checksum which
678 * is not added by the HW.
679 */
680static int get_fixed_ipv6_csum(__wsum hw_checksum, struct sk_buff *skb,
681 struct ipv6hdr *ipv6h)
682{
683 __wsum csum_pseudo_hdr = 0;
684
685 if (ipv6h->nexthdr == IPPROTO_FRAGMENT || ipv6h->nexthdr == IPPROTO_HOPOPTS)
686 return -1;
687 hw_checksum = csum_add(hw_checksum, (__force __wsum)(ipv6h->nexthdr << 8));
688
689 csum_pseudo_hdr = csum_partial(&ipv6h->saddr,
690 sizeof(ipv6h->saddr) + sizeof(ipv6h->daddr), 0);
691 csum_pseudo_hdr = csum_add(csum_pseudo_hdr, (__force __wsum)ipv6h->payload_len);
692 csum_pseudo_hdr = csum_add(csum_pseudo_hdr, (__force __wsum)ntohs(ipv6h->nexthdr));
693
694 skb->csum = csum_sub(hw_checksum, csum_pseudo_hdr);
695 skb->csum = csum_add(skb->csum, csum_partial(ipv6h, sizeof(struct ipv6hdr), 0));
696 return 0;
697}
698#endif
699static int check_csum(struct mlx4_cqe *cqe, struct sk_buff *skb, void *va,
700 int hwtstamp_rx_filter)
701{
702 __wsum hw_checksum = 0;
703
704 void *hdr = (u8 *)va + sizeof(struct ethhdr);
705
706 hw_checksum = csum_unfold((__force __sum16)cqe->checksum);
707
708 if (((struct ethhdr *)va)->h_proto == htons(ETH_P_8021Q) &&
709 hwtstamp_rx_filter != HWTSTAMP_FILTER_NONE) {
710 /* next protocol non IPv4 or IPv6 */
711 if (((struct vlan_hdr *)hdr)->h_vlan_encapsulated_proto
712 != htons(ETH_P_IP) &&
713 ((struct vlan_hdr *)hdr)->h_vlan_encapsulated_proto
714 != htons(ETH_P_IPV6))
715 return -1;
716 hw_checksum = get_fixed_vlan_csum(hw_checksum, hdr);
717 hdr += sizeof(struct vlan_hdr);
718 }
719
720 if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV4))
721 get_fixed_ipv4_csum(hw_checksum, skb, hdr);
722#if IS_ENABLED(CONFIG_IPV6)
723 else if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV6))
724 if (get_fixed_ipv6_csum(hw_checksum, skb, hdr))
725 return -1;
726#endif
727 return 0;
728}
729
646int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget) 730int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget)
647{ 731{
648 struct mlx4_en_priv *priv = netdev_priv(dev); 732 struct mlx4_en_priv *priv = netdev_priv(dev);
@@ -744,73 +828,95 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
744 (cqe->vlan_my_qpn & cpu_to_be32(MLX4_CQE_L2_TUNNEL)); 828 (cqe->vlan_my_qpn & cpu_to_be32(MLX4_CQE_L2_TUNNEL));
745 829
746 if (likely(dev->features & NETIF_F_RXCSUM)) { 830 if (likely(dev->features & NETIF_F_RXCSUM)) {
747 if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) && 831 if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_TCP |
748 (cqe->checksum == cpu_to_be16(0xffff))) { 832 MLX4_CQE_STATUS_UDP)) {
749 ring->csum_ok++; 833 if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) &&
750 /* This packet is eligible for GRO if it is: 834 cqe->checksum == cpu_to_be16(0xffff)) {
751 * - DIX Ethernet (type interpretation) 835 ip_summed = CHECKSUM_UNNECESSARY;
752 * - TCP/IP (v4) 836 ring->csum_ok++;
753 * - without IP options 837 } else {
754 * - not an IP fragment 838 ip_summed = CHECKSUM_NONE;
755 * - no LLS polling in progress 839 ring->csum_none++;
756 */ 840 }
757 if (!mlx4_en_cq_busy_polling(cq) && 841 } else {
758 (dev->features & NETIF_F_GRO)) { 842 if (priv->flags & MLX4_EN_FLAG_RX_CSUM_NON_TCP_UDP &&
759 struct sk_buff *gro_skb = napi_get_frags(&cq->napi); 843 (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV4 |
760 if (!gro_skb) 844 MLX4_CQE_STATUS_IPV6))) {
761 goto next; 845 ip_summed = CHECKSUM_COMPLETE;
762 846 ring->csum_complete++;
763 nr = mlx4_en_complete_rx_desc(priv, 847 } else {
764 rx_desc, frags, gro_skb, 848 ip_summed = CHECKSUM_NONE;
765 length); 849 ring->csum_none++;
766 if (!nr) 850 }
767 goto next; 851 }
768 852 } else {
769 skb_shinfo(gro_skb)->nr_frags = nr; 853 ip_summed = CHECKSUM_NONE;
770 gro_skb->len = length; 854 ring->csum_none++;
771 gro_skb->data_len = length; 855 }
772 gro_skb->ip_summed = CHECKSUM_UNNECESSARY;
773 856
774 if (l2_tunnel) 857 /* This packet is eligible for GRO if it is:
775 gro_skb->csum_level = 1; 858 * - DIX Ethernet (type interpretation)
776 if ((cqe->vlan_my_qpn & 859 * - TCP/IP (v4)
777 cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) && 860 * - without IP options
778 (dev->features & NETIF_F_HW_VLAN_CTAG_RX)) { 861 * - not an IP fragment
779 u16 vid = be16_to_cpu(cqe->sl_vid); 862 * - no LLS polling in progress
863 */
864 if (!mlx4_en_cq_busy_polling(cq) &&
865 (dev->features & NETIF_F_GRO)) {
866 struct sk_buff *gro_skb = napi_get_frags(&cq->napi);
867 if (!gro_skb)
868 goto next;
869
870 nr = mlx4_en_complete_rx_desc(priv,
871 rx_desc, frags, gro_skb,
872 length);
873 if (!nr)
874 goto next;
875
876 if (ip_summed == CHECKSUM_COMPLETE) {
877 void *va = skb_frag_address(skb_shinfo(gro_skb)->frags);
878 if (check_csum(cqe, gro_skb, va, ring->hwtstamp_rx_filter)) {
879 ip_summed = CHECKSUM_NONE;
880 ring->csum_none++;
881 ring->csum_complete--;
882 }
883 }
780 884
781 __vlan_hwaccel_put_tag(gro_skb, htons(ETH_P_8021Q), vid); 885 skb_shinfo(gro_skb)->nr_frags = nr;
782 } 886 gro_skb->len = length;
887 gro_skb->data_len = length;
888 gro_skb->ip_summed = ip_summed;
783 889
784 if (dev->features & NETIF_F_RXHASH) 890 if (l2_tunnel && ip_summed == CHECKSUM_UNNECESSARY)
785 skb_set_hash(gro_skb, 891 gro_skb->encapsulation = 1;
786 be32_to_cpu(cqe->immed_rss_invalid), 892 if ((cqe->vlan_my_qpn &
787 PKT_HASH_TYPE_L3); 893 cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) &&
894 (dev->features & NETIF_F_HW_VLAN_CTAG_RX)) {
895 u16 vid = be16_to_cpu(cqe->sl_vid);
788 896
789 skb_record_rx_queue(gro_skb, cq->ring); 897 __vlan_hwaccel_put_tag(gro_skb, htons(ETH_P_8021Q), vid);
790 skb_mark_napi_id(gro_skb, &cq->napi); 898 }
791 899
792 if (ring->hwtstamp_rx_filter == HWTSTAMP_FILTER_ALL) { 900 if (dev->features & NETIF_F_RXHASH)
793 timestamp = mlx4_en_get_cqe_ts(cqe); 901 skb_set_hash(gro_skb,
794 mlx4_en_fill_hwtstamps(mdev, 902 be32_to_cpu(cqe->immed_rss_invalid),
795 skb_hwtstamps(gro_skb), 903 PKT_HASH_TYPE_L3);
796 timestamp);
797 }
798 904
799 napi_gro_frags(&cq->napi); 905 skb_record_rx_queue(gro_skb, cq->ring);
800 goto next; 906 skb_mark_napi_id(gro_skb, &cq->napi);
801 }
802 907
803 /* GRO not possible, complete processing here */ 908 if (ring->hwtstamp_rx_filter == HWTSTAMP_FILTER_ALL) {
804 ip_summed = CHECKSUM_UNNECESSARY; 909 timestamp = mlx4_en_get_cqe_ts(cqe);
805 } else { 910 mlx4_en_fill_hwtstamps(mdev,
806 ip_summed = CHECKSUM_NONE; 911 skb_hwtstamps(gro_skb),
807 ring->csum_none++; 912 timestamp);
808 } 913 }
809 } else { 914
810 ip_summed = CHECKSUM_NONE; 915 napi_gro_frags(&cq->napi);
811 ring->csum_none++; 916 goto next;
812 } 917 }
813 918
919 /* GRO not possible, complete processing here */
814 skb = mlx4_en_rx_skb(priv, rx_desc, frags, length); 920 skb = mlx4_en_rx_skb(priv, rx_desc, frags, length);
815 if (!skb) { 921 if (!skb) {
816 priv->stats.rx_dropped++; 922 priv->stats.rx_dropped++;
@@ -822,6 +928,14 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
822 goto next; 928 goto next;
823 } 929 }
824 930
931 if (ip_summed == CHECKSUM_COMPLETE) {
932 if (check_csum(cqe, skb, skb->data, ring->hwtstamp_rx_filter)) {
933 ip_summed = CHECKSUM_NONE;
934 ring->csum_complete--;
935 ring->csum_none++;
936 }
937 }
938
825 skb->ip_summed = ip_summed; 939 skb->ip_summed = ip_summed;
826 skb->protocol = eth_type_trans(skb, dev); 940 skb->protocol = eth_type_trans(skb, dev);
827 skb_record_rx_queue(skb, cq->ring); 941 skb_record_rx_queue(skb, cq->ring);
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 9f821964a1b9..2f6ba420ac03 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -1629,6 +1629,7 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
1629 struct mlx4_init_hca_param init_hca; 1629 struct mlx4_init_hca_param init_hca;
1630 u64 icm_size; 1630 u64 icm_size;
1631 int err; 1631 int err;
1632 struct mlx4_config_dev_params params;
1632 1633
1633 if (!mlx4_is_slave(dev)) { 1634 if (!mlx4_is_slave(dev)) {
1634 err = mlx4_QUERY_FW(dev); 1635 err = mlx4_QUERY_FW(dev);
@@ -1762,6 +1763,14 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
1762 goto unmap_bf; 1763 goto unmap_bf;
1763 } 1764 }
1764 1765
1766 /* Query CONFIG_DEV parameters */
1767 err = mlx4_config_dev_retrieval(dev, &params);
1768 if (err && err != -ENOTSUPP) {
1769 mlx4_err(dev, "Failed to query CONFIG_DEV parameters\n");
1770 } else if (!err) {
1771 dev->caps.rx_checksum_flags_port[1] = params.rx_csum_flags_port_1;
1772 dev->caps.rx_checksum_flags_port[2] = params.rx_csum_flags_port_2;
1773 }
1765 priv->eq_table.inta_pin = adapter.inta_pin; 1774 priv->eq_table.inta_pin = adapter.inta_pin;
1766 memcpy(dev->board_id, adapter.board_id, sizeof dev->board_id); 1775 memcpy(dev->board_id, adapter.board_id, sizeof dev->board_id);
1767 1776
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index ef83d127f406..de456749ffae 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -326,6 +326,7 @@ struct mlx4_en_rx_ring {
326#endif 326#endif
327 unsigned long csum_ok; 327 unsigned long csum_ok;
328 unsigned long csum_none; 328 unsigned long csum_none;
329 unsigned long csum_complete;
329 int hwtstamp_rx_filter; 330 int hwtstamp_rx_filter;
330 cpumask_var_t affinity_mask; 331 cpumask_var_t affinity_mask;
331}; 332};
@@ -449,6 +450,7 @@ struct mlx4_en_port_stats {
449 unsigned long rx_alloc_failed; 450 unsigned long rx_alloc_failed;
450 unsigned long rx_chksum_good; 451 unsigned long rx_chksum_good;
451 unsigned long rx_chksum_none; 452 unsigned long rx_chksum_none;
453 unsigned long rx_chksum_complete;
452 unsigned long tx_chksum_offload; 454 unsigned long tx_chksum_offload;
453#define NUM_PORT_STATS 9 455#define NUM_PORT_STATS 9
454}; 456};
@@ -507,7 +509,8 @@ enum {
507 MLX4_EN_FLAG_ENABLE_HW_LOOPBACK = (1 << 2), 509 MLX4_EN_FLAG_ENABLE_HW_LOOPBACK = (1 << 2),
508 /* whether we need to drop packets that hardware loopback-ed */ 510 /* whether we need to drop packets that hardware loopback-ed */
509 MLX4_EN_FLAG_RX_FILTER_NEEDED = (1 << 3), 511 MLX4_EN_FLAG_RX_FILTER_NEEDED = (1 << 3),
510 MLX4_EN_FLAG_FORCE_PROMISC = (1 << 4) 512 MLX4_EN_FLAG_FORCE_PROMISC = (1 << 4),
513 MLX4_EN_FLAG_RX_CSUM_NON_TCP_UDP = (1 << 5),
511}; 514};
512 515
513#define MLX4_EN_MAC_HASH_SIZE (1 << BITS_PER_BYTE) 516#define MLX4_EN_MAC_HASH_SIZE (1 << BITS_PER_BYTE)
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 5cc5eac47d1b..3d9bff00f24a 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -497,6 +497,7 @@ struct mlx4_caps {
497 u16 hca_core_clock; 497 u16 hca_core_clock;
498 u64 phys_port_id[MLX4_MAX_PORTS + 1]; 498 u64 phys_port_id[MLX4_MAX_PORTS + 1];
499 int tunnel_offload_mode; 499 int tunnel_offload_mode;
500 u8 rx_checksum_flags_port[MLX4_MAX_PORTS + 1];
500}; 501};
501 502
502struct mlx4_buf_list { 503struct mlx4_buf_list {