Commit 905d1a22 authored by Paul Greenwalt's avatar Paul Greenwalt Committed by Paolo Abeni
Browse files

ice: Add E830 checksum offload support



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: default avatarAlice Michael <alice.michael@intel.com>
Signed-off-by: default avatarAlice Michael <alice.michael@intel.com>
Co-developed-by: default avatarEric Joyner <eric.joyner@intel.com>
Signed-off-by: default avatarEric Joyner <eric.joyner@intel.com>
Signed-off-by: default avatarPaul Greenwalt <paul.greenwalt@intel.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
Link: https://patch.msgid.link/20250310174502.3708121-2-anthony.l.nguyen@intel.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 50698b29
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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,
+7 −2
Original line number Diff line number Diff line
@@ -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)

+7 −1
Original line number Diff line number Diff line
@@ -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);
	}
}

/**
+18 −0
Original line number Diff line number Diff line
@@ -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;
}

+26 −1
Original line number Diff line number Diff line
@@ -1809,6 +1809,7 @@ ice_tx_map(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first,
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);
	}

Loading