sifive/
plic.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Platform Level Interrupt Control peripheral driver.
6
7use kernel::utilities::cells::VolatileCell;
8use kernel::utilities::registers::interfaces::{Readable, Writeable};
9use kernel::utilities::registers::LocalRegisterCopy;
10use kernel::utilities::registers::{register_bitfields, ReadOnly, ReadWrite};
11use kernel::utilities::StaticRef;
12
13/// Place the register map definition in a private module to disallow direct access to it's
14/// fields from the Plic struct implementation, which should only use a getter/setter with
15/// appropriate bounds set
16
17///    The generic SiFive PLIC specification:
18///    <https://github.com/riscv/riscv-plic-spec/blob/master/riscv-plic.adoc>
19///    is defining maximum of 1023 interrupt sources
20
21// TODO: replace with const generic for `priority` and `_reserved1` field
22// in the [PlicRegisters] when const generic expressions are stable
23const MAX_INTERRUPTS: usize = 1023;
24/// maximum number of bit-coded registers, 1 bit per interrupt
25const MAX_BIT_REGS: usize = MAX_INTERRUPTS.div_ceil(32);
26
27/// PLIC registers for *machine mode* context only at this time.
28///
29/// The spec defines extra sets of registers for additional contexts,
30/// that is supervisor, user and other modes, but these aren't supported
31/// by the current code.
32#[repr(C)]
33pub struct PlicRegisters {
34    /// Interrupt Priority Register
35    _reserved0: u32,
36    priority: [ReadWrite<u32, priority::Register>; MAX_INTERRUPTS],
37    _reserved1: [u8; 0x1000 - (MAX_INTERRUPTS + 1) * 4],
38    /// Interrupt Pending Register
39    pending: [ReadOnly<u32>; MAX_BIT_REGS],
40    _reserved2: [u8; 0x1000 - MAX_BIT_REGS * 4],
41    /// Interrupt Enable Register
42    enable: [ReadWrite<u32>; MAX_BIT_REGS],
43    _reserved3: [u8; 0x20_0000 - 0x2000 - MAX_BIT_REGS * 4],
44    /// Priority Threshold Register
45    threshold: ReadWrite<u32, priority::Register>,
46    /// Claim/Complete Register
47    claim: ReadWrite<u32>,
48}
49
50/// Check that the registers are aligned to the PLIC memory map
51const _: () = assert!(core::mem::offset_of!(PlicRegisters, priority) == 0x4);
52const _: () = assert!(core::mem::offset_of!(PlicRegisters, pending) == 0x1000);
53const _: () = assert!(core::mem::offset_of!(PlicRegisters, enable) == 0x2000);
54const _: () = assert!(core::mem::offset_of!(PlicRegisters, threshold) == 0x20_0000);
55const _: () = assert!(core::mem::offset_of!(PlicRegisters, claim) == 0x20_0004);
56
57/// A wrapper around the PLIC registers to provide safe access to the registers
58/// within the defined interrupt number range
59struct RegsWrapper {
60    registers: StaticRef<PlicRegisters>,
61    total_ints: usize,
62}
63
64impl RegsWrapper {
65    const fn new(registers: StaticRef<PlicRegisters>, total_ints: usize) -> Self {
66        Self {
67            registers,
68            total_ints,
69        }
70    }
71
72    fn get_enable_regs(&self) -> &[ReadWrite<u32>] {
73        // One bit per interrupt, total number of registers is
74        // the number of interrupts divided by 32 rounded up
75        &self.registers.enable[0..self.total_ints.div_ceil(32)]
76    }
77
78    // Unused by the current code
79    #[allow(dead_code)]
80    fn get_pending_regs(&self) -> &[ReadOnly<u32>] {
81        // One bit per interrupt, total number of registers is
82        // the number of interrupts divided by 32 rounded up
83        &self.registers.pending[0..self.total_ints.div_ceil(32)]
84    }
85
86    fn get_priority_regs(&self) -> &[ReadWrite<u32, priority::Register>] {
87        // One 32-bit register per interrupt source
88        &self.registers.priority[0..self.total_ints]
89    }
90
91    fn get_threshold_reg(&self) -> &ReadWrite<u32, priority::Register> {
92        &self.registers.threshold
93    }
94
95    fn get_claim_reg(&self) -> &ReadWrite<u32> {
96        &self.registers.claim
97    }
98}
99
100register_bitfields![u32,
101    priority [
102        Priority OFFSET(0) NUMBITS(3) []
103    ]
104];
105
106/// The PLIC instance generic parameter indicates the total number of
107/// interrupt sources implemented on the specific chip.
108///
109/// 51 is a default for backwards compatibility with the SiFive based
110/// platforms implemented without the generic parameter.
111pub struct Plic<const TOTAL_INTS: usize = 51> {
112    registers: RegsWrapper,
113    saved: [VolatileCell<LocalRegisterCopy<u32>>; 2],
114}
115
116impl<const TOTAL_INTS: usize> Plic<TOTAL_INTS> {
117    pub const fn new(base: StaticRef<PlicRegisters>) -> Self {
118        Plic {
119            registers: RegsWrapper::new(base, TOTAL_INTS),
120            saved: [
121                VolatileCell::new(LocalRegisterCopy::new(0)),
122                VolatileCell::new(LocalRegisterCopy::new(0)),
123            ],
124        }
125    }
126
127    /// Clear all pending interrupts. The [`PLIC specification`] section 7:
128    /// > A successful claim will also atomically clear the corresponding pending bit on the interrupt source..
129    /// Note that this function will only clear the enabled interrupt sources, as only those can be claimed.
130    /// [`PLIC specification`]: <https://github.com/riscv/riscv-plic-spec/blob/master/riscv-plic.adoc>
131    pub fn clear_all_pending(&self) {
132        let claim = self.registers.get_claim_reg();
133        loop {
134            let id = claim.get();
135            if id == 0 {
136                break;
137            }
138            claim.set(id);
139        }
140    }
141
142    /// Enable a list of interrupt IDs. The IDs must be in the range 1..TOTAL_INTS.
143    pub fn enable_specific_interrupts(&self, interrupts: &[u32]) {
144        let enable_regs = self.registers.get_enable_regs();
145        for interrupt in interrupts {
146            let offset = interrupt / 32;
147            let irq = interrupt % 32;
148            let old_value = enable_regs[offset as usize].get();
149            enable_regs[offset as usize].set(old_value | (1 << irq));
150
151            // Set some default priority for each interrupt. This is not really used
152            // at this point.
153            // The priority registers indexed 0 for interrupt 1, 1 for interrupt 2, etc.
154            // so we subtract 1 from the interrupt number to get the correct index.
155            self.registers.get_priority_regs()[*interrupt as usize - 1]
156                .write(priority::Priority.val(4));
157        }
158        // Accept all interrupts.
159        self.registers
160            .get_threshold_reg()
161            .write(priority::Priority.val(0));
162    }
163
164    pub fn disable_specific_interrupts(&self, interrupts: &[u32]) {
165        let enable_regs = self.registers.get_enable_regs();
166        for interrupt in interrupts {
167            let offset = interrupt / 32;
168            let irq = interrupt % 32;
169            let old_value = enable_regs[offset as usize].get();
170            enable_regs[offset as usize].set(old_value & !(1 << irq));
171        }
172    }
173
174    /// Enable all interrupts.
175    pub fn enable_all(&self) {
176        let enable_regs = self.registers.get_enable_regs();
177        let priority_regs = &self.registers.get_priority_regs();
178
179        for enable in enable_regs.iter() {
180            enable.set(0xFFFF_FFFF);
181        }
182
183        // Set some default priority for each interrupt. This is not really used
184        // at this point.
185        for priority in priority_regs.iter() {
186            priority.write(priority::Priority.val(4));
187        }
188
189        // Accept all interrupts.
190        self.registers
191            .get_threshold_reg()
192            .write(priority::Priority.val(0));
193    }
194
195    /// Disable all interrupts.
196    pub fn disable_all(&self) {
197        let enable_regs = self.registers.get_enable_regs();
198
199        for enable in enable_regs.iter() {
200            enable.set(0);
201        }
202    }
203
204    /// Get the index (0-256) of the lowest number pending interrupt, or `None` if
205    /// none is pending. RISC-V PLIC has a "claim" register which makes it easy
206    /// to grab the highest priority pending interrupt.
207    pub fn next_pending(&self) -> Option<u32> {
208        let claim = self.registers.get_claim_reg().get();
209        if claim == 0 {
210            None
211        } else {
212            Some(claim)
213        }
214    }
215
216    /// Save the current interrupt to be handled later
217    /// This will save the interrupt at index internally to be handled later.
218    /// Interrupts must be disabled before this is called.
219    /// Saved interrupts can be retrieved by calling `get_saved_interrupts()`.
220    /// Saved interrupts are cleared when `'complete()` is called.
221    pub unsafe fn save_interrupt(&self, index: u32) {
222        let offset = usize::from(index >= 32);
223        let irq = index % 32;
224
225        // OR the current saved state with the new value
226        let new_saved = self.saved[offset].get().get() | 1 << irq;
227
228        // Set the new state
229        self.saved[offset].set(LocalRegisterCopy::new(new_saved));
230    }
231
232    /// The `next_pending()` function will only return enabled interrupts.
233    /// This function will return a pending interrupt that has been disabled by
234    /// `save_interrupt()`.
235    pub fn get_saved_interrupts(&self) -> Option<u32> {
236        for (i, pending) in self.saved.iter().enumerate() {
237            let saved = pending.get().get();
238            if saved != 0 {
239                return Some(saved.trailing_zeros() + (i as u32 * 32));
240            }
241        }
242
243        None
244    }
245
246    /// Signal that an interrupt is finished being handled. In Tock, this should be
247    /// called from the normal main loop (not the interrupt handler).
248    /// Interrupts must be disabled before this is called.
249    pub unsafe fn complete(&self, index: u32) {
250        self.registers.get_claim_reg().set(index);
251
252        let offset = usize::from(index >= 32);
253        let irq = index % 32;
254
255        // OR the current saved state with the new value
256        let new_saved = self.saved[offset].get().get() & !(1 << irq);
257
258        // Set the new state
259        self.saved[offset].set(LocalRegisterCopy::new(new_saved));
260    }
261
262    /// This is a generic implementation. There may be board specific versions as
263    /// some platforms have added more bits to the `mtvec` register.
264    pub fn suppress_all(&self) {
265        // Accept all interrupts.
266        self.registers
267            .get_threshold_reg()
268            .write(priority::Priority.val(0));
269    }
270}