diff --git a/components/esp_eth/src/esp_eth_mac_esp32.c b/components/esp_eth/src/esp_eth_mac_esp32.c index e9c051dd6d..9569a7fabe 100644 --- a/components/esp_eth/src/esp_eth_mac_esp32.c +++ b/components/esp_eth/src/esp_eth_mac_esp32.c @@ -75,6 +75,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; @@ -335,10 +338,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); @@ -383,7 +382,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; } @@ -404,22 +402,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; } @@ -435,87 +419,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->flow_control_high_water_mark = FLOW_CONTROL_HIGH_WATER_MARK; - emac->flow_control_low_water_mark = FLOW_CONTROL_LOW_WATER_MARK; - 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.set_peer_pause_ability = emac_esp32_set_peer_pause_ability; - emac->parent.enable_flow_ctrl = emac_esp32_enable_flow_ctrl; - 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 = cpu_hal_get_core_id(); - } - 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); @@ -539,6 +444,110 @@ 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 = cpu_hal_get_core_id(); + } + 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->flow_control_high_water_mark = FLOW_CONTROL_HIGH_WATER_MARK; + emac->flow_control_low_water_mark = FLOW_CONTROL_LOW_WATER_MARK; + 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.set_peer_pause_ability = emac_esp32_set_peer_pause_ability; + emac->parent.enable_flow_ctrl = emac_esp32_enable_flow_ctrl; + 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 0f3f541ca2..875d028beb 100644 --- a/components/esp_eth/src/esp_eth_phy_dm9051.c +++ b/components/esp_eth/src/esp_eth_phy_dm9051.c @@ -212,6 +212,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); @@ -241,7 +246,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 2492aed4a9..56130d441f 100644 --- a/components/esp_eth/src/esp_eth_phy_dp83848.c +++ b/components/esp_eth/src/esp_eth_phy_dp83848.c @@ -201,6 +201,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); @@ -230,8 +235,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 0562d0f3cd..e8053fe87b 100644 --- a/components/esp_eth/src/esp_eth_phy_ip101.c +++ b/components/esp_eth/src/esp_eth_phy_ip101.c @@ -241,6 +241,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); @@ -267,8 +272,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_ksz8041.c b/components/esp_eth/src/esp_eth_phy_ksz8041.c index cc75e33582..046b7eff76 100644 --- a/components/esp_eth/src/esp_eth_phy_ksz8041.c +++ b/components/esp_eth/src/esp_eth_phy_ksz8041.c @@ -189,6 +189,11 @@ static esp_err_t ksz8041_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 `ksz8041_get_link()` + */ static esp_err_t ksz8041_negotiate(esp_eth_phy_t *phy) { phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent); @@ -205,8 +210,8 @@ static esp_err_t ksz8041_negotiate(esp_eth_phy_t *phy) bmsr_reg_t bmsr; pc2r_reg_t pc2r; uint32_t to = 0; - for (to = 0; to < ksz8041->autonego_timeout_ms / 10; to++) { - vTaskDelay(pdMS_TO_TICKS(10)); + for (to = 0; to < ksz8041->autonego_timeout_ms / 100; to++) { + vTaskDelay(pdMS_TO_TICKS(100)); PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_PC2R_REG_ADDR, &(pc2r.val)) == ESP_OK, @@ -216,7 +221,7 @@ static esp_err_t ksz8041_negotiate(esp_eth_phy_t *phy) } } /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */ - if (to >= ksz8041->autonego_timeout_ms / 10) { + if ((to >= ksz8041->autonego_timeout_ms / 100) && (ksz8041->link_status == ETH_LINK_UP)) { ESP_LOGW(TAG, "auto negotiation timeout"); } /* Updata information about link, speed, duplex */ diff --git a/components/esp_eth/src/esp_eth_phy_lan8720.c b/components/esp_eth/src/esp_eth_phy_lan8720.c index aefcc78748..d0dc378a56 100644 --- a/components/esp_eth/src/esp_eth_phy_lan8720.c +++ b/components/esp_eth/src/esp_eth_phy_lan8720.c @@ -286,6 +286,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); @@ -315,7 +320,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 9bf6d34b3e..973e73e2e8 100644 --- a/components/esp_eth/src/esp_eth_phy_rtl8201.c +++ b/components/esp_eth/src/esp_eth_phy_rtl8201.c @@ -195,6 +195,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); @@ -221,8 +226,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;