mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-06 05:31:57 +00:00
The SAM E70 Ethernet driver uses scatter gather DMA to transmit data. Each fragment of a network packet is mapped from a set of descriptors that is used by the controller to do the DMA transfer. Each descriptor contain an address and a length/status. The important status bits are GMAC_TXW1_LASTBUFFER to indicate the last fragment of a packet and GMAC_TXW1_USED to indicate that a descriptor has been processed by the controller. When starting a transmission, the controller start at the descriptor after the last one that has been processed. If the descriptor is NOT flagged by GMAC_TXW1_USED, it sends a first packet by sending all the fragments up to a descriptor flagged with GMAC_TXW1_LASTBUFFER. The first descriptor of a packet *and only the first descriptor of a packet* is then modified to flag it with GMAC_TXW1_USED and to provide a status (mostly related to errors and checksum offloading). It then continues with the next packet and so on and only stops if the next descriptor after GMAC_TXW1_LASTBUFFER is flagged with GMAC_TXW1_USED. Therefore in order for the controller to stop processing descriptors, the strategy is to flag the next descriptor after the last fragment to be sent with GMAC_TXW1_USED. When the next packet has to be queued, the flag can be removed before starting a transmission. This is what is currently done in the current driver. However there is a small race condition in the implementation: if packets are queued fast enough, the controller is still sending the fragment of the previous packet when the descriptor are written. When writing the first descriptor, the GMAC_TXW1_USED flag is removed. This is done after writing the address (with a memory barrier) so that looks safe. However given that the GMAC_TXW1_USED flag is only added by the controller to the first descriptor of a packet it means the next descriptor might have it cleared. In that case the descriptor is processed, and a junk packet is sent. That also desynchronize eth_tx and tx_complete as one or more packets than expected are transmitted. In order to fix that the strategy is slightly changed to initially write the first descriptor with the GMAC_TXW1_USED flag set. Once all the descriptors from the packet are written the bit is cleared (after a memory barrier). Then the transmission can be started safely. The patch also does a small optimization writing the next descriptor with only the GMAC_TXW1_USED bit set instead of setting this bit. As this will be a non-cached area, it's better avoiding a read followed by a write if not necessary. Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> |
||
---|---|---|
.. | ||
CMakeLists.txt | ||
eth_dw_priv.h | ||
eth_dw.c | ||
eth_e1000_priv.h | ||
eth_e1000.c | ||
eth_enc28j60_priv.h | ||
eth_enc28j60.c | ||
eth_mcux.c | ||
eth_native_posix_adapt.c | ||
eth_native_posix_priv.h | ||
eth_native_posix.c | ||
eth_sam_gmac_priv.h | ||
eth_sam_gmac.c | ||
eth_smsc911x_priv.h | ||
eth_smsc911x.c | ||
eth_stellaris_priv.h | ||
eth_stellaris.c | ||
eth_stm32_hal_priv.h | ||
eth_stm32_hal.c | ||
Kconfig | ||
Kconfig.dw | ||
Kconfig.e1000 | ||
Kconfig.enc28j60 | ||
Kconfig.mcux | ||
Kconfig.native_posix | ||
Kconfig.sam_gmac | ||
Kconfig.smsc911x | ||
Kconfig.stellaris | ||
Kconfig.stm32_hal | ||
phy_sam_gmac.c | ||
phy_sam_gmac.h |