From f08caaf6770acd0e7d33fe321d585ab6d6cb1a2d Mon Sep 17 00:00:00 2001 From: Markus Fuchs Date: Sun, 15 Sep 2019 11:33:38 +0200 Subject: [PATCH] drivers: ethernet: stm32: Add carrier state detection This patch adds carrier state detection to the STM32 Ethernet driver. Fixes #16097 Signed-off-by: Markus Fuchs --- drivers/ethernet/Kconfig.stm32_hal | 8 +++++ drivers/ethernet/eth_stm32_hal.c | 47 +++++++++++++++++++++------ drivers/ethernet/eth_stm32_hal_priv.h | 1 + 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/drivers/ethernet/Kconfig.stm32_hal b/drivers/ethernet/Kconfig.stm32_hal index 51fc2411580..2b1acd8c3c1 100644 --- a/drivers/ethernet/Kconfig.stm32_hal +++ b/drivers/ethernet/Kconfig.stm32_hal @@ -88,4 +88,12 @@ config ETH_STM32_HAL_MII help Use the MII physical interface instead of RMII. +config ETH_STM32_CARRIER_CHECK_RX_IDLE_TIMEOUT_MS + int "Carrier check timeout period (ms)" + default 500 + range 100 30000 + help + Set the RX idle timeout period in milliseconds after which the + PHY's carrier status is re-evaluated. + endif # ETH_STM32_HAL diff --git a/drivers/ethernet/eth_stm32_hal.c b/drivers/ethernet/eth_stm32_hal.c index 03a9d04330e..560bc5a84f4 100644 --- a/drivers/ethernet/eth_stm32_hal.c +++ b/drivers/ethernet/eth_stm32_hal.c @@ -230,6 +230,7 @@ static void rx_thread(void *arg1, void *unused1, void *unused2) struct eth_stm32_hal_dev_data *dev_data; struct net_pkt *pkt; int res; + u32_t status; __ASSERT_NO_MSG(arg1 != NULL); ARG_UNUSED(unused1); @@ -241,16 +242,39 @@ static void rx_thread(void *arg1, void *unused1, void *unused2) __ASSERT_NO_MSG(dev_data != NULL); while (1) { - k_sem_take(&dev_data->rx_int_sem, K_FOREVER); - - while ((pkt = eth_rx(dev)) != NULL) { - net_pkt_print_frags(pkt); - res = net_recv_data(dev_data->iface, pkt); - if (res < 0) { - eth_stats_update_errors_rx(dev_data->iface); - LOG_ERR("Failed to enqueue frame " - "into RX queue: %d", res); - net_pkt_unref(pkt); + res = k_sem_take(&dev_data->rx_int_sem, + K_MSEC(CONFIG_ETH_STM32_CARRIER_CHECK_RX_IDLE_TIMEOUT_MS)); + if (res == 0) { + /* semaphore taken, update link status and receive packets */ + if (dev_data->link_up != true) { + dev_data->link_up = true; + net_eth_carrier_on(dev_data->iface); + } + while ((pkt = eth_rx(dev)) != NULL) { + net_pkt_print_frags(pkt); + res = net_recv_data(dev_data->iface, pkt); + if (res < 0) { + eth_stats_update_errors_rx(dev_data->iface); + LOG_ERR("Failed to enqueue frame " + "into RX queue: %d", res); + net_pkt_unref(pkt); + } + } + } else if (res == -EAGAIN) { + /* semaphore timeout period expired, check link status */ + if (HAL_ETH_ReadPHYRegister(&dev_data->heth, PHY_BSR, + (uint32_t *) &status) == HAL_OK) { + if ((status & PHY_LINKED_STATUS) == PHY_LINKED_STATUS) { + if (dev_data->link_up != true) { + dev_data->link_up = true; + net_eth_carrier_on(dev_data->iface); + } + } else { + if (dev_data->link_up != false) { + dev_data->link_up = false; + net_eth_carrier_off(dev_data->iface); + } + } } } } @@ -382,6 +406,8 @@ static void eth_iface_init(struct net_if *iface) return; } + dev_data->link_up = false; + /* Initialize semaphores */ k_mutex_init(&dev_data->tx_mutex); k_sem_init(&dev_data->rx_int_sem, 0, UINT_MAX); @@ -417,6 +443,7 @@ static void eth_iface_init(struct net_if *iface) NET_LINK_ETHERNET); ethernet_init(iface); + net_if_flag_set(iface, NET_IF_NO_AUTO_START); } static enum ethernet_hw_caps eth_stm32_hal_get_capabilities(struct device *dev) diff --git a/drivers/ethernet/eth_stm32_hal_priv.h b/drivers/ethernet/eth_stm32_hal_priv.h index 50cd386fdd4..7bc1ff3b69e 100644 --- a/drivers/ethernet/eth_stm32_hal_priv.h +++ b/drivers/ethernet/eth_stm32_hal_priv.h @@ -37,6 +37,7 @@ struct eth_stm32_hal_dev_data { K_THREAD_STACK_MEMBER(rx_thread_stack, CONFIG_ETH_STM32_HAL_RX_THREAD_STACK_SIZE); struct k_thread rx_thread; + bool link_up; }; #define DEV_CFG(dev) \