Skip to content

Commit 6a07e3a

Browse files
Linus Walleijkuba-moo
authored andcommitted
net: ethernet: cortina: Use TOE/TSO on all TCP
It is desireable to push the hardware accelerator to also process non-segmented TCP frames: we pass the skb->len to the "TOE/TSO" offloader and it will handle them. Without this quirk the driver becomes unstable and lock up and and crash. I do not know exactly why, but it is probably due to the TOE (TCP offload engine) feature that is coupled with the segmentation feature - it is not possible to turn one part off and not the other, either both TOE and TSO are active, or neither of them. Not having the TOE part active seems detrimental, as if that hardware feature is not really supposed to be turned off. The datasheet says: "Based on packet parsing and TCP connection/NAT table lookup results, the NetEngine puts the packets belonging to the same TCP connection to the same queue for the software to process. The NetEngine puts incoming packets to the buffer or series of buffers for a jumbo packet. With this hardware acceleration, IP/TCP header parsing, checksum validation and connection lookup are offloaded from the software processing." After numerous tests with the hardware locking up after something between minutes and hours depending on load using iperf3 I have concluded this is necessary to stabilize the hardware. Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Link: https://patch.msgid.link/20250408-gemini-ethernet-tso-always-v1-1-e669f932359c@linaro.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 330689f commit 6a07e3a

File tree

1 file changed

+29
-8
lines changed

1 file changed

+29
-8
lines changed

drivers/net/ethernet/cortina/gemini.c

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,13 +1144,21 @@ static int gmac_map_tx_bufs(struct net_device *netdev, struct sk_buff *skb,
11441144
struct gmac_txdesc *txd;
11451145
skb_frag_t *skb_frag;
11461146
dma_addr_t mapping;
1147+
bool tcp = false;
11471148
void *buffer;
11481149
u16 mss;
11491150
int ret;
11501151

11511152
word1 = skb->len;
11521153
word3 = SOF_BIT;
11531154

1155+
/* Determine if we are doing TCP */
1156+
if (skb->protocol == htons(ETH_P_IP))
1157+
tcp = (ip_hdr(skb)->protocol == IPPROTO_TCP);
1158+
else
1159+
/* IPv6 */
1160+
tcp = (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP);
1161+
11541162
mss = skb_shinfo(skb)->gso_size;
11551163
if (mss) {
11561164
/* This means we are dealing with TCP and skb->len is the
@@ -1163,8 +1171,26 @@ static int gmac_map_tx_bufs(struct net_device *netdev, struct sk_buff *skb,
11631171
mss, skb->len);
11641172
word1 |= TSS_MTU_ENABLE_BIT;
11651173
word3 |= mss;
1174+
} else if (tcp) {
1175+
/* Even if we are not using TSO, use the hardware offloader
1176+
* for transferring the TCP frame: this hardware has partial
1177+
* TCP awareness (called TOE - TCP Offload Engine) and will
1178+
* according to the datasheet put packets belonging to the
1179+
* same TCP connection in the same queue for the TOE/TSO
1180+
* engine to process. The engine will deal with chopping
1181+
* up frames that exceed ETH_DATA_LEN which the
1182+
* checksumming engine cannot handle (see below) into
1183+
* manageable chunks. It flawlessly deals with quite big
1184+
* frames and frames containing custom DSA EtherTypes.
1185+
*/
1186+
mss = netdev->mtu + skb_tcp_all_headers(skb);
1187+
mss = min(mss, skb->len);
1188+
netdev_dbg(netdev, "TOE/TSO len %04x mtu %04x mss %04x\n",
1189+
skb->len, netdev->mtu, mss);
1190+
word1 |= TSS_MTU_ENABLE_BIT;
1191+
word3 |= mss;
11661192
} else if (skb->len >= ETH_FRAME_LEN) {
1167-
/* Hardware offloaded checksumming isn't working on frames
1193+
/* Hardware offloaded checksumming isn't working on non-TCP frames
11681194
* bigger than 1514 bytes. A hypothesis about this is that the
11691195
* checksum buffer is only 1518 bytes, so when the frames get
11701196
* bigger they get truncated, or the last few bytes get
@@ -1181,21 +1207,16 @@ static int gmac_map_tx_bufs(struct net_device *netdev, struct sk_buff *skb,
11811207
}
11821208

11831209
if (skb->ip_summed == CHECKSUM_PARTIAL) {
1184-
int tcp = 0;
1185-
11861210
/* We do not switch off the checksumming on non TCP/UDP
11871211
* frames: as is shown from tests, the checksumming engine
11881212
* is smart enough to see that a frame is not actually TCP
11891213
* or UDP and then just pass it through without any changes
11901214
* to the frame.
11911215
*/
1192-
if (skb->protocol == htons(ETH_P_IP)) {
1216+
if (skb->protocol == htons(ETH_P_IP))
11931217
word1 |= TSS_IP_CHKSUM_BIT;
1194-
tcp = ip_hdr(skb)->protocol == IPPROTO_TCP;
1195-
} else { /* IPv6 */
1218+
else
11961219
word1 |= TSS_IPV6_ENABLE_BIT;
1197-
tcp = ipv6_hdr(skb)->nexthdr == IPPROTO_TCP;
1198-
}
11991220

12001221
word1 |= tcp ? TSS_TCP_CHKSUM_BIT : TSS_UDP_CHKSUM_BIT;
12011222
}

0 commit comments

Comments
 (0)