Эх сурвалжийг харах

ethernet: better control start/stop/uninstall/install

morris 5 жил өмнө
parent
commit
63dae58176

+ 29 - 15
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(&eth_driver->ref_count, 1);
+    atomic_init(&eth_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(&eth_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(&eth_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(&eth_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(&eth_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, &eth_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(&eth_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, &eth_driver, sizeof(eth_driver), 0) == ESP_OK,
+              "send ETHERNET_EVENT_STOP event failed", err, ESP_FAIL);
     return ESP_OK;
 err:
     return ret;