Skip to main content

strat9_bus_drivers/
probe.rs

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