1use crate::mmio::{MmioRegion, memory_barrier};
2use alloc::vec;
3
4const REGION_SIZE: usize = 4096;
5const REGION_WORDS: usize = REGION_SIZE / core::mem::size_of::<u64>();
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8pub enum ProbeMode {
9 Quick,
10 Full,
11}
12
13pub struct ProbeResult {
14 pub passed: u32,
15 pub failed: u32,
16}
17
18impl ProbeResult {
19 fn new() -> Self {
21 Self {
22 passed: 0,
23 failed: 0,
24 }
25 }
26
27 fn check(&mut self, ok: bool) {
29 if ok {
30 self.passed += 1;
31 } else {
32 self.failed += 1;
33 }
34 }
35
36 pub fn all_passed(&self) -> bool {
38 self.failed == 0 && self.passed > 0
39 }
40}
41
42fn zero_buf(buf: &mut [u64]) {
44 buf.fill(0);
45}
46
47pub fn run_mmio_self_test() -> ProbeResult {
53 run_mmio_self_test_with_mode(ProbeMode::Full)
54}
55
56pub fn run_mmio_self_test_with_mode(mode: ProbeMode) -> ProbeResult {
58 let mut r = ProbeResult::new();
59 let mut buf = vec![0u64; REGION_WORDS];
60 let base = buf.as_mut_ptr() as usize;
61
62 match mode {
63 ProbeMode::Quick => {
64 probe_lifecycle(&mut r, base);
65 zero_buf(&mut buf);
66 probe_read_write_32(&mut r, base);
67 zero_buf(&mut buf);
68 probe_boundary_offsets(&mut r, base);
69 zero_buf(&mut buf);
70 probe_memory_barrier(&mut r, base);
71 }
72 ProbeMode::Full => {
73 probe_lifecycle(&mut r, base);
74 zero_buf(&mut buf);
75 probe_read_write_8(&mut r, base);
76 zero_buf(&mut buf);
77 probe_read_write_16(&mut r, base);
78 zero_buf(&mut buf);
79 probe_read_write_32(&mut r, base);
80 zero_buf(&mut buf);
81 probe_read_write_64(&mut r, base);
82 zero_buf(&mut buf);
83 probe_set_bits(&mut r, base);
84 zero_buf(&mut buf);
85 probe_clear_bits(&mut r, base);
86 zero_buf(&mut buf);
87 probe_modify32(&mut r, base);
88 zero_buf(&mut buf);
89 probe_read_field32(&mut r, base);
90 zero_buf(&mut buf);
91 probe_write_field32(&mut r, base);
92 zero_buf(&mut buf);
93 probe_boundary_offsets(&mut r, base);
94 zero_buf(&mut buf);
95 probe_multi_width_overlap(&mut r, base);
96 zero_buf(&mut buf);
97 probe_walking_ones_32(&mut r, base);
98 zero_buf(&mut buf);
99 probe_walking_ones_64(&mut r, base);
100 zero_buf(&mut buf);
101 probe_memory_barrier(&mut r, base);
102 zero_buf(&mut buf);
103 probe_reinit(&mut r, base);
104 }
105 }
106
107 r
108}
109
110fn make_region(base: usize) -> MmioRegion {
112 let mut reg = MmioRegion::new();
113 reg.init(base, REGION_SIZE);
114 reg
115}
116
117fn probe_lifecycle(r: &mut ProbeResult, base: usize) {
119 let uninit = MmioRegion::new();
120 r.check(!uninit.is_valid());
121 r.check(uninit.base() == 0);
122
123 let reg = make_region(base);
124 r.check(reg.is_valid());
125 r.check(reg.base() == base);
126}
127
128fn probe_read_write_8(r: &mut ProbeResult, base: usize) {
130 let reg = make_region(base);
131
132 reg.write8(0, 0xAB);
133 r.check(reg.read8(0) == 0xAB);
134
135 reg.write8(1, 0x00);
136 r.check(reg.read8(1) == 0x00);
137
138 reg.write8(2, 0xFF);
139 r.check(reg.read8(2) == 0xFF);
140
141 reg.write8(0, 0x12);
142 r.check(reg.read8(0) == 0x12);
143 r.check(reg.read8(2) == 0xFF);
144
145 for i in 0..16u8 {
146 reg.write8(i as usize, i.wrapping_mul(17));
147 }
148 for i in 0..16u8 {
149 r.check(reg.read8(i as usize) == i.wrapping_mul(17));
150 }
151}
152
153fn probe_read_write_16(r: &mut ProbeResult, base: usize) {
155 let reg = make_region(base);
156
157 reg.write16(0, 0xBEEF);
158 r.check(reg.read16(0) == 0xBEEF);
159
160 reg.write16(2, 0x0000);
161 r.check(reg.read16(2) == 0x0000);
162
163 reg.write16(4, 0xFFFF);
164 r.check(reg.read16(4) == 0xFFFF);
165
166 r.check(reg.read16(0) == 0xBEEF);
167
168 reg.write16(0, 0x1234);
169 reg.write16(2, 0x5678);
170 let combined = reg.read32(0);
171 let expected = 0x1234u32 | (0x5678u32 << 16);
172 r.check(combined == expected);
173}
174
175fn probe_read_write_32(r: &mut ProbeResult, base: usize) {
177 let reg = make_region(base);
178
179 reg.write32(0, 0xDEADBEEF);
180 r.check(reg.read32(0) == 0xDEADBEEF);
181
182 reg.write32(4, 0x00000000);
183 r.check(reg.read32(4) == 0x00000000);
184
185 reg.write32(8, 0xFFFFFFFF);
186 r.check(reg.read32(8) == 0xFFFFFFFF);
187
188 r.check(reg.read32(0) == 0xDEADBEEF);
189
190 reg.write32(0, 0x01020304);
191 r.check(reg.read8(0) == 0x04);
192 r.check(reg.read8(1) == 0x03);
193 r.check(reg.read8(2) == 0x02);
194 r.check(reg.read8(3) == 0x01);
195
196 for i in 0..32u32 {
197 let off = (i as usize) * 4;
198 if off + 4 > REGION_SIZE {
199 break;
200 }
201 reg.write32(off, i.wrapping_mul(0x11111111));
202 }
203 for i in 0..32u32 {
204 let off = (i as usize) * 4;
205 if off + 4 > REGION_SIZE {
206 break;
207 }
208 r.check(reg.read32(off) == i.wrapping_mul(0x11111111));
209 }
210}
211
212fn probe_read_write_64(r: &mut ProbeResult, base: usize) {
214 let reg = make_region(base);
215
216 reg.write64(0, 0xCAFEBABE_DEADBEEF);
217 r.check(reg.read64(0) == 0xCAFEBABE_DEADBEEF);
218
219 reg.write64(8, 0x0000000000000000);
220 r.check(reg.read64(8) == 0x0000000000000000);
221
222 reg.write64(16, 0xFFFFFFFFFFFFFFFF);
223 r.check(reg.read64(16) == 0xFFFFFFFFFFFFFFFF);
224
225 r.check(reg.read64(0) == 0xCAFEBABE_DEADBEEF);
226
227 r.check(reg.read32(0) == 0xDEADBEEF);
228 r.check(reg.read32(4) == 0xCAFEBABE);
229}
230
231fn probe_set_bits(r: &mut ProbeResult, base: usize) {
233 let reg = make_region(base);
234
235 reg.write32(0, 0x00000000);
236 reg.set_bits32(0, 0x0000000F);
237 r.check(reg.read32(0) == 0x0000000F);
238
239 reg.set_bits32(0, 0x000000F0);
240 r.check(reg.read32(0) == 0x000000FF);
241
242 reg.set_bits32(0, 0x000000FF);
243 r.check(reg.read32(0) == 0x000000FF);
244
245 reg.write32(0, 0x80000000);
246 reg.set_bits32(0, 0x00000001);
247 r.check(reg.read32(0) == 0x80000001);
248}
249
250fn probe_clear_bits(r: &mut ProbeResult, base: usize) {
252 let reg = make_region(base);
253
254 reg.write32(0, 0xFFFFFFFF);
255 reg.clear_bits32(0, 0x0000000F);
256 r.check(reg.read32(0) == 0xFFFFFFF0);
257
258 reg.clear_bits32(0, 0x000000F0);
259 r.check(reg.read32(0) == 0xFFFFFF00);
260
261 reg.clear_bits32(0, 0x00000000);
262 r.check(reg.read32(0) == 0xFFFFFF00);
263
264 reg.write32(0, 0x80000001);
265 reg.clear_bits32(0, 0x80000000);
266 r.check(reg.read32(0) == 0x00000001);
267}
268
269fn probe_modify32(r: &mut ProbeResult, base: usize) {
271 let reg = make_region(base);
272
273 reg.write32(0, 0xAABBCCDD);
274 reg.modify32(0, 0x0000FF00, 0x00001200);
275 r.check(reg.read32(0) == 0xAABB12DD);
276
277 reg.write32(0, 0xFFFFFFFF);
278 reg.modify32(0, 0xFFFFFFFF, 0x12345678);
279 r.check(reg.read32(0) == 0x12345678);
280
281 reg.write32(0, 0x00000000);
282 reg.modify32(0, 0x00000000, 0x00000000);
283 r.check(reg.read32(0) == 0x00000000);
284
285 reg.write32(0, 0x00FF00FF);
286 reg.modify32(0, 0x00FF0000, 0x00AB0000);
287 r.check(reg.read32(0) == 0x00AB00FF);
288}
289
290fn probe_read_field32(r: &mut ProbeResult, base: usize) {
292 let reg = make_region(base);
293
294 reg.write32(0, 0x12345678);
295
296 r.check(reg.read_field32(0, 0x000000FF, 0) == 0x78);
297 r.check(reg.read_field32(0, 0x0000FF00, 8) == 0x56);
298 r.check(reg.read_field32(0, 0x00FF0000, 16) == 0x34);
299 r.check(reg.read_field32(0, 0xFF000000, 24) == 0x12);
300
301 r.check(reg.read_field32(0, 0x0000000F, 0) == 0x08);
302 r.check(reg.read_field32(0, 0x000F0000, 16) == 0x04);
303
304 reg.write32(0, 0x00000000);
305 r.check(reg.read_field32(0, 0xFFFFFFFF, 0) == 0x00000000);
306
307 reg.write32(0, 0xFFFFFFFF);
308 r.check(reg.read_field32(0, 0xFFFFFFFF, 0) == 0xFFFFFFFF);
309}
310
311fn probe_write_field32(r: &mut ProbeResult, base: usize) {
313 let reg = make_region(base);
314
315 reg.write32(0, 0x00000000);
316 reg.write_field32(0, 0x000000FF, 0, 0xAB);
317 r.check(reg.read32(0) == 0x000000AB);
318
319 reg.write32(0, 0xFFFFFFFF);
320 reg.write_field32(0, 0x0000FF00, 8, 0x42);
321 r.check(reg.read32(0) == 0xFFFF42FF);
322
323 reg.write32(0, 0x12345678);
324 reg.write_field32(0, 0xFF000000, 24, 0x99);
325 r.check(reg.read32(0) == 0x99345678);
326
327 reg.write32(0, 0xAAAAAAAA);
328 reg.write_field32(0, 0x000F0000, 16, 0x05);
329 let val = reg.read32(0);
330 r.check((val & 0x000F0000) >> 16 == 0x05);
331 r.check((val & 0xFFF0FFFF) == 0xAAA0AAAA);
332}
333
334fn probe_boundary_offsets(r: &mut ProbeResult, base: usize) {
336 let reg = make_region(base);
337
338 reg.write8(0, 0x01);
339 r.check(reg.read8(0) == 0x01);
340
341 reg.write8(REGION_SIZE - 1, 0xFE);
342 r.check(reg.read8(REGION_SIZE - 1) == 0xFE);
343
344 reg.write16(REGION_SIZE - 2, 0xABCD);
345 r.check(reg.read16(REGION_SIZE - 2) == 0xABCD);
346
347 reg.write32(REGION_SIZE - 4, 0xDEADC0DE);
348 r.check(reg.read32(REGION_SIZE - 4) == 0xDEADC0DE);
349
350 reg.write64(REGION_SIZE - 8, 0x0102030405060708);
351 r.check(reg.read64(REGION_SIZE - 8) == 0x0102030405060708);
352}
353
354fn probe_multi_width_overlap(r: &mut ProbeResult, base: usize) {
356 let reg = make_region(base);
357
358 reg.write64(0, 0);
359 reg.write8(0, 0x11);
360 reg.write8(1, 0x22);
361 reg.write8(2, 0x33);
362 reg.write8(3, 0x44);
363 reg.write8(4, 0x55);
364 reg.write8(5, 0x66);
365 reg.write8(6, 0x77);
366 reg.write8(7, 0x88);
367 r.check(reg.read16(0) == 0x2211);
368 r.check(reg.read16(2) == 0x4433);
369 r.check(reg.read32(0) == 0x44332211);
370 r.check(reg.read32(4) == 0x88776655);
371 r.check(reg.read64(0) == 0x8877665544332211);
372
373 reg.write32(0, 0xAABBCCDD);
374 r.check(reg.read8(0) == 0xDD);
375 r.check(reg.read8(1) == 0xCC);
376 r.check(reg.read8(2) == 0xBB);
377 r.check(reg.read8(3) == 0xAA);
378 r.check(reg.read16(0) == 0xCCDD);
379 r.check(reg.read16(2) == 0xAABB);
380}
381
382fn probe_walking_ones_32(r: &mut ProbeResult, base: usize) {
384 let reg = make_region(base);
385
386 for bit in 0..32u32 {
387 let val = 1u32 << bit;
388 reg.write32(0, val);
389 r.check(reg.read32(0) == val);
390 }
391
392 reg.write32(0, 0);
393 for bit in 0..32u32 {
394 reg.set_bits32(0, 1u32 << bit);
395 }
396 r.check(reg.read32(0) == 0xFFFFFFFF);
397
398 for bit in 0..32u32 {
399 reg.clear_bits32(0, 1u32 << bit);
400 }
401 r.check(reg.read32(0) == 0x00000000);
402}
403
404fn probe_walking_ones_64(r: &mut ProbeResult, base: usize) {
406 let reg = make_region(base);
407
408 for bit in 0..64u32 {
409 let val = 1u64 << bit;
410 reg.write64(0, val);
411 r.check(reg.read64(0) == val);
412 }
413
414 reg.write64(0, 0xAAAAAAAAAAAAAAAA);
415 r.check(reg.read64(0) == 0xAAAAAAAAAAAAAAAA);
416
417 reg.write64(0, 0x5555555555555555);
418 r.check(reg.read64(0) == 0x5555555555555555);
419}
420
421fn probe_memory_barrier(r: &mut ProbeResult, base: usize) {
423 let reg = make_region(base);
424
425 reg.write32(0, 0x11111111);
426 memory_barrier();
427 r.check(reg.read32(0) == 0x11111111);
428
429 reg.write32(0, 0x22222222);
430 memory_barrier();
431 reg.write32(4, 0x33333333);
432 memory_barrier();
433 r.check(reg.read32(0) == 0x22222222);
434 r.check(reg.read32(4) == 0x33333333);
435
436 for i in 0..16u32 {
437 reg.write32((i as usize) * 4, i);
438 memory_barrier();
439 }
440 for i in 0..16u32 {
441 r.check(reg.read32((i as usize) * 4) == i);
442 }
443}
444
445fn probe_reinit(r: &mut ProbeResult, base: usize) {
447 let mut reg = MmioRegion::new();
448 r.check(!reg.is_valid());
449
450 reg.init(base, REGION_SIZE);
451 r.check(reg.is_valid());
452 r.check(reg.base() == base);
453 reg.write32(0, 0xABCD1234);
454 r.check(reg.read32(0) == 0xABCD1234);
455
456 let mut buf2 = vec![0u64; REGION_WORDS];
457 let base2 = buf2.as_mut_ptr() as usize;
458 reg.init(base2, REGION_SIZE);
459 r.check(reg.is_valid());
460 r.check(reg.base() == base2);
461 r.check(reg.base() != base);
462 r.check(reg.read32(0) == 0x00000000);
463
464 reg.write32(0, 0x99887766);
465 r.check(reg.read32(0) == 0x99887766);
466}