Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers: ethernet: stm32h7 IT based ethernet TX #27188

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 126 additions & 8 deletions drivers/ethernet/eth_stm32_hal.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
#define ETH_MEDIA_INTERFACE_MII HAL_ETH_MII_MODE
#define ETH_MEDIA_INTERFACE_RMII HAL_ETH_RMII_MODE

#define ETH_DMA_TRANSMIT_TIMEOUT 20U /* transmit timeout in sys tiks */
#define ETH_DMA_TX_TIMEOUT_MS 20U /* transmit timeout in milliseconds */

/* Only one tx_buffer is sufficient to pass only 1 dma_buffer */
#define ETH_TXBUF_DEF_NB 1U
#else

#define GET_FIRST_DMA_TX_DESC(heth) (heth->TxDesc)
Expand Down Expand Up @@ -184,7 +186,7 @@ static int eth_tx(struct device *dev, struct net_pkt *pkt)

total_len = net_pkt_get_len(pkt);
if (total_len > ETH_TX_BUF_SIZE) {
LOG_ERR("PKT to big");
LOG_ERR("PKT too big");
res = -EIO;
goto error;
}
Expand All @@ -210,9 +212,9 @@ static int eth_tx(struct device *dev, struct net_pkt *pkt)
}

#if defined(CONFIG_SOC_SERIES_STM32H7X)
ETH_BufferTypeDef tx_buffer_def[ETH_TXBUFNB];
ETH_BufferTypeDef tx_buffer_def[ETH_TXBUF_DEF_NB];

memset(tx_buffer_def, 0, ETH_TXBUFNB*sizeof(ETH_BufferTypeDef));
memset(tx_buffer_def, 0, ETH_TXBUF_DEF_NB*sizeof(ETH_BufferTypeDef));

tx_buffer_def[cur_tx_desc_idx].buffer = dma_buffer;
tx_buffer_def[cur_tx_desc_idx].len = total_len;
Expand All @@ -221,18 +223,72 @@ static int eth_tx(struct device *dev, struct net_pkt *pkt)
tx_config.Length = total_len;
tx_config.TxBuffer = tx_buffer_def;

hal_ret = HAL_ETH_Transmit(heth, &tx_config, ETH_DMA_TRANSMIT_TIMEOUT);
/* Reset TX complete interrupt semaphore before TX request*/
k_sem_reset(&dev_data->tx_int_sem);

/* tx_buffer is allocated on function stack, we need */
/* to wait for the transfer to complete */
/* So it is not freed before the interrupt happens */
hal_ret = HAL_ETH_Transmit_IT(heth, &tx_config);

if (hal_ret != HAL_OK) {
LOG_ERR("HAL_ETH_Transmit: failed!");
res = -EIO;
goto error;
}

/* Wait for end of TX buffer transmission */
/* If the semaphore timeout breaks, it means */
/* an error occurred or IT was not fired */
if (k_sem_take(&dev_data->tx_int_sem,
K_MSEC(ETH_DMA_TX_TIMEOUT_MS)) != 0) {

LOG_ERR("HAL_ETH_TransmitIT tx_int_sem take timeout");
res = -EIO;

/* Content of the packet could be the reason for timeout */
LOG_HEXDUMP_ERR(dma_buffer, total_len, "eth packet timeout");

/* Check for errors */
/* Ethernet device was put in error state */
/* Error state is unrecoverable ? */
if (HAL_ETH_GetState(heth) == HAL_ETH_STATE_ERROR) {
LOG_ERR("%s: ETH in error state: errorcode:%x",
__func__,
HAL_ETH_GetError(heth));
/* TODO recover from error state by restarting eth */
}

/* Check for DMA errors */
if (HAL_ETH_GetDMAError(heth)) {
LOG_ERR("%s: ETH DMA error: dmaerror:%x",
__func__,
HAL_ETH_GetDMAError(heth));
/* DMA fatal bus errors are putting in error state*/
/* TODO recover from this */
}

/* Check for MAC errors */
if (HAL_ETH_GetDMAError(heth)) {
LOG_ERR("%s: ETH DMA error: macerror:%x",
__func__,
HAL_ETH_GetDMAError(heth));
/* MAC errors are putting in error state*/
/* TODO recover from this */
}

goto error;
}

#else
hal_ret = HAL_ETH_TransmitFrame(heth, total_len);
#endif /* CONFIG_SOC_SERIES_STM32H7X */

if (hal_ret != HAL_OK) {
LOG_ERR("HAL_ETH_Transmit{Frame}: failed!");
LOG_ERR("HAL_ETH_Transmit: failed!");
res = -EIO;
goto error;
}

#if !defined(CONFIG_SOC_SERIES_STM32H7X)
/* When Transmit Underflow flag is set, clear it and issue a
* Transmit Poll Demand to resume transmission.
*/
Expand Down Expand Up @@ -484,7 +540,66 @@ static void eth_isr(void *arg)

HAL_ETH_IRQHandler(heth);
}
#ifdef CONFIG_SOC_SERIES_STM32H7X
void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *heth_handle)
{
__ASSERT_NO_MSG(heth_handle != NULL);

struct eth_stm32_hal_dev_data *dev_data =
CONTAINER_OF(heth_handle, struct eth_stm32_hal_dev_data, heth);

__ASSERT_NO_MSG(dev_data != NULL);

k_sem_give(&dev_data->tx_int_sem);

}
/* DMA and MAC errors callback only appear in H7 series */
void HAL_ETH_DMAErrorCallback(ETH_HandleTypeDef *heth_handle)
{
__ASSERT_NO_MSG(heth_handle != NULL);

LOG_ERR("%s errorcode:%x dmaerror:%x",
__func__,
HAL_ETH_GetError(heth_handle),
HAL_ETH_GetDMAError(heth_handle));

/* State of eth handle is ERROR in case of unrecoverable error */
/* unrecoverable (ETH_DMACSR_FBE | ETH_DMACSR_TPS | ETH_DMACSR_RPS) */
if (HAL_ETH_GetState(heth_handle) == HAL_ETH_STATE_ERROR) {
LOG_ERR("%s ethernet in error state", __func__);
/* TODO restart the ETH peripheral to recover */
return;
}

/* Recoverable errors don't put ETH in error state */
/* ETH_DMACSR_CDE | ETH_DMACSR_ETI | ETH_DMACSR_RWT */
/* | ETH_DMACSR_RBU | ETH_DMACSR_AIS) */

/* TODO Check if we were TX transmitting and the unlock semaphore */
/* To return the error as soon as possible else we'll just wait */
/* for the timeout */


}
void HAL_ETH_MACErrorCallback(ETH_HandleTypeDef *heth_handle)
{
__ASSERT_NO_MSG(heth_handle != NULL);

/* MAC errors dumping */
LOG_ERR("%s errorcode:%x macerror:%x",
__func__,
HAL_ETH_GetError(heth_handle),
HAL_ETH_GetMACError(heth_handle));

/* State of eth handle is ERROR in case of unrecoverable error */
if (HAL_ETH_GetState(heth_handle) == HAL_ETH_STATE_ERROR) {
LOG_ERR("%s ethernet in error state", __func__);
/* TODO restart or reconfig ETH peripheral to recover */

return;
}
}
#endif /* CONFIG_SOC_SERIES_STM32H7X */

void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth_handle)
{
Expand Down Expand Up @@ -583,6 +698,9 @@ static int eth_initialize(struct device *dev)
/* Initialize semaphores */
k_mutex_init(&dev_data->tx_mutex);
k_sem_init(&dev_data->rx_int_sem, 0, UINT_MAX);
#ifdef CONFIG_SOC_SERIES_STM32H7X
k_sem_init(&dev_data->tx_int_sem, 0, UINT_MAX);
#endif /* CONFIG_SOC_SERIES_STM32H7X */

/* Start interruption-poll thread */
k_thread_create(&dev_data->rx_thread, dev_data->rx_thread_stack,
Expand Down
3 changes: 3 additions & 0 deletions drivers/ethernet/eth_stm32_hal_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ struct eth_stm32_hal_dev_data {
struct device *clock;
struct k_mutex tx_mutex;
struct k_sem rx_int_sem;
#ifdef CONFIG_SOC_SERIES_STM32H7X
struct k_sem tx_int_sem;
#endif /* CONFIG_SOC_SERIES_STM32H7X */
K_KERNEL_STACK_MEMBER(rx_thread_stack,
CONFIG_ETH_STM32_HAL_RX_THREAD_STACK_SIZE);
struct k_thread rx_thread;
Expand Down