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 <abderrahmane.jarmouni-ext@st.com>
This commit is contained in:
Abderrahmane Jarmouni 2024-03-20 15:25:14 +01:00 committed by Anas Nashif
commit e783aafdd0

View file

@ -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 <stm32_ll_exti.h>
#endif /* CONFIG_PM */
#ifdef CONFIG_DCACHE
#include <zephyr/linker/linker-defs.h>
#include <zephyr/mem_mgmt/mem_attr.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
#endif /* CONFIG_DCACHE */
#include <zephyr/logging/log.h>
#include <zephyr/irq.h>
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;
}