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
//! 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 cratedsb;
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 are the only architecture-specific part left here;
// the trailing barrier comes from `crate::barrier`, which has its own
// three-way split. AArch32 uses CP15 cache-maintenance coprocessor
// writes (DCCMVAC to clean, DCIMVAC to invalidate, DCCIMVAC for both),
// with the same encodings on ARMv6 and ARMv7 — maintenance *by MVA* did
// not change, unlike the barriers; AArch64 uses the `dc cvac` /
// `dc ivac` / `dc civac` cache-maintenance instructions. 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
compile_error!;