From 63dae581767274d7ff08bdd238d5daf722c5ae1e Mon Sep 17 00:00:00 2001 From: morris Date: Sat, 9 May 2020 12:49:29 +0800 Subject: [PATCH] ethernet: better control start/stop/uninstall/install --- components/esp_eth/src/esp_eth.c | 44 +++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/components/esp_eth/src/esp_eth.c b/components/esp_eth/src/esp_eth.c index 6c80bb2c5..a895b5b09 100644 --- a/components/esp_eth/src/esp_eth.c +++ b/components/esp_eth/src/esp_eth.c @@ -34,7 +34,10 @@ static const char *TAG = "esp_eth"; ESP_EVENT_DEFINE_BASE(ETH_EVENT); -#define ESP_ETH_FLAGS_STARTED (1<<0) +typedef enum { + ESP_ETH_FSM_STOP, + ESP_ETH_FSM_START +} esp_eth_fsm_t; /** * @brief The Ethernet driver mainly consists of PHY, MAC and @@ -56,7 +59,7 @@ typedef struct { eth_link_t link; atomic_int ref_count; void *priv; - uint32_t flags; + _Atomic esp_eth_fsm_t fsm; esp_err_t (*stack_input)(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t length, void *priv); esp_err_t (*on_lowlevel_init_done)(esp_eth_handle_t eth_handle); esp_err_t (*on_lowlevel_deinit_done)(esp_eth_handle_t eth_handle); @@ -175,6 +178,7 @@ esp_err_t esp_eth_driver_install(const esp_eth_config_t *config, esp_eth_handle_ esp_eth_driver_t *eth_driver = heap_caps_calloc(1, sizeof(esp_eth_driver_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); ETH_CHECK(eth_driver, "request memory for eth_driver failed", err, ESP_ERR_NO_MEM); atomic_init(ð_driver->ref_count, 1); + atomic_init(ð_driver->fsm, ESP_ETH_FSM_STOP); eth_driver->mac = mac; eth_driver->phy = phy; eth_driver->link = ETH_LINK_DOWN; @@ -221,9 +225,20 @@ esp_err_t esp_eth_driver_uninstall(esp_eth_handle_t hdl) esp_err_t ret = ESP_OK; esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl; ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG); + // check if driver has started + esp_eth_fsm_t expected_fsm = ESP_ETH_FSM_STOP; + if (!atomic_compare_exchange_strong(ð_driver->fsm, &expected_fsm, ESP_ETH_FSM_STOP)) { + ESP_LOGW(TAG, "driver not stopped yet"); + ret = ESP_ERR_INVALID_STATE; + goto err; + } // don't uninstall driver unless there's only one reference - ETH_CHECK(atomic_load(ð_driver->ref_count) == 1, - "more than one reference to ethernet driver", err, ESP_ERR_INVALID_STATE); + int expected_ref_count = 1; + if (!atomic_compare_exchange_strong(ð_driver->ref_count, &expected_ref_count, 0)) { + ESP_LOGE(TAG, "%d ethernet reference in use", expected_ref_count); + ret = ESP_ERR_INVALID_STATE; + goto err; + } esp_eth_mac_t *mac = eth_driver->mac; esp_eth_phy_t *phy = eth_driver->phy; ETH_CHECK(xTimerDelete(eth_driver->check_link_timer, 0) == pdPASS, "delete eth_link_timer failed", err, ESP_FAIL); @@ -241,12 +256,12 @@ esp_err_t esp_eth_start(esp_eth_handle_t hdl) esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl; ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG); // check if driver has started - if (eth_driver->flags & ESP_ETH_FLAGS_STARTED) { + esp_eth_fsm_t expected_fsm = ESP_ETH_FSM_STOP; + if (!atomic_compare_exchange_strong(ð_driver->fsm, &expected_fsm, ESP_ETH_FSM_START)) { ESP_LOGW(TAG, "driver started already"); ret = ESP_ERR_INVALID_STATE; goto err; } - eth_driver->flags |= ESP_ETH_FLAGS_STARTED; ETH_CHECK(eth_driver->phy->reset(eth_driver->phy) == ESP_OK, "reset phy failed", err, ESP_FAIL); ETH_CHECK(xTimerStart(eth_driver->check_link_timer, 0) == pdPASS, "start eth_link_timer failed", err, ESP_FAIL); @@ -265,19 +280,18 @@ esp_err_t esp_eth_stop(esp_eth_handle_t hdl) esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl; ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG); // check if driver has started - if (eth_driver->flags & ESP_ETH_FLAGS_STARTED) { - eth_driver->flags &= ~ESP_ETH_FLAGS_STARTED; - esp_eth_mac_t *mac = eth_driver->mac; - ETH_CHECK(mac->stop(mac) == ESP_OK, "stop mac failed", err, ESP_FAIL); - ETH_CHECK(xTimerStop(eth_driver->check_link_timer, 0) == pdPASS, - "stop eth_link_timer failed", err, ESP_FAIL); - ETH_CHECK(esp_event_post(ETH_EVENT, ETHERNET_EVENT_STOP, ð_driver, sizeof(eth_driver), 0) == ESP_OK, - "send ETHERNET_EVENT_STOP event failed", err, ESP_FAIL); - } else { + esp_eth_fsm_t expected_fsm = ESP_ETH_FSM_START; + if (!atomic_compare_exchange_strong(ð_driver->fsm, &expected_fsm, ESP_ETH_FSM_STOP)) { ESP_LOGW(TAG, "driver not started yet"); ret = ESP_ERR_INVALID_STATE; goto err; } + esp_eth_mac_t *mac = eth_driver->mac; + ETH_CHECK(mac->stop(mac) == ESP_OK, "stop mac failed", err, ESP_FAIL); + ETH_CHECK(xTimerStop(eth_driver->check_link_timer, 0) == pdPASS, + "stop eth_link_timer failed", err, ESP_FAIL); + ETH_CHECK(esp_event_post(ETH_EVENT, ETHERNET_EVENT_STOP, ð_driver, sizeof(eth_driver), 0) == ESP_OK, + "send ETHERNET_EVENT_STOP event failed", err, ESP_FAIL); return ESP_OK; err: return ret;