driver_interface/timer/
mod.rs

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
use core::{
    sync::atomic::{Ordering, fence},
    time::Duration,
};

use crate::{DriverGeneric, interrupt_controller::IrqConfig};
use alloc::boxed::Box;

mod queue;

pub type Hardware = Box<dyn Interface>;
pub type OnProbeFdt = fn(&[IrqConfig]) -> Hardware;
pub type HardwareCPU = Box<dyn InterfaceCPU>;
const NANO_PER_SEC: u128 = 1_000_000_000;

pub trait Interface: Send {
    fn get_current_cpu(&mut self) -> Box<dyn InterfaceCPU>;
}

pub trait InterfaceCPU: DriverGeneric + Sync {
    fn set_timeval(&mut self, ticks: u64);
    fn current_ticks(&self) -> u64;
    fn tick_hz(&self) -> u64;
    fn set_irq_enable(&mut self, enable: bool);
    fn get_irq_status(&self) -> bool;
    fn irq(&self) -> IrqConfig;
}

pub struct Timer {
    timer: HardwareCPU,
    q: queue::Queue,
}

unsafe impl Sync for Timer {}

impl Timer {
    pub fn new(timer: HardwareCPU) -> Self {
        Self {
            timer,
            q: queue::Queue::new(),
        }
    }

    pub fn enable(&mut self) {
        let _ = self.timer.open();
    }

    pub fn since_boot(&self) -> Duration {
        self.tick_to_duration(self.timer.current_ticks())
    }

    pub fn after(&mut self, duration: Duration, callback: impl Fn() + 'static) {
        let ticks = self.duration_to_tick(duration);

        let event = queue::Event {
            interval: None,
            at_tick: self.timer.current_ticks() + ticks,
            callback: Box::new(callback),
            called: false,
        };

        self.add_event(event);
    }

    pub fn every(&mut self, duration: Duration, callback: impl Fn() + 'static) {
        let ticks = self.duration_to_tick(duration);

        let event = queue::Event {
            interval: Some(ticks),
            at_tick: self.timer.current_ticks() + ticks,
            callback: Box::new(callback),
            called: false,
        };

        self.add_event(event);
    }

    fn add_event(&mut self, event: queue::Event) {
        self.timer.set_irq_enable(false);
        fence(Ordering::SeqCst);

        let next_tick = self.q.add_and_next_tick(event);
        let v = next_tick - self.timer.current_ticks();
        self.timer.set_timeval(v);

        fence(Ordering::SeqCst);
        self.timer.set_irq_enable(true);
    }

    pub fn handle_irq(&mut self) {
        while let Some(event) = self.q.pop(self.timer.current_ticks()) {
            (event.callback)();
        }

        match self.q.next_tick() {
            Some(next_tick) => {
                self.timer.set_timeval(next_tick);
            }
            None => {
                self.timer.set_irq_enable(false);
            }
        }
    }

    pub fn set_irq_enable(&mut self, enable: bool) {
        self.timer.set_irq_enable(enable);
    }

    fn tick_to_duration(&self, tick: u64) -> Duration {
        Duration::from_nanos((tick as u128 * NANO_PER_SEC / self.timer.tick_hz() as u128) as _)
    }

    fn duration_to_tick(&self, duration: Duration) -> u64 {
        (duration.as_nanos() * self.timer.tick_hz() as u128 / NANO_PER_SEC) as _
    }

    pub fn irq(&self) -> IrqConfig {
        self.timer.irq()
    }
}