diff --git a/drivers/ethernet/Kconfig.stm32_hal b/drivers/ethernet/Kconfig.stm32_hal index 3fd26ab4adde0..662e1e7c784c8 100644 --- a/drivers/ethernet/Kconfig.stm32_hal +++ b/drivers/ethernet/Kconfig.stm32_hal @@ -81,6 +81,14 @@ config ETH_STM32_HW_CHECKSUM performances. See reference manual for more information on this feature. +config ETH_STM32_HAL_TX_ASYNC + bool "Use TX async mode" + default n + depends on ETH_STM32_HAL_API_V2 + help + Enable TX transmission asynchronous mode to enhance throughput + performances. + menuconfig PTP_CLOCK_STM32_HAL bool "STM32 HAL PTP clock driver support" default y diff --git a/drivers/ethernet/eth_stm32_hal_v2.c b/drivers/ethernet/eth_stm32_hal_v2.c index 59d64bbaa76e5..4303ead523de0 100644 --- a/drivers/ethernet/eth_stm32_hal_v2.c +++ b/drivers/ethernet/eth_stm32_hal_v2.c @@ -116,6 +116,120 @@ static inline uint16_t allocate_tx_buffer(void) } } +#if defined(CONFIG_ETH_STM32_HAL_TX_ASYNC) +/* allocate a tx context and mark it as used, the first tx buffer is also allocated */ +static struct eth_stm32_tx_context *allocate_tx_context_async(struct net_pkt *pkt) +{ + int tx_index; + + for (uint16_t index = 0; index < ETH_TX_DESC_CNT; index++) { + if (!dma_tx_context[index].used) { + dma_tx_context[index].used = true; + dma_tx_context[index].pkt = pkt; + tx_index = allocate_tx_buffer(); + if (tx_index < 0) { + return NULL; + } + dma_tx_context[index].first_tx_buffer_index = tx_index; + return &dma_tx_context[index]; + } + } + return NULL; +} + +int eth_stm32_tx(const struct device *dev, struct net_pkt *pkt) +{ + struct eth_stm32_hal_dev_data *dev_data = dev->data; + ETH_HandleTypeDef *heth = &dev_data->heth; + int res = 0; + size_t total_len; + size_t remaining_read; + struct eth_stm32_tx_context *ctx = NULL; + struct eth_stm32_tx_buffer_header *buf_header = NULL; + HAL_StatusTypeDef hal_ret = HAL_OK; + +#if defined(CONFIG_PTP_CLOCK_STM32_HAL) + bool timestamped_frame; +#endif /* CONFIG_PTP_CLOCK_STM32_HAL */ + + __ASSERT_NO_MSG(pkt != NULL); + __ASSERT_NO_MSG(pkt->frags != NULL); + + total_len = net_pkt_get_len(pkt); + if (total_len > (ETH_STM32_TX_BUF_SIZE * ETH_TXBUFNB)) { + LOG_ERR("PKT too big"); + return -EIO; + } + + k_mutex_lock(&dev_data->tx_mutex, K_FOREVER); + + while (ctx == NULL) { + ctx = allocate_tx_context_async(pkt); + if (ctx == NULL) { + k_sem_take(&dev_data->tx_int_sem, K_MSEC(ETH_DMA_TX_TIMEOUT_MS)); + hal_ret = HAL_ETH_ReleaseTxPacket(heth); + __ASSERT_NO_MSG(hal_ret == HAL_OK); + } + } + buf_header = &dma_tx_buffer_header[ctx->first_tx_buffer_index]; + +#if defined(CONFIG_PTP_CLOCK_STM32_HAL) + timestamped_frame = eth_stm32_is_ptp_pkt(net_pkt_iface(pkt), pkt) || + net_pkt_is_tx_timestamping(pkt); + if (timestamped_frame) { + /* Enable transmit timestamp */ + if (HAL_ETH_PTP_InsertTxTimestamp(heth) != HAL_OK) { + res = -EIO; + goto error; + } + } +#endif /* CONFIG_PTP_CLOCK_STM32_HAL */ + + remaining_read = total_len; + /* fill and allocate buffer until remaining data fits in one buffer */ + while (remaining_read > ETH_STM32_TX_BUF_SIZE) { + res = net_pkt_read(pkt, buf_header->tx_buff.buffer, ETH_STM32_TX_BUF_SIZE); + if (res < 0) { + goto error; + } + + const uint16_t next_buffer_id = allocate_tx_buffer(); + + buf_header->tx_buff.len = ETH_STM32_TX_BUF_SIZE; + /* append new buffer to the linked list */ + buf_header->tx_buff.next = &dma_tx_buffer_header[next_buffer_id].tx_buff; + /* and adjust tail pointer */ + buf_header = &dma_tx_buffer_header[next_buffer_id]; + remaining_read -= ETH_STM32_TX_BUF_SIZE; + } + res = net_pkt_read(pkt, buf_header->tx_buff.buffer, remaining_read); + if (res < 0) { + goto error; + } + buf_header->tx_buff.len = remaining_read; + buf_header->tx_buff.next = NULL; + + tx_config.Length = total_len; + tx_config.pData = ctx; + tx_config.TxBuffer = &dma_tx_buffer_header[ctx->first_tx_buffer_index].tx_buff; + + if (HAL_ETH_Transmit_IT(heth, &tx_config) != HAL_OK) { + LOG_ERR("HAL_ETH_Transmit: failed!"); + res = -EIO; + } + +error: + if (res < 0 && ctx) { + /* We need to release the tx context and its buffers */ + HAL_ETH_TxFreeCallback((uint32_t *)ctx); + } + + k_mutex_unlock(&dev_data->tx_mutex); + + return res; +} +#else + /* allocate a tx context and mark it as used, the first tx buffer is also allocated */ static inline struct eth_stm32_tx_context *allocate_tx_context(struct net_pkt *pkt) { @@ -132,28 +246,6 @@ static inline struct eth_stm32_tx_context *allocate_tx_context(struct net_pkt *p } } -void eth_stm32_setup_mac_filter(ETH_HandleTypeDef *heth) -{ - ETH_MACFilterConfigTypeDef MACFilterConf; - HAL_StatusTypeDef __maybe_unused hal_ret; - - __ASSERT_NO_MSG(heth != NULL); - - hal_ret = HAL_ETH_GetMACFilterConfig(heth, &MACFilterConf); - __ASSERT_NO_MSG(hal_ret == HAL_OK); - - MACFilterConf.HashMulticast = - IS_ENABLED(CONFIG_ETH_STM32_MULTICAST_FILTER) ? ENABLE : DISABLE; - MACFilterConf.PassAllMulticast = - IS_ENABLED(CONFIG_ETH_STM32_MULTICAST_FILTER) ? DISABLE : ENABLE; - MACFilterConf.HachOrPerfectFilter = DISABLE; - - hal_ret = HAL_ETH_SetMACFilterConfig(heth, &MACFilterConf); - __ASSERT_NO_MSG(hal_ret == HAL_OK); - - k_sleep(K_MSEC(1)); -} - int eth_stm32_tx(const struct device *dev, struct net_pkt *pkt) { struct eth_stm32_hal_dev_data *dev_data = dev->data; @@ -294,6 +386,7 @@ int eth_stm32_tx(const struct device *dev, struct net_pkt *pkt) return res; } +#endif /* ETH_STM32_HAL_TX_ASYNC */ struct net_pkt *eth_stm32_rx(const struct device *dev) { @@ -512,7 +605,7 @@ int eth_stm32_hal_init(const struct device *dev) /* Initialize semaphores */ k_mutex_init(&dev_data->tx_mutex); k_sem_init(&dev_data->rx_int_sem, 0, K_SEM_MAX_LIMIT); - k_sem_init(&dev_data->tx_int_sem, 0, K_SEM_MAX_LIMIT); + k_sem_init(&dev_data->tx_int_sem, 0, 1); /* Tx config init: */ memset(&tx_config, 0, sizeof(ETH_TxPacketConfig)); @@ -559,6 +652,28 @@ void eth_stm32_set_mac_config(const struct device *dev, struct phy_link_state *s } } +void eth_stm32_setup_mac_filter(ETH_HandleTypeDef *heth) +{ + ETH_MACFilterConfigTypeDef MACFilterConf; + HAL_StatusTypeDef __maybe_unused hal_ret; + + __ASSERT_NO_MSG(heth != NULL); + + hal_ret = HAL_ETH_GetMACFilterConfig(heth, &MACFilterConf); + __ASSERT_NO_MSG(hal_ret == HAL_OK); + + MACFilterConf.HashMulticast = + IS_ENABLED(CONFIG_ETH_STM32_MULTICAST_FILTER) ? ENABLE : DISABLE; + MACFilterConf.PassAllMulticast = + IS_ENABLED(CONFIG_ETH_STM32_MULTICAST_FILTER) ? DISABLE : ENABLE; + MACFilterConf.HachOrPerfectFilter = DISABLE; + + hal_ret = HAL_ETH_SetMACFilterConfig(heth, &MACFilterConf); + __ASSERT_NO_MSG(hal_ret == HAL_OK); + + k_sleep(K_MSEC(1)); +} + int eth_stm32_hal_start(const struct device *dev) { struct eth_stm32_hal_dev_data *dev_data = dev->data; diff --git a/samples/net/zperf/boards/nucleo_h743zi.conf b/samples/net/zperf/boards/nucleo_h743zi.conf new file mode 100644 index 0000000000000..2912efb8d1d8a --- /dev/null +++ b/samples/net/zperf/boards/nucleo_h743zi.conf @@ -0,0 +1 @@ +CONFIG_ETH_STM32_HAL_TX_ASYNC=y diff --git a/samples/net/zperf/sample.yaml b/samples/net/zperf/sample.yaml index 8124d750a80ec..0115945f67e1f 100644 --- a/samples/net/zperf/sample.yaml +++ b/samples/net/zperf/sample.yaml @@ -17,6 +17,10 @@ tests: platform_allow: qemu_x86 extra_configs: - CONFIG_NET_ZPERF_SERVER=n + sample.net.zperf.async_tx.stm32: + filter: dt_compat_enabled("st,stm32-ethernet") + extra_configs: + - CONFIG_ETH_STM32_HAL_TX_ASYNC=y sample.net.zperf_st: harness: console harness_config: