From 4215adcdb4fe78ffdbdf708ea000c19a17c09e35 Mon Sep 17 00:00:00 2001 From: Armando Date: Wed, 27 Sep 2023 13:08:28 +0800 Subject: [PATCH] feat(cache): added cache msync doc --- .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32p4/include/soc/soc_caps.h | 1 + .../diagrams/mmu/cache_align_issue.png | Bin 0 -> 40154 bytes docs/conf_common.py | 4 + docs/doxygen/Doxyfile | 1 + docs/en/api-reference/system/index.rst | 1 + docs/en/api-reference/system/mm.rst | 11 +- docs/en/api-reference/system/mm_sync.rst | 146 ++++++++++++++++++ docs/zh_CN/api-reference/system/index.rst | 1 + docs/zh_CN/api-reference/system/mm_sync.rst | 1 + 10 files changed, 160 insertions(+), 10 deletions(-) create mode 100644 docs/_static/diagrams/mmu/cache_align_issue.png create mode 100644 docs/en/api-reference/system/mm_sync.rst create mode 100644 docs/zh_CN/api-reference/system/mm_sync.rst diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 6e71422bd9..f46468c557 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -115,6 +115,10 @@ config SOC_SPIRAM_SUPPORTED bool default y +config SOC_PSRAM_DMA_CAPABLE + bool + default y + config SOC_XTAL_SUPPORT_40M bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 2e97a113fc..04d5dba19e 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -74,6 +74,7 @@ #define SOC_LP_GPIO_MATRIX_SUPPORTED 1 #define SOC_LP_PERIPHERALS_SUPPORTED 1 #define SOC_SPIRAM_SUPPORTED 1 +#define SOC_PSRAM_DMA_CAPABLE 1 // #define SOC_ULP_SUPPORTED 1 //TODO: IDF-7534 // #define SOC_SDMMC_HOST_SUPPORTED 1 //TODO: IDF-6502 // #define SOC_CLK_TREE_SUPPORTED 1 //TODO: IDF-7526 diff --git a/docs/_static/diagrams/mmu/cache_align_issue.png b/docs/_static/diagrams/mmu/cache_align_issue.png new file mode 100644 index 0000000000000000000000000000000000000000..8b3c8f1430caccf0e05b303a7214f4f67579f60b GIT binary patch literal 40154 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

*Mx*dwVOMZVFY|4Q*YRl@ZZC?$8>&d=#)}y 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 for more details. Thread Safety @@ -174,9 +171,3 @@ API Reference - ESP MMAP Driver ------------------------------- .. include-build-file:: inc/esp_mmu_map.inc - - -API Reference - ESP MSYNC Driver --------------------------------- - -.. include-build-file:: inc/esp_cache.inc diff --git a/docs/en/api-reference/system/mm_sync.rst b/docs/en/api-reference/system/mm_sync.rst new file mode 100644 index 0000000000..6aa0ec3819 --- /dev/null +++ b/docs/en/api-reference/system/mm_sync.rst @@ -0,0 +1,146 @@ +Memory Synchronization +********************** + +.. toctree:: + :maxdepth: 1 + + +Introduction +============ + +.. only:: SOC_PSRAM_DMA_CAPABLE + + {IDF_TARGET_NAME} can access its connected PSRAM via these ways: + + - CPU + - DMA + +.. only:: SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + + {IDF_TARGET_NAME} can access its internal memory via these ways: + + - CPU + - DMA + +By default, CPU accesses the above mentioned memory via cache. Whereas DMA accesses the memory directly, without going through cache. + +This leads to potential cache data coherence issue: + +- When a DMA transaction changes the content of a piece of memory, and the content has been cached already. Under this condition: + + - CPU may read stale data. + - the stale data in the cache may be written back to the memory. The new data updated by the previous DMA transaction will be overwritten. + +- CPU changes the content of an address. The content is in the cache, but not in the memory yet (cache will write back the content to the memory according to its own strategy). Under this condition: + + - The next DMA transactions to read this content from the memory will get stale data. + +There are three common methods to address such cache data coherence issue: + +.. list:: + + 1. Hardware based cache Coherent Interconnect, {IDF_TARGET_NAME} does not have such ability. + 2. Use the DMA buffer from non-cacheable memory. Memory that CPU access it without going through cache is called non-cacheable memory. + 3. Explicitly call a memory synchronization API to writeback the content in the cache back to the memory, or invalidate the content in the cache. + + +Memory Synchronisation Driver +============================= + +The suggested way to deal with such cache data coherence issue is by using the memory synchronization API :cpp:func:`esp_cache_msync` provided by ESP-IDF `esp_mm` component. + + +Driver Concept +-------------- + +Direction of the cache memory synchronization: + +- :c:macro:`ESP_CACHE_MSYNC_FLAG_DIR_C2M`, for synchronization from cache to memory. +- :c:macro:`ESP_CACHE_MSYNC_FLAG_DIR_M2C`, for synchronization from memory to cache. + +Type of the cache memory synchronization: + +- :c:macro:`ESP_CACHE_MSYNC_FLAG_TYPE_DATA`, for synchronization to a data address region. +- :c:macro:`ESP_CACHE_MSYNC_FLAG_TYPE_INST`, for synchronization to an instruction address region. + + +Driver Behaviour +---------------- + +Calling :cpp:func:`esp_cache_msync` will do a synchronization between cache and memory. The first parameter `addr` and the second parameter `size` together describe the memory region that is to be synchronized. About the third parameter `flags`: + +.. list:: + + - :c:macro:`ESP_CACHE_MSYNC_FLAG_DIR_C2M`. With this flag, content in the specified address region is written back to the memory. This direction is usually used **after** the content of an address is updated by the CPU, e.g. a memset to the address. Operation in this direction should happen **before** a DMA operation to the same address. + - :c:macro:`ESP_CACHE_MSYNC_FLAG_DIR_M2C`. With this flag, content in the specified address region is invalidated from the cache. This direction is usually used **after** the content of an address is updated by the DMA. Operation in this direction should happen **before** a CPU read operation to the same address. + +The above two flags help select the synchronization direction. Specially, if neither of these two flags are used, :cpp:func:`esp_cache_msync` will by default select the :c:macro:`ESP_CACHE_MSYNC_FLAG_DIR_C2M` direction. Users are not allowed to set both of the two flags at the same time. + +.. list:: + + - :c:macro:`ESP_CACHE_MSYNC_FLAG_TYPE_DATA`. + - :c:macro:`ESP_CACHE_MSYNC_FLAG_TYPE_INST`. + +The above two flags help select the type of the synchronization address. Specially, if neither of these two flags are used, :cpp:func:`esp_cache_msync` will by default select the :c:macro:`ESP_CACHE_MSYNC_FLAG_TYPE_DATA` direction. Users are not allowed to set both of the two flags at the same time. + + +.. list:: + + - :c:macro:`ESP_CACHE_MSYNC_FLAG_INVALIDATE`. This flag is used to trigger a cache invalidation to the specified address region, after the region is written back to the memory. This flag is mainly used for :c:macro:`ESP_CACHE_MSYNC_FLAG_DIR_C2M` direction. For :c:macro:`ESP_CACHE_MSYNC_FLAG_DIR_M2C` direction, behaviour is the same as if the :c:macro:`ESP_CACHE_MSYNC_FLAG_INVALIDATE` flag is not set. + - :c:macro:`ESP_CACHE_MSYNC_FLAG_UNALIGNED`. This flag force the :cpp:func:`esp_cache_msync` API to do synchronization without checking the address and size alignment. For more details, see chapter `Address Alignment Requirement` following. + + +Address Alignment Requirement +============================= + +There is address and size alignment requirement (in bytes) for using :cpp:func:`esp_cache_msync`. The alignment requirement comes from cache. + +- An address region whose start address and size both meet the cache memory synchronization alignment requirement is defined as an **aligned address region**. +- An address region whose start address or size does not meet the cache memory synchronization alignment requirement is defined as an **unaligned address region**. + +By default, if you specify an unaligned address region, :cpp:func:`esp_cache_msync` will return an :c:macro:`ESP_ERR_INVALID_ARG` error, together with the required alignment. + + +Memory Allocation Helper +------------------------ + +cache memory synchronization is usually considered when DMA is involved. ESP-IDF provides an API to do memory allocation that can meet the alignment requirement from both the cache and the DMA. + +- :cpp:func:`esp_dma_malloc`, this API allocates a chunk of memory that meets the alignment requirement from both the cache and the DMA. +- :cpp:func:`esp_dma_calloc`, this API allocates a chunk of memory that meets the alignment requirement from both the cache and the DMA. The initialized value in the memory is set to zero. + +You can also use :c:macro:`ESP_DMA_MALLOC_FLAG_PSRAM` to allocate from the PSRAM. + + +Warning for Address Alignment Requirement +----------------------------------------- + +You can set the :c:macro:`ESP_CACHE_MSYNC_FLAG_UNALIGNED` flag to bypass such check. Note you should be very careful about using this flag. cache memory synchronization to an unaligned address region may silently corrupt the memory. + +For example, assume: + +- alignment requirement is 0x40 bytes. +- a call to :cpp:func:`esp_cache_msync`, with `ESP_CACHE_MSYNC_FLAG_DIR_M2C | ESP_CACHE_MSYNC_FLAG_UNALIGNED` flags, the specified address region is 0x4000_0020 ~ 0x4000_0060 (see **data C** in below graph). + +Above settings will trigger a cache invalidation to the address region 0x4000_0000 ~ 0x4000_0080, see **sync item0** and **sync item1** in the below graph. + +If the content in 0x4000_0000 ~ 0x4000_0020 (**data A** in the below graph) or 0x4000_0060 ~ 0x4000_0080 (**data B** in the below graph) are not written back to the memory yet, then these **data A** and **data B** will be discarded. + +.. image:: /../_static/diagrams/mmu/cache_align_issue.png + :scale: 80 % + :align: center + + +API Reference +============= + +API Reference - ESP Msync Driver +-------------------------------- + +.. include-build-file:: inc/esp_cache.inc + + +API Reference - ESP DMA Utils +----------------------------- + +.. include-build-file:: inc/esp_dma_utils.inc diff --git a/docs/zh_CN/api-reference/system/index.rst b/docs/zh_CN/api-reference/system/index.rst index 6d0216bf22..e617a7a9c7 100644 --- a/docs/zh_CN/api-reference/system/index.rst +++ b/docs/zh_CN/api-reference/system/index.rst @@ -21,6 +21,7 @@ System API freertos_additions mem_alloc mm + :SOC_PSRAM_DMA_CAPABLE or SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE: mm_sync heap_debug esp_timer internal-unstable diff --git a/docs/zh_CN/api-reference/system/mm_sync.rst b/docs/zh_CN/api-reference/system/mm_sync.rst new file mode 100644 index 0000000000..9527c4df23 --- /dev/null +++ b/docs/zh_CN/api-reference/system/mm_sync.rst @@ -0,0 +1 @@ +.. include:: ../../../en/api-reference/system/mm_sync.rst