Skip to content

Commit d9a093d

Browse files
Wei Fangkuba-moo
authored andcommitted
net: enetc: add Tx checksum offload for i.MX95 ENETC
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 <[email protected]> Reviewed-by: Frank Li <[email protected]> Reviewed-by: Claudiu Manoil <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent a502ea6 commit d9a093d

File tree

4 files changed

+63
-10
lines changed

4 files changed

+63
-10
lines changed

drivers/net/ethernet/freescale/enetc/enetc.c

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,27 @@ static int enetc_ptp_parse(struct sk_buff *skb, u8 *udp,
146146
return 0;
147147
}
148148

149+
static bool enetc_tx_csum_offload_check(struct sk_buff *skb)
150+
{
151+
switch (skb->csum_offset) {
152+
case offsetof(struct tcphdr, check):
153+
case offsetof(struct udphdr, check):
154+
return true;
155+
default:
156+
return false;
157+
}
158+
}
159+
160+
static bool enetc_skb_is_ipv6(struct sk_buff *skb)
161+
{
162+
return vlan_get_protocol(skb) == htons(ETH_P_IPV6);
163+
}
164+
165+
static bool enetc_skb_is_tcp(struct sk_buff *skb)
166+
{
167+
return skb->csum_offset == offsetof(struct tcphdr, check);
168+
}
169+
149170
static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb)
150171
{
151172
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)
163184
dma_addr_t dma;
164185
u8 flags = 0;
165186

187+
enetc_clear_tx_bd(&temp_bd);
188+
if (skb->ip_summed == CHECKSUM_PARTIAL) {
189+
/* Can not support TSD and checksum offload at the same time */
190+
if (priv->active_offloads & ENETC_F_TXCSUM &&
191+
enetc_tx_csum_offload_check(skb) && !tx_ring->tsd_enable) {
192+
temp_bd.l3_aux0 = FIELD_PREP(ENETC_TX_BD_L3_START,
193+
skb_network_offset(skb));
194+
temp_bd.l3_aux1 = FIELD_PREP(ENETC_TX_BD_L3_HDR_LEN,
195+
skb_network_header_len(skb) / 4);
196+
temp_bd.l3_aux1 |= FIELD_PREP(ENETC_TX_BD_L3T,
197+
enetc_skb_is_ipv6(skb));
198+
if (enetc_skb_is_tcp(skb))
199+
temp_bd.l4_aux = FIELD_PREP(ENETC_TX_BD_L4T,
200+
ENETC_TXBD_L4T_TCP);
201+
else
202+
temp_bd.l4_aux = FIELD_PREP(ENETC_TX_BD_L4T,
203+
ENETC_TXBD_L4T_UDP);
204+
flags |= ENETC_TXBD_FLAGS_CSUM_LSO | ENETC_TXBD_FLAGS_L4CS;
205+
} else if (skb_checksum_help(skb)) {
206+
return 0;
207+
}
208+
}
209+
166210
i = tx_ring->next_to_use;
167211
txbd = ENETC_TXBD(*tx_ring, i);
168212
prefetchw(txbd);
@@ -173,7 +217,6 @@ static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb)
173217

174218
temp_bd.addr = cpu_to_le64(dma);
175219
temp_bd.buf_len = cpu_to_le16(len);
176-
temp_bd.lstatus = 0;
177220

178221
tx_swbd = &tx_ring->tx_swbd[i];
179222
tx_swbd->dma = dma;
@@ -594,7 +637,7 @@ static netdev_tx_t enetc_start_xmit(struct sk_buff *skb,
594637
{
595638
struct enetc_ndev_priv *priv = netdev_priv(ndev);
596639
struct enetc_bdr *tx_ring;
597-
int count, err;
640+
int count;
598641

599642
/* Queue one-step Sync packet if already locked */
600643
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,
627670
return NETDEV_TX_BUSY;
628671
}
629672

630-
if (skb->ip_summed == CHECKSUM_PARTIAL) {
631-
err = skb_checksum_help(skb);
632-
if (err)
633-
goto drop_packet_err;
634-
}
635673
enetc_lock_mdio();
636674
count = enetc_map_tx_buffs(tx_ring, skb);
637675
enetc_unlock_mdio();
@@ -3274,6 +3312,7 @@ static const struct enetc_drvdata enetc_pf_data = {
32743312

32753313
static const struct enetc_drvdata enetc4_pf_data = {
32763314
.sysclk_freq = ENETC_CLK_333M,
3315+
.tx_csum = true,
32773316
.pmac_offset = ENETC4_PMAC_OFFSET,
32783317
.eth_ops = &enetc4_pf_ethtool_ops,
32793318
};

drivers/net/ethernet/freescale/enetc/enetc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ enum enetc_errata {
234234

235235
struct enetc_drvdata {
236236
u32 pmac_offset; /* Only valid for PSI which supports 802.1Qbu */
237+
u8 tx_csum:1;
237238
u64 sysclk_freq;
238239
const struct ethtool_ops *eth_ops;
239240
};
@@ -341,6 +342,7 @@ enum enetc_active_offloads {
341342
ENETC_F_QBV = BIT(9),
342343
ENETC_F_QCI = BIT(10),
343344
ENETC_F_QBU = BIT(11),
345+
ENETC_F_TXCSUM = BIT(12),
344346
};
345347

346348
enum enetc_flags_bit {

drivers/net/ethernet/freescale/enetc/enetc_hw.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,16 @@ union enetc_tx_bd {
558558
__le16 frm_len;
559559
union {
560560
struct {
561-
u8 reserved[3];
561+
u8 l3_aux0;
562+
#define ENETC_TX_BD_L3_START GENMASK(6, 0)
563+
#define ENETC_TX_BD_IPCS BIT(7)
564+
u8 l3_aux1;
565+
#define ENETC_TX_BD_L3_HDR_LEN GENMASK(6, 0)
566+
#define ENETC_TX_BD_L3T BIT(7)
567+
u8 l4_aux;
568+
#define ENETC_TX_BD_L4T GENMASK(7, 5)
569+
#define ENETC_TXBD_L4T_UDP 1
570+
#define ENETC_TXBD_L4T_TCP 2
562571
u8 flags;
563572
}; /* default layout */
564573
__le32 txstart;
@@ -582,10 +591,10 @@ union enetc_tx_bd {
582591
};
583592

584593
enum enetc_txbd_flags {
585-
ENETC_TXBD_FLAGS_RES0 = BIT(0), /* reserved */
594+
ENETC_TXBD_FLAGS_L4CS = BIT(0), /* For ENETC 4.1 and later */
586595
ENETC_TXBD_FLAGS_TSE = BIT(1),
587596
ENETC_TXBD_FLAGS_W = BIT(2),
588-
ENETC_TXBD_FLAGS_RES3 = BIT(3), /* reserved */
597+
ENETC_TXBD_FLAGS_CSUM_LSO = BIT(3), /* For ENETC 4.1 and later */
589598
ENETC_TXBD_FLAGS_TXSTART = BIT(4),
590599
ENETC_TXBD_FLAGS_EX = BIT(6),
591600
ENETC_TXBD_FLAGS_F = BIT(7)

drivers/net/ethernet/freescale/enetc/enetc_pf_common.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
119119

120120
ndev->priv_flags |= IFF_UNICAST_FLT;
121121

122+
if (si->drvdata->tx_csum)
123+
priv->active_offloads |= ENETC_F_TXCSUM;
124+
122125
/* TODO: currently, i.MX95 ENETC driver does not support advanced features */
123126
if (!is_enetc_rev1(si)) {
124127
ndev->hw_features &= ~(NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK);

0 commit comments

Comments
 (0)