From 8534799d6692a86de59adeb5d089fbcb61f0bb09 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 7 Apr 2021 21:15:24 +0200 Subject: [PATCH 1/2] esp_eth: Fix w5500 to correctly read registers on -Os Reading SPI data may come in 4-byte units and thus result in unwanted overwrites if smaller size registers read, especially if multiple placed one after another. Fixed by using direct reads to `trans` structure for sizes smaller or equal to 4. Closes https://github.com/espressif/esp-idf/issues/6579 --- components/esp_eth/src/esp_eth_mac_w5500.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/esp_eth/src/esp_eth_mac_w5500.c b/components/esp_eth/src/esp_eth_mac_w5500.c index ce69385a83..e713da9e74 100644 --- a/components/esp_eth/src/esp_eth_mac_w5500.c +++ b/components/esp_eth/src/esp_eth_mac_w5500.c @@ -93,6 +93,7 @@ static esp_err_t w5500_read(emac_w5500_t *emac, uint32_t address, void *value, u esp_err_t ret = ESP_OK; spi_transaction_t trans = { + .flags = len <= 4 ? SPI_TRANS_USE_RXDATA : 0, // use direct reads for registers to prevent overwrites by 4-byte boundary writes .cmd = (address >> W5500_ADDR_OFFSET), .addr = ((address & 0xFFFF) | (W5500_ACCESS_MODE_READ << W5500_RWB_OFFSET) | W5500_SPI_OP_MODE_VDM), .length = 8 * len, @@ -107,6 +108,9 @@ static esp_err_t w5500_read(emac_w5500_t *emac, uint32_t address, void *value, u } else { ret = ESP_ERR_TIMEOUT; } + if ((trans.flags&SPI_TRANS_USE_RXDATA) && len <= 4) { + memcpy(value, trans.rx_data, len); // copy register values to output + } return ret; } From 2fb93e6a5462a83c9f35c3d7a8c13dfa2b34e0d0 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 8 Apr 2021 10:16:08 +0200 Subject: [PATCH 2/2] 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);