ethernet: better control start/stop/uninstall/install

This commit is contained in:
morris 2020-05-09 12:49:29 +08:00
parent e07023b9c7
commit 63dae58176

View file

@ -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;