1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! Internal D-cache maintenance for the DMA-driven drivers.
//!
//! The mailbox, SD, touch, and USB paths hand buffers to bus masters
//! (the VideoCore, the EMMC controller, the DWC2 USB core) that read and
//! write RAM directly, bypassing this core's data cache. Before telling
//! one of them to read an ARM-written buffer, [`clean_range`] writes the
//! covering lines back to RAM; before reading a buffer one of them wrote,
//! [`invalidate_range`] drops the stale cached copies so the read comes
//! from RAM. Each ends with a barrier so the maintenance has completed
//! before the DMA is kicked off or the data is read.
//!
//! Consolidated here (rather than a private copy per driver) so the one
//! architecture-specific piece — the cache-maintenance instructions —
//! lives in a single place.
use asm;
/// Conservative minimum D-cache line size, in bytes.
///
/// The true line size is discoverable at runtime (the `CTR` register's
/// `DminLine` field), but walking a buffer in strides this small is
/// always safe: on hardware with a bigger line (this SoC's Cortex-A7 and
/// Cortex-A53 both use 64 bytes) a clean/invalidate-by-address op affects
/// the whole line containing the address, so a smaller stride just
/// touches each line more than once — harmless — where a stride larger
/// than the true line size could skip one.
pub const MIN_CACHE_LINE: u32 = 32;
/// Cleans (writes back, without invalidating) every cache line covering
/// `len` bytes from `address`, then barriers — makes an ARM-side write
/// actually visible in RAM before a bus master is told to read it.
pub
/// Invalidates every cache line covering `len` bytes from `address`, then
/// barriers — forces the next ARM-side read to come from RAM instead of
/// whatever this core cached before a bus master wrote its response
/// there.
pub
// The per-line ops and the barrier are the only architecture-specific
// part. AArch32 uses CP15 cache-maintenance coprocessor writes (DCCMVAC
// to clean, DCIMVAC to invalidate) and a bare `dsb`; AArch64 uses the
// `dc cvac` / `dc ivac` cache-maintenance instructions and `dsb sy`. Both
// operate to the point of coherency — the level shared with the bus
// masters. On AArch64 the `{0:x}` operand selects the 64-bit view of the
// (zero-extended, always < 4 GB on this SoC) address, since `dc` takes an
// X register.
/// Cleans the single cache line containing `line` to the point of
/// coherency.
unsafe
/// Cleans the single cache line containing `line` to the point of
/// coherency.
unsafe
/// Invalidates the single cache line containing `line` to the point of
/// coherency.
unsafe
/// Invalidates the single cache line containing `line` to the point of
/// coherency.
unsafe
/// Data synchronization barrier over the full system domain — completes
/// the cache maintenance above before the caller kicks off DMA.
/// Data synchronization barrier over the full system domain — completes
/// the cache maintenance above before the caller kicks off DMA.
compile_error!;