genet MTU for upstream - #7617
Conversation
|
39dfaf2 contains a brutal approach to make MTU 9000 work (without any offloading). Performs quite ok, but needs more testing |
39dfaf2 to
c702d70
Compare
c702d70 to
66f6684
Compare
|
I'm still waiting on documentation from Broadcom to read the official word on how jumbo frames with offload was meant to work (if it was). Seeing as it was the offloading headers that seemed to cause issues, I did wonder if disabling offloading would allow it to work with bigger buffers. I only had a very quick read through the patches, but wonder if we can "dynamically" disable offload when the mtu is increased above the magic threshold. Possibly not based on the comment of losing the queues as well. I had considered VLAN headers, but didn't know the answer off the top of my head, and wasn't in a position to set up VLANs to test. Thanks for taking care of it. I'm not fussed over |
|
@ffainelli and @Ryceancurry if you can spare some time, your thoughts on this would be really appreciated (as always). Thanks! |
|
https://lore.kernel.org/netdev/20260406-devel-autonomous-eee-v1-1-b335e7143711@tipi-net.de/t/
https://datasheets.raspberrypi.com/cm4/cm4-datasheet.pdf#page=7
https://www.broadcom.com/products/ethernet-connectivity/phy-and-poe/copper/gigabit/bcm54210
https://magazine.raspberrypi.com/articles/raspberry-pi-4-in-detail
https://www.broadcom.com/products/ethernet-connectivity/phy-and-poe/copper/gigabit/bcm54213
While we do understand the importance of taking one step at a time, it would be great to test whether |
Can you give me more color on the failure? Do we see fragmented packets? Is the packet corrupted? Or do we not receive a RX descriptor at all? Full disclosure, I threw AI at the RTL(I'm a SW guy), it suggests a RTL bug where the RSB is reserved at every packet ready threshold. So I wonder if we are seeing a 64B hole between each 3820B chunk within the jumbo packet. At least that is the running theory right now. I will continue to dig. |
|
Status blocks off, what's the true max frame length the MAC can handle ? |
|
Thanks for looking into this too!
With status block enabled and threshold at 0xf0 I get a descriptor (one per oversized frame): 3904 = 64 (RSB) + 2 (align) + 3838. Payload is fine and matches my test pattern. I also don't see any holes, just a hart cut off. I've also tested with 3840, 5000 and 9014 B frames and all of them produce the same descriptor. Some things I've noticed and might be worth mentioning:
For contrast, with |
I've tested further and came up with a solution which allows to switch to higher MTU on a live interface (tested 1514, 4096, 8192, 9014 B frames with threshold at 0xf0). Anyway, blocks needs to be disabled for anything higher. If I keep the TSB to preserve TX checksum offload, RX is still fine at 986 Mbit/s but TX drops to 0. A while ago I proposed to get rid of the TX queues in genet [1]. Florian and Justin reviewed and tested it, but the reasoning was not good enough. Even though the queues are not absolutely blocking it,the TSB has no queue selection role anymore and it would simplify the jumbo patch. Might be worth a v2. [1] https://lore.kernel.org/netdev/20260612205915.3156127-1-nb@tipi-net.de/ |
66f6684 to
36e861a
Compare
|
Patch tested on Audiolinux. |
As far as I can see the only limitation is the MAC's 14 bit frame len field. so 16383B I reproduced the 9000B frames with RSB enabled. I printed out the entire 9000B packet and see corruption at each PKT RDY THRESHOLD. 3838B and ~7700B. This confirms my suspicion. The HW puts a 64B header per PKT RDY THRESHOLD. I think the correct way to do this is to set rx_buf_size to PKT RDY THRESHOLD. Then use rx scatter gather with multiple descriptors. We need to strip 64B off of each fragment. Unfortunately this means a big rework on the RX side. |
|
@nbuchwitz we can test 16K with the current patch, it is just a question of ENET_MAX_JUMBO_MTU ? |
b060753 to
124162d
Compare
That helped a lot, thanks. I swapped the MTU 9000 patch for your approach and it works well. The TSB even can stay on with a little quirk. I also bumped max_mtu to what the 14 bit UMAC_MAX_FRAME_LEN allows, 16347. Do you now if the status block bug is in all GENET (non v1) versions? I only have v5 here to test. |
|
@nbuchwitz work great in 1G (I get 9184 the limitation is on other side) but configured in 100M there are packet loss with mtu > 9080 |
Could you show me the little quirk you used to keep the TSB enabled? On my Raspberry Pi 4 / GENET v5, MTU 13500 works, but around 13505 it becomes unstable and MTU 14000 fails with RX CRC errors. I noticed that a 14000 MTU results in a 14014-byte skb becoming a 14078-byte DMA buffer after the 64-byte TSB is added. |
The "quirk" is to dynamically switch of TX checksum based on the mtu (threshold is the previous 3820). See the last patch for details. Pi4 is afaik limited by the phy around 10k (see comment above). Cm4 should (theoretically) something around 18k |
Haven't tested it yet with fast ethernet. If the time permits I will do some measurements with different mtu and speed. I want to measure the cpu impact of sw checksum. For jumbo frames I assume not much of a penalty |
Thanks, that clarifies the TSB quirk. Interestingly, with two Pi4 Model B (Rev 1.1 and Rev 1.5) directly connected, I can get MTU 13500 working reliably in one direction (10/10 pings), while the opposite direction fails. Around 13503–13507 it becomes unstable/fails. So the Pi4 PHY seems capable of going significantly beyond 10k in at least some cases. Do you know what exactly imposes the ~10k PHY limit you mentioned (PHY register/buffer/specification), and whether it differs between Pi4 board revisions? |
|
Do you really see such big payload or is this already capped by phy and it just works "magically" with the 10k limit? Limit is stated in the datasheet. So I'd assume it's related to the buffer / state machine |
Yes, at least at the GENET MAC/driver level I really see the full size. For 10 successful MTU 13500 pings, txq3_packets increases by 10 and txq3_bytes by 135140, i.e. exactly 13514 bytes per packet. tx_oversize also increases by 10 on TX and rx_oversize by 10 on RX, with no additional CRC errors. I'm using However, I haven't verified on the wire between MAC and PHY, so you're right that this doesn't prove the PHY actually handles the full ~13.5K frame as such. Interestingly, Rev 1.1 -> Rev 1.5 works at MTU 13500, while Rev 1.5 -> Rev 1.1 fails, even though the receiving side counts the request and generates a 13514-byte reply. Which PHY datasheet/section states the ~10K limit? I'd like to check exactly what that limit refers to. |
|
https://www.broadcom.com/products/ethernet-connectivity/phy-and-poe/copper/gigabit/bcm54213pe
|
Thanks! yes, I confirmed that both of my Pi4s (Rev 1.1 and Rev 1.5) are using the BCM54213PE PHY ( So the 10 KB limit you mentioned is indeed the one stated in the BCM54213PE datasheet. However, MTU 13500 is really passing end-to-end in my tests: with Above that it becomes unreliable very quickly (around 13503–13507 in my tests), and at MTU 14000 it fails. I also see RX CRC errors when operating around this boundary, so this is clearly outside the PHY's guaranteed operating range. Interestingly, both Pi4 revisions use exactly the same BCM54213PE, so the different behaviour I saw between the two boards isn't explained by a different PHY model. I agree that this could be related to an internal PHY buffer/state-machine limit rather than a simple hard packet-size check. |
|
I will be able to test 16k CM4 tomorrow |
bcmgenet_hfb_init() runs INIT_LIST_HEAD() on priv->rxnfc_list, which drops every rule off the list, and bcmgenet_open() calls it on each ifup. Every rule the user configured is silently lost: # ethtool -N eth0 flow-type ether dst $MAC action 0 Added rule with ID 0 # ethtool -n eth0 | grep -c Filter: 1 # ip link set eth0 down && ip link set eth0 up # ethtool -n eth0 | grep -c Filter: 0 Initialise the lists once at probe and restore the rules on open, as bcmgenet_resume() already does. Fixes: 3e37095 ("net: bcmgenet: add support for ethtool rxnfc flows") Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
bcmgenet_netif_stop() disables the Tx queues first and stops Tx NAPI several steps later. A completion in flight calls netif_tx_wake_queue() in between, so a queue runs again while bcmgenet_dma_teardown() and bcmgenet_fini_dma() free the rings, and a transmit entering that window touches freed control blocks. Close is safe because dev_deactivate_many() stops the qdisc before ndo_stop() runs. bcmgenet_suspend() leaves it running, so stop Tx NAPI before the queues. Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
bcmgenet_netif_stop() already takes stop_phy. Give the start side the same choice so a caller that left the PHY running can bring the datapath back without tripping the phy_start() state check. No functional change. Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
ENET_MAX_MTU_SIZE holds a frame length, not an MTU. Both users program it into hardware that wants a frame length, so the name misleads as soon as the MTU stops being fixed at ETH_DATA_LEN. Name the receive offset too, which is open coded as 66. No functional change. Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
The receive buffer is a fixed 2048 bytes and the packet ready thresholds keep whatever the reset left them at, so neither follows the MTU. Compute the threshold from the MTU, program it into RBUF and TBUF, and size the buffer to what that threshold lets the hardware deliver, the status block on top of the threshold itself. The MTU is still fixed at ETH_DATA_LEN, so the threshold works out as the reset default and only the buffer grows, by the 64 bytes of status block it always had to hold. Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
The driver never sets dev->max_mtu, so the MTU is stuck at ETH_DATA_LEN. The thresholds follow the MTU, and their registers are 8 bit in units of 16 bytes and want a multiple of the 256 byte burst size, so 0xf0 is the largest usable value. That leaves an MTU of 3820 once the alignment bytes, the Ethernet header and a VLAN tag are taken off. Resize the buffers and rewrite the registers in place, so the PHY keeps running and the link stays up. A failed allocation falls back to the previous size, and if even that fails take the interface down rather than run on rings that are not there. Link: raspberrypi#5561 Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
124162d to
7ad4826
Compare
A frame longer than the packet ready threshold is not truncated. The hardware splits it across descriptors and writes a status block at the start of each one, so the first fragment arrives with SOP set and no EOP and is dropped as fragmented. That caps the MTU at 3820. In order to support a larger MTU, the fragments have to be reassembled after the status blocks have been stripped. The MAC only checksums frames up to the threshold and drops longer ones silently, so check those in software. That costs little at jumbo sizes, where the larger frame saves more per packet overhead. Use 16347 as the maximum MTU, based on the 14 bit UMAC_MAX_FRAME_LEN, which counts the FCS. Suggested-by: Justin Chen <justin.chen@broadcom.com> Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
7ad4826 to
2121751
Compare
|
I've created a second draft PR so it can be A/B tested. The other PR contains the patch set + 3 prep patches and is based on the series for net-next, as the driver upstream has been converted to page pool. |
Based on @6by9's #7614, with the goal of upstreaming the MTU support.
I've tested the original patch on CM4 and discovered some issues. So I've created a slightly different patch (series) which I intend to send to netdev. It also contains some fixes Sashiko would have flagged any way...
TBUF_PKT_RDY_THLD (TBUF + 0x10)is never programmed and it stays at0x80. At MTU3824TX iperf3 is stuck at 0.00 Mbit/s while ping works and the link is up.tx_pkts rises, buttx_good_pktsdoesn't. Kudos to @wtschueller who discovered this Jumbo frame support on Pi4 ethernet (Genet) #5561UMAC_MAX_FRAME_LENgets the MTU value, but it's a frame length and counts the FCS. Frames from3824up result inrx_length_errors(at least in my testing), so the real limit seems to be MTU3806.RX_BUF_LENGTH 10240costs no throughput (936/941 at MTU 1500, same as unpatched) but is above KMALLOC_MAX_CACHE_SIZE on arm64, thus it cant hurt to derive it from the MTU instead.0xf0seems to be the real limit:0xfbreceives fine but resulted in TX hard-hung on my setup.Happy to add @6by9 as Co-developed-by since it's based on your findings. But this requires a Signed-off, which I wouldn't add without consent.