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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//! 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
/// Cleans *and* invalidates every cache line covering `len` bytes from
/// `address`, then barriers — writes back anything this core had dirty and
/// leaves nothing cached behind.
///
/// The one place this is needed rather than one of the two halves above is
/// when memory stops being cacheable at all: a region about to be remapped
/// Normal Non-cacheable (`crate::mmu::set_uncached`) must have no cached
/// copy left, dirty or clean. A plain invalidate would discard writes that
/// never reached RAM; a plain clean would leave clean lines that the new,
/// non-cacheable accesses bypass, so a later eviction could still hand back
/// pre-remap data.
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, DCCIMVAC for both) and a bare `dsb`;
// AArch64 uses the `dc cvac` / `dc ivac` / `dc civac` cache-maintenance
// instructions and `dsb sy`. All 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
/// Cleans and invalidates the single cache line containing `line` to the
/// point of coherency.
unsafe
/// Cleans and 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.
///
/// Also the ordering barrier for the VideoCore shared-memory protocols
/// (`crate::vchiq`), whose region is mapped non-cacheable rather than
/// maintained by hand: no maintenance is needed there, but plain
/// Normal-memory accesses can still be reordered and merged, so publishing
/// a structure before the flag that advertises it still needs this.
pub
/// Data synchronization barrier over the full system domain — completes
/// the cache maintenance above before the caller kicks off DMA. See the
/// AArch32 definition's doc comment for its second use.
pub
compile_error!;