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>
diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c
index e79ba3b..f5a831f 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 <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 @@
#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 @@
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 @@
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 @@
} 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;
}