Add Doxygen pages for RT-Thread device-model drivers: platform/OFW, DM core (bus, dm, power), clk/regulator/reset/power-domain, PCI/PIC, Phye, DMA/hwcache, block/SCSI/ATA/NVMe/UFS/SDIO, SCMI, RPMsg, mailbox, NVMem, NUMA, syscon, thermal, input/LED/IIO/graphic, and related power/charger/supply docs. Expand device-driver INDEX.md with ~90 @subpage entries so all new pages appear in the driver chapter navigation. Update existing UART/SPI/RTC/pin/framework/dtc pages: UART docs moved from serial/ to uart/ (uart + uart_dm + uart_earlycon); SPI and RTC gain DM companion pages; pin links to pin_dm; framework points at DM topics. Focus on registration/probe flow and in-tree APIs; no standalone VirtIO subsystem page (transport code still incomplete). Test plan: build Doxygen for documentation/ and verify device-driver INDEX links resolve without missing @ref/@subpage warnings. Signed-off-by: GuEe-GUI <2991707448@qq.com>
8.9 KiB
@page page_device_hwcache Hardware cache (hwcache)
CPU cache maintenance (hwcache)
On RT-Thread, CPU D-cache / I-cache maintenance for DMA coherence, MMU table updates, and dynamic code loading is done through architecture code in libcpu and, when RT_USING_HWCACHE is enabled, the DM helper module components/drivers/hwcache/.
Most drivers in the tree call the BSP APIs in include/rthw.h (rt_hw_cpu_dcache_ops, rt_hw_cpu_icache_ops). The rt_hwcache_* functions in drivers/hwcache.h are a thin DM layer that forwards to struct rt_hwcache_ops pointers filled from device tree stubs or SoC code.
Documentation path: hwcache/hwcache.md (not cache/ — the subsystem name is hwcache).
Kconfig
| Option | Role |
|---|---|
RT_USING_CACHE |
Enables rthw.h cache APIs (required for real flush/invalidate) |
RT_USING_HWCACHE |
Builds components/drivers/hwcache/hwcache.c; depends on RT_USING_DM and RT_USING_CACHE |
SOC_DM_HWCACHE_DIR |
BSP may add extra Kconfig under SoC DM hwcache drivers |
If RT_USING_CACHE is off, rthw.h defines rt_hw_cpu_*_ops as empty macros — maintenance becomes no-ops.
Two API layers (do not mix up)
Application / NVMe / SDIO / DMA pool / …
│
▼
rt_hw_cpu_dcache_ops() / rt_hw_cpu_icache_ops() ← include/rthw.h (usual)
│
▼
libcpu/*/cache.c (per architecture)
Optional parallel path when RT_USING_HWCACHE:
│
▼
rt_hwcache_dcache_ops() / rt_hwcache_icache_ops() ← drivers/hwcache.h
│
▼
rt_dm_cpu_dcache_ops / rt_dm_cpu_icache_ops
│
▼
struct rt_hwcache_ops (flush/invalidate from OFW stub or SoC init)
| Layer | Header | Typical caller |
|---|---|---|
| Architecture (primary) | rthw.h |
nvme, sdio, ahci, ufs, dma_pool, USB glue, lwp, dlmodule |
| DM hwcache | drivers/hwcache.h |
Code that explicitly uses rt_hwcache_* or SoC RT_HWCACHE_OFW_DECLARE setup |
Unless your BSP connects rt_dm_cpu_dcache_ops to the same implementation as rt_hw_cpu_dcache_ops, calling only one layer may be insufficient. Driver authors: use rt_hw_cpu_dcache_ops unless the BSP documents rt_hwcache_* as the canonical path.
Architecture API (rthw.h)
Enabled when RT_USING_CACHE is set.
Opcodes
enum RT_HW_CACHE_OPS {
RT_HW_CACHE_FLUSH = 0x01, /* clean / write-back to RAM */
RT_HW_CACHE_INVALIDATE = 0x02, /* discard cached copy, refetch from RAM */
};
RT_CPU_CACHE_LINE_SZ (default 32) is the usual alignment hint for maintenance ranges.
D-cache
| Function | Role |
|---|---|
rt_hw_cpu_dcache_enable() |
Enable D-cache |
rt_hw_cpu_dcache_disable() |
Disable D-cache |
rt_hw_cpu_dcache_status() |
Non-zero if enabled |
rt_hw_cpu_dcache_ops(ops, addr, size) |
Flush or invalidate [addr, addr+size) |
I-cache
| Function | Role |
|---|---|
rt_hw_cpu_icache_enable() |
Enable I-cache |
rt_hw_cpu_icache_disable() |
Disable I-cache |
rt_hw_cpu_icache_status() |
Non-zero if enabled |
rt_hw_cpu_icache_ops(ops, addr, size) |
Typically invalidate after loading code |
Example (DMA TX buffer)
/* CPU filled buffer; device DMA will read RAM */
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, buf, len);
/* After device DMA wrote RAM; CPU will read buffer */
rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, buf, len);
DM hwcache API (drivers/hwcache.h)
Implementation: components/drivers/hwcache/hwcache.c.
struct rt_hwcache_ops
| Callback | Role |
|---|---|
enable / disable |
Turn cache on/off |
status |
Query enabled state |
flush(vaddr, size) |
Clean D-cache (or unified) for region |
invalidate(vaddr, size) |
Invalidate region |
Global pointers (set by platform init or OFW stub):
rt_dm_cpu_dcache_opsrt_dm_cpu_icache_ops
rt_hwcache_* wrappers
| Function | Maps to |
|---|---|
rt_hwcache_dcache_enable/disable/status |
rt_dm_cpu_dcache_ops |
rt_hwcache_dcache_ops(op, addr, size) |
flush if op == RT_HW_CACHE_FLUSH, invalidate if RT_HW_CACHE_INVALIDATE |
rt_hwcache_icache_* |
Same for rt_dm_cpu_icache_ops |
If the corresponding rt_dm_cpu_*_ops is NULL, calls are no-ops (safe but ineffective).
Initialization
rt_err_t rt_hwcache_init(void);
With RT_USING_OFW, walks all DT nodes and runs rt_ofw_stub_probe_range for stubs in the hwcache linker range (RT_OFW_STUB_RANGE_EXPORT(hwcache, ...) in hwcache.c). Stub handlers typically assign rt_dm_cpu_dcache_ops / rt_dm_cpu_icache_ops.
OFW registration macro
RT_HWCACHE_OFW_DECLARE(name, ids, handler);
Expands to RT_OFW_STUB_EXPORT(name, ids, hwcache, handler). handler(struct rt_ofw_node *np, const struct rt_ofw_node_id *id) should install struct rt_hwcache_ops into the global pointers. See @ref page_device_ofw (stub sections).
SoC-specific drivers may live under SOC_DM_HWCACHE_DIR (per hwcache/Kconfig).
DMA and coherence
| Path | Cache maintenance |
|---|---|
dma-coherent DT property |
rt_dma_device_is_coherent — map ops may skip explicit flush (platform-dependent) |
Coherent DMA pool (dma_pool.c) |
sync_out: rt_hw_cpu_dcache_ops(FLUSH); sync_in: INVALIDATE |
| Non-coherent pool | Physical address only; CPU must still maintain if CPU touches the buffer |
Coordinate with @ref page_device_dma and @ref page_device_dma_pool — avoid double flush and invalidate-before-flush on dirty TX buffers.
Drivers that use cache maintenance (examples)
| Subsystem | File | Typical pattern |
|---|---|---|
| NVMe | nvme/nvme.c |
Flush PRP/list buffers before doorbell; invalidate after read |
| SDHCI / SDIO | sdio/dev_sdhci.c, sdio-dw.c |
Flush before TX DMA; invalidate after RX |
| AHCI | ata/ahci.c |
Flush/invalidate command tables and DMA buffers |
| UFS | ufs/ufs.c |
Flush UTRD/UCD before run; invalidate after completion |
| DMA PL330 | dma/dma-pl330.c |
Flush microcode buffer |
| USB | CherryUSB glue | Platform-specific flush/invalidate hooks |
| GICv3 ITS | pic/pic-gicv3-its.c |
Flush ITS command/ITT tables |
| DFS pcache | dfs_v2/dfs_pcache.c |
Flush + I-invalidate on mapped pages |
| Dynamic load | libc/dlmodule.c, lwp/ |
Flush data, invalidate I-cache for new code |
These use rt_hw_cpu_*_ops from rthw.h, not rt_hwcache_*, unless your port unifies them.
Use cases
- Non-coherent DMA — CPU writes → flush before device read; device writes → invalidate before CPU read.
- MMU / page tables — flush page table memory after CPU fills entries (see
libcpu/*/mmu.c). - Self-modifying / relocated code — flush D-cache if instructions were stored through D-cache, then invalidate I-cache.
- Framebuffer / uncached mapping — prefer correct MMU memory attributes (@ref page_device_graphic_framebuffer); use explicit ops only when mapping is cacheable.
Driver / BSP quick notes
| Topic | Guidance |
|---|---|
Prefer rt_hw_cpu_* |
Matches existing storage and DMA drivers in components/drivers |
| Range size | Cover full DMA buffer; align to cache line when port requires it |
| TX ordering | Flush before kicking device — never invalidate dirty lines first |
| RX ordering | Invalidate before CPU reads device-written RAM |
| Harvard cores | After loading code via data path: flush D + invalidate I |
rt_hwcache_init |
Call during early init if SoC uses RT_HWCACHE_OFW_DECLARE to publish ops |
| Performance | Scope maintenance to touched regions; do not flush entire RAM |
Pitfalls
rt_hwcache_*_disable()inhwcache.ccurrently invokesops->enableinhwcache_disable()(likely a bug). Preferrt_hw_cpu_dcache_disable()or fix SoC ops until upstream is corrected.- Double maintenance with
rt_dma_sync_*and manualrt_hw_cpu_dcache_opson the same buffer. RT_USING_CACHEoff — silent no-ops; DMA corruption on non-coherent SoCs.- Assuming
rt_hwcache_*runs on all boards — only effective afterrt_dm_cpu_*_opsare assigned. - I-cache only invalidate after external loaders without D-cache flush when stores went through D-cache.
See also
components/drivers/include/drivers/hwcache.hcomponents/drivers/hwcache/hwcache.cinclude/rthw.h—RT_HW_CACHE_*,rt_hw_cpu_dcache_ops- @ref page_device_dma
- @ref page_device_dma_pool
- @ref page_device_ofw — OFW stub mechanism