From e783aafdd05728a5e17fd42e43bcb886da0d74d4 Mon Sep 17 00:00:00 2001 From: Abderrahmane Jarmouni Date: Wed, 20 Mar 2024 15:25:14 +0100 Subject: [PATCH] drivers: uart_stm32: add DCache support in async DMA mode Adapt the driver to verify if DMA buffers are located in noncacheable memory when DCache is activated, in order to avoid cache coherency issues. This is required until manual cache coherency management is implemented. Signed-off-by: Abderrahmane Jarmouni --- drivers/serial/uart_stm32.c | 53 +++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index e79ba3bf0f3..f5a831f0d2b 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2016 Open-RnD Sp. z o.o. * Copyright (c) 2016 Linaro Limited. + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -39,6 +40,12 @@ #include #endif /* CONFIG_PM */ +#ifdef CONFIG_DCACHE +#include +#include +#include +#endif /* CONFIG_DCACHE */ + #include #include LOG_MODULE_REGISTER(uart_stm32, CONFIG_UART_LOG_LEVEL); @@ -1301,6 +1308,32 @@ static void uart_stm32_isr(const struct device *dev) #ifdef CONFIG_UART_ASYNC_API +#ifdef CONFIG_DCACHE +static bool buf_in_nocache(uintptr_t buf, size_t len_bytes) +{ + bool buf_within_nocache = false; + +#ifdef CONFIG_NOCACHE_MEMORY + buf_within_nocache = (buf >= ((uintptr_t)_nocache_ram_start)) && + ((buf + len_bytes - 1) <= ((uintptr_t)_nocache_ram_end)); + if (buf_within_nocache) { + return true; + } +#endif /* CONFIG_NOCACHE_MEMORY */ + + buf_within_nocache = mem_attr_check_buf( + (void *)buf, len_bytes, DT_MEM_ARM_MPU_RAM_NOCACHE) == 0; + if (buf_within_nocache) { + return true; + } + + buf_within_nocache = (buf >= ((uintptr_t)__rodata_region_start)) && + ((buf + len_bytes - 1) <= ((uintptr_t)__rodata_region_end)); + + return buf_within_nocache; +} +#endif /* CONFIG_DCACHE */ + static int uart_stm32_async_callback_set(const struct device *dev, uart_callback_t callback, void *user_data) @@ -1512,6 +1545,13 @@ static int uart_stm32_async_tx(const struct device *dev, return -EBUSY; } +#ifdef CONFIG_DCACHE + if (!buf_in_nocache((uintptr_t)tx_data, buf_size)) { + LOG_ERR("Tx buffer should be placed in a nocache memory region"); + return -EFAULT; + } +#endif /* CONFIG_DCACHE */ + data->dma_tx.buffer = (uint8_t *)tx_data; data->dma_tx.buffer_length = buf_size; data->dma_tx.timeout = timeout; @@ -1572,6 +1612,13 @@ static int uart_stm32_async_rx_enable(const struct device *dev, return -EBUSY; } +#ifdef CONFIG_DCACHE + if (!buf_in_nocache((uintptr_t)rx_buf, buf_size)) { + LOG_ERR("Rx buffer should be placed in a nocache memory region"); + return -EFAULT; + } +#endif /* CONFIG_DCACHE */ + data->dma_rx.offset = 0; data->dma_rx.buffer = rx_buf; data->dma_rx.buffer_length = buf_size; @@ -1696,6 +1743,12 @@ static int uart_stm32_async_rx_buf_rsp(const struct device *dev, uint8_t *buf, } else if (!data->dma_rx.enabled) { err = -EACCES; } else { +#ifdef CONFIG_DCACHE + if (!buf_in_nocache((uintptr_t)buf, len)) { + LOG_ERR("Rx buffer should be placed in a nocache memory region"); + return -EFAULT; + } +#endif /* CONFIG_DCACHE */ data->rx_next_buffer = buf; data->rx_next_buffer_len = len; }