]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ice: Add E830 checksum offload support
authorPaul Greenwalt <paul.greenwalt@intel.com>
Mon, 10 Mar 2025 17:44:54 +0000 (10:44 -0700)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 18 Mar 2025 09:15:49 +0000 (10:15 +0100)
E830 supports raw receive and generic transmit checksum offloads.

Raw receive checksum support is provided by hardware calculating the
checksum over the whole packet, regardless of type. The calculated
checksum is provided to driver in the Rx flex descriptor. Then the driver
assigns the checksum to skb->csum and sets skb->ip_summed to
CHECKSUM_COMPLETE.

Generic transmit checksum support is provided by hardware calculating the
checksum given two offsets: the start offset to begin checksum calculation,
and the offset to insert the calculated checksum in the packet. Support is
advertised to the stack using NETIF_F_HW_CSUM feature.

E830 has the following limitations when both generic transmit checksum
offload and TCP Segmentation Offload (TSO) are enabled:

1. Inner packet header modification is not supported. This restriction
   includes the inability to alter TCP flags, such as the push flag. As a
   result, this limitation can impact the receiver's ability to coalesce
   packets, potentially degrading network throughput.
2. The Maximum Segment Size (MSS) is limited to 1023 bytes, which prevents
   support of Maximum Transmission Unit (MTU) greater than 1063 bytes.

Therefore NETIF_F_HW_CSUM and NETIF_F_ALL_TSO features are mutually
exclusive. NETIF_F_HW_CSUM hardware feature support is indicated but is not
enabled by default. Instead, IP checksums and NETIF_F_ALL_TSO are the
defaults. Enforcement of mutual exclusivity of NETIF_F_HW_CSUM and
NETIF_F_ALL_TSO is done in ice_set_features(). Mutual exclusivity
of IP checksums and NETIF_F_HW_CSUM is handled by netdev_fix_features().

When NETIF_F_HW_CSUM is requested the provided skb->csum_start and
skb->csum_offset are passed to hardware in the Tx context descriptor
generic checksum (GCS) parameters. Hardware calculates the 1's complement
from skb->csum_start to the end of the packet, and inserts the result in
the packet at skb->csum_offset.

Co-developed-by: Alice Michael <alice.michael@intel.com>
Signed-off-by: Alice Michael <alice.michael@intel.com>
Co-developed-by: Eric Joyner <eric.joyner@intel.com>
Signed-off-by: Eric Joyner <eric.joyner@intel.com>
Signed-off-by: Paul Greenwalt <paul.greenwalt@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Link: https://patch.msgid.link/20250310174502.3708121-2-anthony.l.nguyen@intel.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/intel/ice/ice.h
drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
drivers/net/ethernet/intel/ice/ice_lib.c
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/intel/ice/ice_txrx.c
drivers/net/ethernet/intel/ice/ice_txrx.h
drivers/net/ethernet/intel/ice/ice_txrx_lib.c

index 5ceeae664598cdf21d49951765672d5bf958f474..fd083647c14acb1eba633e342c847b7274413ca4 100644 (file)
@@ -201,6 +201,7 @@ enum ice_feature {
        ICE_F_SMA_CTRL,
        ICE_F_CGU,
        ICE_F_GNSS,
+       ICE_F_GCS,
        ICE_F_ROCE_LAG,
        ICE_F_SRIOV_LAG,
        ICE_F_MBX_LIMIT,
index 1479b45738af15bf6e00aed24b2c6a3f91675f4d..77ba26538b07b837a6b3d614c8c3effe9d65ec5d 100644 (file)
@@ -229,7 +229,7 @@ struct ice_32b_rx_flex_desc_nic {
        __le16 status_error1;
        u8 flexi_flags2;
        u8 ts_low;
-       __le16 l2tag2_1st;
+       __le16 raw_csum;
        __le16 l2tag2_2nd;
 
        /* Qword 3 */
@@ -478,10 +478,15 @@ enum ice_tx_desc_len_fields {
 struct ice_tx_ctx_desc {
        __le32 tunneling_params;
        __le16 l2tag2;
-       __le16 rsvd;
+       __le16 gcs;
        __le64 qw1;
 };
 
+#define ICE_TX_GCS_DESC_START_M                GENMASK(7, 0)
+#define ICE_TX_GCS_DESC_OFFSET_M       GENMASK(11, 8)
+#define ICE_TX_GCS_DESC_TYPE_M         GENMASK(14, 12)
+#define ICE_TX_GCS_DESC_CSUM_PSH       1
+
 #define ICE_TXD_CTX_QW1_CMD_S  4
 #define ICE_TXD_CTX_QW1_CMD_M  (0x7FUL << ICE_TXD_CTX_QW1_CMD_S)
 
index d7aa8487943a6517c81a12f8df8f2956d2e283e3..0bcf9d127ac9e7d28c607ad3d3c2529ab640ef35 100644 (file)
@@ -1431,6 +1431,10 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi)
                ring->dev = dev;
                ring->count = vsi->num_rx_desc;
                ring->cached_phctime = pf->ptp.cached_phc_time;
+
+               if (ice_is_feature_supported(pf, ICE_F_GCS))
+                       ring->flags |= ICE_RX_FLAGS_RING_GCS;
+
                WRITE_ONCE(vsi->rx_rings[i], ring);
        }
 
@@ -3899,8 +3903,10 @@ void ice_init_feature_support(struct ice_pf *pf)
                break;
        }
 
-       if (pf->hw.mac_type == ICE_MAC_E830)
+       if (pf->hw.mac_type == ICE_MAC_E830) {
                ice_set_feature_support(pf, ICE_F_MBX_LIMIT);
+               ice_set_feature_support(pf, ICE_F_GCS);
+       }
 }
 
 /**
index 6470bbb680cb1f10326a4f4edd51fa7bf69da576..049edeb60104395a7bf1f9161ef98ff18bad914a 100644 (file)
@@ -3634,6 +3634,12 @@ void ice_set_netdev_features(struct net_device *netdev)
        /* Allow core to manage IRQs affinity */
        netif_set_affinity_auto(netdev);
 
+       /* Mutual exclusivity for TSO and GCS is enforced by the set features
+        * ndo callback.
+        */
+       if (ice_is_feature_supported(pf, ICE_F_GCS))
+               netdev->hw_features |= NETIF_F_HW_CSUM;
+
        netif_set_tso_max_size(netdev, ICE_MAX_TSO_SIZE);
 }
 
@@ -6549,6 +6555,18 @@ ice_set_features(struct net_device *netdev, netdev_features_t features)
        if (changed & NETIF_F_LOOPBACK)
                ret = ice_set_loopback(vsi, !!(features & NETIF_F_LOOPBACK));
 
+       /* Due to E830 hardware limitations, TSO (NETIF_F_ALL_TSO) with GCS
+        * (NETIF_F_HW_CSUM) is not supported.
+        */
+       if (ice_is_feature_supported(pf, ICE_F_GCS) &&
+           ((features & NETIF_F_HW_CSUM) && (features & NETIF_F_ALL_TSO))) {
+               if (netdev->features & NETIF_F_HW_CSUM)
+                       dev_err(ice_pf_to_dev(pf), "To enable TSO, you must first disable HW checksum.\n");
+               else
+                       dev_err(ice_pf_to_dev(pf), "To enable HW checksum, you must first disable TSO.\n");
+               return -EIO;
+       }
+
        return ret;
 }
 
index 380ba1e8b3b2c833363430e61e67fb6969b1a156..1e4f6f6ee449c96ed1afe6fa4c677a7b2caf53e8 100644 (file)
@@ -1809,6 +1809,7 @@ dma_error:
 static
 int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
 {
+       const struct ice_tx_ring *tx_ring = off->tx_ring;
        u32 l4_len = 0, l3_len = 0, l2_len = 0;
        struct sk_buff *skb = first->skb;
        union {
@@ -1958,6 +1959,30 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
        l3_len = l4.hdr - ip.hdr;
        offset |= (l3_len / 4) << ICE_TX_DESC_LEN_IPLEN_S;
 
+       if ((tx_ring->netdev->features & NETIF_F_HW_CSUM) &&
+           !(first->tx_flags & ICE_TX_FLAGS_TSO) &&
+           !skb_csum_is_sctp(skb)) {
+               /* Set GCS */
+               u16 csum_start = (skb->csum_start - skb->mac_header) / 2;
+               u16 csum_offset = skb->csum_offset / 2;
+               u16 gcs_params;
+
+               gcs_params = FIELD_PREP(ICE_TX_GCS_DESC_START_M, csum_start) |
+                            FIELD_PREP(ICE_TX_GCS_DESC_OFFSET_M, csum_offset) |
+                            FIELD_PREP(ICE_TX_GCS_DESC_TYPE_M,
+                                       ICE_TX_GCS_DESC_CSUM_PSH);
+
+               /* Unlike legacy HW checksums, GCS requires a context
+                * descriptor.
+                */
+               off->cd_qw1 |= ICE_TX_DESC_DTYPE_CTX;
+               off->cd_gcs_params = gcs_params;
+               /* Fill out CSO info in data descriptors */
+               off->td_offset |= offset;
+               off->td_cmd |= cmd;
+               return 1;
+       }
+
        /* Enable L4 checksum offloads */
        switch (l4_proto) {
        case IPPROTO_TCP:
@@ -2441,7 +2466,7 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring)
                /* setup context descriptor */
                cdesc->tunneling_params = cpu_to_le32(offload.cd_tunnel_params);
                cdesc->l2tag2 = cpu_to_le16(offload.cd_l2tag2);
-               cdesc->rsvd = cpu_to_le16(0);
+               cdesc->gcs = cpu_to_le16(offload.cd_gcs_params);
                cdesc->qw1 = cpu_to_le64(offload.cd_qw1);
        }
 
index 806bce701df349fd963902c16e4a12990310fe98..a4b1e95146327df49c45fba642de2b3e554d6b96 100644 (file)
@@ -193,6 +193,7 @@ struct ice_tx_offload_params {
        u32 td_l2tag1;
        u32 cd_tunnel_params;
        u16 cd_l2tag2;
+       u16 cd_gcs_params;
        u8 header_len;
 };
 
@@ -366,6 +367,7 @@ struct ice_rx_ring {
 #define ICE_RX_FLAGS_RING_BUILD_SKB    BIT(1)
 #define ICE_RX_FLAGS_CRC_STRIP_DIS     BIT(2)
 #define ICE_RX_FLAGS_MULTIDEV          BIT(3)
+#define ICE_RX_FLAGS_RING_GCS          BIT(4)
        u8 flags;
        /* CL5 - 5th cacheline starts here */
        struct xdp_rxq_info xdp_rxq;
index 2719f0e20933f2eb27c236ab9cc7bab02989f9e6..45cfaabc41cbeb9b119a0e95547e012e0df1e188 100644 (file)
@@ -80,6 +80,23 @@ ice_rx_hash_to_skb(const struct ice_rx_ring *rx_ring,
                libeth_rx_pt_set_hash(skb, hash, decoded);
 }
 
+/**
+ * ice_rx_gcs - Set generic checksum in skb
+ * @skb: skb currently being received and modified
+ * @rx_desc: receive descriptor
+ */
+static void ice_rx_gcs(struct sk_buff *skb,
+                      const union ice_32b_rx_flex_desc *rx_desc)
+{
+       const struct ice_32b_rx_flex_desc_nic *desc;
+       u16 csum;
+
+       desc = (struct ice_32b_rx_flex_desc_nic *)rx_desc;
+       skb->ip_summed = CHECKSUM_COMPLETE;
+       csum = (__force u16)desc->raw_csum;
+       skb->csum = csum_unfold((__force __sum16)swab16(csum));
+}
+
 /**
  * ice_rx_csum - Indicate in skb if checksum is good
  * @ring: the ring we care about
@@ -107,6 +124,15 @@ ice_rx_csum(struct ice_rx_ring *ring, struct sk_buff *skb,
        rx_status0 = le16_to_cpu(rx_desc->wb.status_error0);
        rx_status1 = le16_to_cpu(rx_desc->wb.status_error1);
 
+       if ((ring->flags & ICE_RX_FLAGS_RING_GCS) &&
+           rx_desc->wb.rxdid == ICE_RXDID_FLEX_NIC &&
+           (decoded.inner_prot == LIBETH_RX_PT_INNER_TCP ||
+            decoded.inner_prot == LIBETH_RX_PT_INNER_UDP ||
+            decoded.inner_prot == LIBETH_RX_PT_INNER_ICMP)) {
+               ice_rx_gcs(skb, rx_desc);
+               return;
+       }
+
        /* check if HW has decoded the packet and checksum */
        if (!(rx_status0 & BIT(ICE_RX_FLEX_DESC_STATUS0_L3L4P_S)))
                return;