From 2fb93e6a5462a83c9f35c3d7a8c13dfa2b34e0d0 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 8 Apr 2021 10:16:08 +0200 Subject: [PATCH] esp_eth: Fix w5500 to break from potentially infinite tx loop The issue typically happens for link-down during Tx. Added two retry levels, one before checking the sanity of the w5500 phy register and another for the Tx done itself (if the device is in the sane state) Closes https://github.com/espressif/esp-idf/issues/6233 --- components/esp_eth/src/esp_eth_mac_w5500.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/components/esp_eth/src/esp_eth_mac_w5500.c b/components/esp_eth/src/esp_eth_mac_w5500.c index e713da9e74..1f97d7fd68 100644 --- a/components/esp_eth/src/esp_eth_mac_w5500.c +++ b/components/esp_eth/src/esp_eth_mac_w5500.c @@ -502,6 +502,16 @@ static esp_err_t emac_w5500_set_peer_pause_ability(esp_eth_mac_t *mac, uint32_t return ESP_ERR_NOT_SUPPORTED; } +static inline bool is_w5500_sane_for_rxtx(emac_w5500_t *emac) +{ + uint8_t phycfg; + /* phy is ok for rx and tx operations if bits RST and LNK are set (no link down, no reset) */ + if (w5500_read(emac, W5500_REG_PHYCFGR, &phycfg, 1) == ESP_OK && (phycfg & 0x8001)) { + return true; + } + return false; +} + static esp_err_t emac_w5500_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint32_t length) { esp_err_t ret = ESP_OK; @@ -525,10 +535,14 @@ static esp_err_t emac_w5500_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint32_t MAC_CHECK(w5500_send_command(emac, W5500_SCR_SEND, 100) == ESP_OK, "issue SEND command failed", err, ESP_FAIL); // pooling the TX done event + int retry = 0; uint8_t status = 0; - do { + while (!(status & W5500_SIR_SEND)) { MAC_CHECK(w5500_read(emac, W5500_REG_SOCK_IR(0), &status, sizeof(status)) == ESP_OK, "read SOCK0 IR failed", err, ESP_FAIL); - } while (!(status & W5500_SIR_SEND)); + if ((retry++ > 3 && !is_w5500_sane_for_rxtx(emac)) || retry > 10) { + return ESP_FAIL; + } + } // clear the event bit status = W5500_SIR_SEND; MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_IR(0), &status, sizeof(status)) == ESP_OK, "write SOCK0 IR failed", err, ESP_FAIL);