]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: enetc: add Tx checksum offload for i.MX95 ENETC
authorWei Fang <wei.fang@nxp.com>
Thu, 19 Dec 2024 05:47:52 +0000 (13:47 +0800)
committerJakub Kicinski <kuba@kernel.org>
Mon, 23 Dec 2024 17:54:33 +0000 (09:54 -0800)
In addition to supporting Rx checksum offload, i.MX95 ENETC also supports
Tx checksum offload. The transmit checksum offload is implemented through
the Tx BD. To support Tx checksum offload, software needs to fill some
auxiliary information in Tx BD, such as IP version, IP header offset and
size, whether L4 is UDP or TCP, etc.

Same as Rx checksum offload, Tx checksum offload capability isn't defined
in register, so tx_csum bit is added to struct enetc_drvdata to indicate
whether the device supports Tx checksum offload.

Signed-off-by: Wei Fang <wei.fang@nxp.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Reviewed-by: Claudiu Manoil <claudiu.manoil@nxp.com>
Link: https://patch.msgid.link/20241219054755.1615626-2-wei.fang@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/freescale/enetc/enetc.c
drivers/net/ethernet/freescale/enetc/enetc.h
drivers/net/ethernet/freescale/enetc/enetc_hw.h
drivers/net/ethernet/freescale/enetc/enetc_pf_common.c

index 535969fa0fdbef8c6840bf335fce603b666d85a1..88f12c88110ff400392af243af0e5c09198b1171 100644 (file)
@@ -146,6 +146,27 @@ static int enetc_ptp_parse(struct sk_buff *skb, u8 *udp,
        return 0;
 }
 
+static bool enetc_tx_csum_offload_check(struct sk_buff *skb)
+{
+       switch (skb->csum_offset) {
+       case offsetof(struct tcphdr, check):
+       case offsetof(struct udphdr, check):
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool enetc_skb_is_ipv6(struct sk_buff *skb)
+{
+       return vlan_get_protocol(skb) == htons(ETH_P_IPV6);
+}
+
+static bool enetc_skb_is_tcp(struct sk_buff *skb)
+{
+       return skb->csum_offset == offsetof(struct tcphdr, check);
+}
+
 static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb)
 {
        bool do_vlan, do_onestep_tstamp = false, do_twostep_tstamp = false;
@@ -163,6 +184,29 @@ static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb)
        dma_addr_t dma;
        u8 flags = 0;
 
+       enetc_clear_tx_bd(&temp_bd);
+       if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               /* Can not support TSD and checksum offload at the same time */
+               if (priv->active_offloads & ENETC_F_TXCSUM &&
+                   enetc_tx_csum_offload_check(skb) && !tx_ring->tsd_enable) {
+                       temp_bd.l3_aux0 = FIELD_PREP(ENETC_TX_BD_L3_START,
+                                                    skb_network_offset(skb));
+                       temp_bd.l3_aux1 = FIELD_PREP(ENETC_TX_BD_L3_HDR_LEN,
+                                                    skb_network_header_len(skb) / 4);
+                       temp_bd.l3_aux1 |= FIELD_PREP(ENETC_TX_BD_L3T,
+                                                     enetc_skb_is_ipv6(skb));
+                       if (enetc_skb_is_tcp(skb))
+                               temp_bd.l4_aux = FIELD_PREP(ENETC_TX_BD_L4T,
+                                                           ENETC_TXBD_L4T_TCP);
+                       else
+                               temp_bd.l4_aux = FIELD_PREP(ENETC_TX_BD_L4T,
+                                                           ENETC_TXBD_L4T_UDP);
+                       flags |= ENETC_TXBD_FLAGS_CSUM_LSO | ENETC_TXBD_FLAGS_L4CS;
+               } else if (skb_checksum_help(skb)) {
+                       return 0;
+               }
+       }
+
        i = tx_ring->next_to_use;
        txbd = ENETC_TXBD(*tx_ring, i);
        prefetchw(txbd);
@@ -173,7 +217,6 @@ static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb)
 
        temp_bd.addr = cpu_to_le64(dma);
        temp_bd.buf_len = cpu_to_le16(len);
-       temp_bd.lstatus = 0;
 
        tx_swbd = &tx_ring->tx_swbd[i];
        tx_swbd->dma = dma;
@@ -594,7 +637,7 @@ static netdev_tx_t enetc_start_xmit(struct sk_buff *skb,
 {
        struct enetc_ndev_priv *priv = netdev_priv(ndev);
        struct enetc_bdr *tx_ring;
-       int count, err;
+       int count;
 
        /* Queue one-step Sync packet if already locked */
        if (skb->cb[0] & ENETC_F_TX_ONESTEP_SYNC_TSTAMP) {
@@ -627,11 +670,6 @@ static netdev_tx_t enetc_start_xmit(struct sk_buff *skb,
                        return NETDEV_TX_BUSY;
                }
 
-               if (skb->ip_summed == CHECKSUM_PARTIAL) {
-                       err = skb_checksum_help(skb);
-                       if (err)
-                               goto drop_packet_err;
-               }
                enetc_lock_mdio();
                count = enetc_map_tx_buffs(tx_ring, skb);
                enetc_unlock_mdio();
@@ -3274,6 +3312,7 @@ static const struct enetc_drvdata enetc_pf_data = {
 
 static const struct enetc_drvdata enetc4_pf_data = {
        .sysclk_freq = ENETC_CLK_333M,
+       .tx_csum = true,
        .pmac_offset = ENETC4_PMAC_OFFSET,
        .eth_ops = &enetc4_pf_ethtool_ops,
 };
index 72fa03dbc2ddbb7cdf580d38b844037d511c2f86..e82eb9a9137c9984a802639875540c2415ce9a40 100644 (file)
@@ -234,6 +234,7 @@ enum enetc_errata {
 
 struct enetc_drvdata {
        u32 pmac_offset; /* Only valid for PSI which supports 802.1Qbu */
+       u8 tx_csum:1;
        u64 sysclk_freq;
        const struct ethtool_ops *eth_ops;
 };
@@ -341,6 +342,7 @@ enum enetc_active_offloads {
        ENETC_F_QBV                     = BIT(9),
        ENETC_F_QCI                     = BIT(10),
        ENETC_F_QBU                     = BIT(11),
+       ENETC_F_TXCSUM                  = BIT(12),
 };
 
 enum enetc_flags_bit {
index 55ba949230ffd097d894046d37ad369e303ba44c..0e259baf36ee6ff2c4ed0006af2ce90b2306b9e2 100644 (file)
@@ -558,7 +558,16 @@ union enetc_tx_bd {
                __le16 frm_len;
                union {
                        struct {
-                               u8 reserved[3];
+                               u8 l3_aux0;
+#define ENETC_TX_BD_L3_START   GENMASK(6, 0)
+#define ENETC_TX_BD_IPCS       BIT(7)
+                               u8 l3_aux1;
+#define ENETC_TX_BD_L3_HDR_LEN GENMASK(6, 0)
+#define ENETC_TX_BD_L3T                BIT(7)
+                               u8 l4_aux;
+#define ENETC_TX_BD_L4T                GENMASK(7, 5)
+#define ENETC_TXBD_L4T_UDP     1
+#define ENETC_TXBD_L4T_TCP     2
                                u8 flags;
                        }; /* default layout */
                        __le32 txstart;
@@ -582,10 +591,10 @@ union enetc_tx_bd {
 };
 
 enum enetc_txbd_flags {
-       ENETC_TXBD_FLAGS_RES0 = BIT(0), /* reserved */
+       ENETC_TXBD_FLAGS_L4CS = BIT(0), /* For ENETC 4.1 and later */
        ENETC_TXBD_FLAGS_TSE = BIT(1),
        ENETC_TXBD_FLAGS_W = BIT(2),
-       ENETC_TXBD_FLAGS_RES3 = BIT(3), /* reserved */
+       ENETC_TXBD_FLAGS_CSUM_LSO = BIT(3), /* For ENETC 4.1 and later */
        ENETC_TXBD_FLAGS_TXSTART = BIT(4),
        ENETC_TXBD_FLAGS_EX = BIT(6),
        ENETC_TXBD_FLAGS_F = BIT(7)
index 0eecfc833164fd0ce6fa5e2db2244fbfc4ba9fa4..09f2d7ec44eb2c94b73b039dc20c0fa3a0f69cc4 100644 (file)
@@ -119,6 +119,9 @@ void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
 
        ndev->priv_flags |= IFF_UNICAST_FLT;
 
+       if (si->drvdata->tx_csum)
+               priv->active_offloads |= ENETC_F_TXCSUM;
+
        /* TODO: currently, i.MX95 ENETC driver does not support advanced features */
        if (!is_enetc_rev1(si)) {
                ndev->hw_features &= ~(NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK);