Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sprot: turn ROT_IRQ into a real IRQ #1696

Merged
merged 14 commits into from
Apr 5, 2024
26 changes: 20 additions & 6 deletions app/gemini-bu/app.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,27 @@ request_reset = ["hiffy"]

[tasks.sys]
name = "drv-stm32xx-sys"
features = ["h753"]
features = ["h753", "exti"]
priority = 1
max-sizes = {flash = 2048, ram = 2048}
uses = ["rcc", "gpios", "system_flash"]
max-sizes = {flash = 4096, ram = 2048}
uses = ["rcc", "gpios", "system_flash", "syscfg", "exti"]
start = true
task-slots = ["jefe"]
notifications = ["exti-wildcard-irq"]

[tasks.sys.interrupts]
"exti.exti0" = "exti-wildcard-irq"
"exti.exti1" = "exti-wildcard-irq"
"exti.exti2" = "exti-wildcard-irq"
"exti.exti3" = "exti-wildcard-irq"
"exti.exti4" = "exti-wildcard-irq"
"exti.exti9_5" = "exti-wildcard-irq"
"exti.exti15_10" = "exti-wildcard-irq"

[tasks.sys.config.gpio-irqs.rot_irq]
port = "E"
pin = 3
owner = {name = "sprot", notification = "rot_irq"}

[tasks.i2c_driver]
name = "drv-stm32xx-i2c-server"
Expand Down Expand Up @@ -119,7 +134,7 @@ start = true
task-slots = ["sys"]
uses = ["spi4"]
features = ["use-spi-core", "h753", "spi4"]
notifications = ["spi-irq"]
notifications = ["spi-irq", "rot-irq", "timer"]
interrupts = {"spi4.irq" = "spi-irq"}

[tasks.validate]
Expand Down Expand Up @@ -303,5 +318,4 @@ clock_divider = "DIV256"

[config.sprot]
# ROT_IRQ (af=0 for GPIO, af=15 when EXTI is implemneted)
# {port = "D", pins = [0], af = 0},
rot_irq = { port = "E", pin = 3, af = 0}
rot_irq = { port = "E", pin = 3, af = 15}
7 changes: 6 additions & 1 deletion app/gimlet/base.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ notifications = ["exti-wildcard-irq"]
"exti.exti9_5" = "exti-wildcard-irq"
"exti.exti15_10" = "exti-wildcard-irq"

[tasks.sys.config.gpio-irqs.rot_irq]
port = "E"
pin = 3
owner = {name = "sprot", notification = "rot_irq"}

[tasks.spi2_driver]
name = "drv-stm32h7-spi-server"
priority = 3
Expand Down Expand Up @@ -288,7 +293,7 @@ start = true
task-slots = ["sys"]
features = ["sink_test", "use-spi-core", "h753", "spi4"]
uses = ["spi4"]
notifications = ["spi-irq"]
notifications = ["spi-irq", "rot-irq", "timer"]
interrupts = {"spi4.irq" = "spi-irq"}

[tasks.validate]
Expand Down
27 changes: 24 additions & 3 deletions app/gimletlet/app.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,27 @@ request_reset = ["hiffy", "control_plane_agent", "udprpc"]
[tasks.jefe.config.on-state-change]
host_sp_comms = "jefe-state-change"

[tasks.sys]
# Enable EXTI in the sys task so that we can notify sprot when the RoT
# raises an IRQ.
features = ["exti"]
notifications = ["exti-wildcard-irq"]
uses = ["syscfg", "exti"]

[tasks.sys.interrupts]
"exti.exti0" = "exti-wildcard-irq"
"exti.exti1" = "exti-wildcard-irq"
"exti.exti2" = "exti-wildcard-irq"
"exti.exti3" = "exti-wildcard-irq"
"exti.exti4" = "exti-wildcard-irq"
"exti.exti9_5" = "exti-wildcard-irq"
"exti.exti15_10" = "exti-wildcard-irq"

[tasks.sys.config.gpio-irqs.rot_irq]
port = "D"
pin = 0
owner = {name = "sprot", notification = "rot_irq"}

[tasks.packrat]
name = "task-packrat"
priority = 3
Expand Down Expand Up @@ -217,14 +238,14 @@ start = true
task-slots = ["sys"]
features = ["sink_test", "use-spi-core", "h753", "spi3"]
uses = ["spi3"]
notifications = ["spi-irq"]
notifications = ["spi-irq", "rot-irq", "timer"]
interrupts = {"spi3.irq" = "spi-irq"}

[config.sprot]
# TODO: This config is inert. Need to implement STM32 build.rs like the LPC55 has.
pins = [
# ROT_IRQ (af=0 for GPIO, af=15 when EXTI is implemented)
{ name = "ROT_IRQ", pin = { port = "D", pin = 0, af = 0, direction = "input"}},
# ROT_IRQ (af=15 for EXTI)
{ name = "ROT_IRQ", pin = { port = "D", pin = 0, af = 15, direction = "input"}},
# SPI6 CS repurposed for debugging
{ name = "DEBUG", pin = { port = "G", pin = 8, af = 0, direction = "output"}}
]
2 changes: 1 addition & 1 deletion app/gimletlet/base-gimletlet2.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ set_reset_reason = ["sys"]
name = "drv-stm32xx-sys"
features = ["h753"]
priority = 1
max-sizes = {flash = 2048, ram = 2048}
max-sizes = {flash = 4096, ram = 2048}
uses = ["rcc", "gpios", "system_flash"]
start = true
task-slots = ["jefe"]
Expand Down
23 changes: 19 additions & 4 deletions app/psc/base.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,27 @@ request_reset = ["hiffy", "control_plane_agent"]

[tasks.sys]
name = "drv-stm32xx-sys"
features = ["h753", "no-panic"]
features = ["h753", "exti", "no-panic"]
priority = 1
max-sizes = {flash = 2048, ram = 2048}
uses = ["rcc", "gpios", "system_flash"]
max-sizes = {flash = 4096, ram = 2048}
uses = ["rcc", "gpios", "system_flash", "syscfg", "exti"]
start = true
task-slots = ["jefe"]
notifications = ["exti-wildcard-irq"]

[tasks.sys.interrupts]
"exti.exti0" = "exti-wildcard-irq"
"exti.exti1" = "exti-wildcard-irq"
"exti.exti2" = "exti-wildcard-irq"
"exti.exti3" = "exti-wildcard-irq"
"exti.exti4" = "exti-wildcard-irq"
"exti.exti9_5" = "exti-wildcard-irq"
"exti.exti15_10" = "exti-wildcard-irq"

[tasks.sys.config.gpio-irqs.rot_irq]
port = "D"
pin = 0
owner = {name = "sprot", notification = "rot_irq"}

[tasks.i2c_driver]
name = "drv-stm32xx-i2c-server"
Expand Down Expand Up @@ -155,7 +170,7 @@ start = true
task-slots = ["sys"]
uses = ["spi4"]
features = ["sink_test", "use-spi-core", "h753", "spi4"]
notifications = ["spi-irq"]
notifications = ["spi-irq", "rot-irq", "timer"]
interrupts = {"spi4.irq" = "spi-irq"}

[tasks.udpecho]
Expand Down
25 changes: 20 additions & 5 deletions app/sidecar/base.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ fwid = true

[kernel]
name = "sidecar"
requires = {flash = 25984, ram = 6256}
requires = {flash = 26176, ram = 6256}
features = ["dump"]

[caboose]
Expand All @@ -31,12 +31,27 @@ request_reset = ["hiffy", "control_plane_agent"]

[tasks.sys]
name = "drv-stm32xx-sys"
features = ["h753", "no-panic"]
features = ["h753", "exti", "no-panic"]
priority = 1
max-sizes = {flash = 2048, ram = 2048}
uses = ["rcc", "gpios", "system_flash"]
max-sizes = {flash = 4096, ram = 2048}
uses = ["rcc", "gpios", "system_flash", "syscfg", "exti"]
start = true
task-slots = ["jefe"]
notifications = ["exti-wildcard-irq"]

[tasks.sys.interrupts]
"exti.exti0" = "exti-wildcard-irq"
"exti.exti1" = "exti-wildcard-irq"
"exti.exti2" = "exti-wildcard-irq"
"exti.exti3" = "exti-wildcard-irq"
"exti.exti4" = "exti-wildcard-irq"
"exti.exti9_5" = "exti-wildcard-irq"
"exti.exti15_10" = "exti-wildcard-irq"

[tasks.sys.config.gpio-irqs.rot_irq]
port = "E"
pin = 3
owner = {name = "sprot", notification = "rot_irq"}

[tasks.update_server]
name = "stm32h7-update-server"
Expand Down Expand Up @@ -113,7 +128,7 @@ start = true
task-slots = ["sys"]
features = ["sink_test", "use-spi-core", "h753", "spi4"]
uses = ["spi4"]
notifications = ["spi-irq"]
notifications = ["spi-irq", "rot-irq", "timer"]
interrupts = {"spi4.irq" = "spi-irq"}

[tasks.udpecho]
Expand Down
111 changes: 92 additions & 19 deletions drv/stm32h7-sprot-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use drv_stm32xx_sys_api as sys_api;
use hubpack::SerializedSize;
use idol_runtime::{NotificationHandler, RequestError};
use ringbuf::*;
use sys_api::IrqControl;
use userlib::*;

cfg_if::cfg_if! {
Expand Down Expand Up @@ -363,31 +364,102 @@ impl<S: SpiServer> Io<S> {

// Poll ROT_IRQ until asserted (true) or deasserted (false).
//
// We sleep and poll for what should be long enough for the RoT to queue
// a response.
//
// TODO: Use STM32 EXTI as an interrupt allows for better performance and
// power efficiency.
//
// STM32 EXTI allows for 16 interrupts for GPIOs.
// Each of those can represent Pin X from a GPIO bank (A through K)
// So, only one bank's Pin 3, for example, can have the #3 interrupt.
// For ROT_IRQ, we would configure for the falling edge to trigger
// the interrupt. That configuration should be specified in the app.toml
// for the board. Work needs to be done to generalize the EXTI facility.
// But, hacking in one interrupt as an example should be ok to start things
// off.
// We do this by asking the `sys` task to notify us when the GPIO pin's
// state changes (using EXTI), and waiting for either that or timeout
// determined based on `max_sleep`.
fn wait_rot_irq(&mut self, desired: bool, max_sleep: u32) -> bool {
let mut slept = 0;
use notifications::{sprot::TIMER_MASK, ROT_IRQ_MASK};
// Determine our edge sensitivity for the interrupt. If we want to wait
// for the line to be asserted, we want to wait for a rising edge. If
// the line is currently asserted, and we're waiting for it to be
// *deasserted*, we want to wait for a falling edge.
let sensitivity = match desired {
true => sys_api::Edge::Rising,
false => sys_api::Edge::Falling,
};
self.sys.gpio_irq_configure(ROT_IRQ_MASK, sensitivity);

// Enable the interrupt.
self.sys
.gpio_irq_control(ROT_IRQ_MASK, IrqControl::Enable)
// Just unwrap this, because the `sys` task should never panic.
.unwrap_lite();

// Determine the deadline after which we'll give up, and start the clock.
let deadline = sys_get_timer()
.now
// Values passed to `max_sleep` are all constants that are small
// enough that this will almost certainly not overflow unless the SP
// has been running without a reset for at least a couple million
// years. Using saturating arithmetic here lets us avoid a bounds
// check.
.saturating_add(max_sleep as u64);
sys_set_timer(Some(deadline), TIMER_MASK);

let mut irq_fired = false;
while self.is_rot_irq_asserted() != desired {
if slept == max_sleep {
// Wait to be notified either by the timeout or by the ROT_IRQ pin
// changing state.
const MASK: u32 = TIMER_MASK | ROT_IRQ_MASK;
let notif = sys_recv_notification(MASK);

// First, check if the IRQ has fired. We do this by checking if the
// ROT_IRQ notification bit has been posted, and then asking the
// `sys` task to confirm that we actually got the IRQ.
//
// N.B. that we check this *before* checking for the timer
// notification bit, because it's possible *both* notifications were
// posted before we were scheduled again, and if the IRQ did fire,
// we'd prefer to honor that.
irq_fired = notif & ROT_IRQ_MASK != 0
&& self
.sys
// If the IRQ hasn't fired, leave it enabled, otherwise,
// if it has fired, don't re-enable the IRQ.
.gpio_irq_control(ROT_IRQ_MASK, IrqControl::Check)
// Sys task shouldn't panic.
.unwrap_lite();
if irq_fired {
break;
}

// If the timer notification was posted, and the GPIO IRQ
// notification wasn't, we've waited for the timeout. Too bad!
if notif & TIMER_MASK != 0 {
// Disable the IRQ, so that we don't get the notification later
// while in `recv`.
self.sys
.gpio_irq_control(
notifications::ROT_IRQ_MASK,
IrqControl::Disable,
)
.unwrap_lite();

// Record the timeout.
self.stats.timeouts = self.stats.timeouts.wrapping_add(1);
ringbuf_entry!(Trace::RotReadyTimeout);
return false;
}
hl::sleep_for(1);
slept += 1;
}

// Ensure the timer gets unset before returning, to avoid frightening
// our IPC server when it's waiting in recv without expecting a timer to
// go off.
sys_set_timer(None, TIMER_MASK);
// If the IRQ didn't fire, let's also disable it, so that it also
// doesn't go off later.
if !irq_fired {
self.sys
.gpio_irq_control(
notifications::ROT_IRQ_MASK,
IrqControl::Disable,
)
.unwrap_lite();
}

// We return `true` here regardless of `irq_fired`, because we may not
// have looped at all, if the line was asserted before we started
// waiting for the IRQ. The timeout case returns early, above.
true
}
}
Expand Down Expand Up @@ -1097,7 +1169,8 @@ impl<S: SpiServer> idl::InOrderSpRotImpl for ServerImpl<S> {

impl<S: SpiServer> NotificationHandler for ServerImpl<S> {
fn current_notification_mask(&self) -> u32 {
// We don't use notifications, don't listen for any.
// Neither our timer nor our GPIO IRQ notifications are needed while the
// server is in recv.
0
}

Expand Down
Loading