diff --git a/components/esp_eth/src/esp_eth_mac_esp32.c b/components/esp_eth/src/esp_eth_mac_esp32.c index a031e84c42..1ba4416af4 100644 --- a/components/esp_eth/src/esp_eth_mac_esp32.c +++ b/components/esp_eth/src/esp_eth_mac_esp32.c @@ -64,6 +64,9 @@ typedef struct { #endif } emac_esp32_t; +static esp_err_t esp_emac_alloc_driver_obj(const eth_mac_config_t *config, emac_esp32_t **emac_out_hdl, void **out_descriptors); +static void esp_emac_free_driver_obj(emac_esp32_t *emac, void *descriptors); + static esp_err_t emac_esp32_set_mediator(esp_eth_mac_t *mac, esp_eth_mediator_t *eth) { esp_err_t ret = ESP_OK; @@ -285,10 +288,6 @@ static esp_err_t emac_esp32_init(esp_eth_mac_t *mac) esp_err_t ret = ESP_OK; emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); esp_eth_mediator_t *eth = emac->eth; - /* enable peripheral clock */ - periph_module_enable(PERIPH_EMAC_MODULE); - /* init clock, config gpio, etc */ - emac_hal_lowlevel_init(&emac->hal); /* init gpio used by smi interface */ emac_esp32_init_smi_gpio(emac); MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL) == ESP_OK, "lowlevel init failed", err, ESP_FAIL); @@ -333,7 +332,6 @@ static esp_err_t emac_esp32_deinit(esp_eth_mac_t *mac) #endif emac_hal_stop(&emac->hal); eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL); - periph_module_disable(PERIPH_EMAC_MODULE); return ESP_OK; } @@ -354,22 +352,8 @@ static esp_err_t emac_esp32_stop(esp_eth_mac_t *mac) static esp_err_t emac_esp32_del(esp_eth_mac_t *mac) { emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); - esp_intr_free(emac->intr_hdl); -#ifdef CONFIG_PM_ENABLE - if (emac->pm_lock) { - esp_pm_lock_delete(emac->pm_lock); - } -#endif - vTaskDelete(emac->rx_task_hdl); - int i = 0; - for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { - free(emac->hal.rx_buf[i]); - } - for (i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { - free(emac->hal.tx_buf[i]); - } - free(emac->hal.descriptors); - free(emac); + esp_emac_free_driver_obj(emac, emac->hal.descriptors); + periph_module_disable(PERIPH_EMAC_MODULE); return ESP_OK; } @@ -385,83 +369,8 @@ IRAM_ATTR void emac_esp32_isr_handler(void *args) } } -esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config) +static void esp_emac_free_driver_obj(emac_esp32_t *emac, void *descriptors) { - esp_err_t ret_code = ESP_OK; - esp_eth_mac_t *ret = NULL; - void *descriptors = NULL; - emac_esp32_t *emac = NULL; - MAC_CHECK(config, "can't set mac config to null", err, NULL); - if (config->flags & ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE) { - emac = heap_caps_calloc(1, sizeof(emac_esp32_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - } else { - emac = calloc(1, sizeof(emac_esp32_t)); - } - MAC_CHECK(emac, "calloc emac failed", err, NULL); - /* alloc memory for ethernet dma descriptor */ - uint32_t desc_size = CONFIG_ETH_DMA_RX_BUFFER_NUM * sizeof(eth_dma_rx_descriptor_t) + - CONFIG_ETH_DMA_TX_BUFFER_NUM * sizeof(eth_dma_tx_descriptor_t); - descriptors = heap_caps_calloc(1, desc_size, MALLOC_CAP_DMA); - MAC_CHECK(descriptors, "calloc descriptors failed", err, NULL); - int i = 0; - /* alloc memory for ethernet dma buffer */ - for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { - emac->rx_buf[i] = heap_caps_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA); - if (!(emac->rx_buf[i])) { - goto err; - } - } - for (i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { - emac->tx_buf[i] = heap_caps_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA); - if (!(emac->tx_buf[i])) { - goto err; - } - } - /* initialize hal layer driver */ - emac_hal_init(&emac->hal, descriptors, emac->rx_buf, emac->tx_buf); - emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms; - emac->smi_mdc_gpio_num = config->smi_mdc_gpio_num; - emac->smi_mdio_gpio_num = config->smi_mdio_gpio_num; - emac->parent.set_mediator = emac_esp32_set_mediator; - emac->parent.init = emac_esp32_init; - emac->parent.deinit = emac_esp32_deinit; - emac->parent.start = emac_esp32_start; - emac->parent.stop = emac_esp32_stop; - emac->parent.del = emac_esp32_del; - emac->parent.write_phy_reg = emac_esp32_write_phy_reg; - emac->parent.read_phy_reg = emac_esp32_read_phy_reg; - emac->parent.set_addr = emac_esp32_set_addr; - emac->parent.get_addr = emac_esp32_get_addr; - emac->parent.set_speed = emac_esp32_set_speed; - emac->parent.set_duplex = emac_esp32_set_duplex; - emac->parent.set_link = emac_esp32_set_link; - emac->parent.set_promiscuous = emac_esp32_set_promiscuous; - emac->parent.transmit = emac_esp32_transmit; - emac->parent.receive = emac_esp32_receive; - /* Interrupt configuration */ - if (config->flags & ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE) { - ret_code = esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, ESP_INTR_FLAG_IRAM, - emac_esp32_isr_handler, &emac->hal, &(emac->intr_hdl)); - } else { - ret_code = esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0, - emac_esp32_isr_handler, &emac->hal, &(emac->intr_hdl)); - } - MAC_CHECK(ret_code == ESP_OK, "alloc emac interrupt failed", err, NULL); -#ifdef CONFIG_PM_ENABLE - MAC_CHECK(esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "emac_esp32", &emac->pm_lock) == ESP_OK, - "create pm lock failed", err, NULL); -#endif - /* create rx task */ - BaseType_t core_num = tskNO_AFFINITY; - if (config->flags & ETH_MAC_FLAG_PIN_TO_CORE) { - core_num = xPortGetCoreID(); - } - BaseType_t xReturned = xTaskCreatePinnedToCore(emac_esp32_rx_task, "emac_rx", config->rx_task_stack_size, emac, - config->rx_task_prio, &emac->rx_task_hdl, core_num); - MAC_CHECK(xReturned == pdPASS, "create emac_rx task failed", err, NULL); - return &(emac->parent); - -err: if (emac) { if (emac->rx_task_hdl) { vTaskDelete(emac->rx_task_hdl); @@ -485,6 +394,106 @@ err: if (descriptors) { free(descriptors); } +} + +static esp_err_t esp_emac_alloc_driver_obj(const eth_mac_config_t *config, emac_esp32_t **emac_out_hdl, void **out_descriptors) +{ + esp_err_t ret = ESP_OK; + emac_esp32_t *emac = NULL; + void *descriptors = NULL; + if (config->flags & ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE) { + emac = heap_caps_calloc(1, sizeof(emac_esp32_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + } else { + emac = calloc(1, sizeof(emac_esp32_t)); + } + MAC_CHECK(emac, "no mem for esp emac object", err, ESP_ERR_NO_MEM); + /* alloc memory for ethernet dma descriptor */ + uint32_t desc_size = CONFIG_ETH_DMA_RX_BUFFER_NUM * sizeof(eth_dma_rx_descriptor_t) + + CONFIG_ETH_DMA_TX_BUFFER_NUM * sizeof(eth_dma_tx_descriptor_t); + descriptors = heap_caps_calloc(1, desc_size, MALLOC_CAP_DMA); + MAC_CHECK(descriptors, "no mem for descriptors", err, ESP_ERR_NO_MEM); + /* alloc memory for ethernet dma buffer */ + for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { + emac->rx_buf[i] = heap_caps_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA); + MAC_CHECK(emac->rx_buf[i], "no mem for RX DMA buffers", err, ESP_ERR_NO_MEM); + } + for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { + emac->tx_buf[i] = heap_caps_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA); + MAC_CHECK(emac->tx_buf[i], "no mem for TX DMA buffers", err, ESP_ERR_NO_MEM); + } + /* alloc PM lock */ +#ifdef CONFIG_PM_ENABLE + MAC_CHECK(esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "emac_esp32", &emac->pm_lock) == ESP_OK, + "create pm lock failed", err, ESP_FAIL); +#endif + /* create rx task */ + BaseType_t core_num = tskNO_AFFINITY; + if (config->flags & ETH_MAC_FLAG_PIN_TO_CORE) { + core_num = xPortGetCoreID(); + } + BaseType_t xReturned = xTaskCreatePinnedToCore(emac_esp32_rx_task, "emac_rx", config->rx_task_stack_size, emac, + config->rx_task_prio, &emac->rx_task_hdl, core_num); + MAC_CHECK(xReturned == pdPASS, "create emac_rx task failed", err, ESP_FAIL); + + *out_descriptors = descriptors; + *emac_out_hdl = emac; + return ESP_OK; +err: + esp_emac_free_driver_obj(emac, descriptors); + return ret; +} + +esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config) +{ + esp_err_t ret_code = ESP_OK; + esp_eth_mac_t *ret = NULL; + void *descriptors = NULL; + emac_esp32_t *emac = NULL; + MAC_CHECK(config, "can't set mac config to null", err, NULL); + ret_code = esp_emac_alloc_driver_obj(config, &emac, &descriptors); + MAC_CHECK(ret_code == ESP_OK, "alloc driver object failed", err, NULL); + + /* enable APB to access Ethernet peripheral registers */ + periph_module_enable(PERIPH_EMAC_MODULE); + /* initialize hal layer driver */ + emac_hal_init(&emac->hal, descriptors, emac->rx_buf, emac->tx_buf); + // config emac data interface + emac_hal_lowlevel_init(&emac->hal); + /* alloc interrupt */ + if (config->flags & ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE) { + ret_code = esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, ESP_INTR_FLAG_IRAM, + emac_esp32_isr_handler, &emac->hal, &(emac->intr_hdl)); + } else { + ret_code = esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0, + emac_esp32_isr_handler, &emac->hal, &(emac->intr_hdl)); + } + MAC_CHECK(ret_code == ESP_OK, "alloc emac interrupt failed", err_intr, NULL); + + emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms; + emac->smi_mdc_gpio_num = config->smi_mdc_gpio_num; + emac->smi_mdio_gpio_num = config->smi_mdio_gpio_num; + emac->parent.set_mediator = emac_esp32_set_mediator; + emac->parent.init = emac_esp32_init; + emac->parent.deinit = emac_esp32_deinit; + emac->parent.start = emac_esp32_start; + emac->parent.stop = emac_esp32_stop; + emac->parent.del = emac_esp32_del; + emac->parent.write_phy_reg = emac_esp32_write_phy_reg; + emac->parent.read_phy_reg = emac_esp32_read_phy_reg; + emac->parent.set_addr = emac_esp32_set_addr; + emac->parent.get_addr = emac_esp32_get_addr; + emac->parent.set_speed = emac_esp32_set_speed; + emac->parent.set_duplex = emac_esp32_set_duplex; + emac->parent.set_link = emac_esp32_set_link; + emac->parent.set_promiscuous = emac_esp32_set_promiscuous; + emac->parent.transmit = emac_esp32_transmit; + emac->parent.receive = emac_esp32_receive; + return &(emac->parent); + +err_intr: + periph_module_disable(PERIPH_EMAC_MODULE); +err: + esp_emac_free_driver_obj(emac, descriptors); return ret; } diff --git a/components/esp_eth/src/esp_eth_phy_dm9051.c b/components/esp_eth/src/esp_eth_phy_dm9051.c index acda61b7e1..effd929177 100644 --- a/components/esp_eth/src/esp_eth_phy_dm9051.c +++ b/components/esp_eth/src/esp_eth_phy_dm9051.c @@ -198,6 +198,11 @@ static esp_err_t dm9051_reset_hw(esp_eth_phy_t *phy) return ESP_OK; } +/** + * @note This function is responsible for restarting a new auto-negotiation, + * the result of negotiation won't be relected to uppler layers. + * Instead, the negotiation result is fetched by linker timer, see `dm9051_get_link()` + */ static esp_err_t dm9051_negotiate(esp_eth_phy_t *phy) { phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); @@ -227,7 +232,7 @@ static esp_err_t dm9051_negotiate(esp_eth_phy_t *phy) break; } } - if (to >= dm9051->autonego_timeout_ms / 100) { + if ((to >= dm9051->autonego_timeout_ms / 100) && (dm9051->link_status == ETH_LINK_UP)) { ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout"); } return ESP_OK; diff --git a/components/esp_eth/src/esp_eth_phy_dp83848.c b/components/esp_eth/src/esp_eth_phy_dp83848.c index f7d379e4b9..93de6dec6e 100644 --- a/components/esp_eth/src/esp_eth_phy_dp83848.c +++ b/components/esp_eth/src/esp_eth_phy_dp83848.c @@ -187,6 +187,11 @@ static esp_err_t dp83848_reset_hw(esp_eth_phy_t *phy) return ESP_OK; } +/** + * @note This function is responsible for restarting a new auto-negotiation, + * the result of negotiation won't be relected to uppler layers. + * Instead, the negotiation result is fetched by linker timer, see `dp83848_get_link()` + */ static esp_err_t dp83848_negotiate(esp_eth_phy_t *phy) { phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent); @@ -216,8 +221,7 @@ static esp_err_t dp83848_negotiate(esp_eth_phy_t *phy) break; } } - /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */ - if (to >= dp83848->autonego_timeout_ms / 100) { + if ((to >= dp83848->autonego_timeout_ms / 100) && (dp83848->link_status == ETH_LINK_UP)) { ESP_LOGW(TAG, "auto negotiation timeout"); } return ESP_OK; diff --git a/components/esp_eth/src/esp_eth_phy_ip101.c b/components/esp_eth/src/esp_eth_phy_ip101.c index 7576c4b5fe..3da5d5824e 100644 --- a/components/esp_eth/src/esp_eth_phy_ip101.c +++ b/components/esp_eth/src/esp_eth_phy_ip101.c @@ -227,6 +227,11 @@ static esp_err_t ip101_reset_hw(esp_eth_phy_t *phy) return ESP_OK; } +/** + * @note This function is responsible for restarting a new auto-negotiation, + * the result of negotiation won't be relected to uppler layers. + * Instead, the negotiation result is fetched by linker timer, see `ip101_get_link()` + */ static esp_err_t ip101_negotiate(esp_eth_phy_t *phy) { phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); @@ -253,8 +258,7 @@ static esp_err_t ip101_negotiate(esp_eth_phy_t *phy) break; } } - /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */ - if (to >= ip101->autonego_timeout_ms / 100) { + if ((to >= ip101->autonego_timeout_ms / 100) && (ip101->link_status == ETH_LINK_UP)) { ESP_LOGW(TAG, "auto negotiation timeout"); } return ESP_OK; diff --git a/components/esp_eth/src/esp_eth_phy_lan8720.c b/components/esp_eth/src/esp_eth_phy_lan8720.c index f2c8d24b4b..5c4563079b 100644 --- a/components/esp_eth/src/esp_eth_phy_lan8720.c +++ b/components/esp_eth/src/esp_eth_phy_lan8720.c @@ -272,6 +272,11 @@ static esp_err_t lan8720_reset_hw(esp_eth_phy_t *phy) return ESP_OK; } +/** + * @note This function is responsible for restarting a new auto-negotiation, + * the result of negotiation won't be relected to uppler layers. + * Instead, the negotiation result is fetched by linker timer, see `lan8720_get_link()` + */ static esp_err_t lan8720_negotiate(esp_eth_phy_t *phy) { phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); @@ -301,7 +306,7 @@ static esp_err_t lan8720_negotiate(esp_eth_phy_t *phy) } } /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */ - if (to >= lan8720->autonego_timeout_ms / 100) { + if (to >= lan8720->autonego_timeout_ms / 100 && (lan8720->link_status == ETH_LINK_UP)) { ESP_LOGW(TAG, "auto negotiation timeout"); } return ESP_OK; diff --git a/components/esp_eth/src/esp_eth_phy_rtl8201.c b/components/esp_eth/src/esp_eth_phy_rtl8201.c index f567e95240..ef8cf87ab2 100644 --- a/components/esp_eth/src/esp_eth_phy_rtl8201.c +++ b/components/esp_eth/src/esp_eth_phy_rtl8201.c @@ -181,6 +181,11 @@ static esp_err_t rtl8201_reset_hw(esp_eth_phy_t *phy) return ESP_OK; } +/** + * @note This function is responsible for restarting a new auto-negotiation, + * the result of negotiation won't be relected to uppler layers. + * Instead, the negotiation result is fetched by linker timer, see `rtl8201_get_link()` + */ static esp_err_t rtl8201_negotiate(esp_eth_phy_t *phy) { phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); @@ -207,8 +212,7 @@ static esp_err_t rtl8201_negotiate(esp_eth_phy_t *phy) break; } } - /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */ - if (to >= rtl8201->autonego_timeout_ms / 100) { + if ((to >= rtl8201->autonego_timeout_ms / 100) && (rtl8201->link_status == ETH_LINK_UP)) { ESP_LOGW(TAG, "auto negotiation timeout"); } return ESP_OK;