From ff28dc232743c949edb7c04e666868d9a6f52ce7 Mon Sep 17 00:00:00 2001 From: Jordan Paige Hendricks Date: Thu, 16 Oct 2025 14:51:23 -0700 Subject: [PATCH] Add task to induce IBC droop --- Cargo.lock | 15 +++++++++ app/gimlet/dev.toml | 7 ++++ drv/i2c-devices/src/bmr491.rs | 7 ++++ idl/drooper.idol | 14 ++++++++ task/drooper/Cargo.toml | 30 +++++++++++++++++ task/drooper/build.rs | 18 ++++++++++ task/drooper/src/main.rs | 63 +++++++++++++++++++++++++++++++++++ 7 files changed, 154 insertions(+) create mode 100644 idl/drooper.idol create mode 100644 task/drooper/Cargo.toml create mode 100644 task/drooper/build.rs create mode 100644 task/drooper/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index db19075cde..eeba953ec9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1021,6 +1021,21 @@ dependencies = [ "subtle", ] +[[package]] +name = "drooper" +version = "0.1.0" +dependencies = [ + "build-i2c", + "drv-i2c-api", + "drv-i2c-devices", + "idol", + "idol-runtime", + "num-traits", + "userlib", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", +] + [[package]] name = "drv-auxflash-api" version = "0.1.0" diff --git a/app/gimlet/dev.toml b/app/gimlet/dev.toml index 125f09df2b..a2c314196d 100644 --- a/app/gimlet/dev.toml +++ b/app/gimlet/dev.toml @@ -13,6 +13,13 @@ task-slots = ["net"] features = ["vlan"] notifications = ["socket"] +[tasks.drooper] +name = "drooper" +start = true +priority = 6 +task-slots = ["i2c_driver"] +notifications = ["timer"] + [config.net.sockets.rpc] kind = "udp" owner = {name = "udprpc", notification = "socket"} diff --git a/drv/i2c-devices/src/bmr491.rs b/drv/i2c-devices/src/bmr491.rs index defbcd64c4..9af3670a13 100644 --- a/drv/i2c-devices/src/bmr491.rs +++ b/drv/i2c-devices/src/bmr491.rs @@ -84,6 +84,13 @@ impl Bmr491 { }) } + pub fn set_vout(&self, v: u16) -> Result<(), Error> { + let mut vout = VOUT_COMMAND::CommandData(0); + let value = Volts(v as f32); + vout.set(self.read_mode()?, pmbus::units::Volts(value.0))?; + pmbus_write!(self.device, VOUT_COMMAND, vout) + } + pub fn read_vout(&self) -> Result { let vout = pmbus_read!(self.device, bmr491::READ_VOUT)?; Ok(Volts(vout.get(self.read_mode()?)?.0)) diff --git a/idl/drooper.idol b/idl/drooper.idol new file mode 100644 index 0000000000..3eb523cc96 --- /dev/null +++ b/idl/drooper.idol @@ -0,0 +1,14 @@ +// Interface to the task to droop the IBC voltage. +Interface( + name: "Drooper", + ops: { + "droop": ( + doc: "Droop the 12V rails for a given ms time period.", + args: { + "time_ms": "u64", + }, + reply: Simple("()"), + idempotent: true, + ), + } +) diff --git a/task/drooper/Cargo.toml b/task/drooper/Cargo.toml new file mode 100644 index 0000000000..6979968a14 --- /dev/null +++ b/task/drooper/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "drooper" +version = "0.1.0" +edition = "2021" + +[dependencies] +idol-runtime.workspace = true +num-traits.workspace = true +userlib = { path = "../../sys/userlib", features = ["panic-messages"] } +zerocopy.workspace = true +zerocopy-derive.workspace = true + +drv-i2c-devices = { path = "../../drv/i2c-devices" } +drv-i2c-api = { path = "../../drv/i2c-api" } + +[build-dependencies] +idol.workspace = true + +build-i2c = { path = "../../build/i2c" } + +# This section is here to discourage RLS/rust-analyzer from doing test builds, +# since test builds don't work for cross compilation. +[[bin]] +name = "drooper" +test = false +doctest = false +bench = false + +[lints] +workspace = true diff --git a/task/drooper/build.rs b/task/drooper/build.rs new file mode 100644 index 0000000000..fde40eca5a --- /dev/null +++ b/task/drooper/build.rs @@ -0,0 +1,18 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +fn main() -> Result<(), Box> { + idol::Generator::new() + .with_counters( + idol::CounterSettings::default().with_server_counters(false), + ) + .build_server_support( + "../../idl/drooper.idol", + "server_stub.rs", + idol::server::ServerStyle::InOrder, + )?; + + build_i2c::codegen(build_i2c::Disposition::Devices)?; + Ok(()) +} diff --git a/task/drooper/src/main.rs b/task/drooper/src/main.rs new file mode 100644 index 0000000000..2df8f19d63 --- /dev/null +++ b/task/drooper/src/main.rs @@ -0,0 +1,63 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +//! +//! drooper: A task to simulate the IBC droop seen in mfg-quality#140 +//! +//! Running this task will cause all U.2s to undergo a PCIe reset event. +//! (Use with caution!) +//! +//! For example, to drop the voltage for 30 ms: +//! $ humility hiffy -c drooper.droop -a time_ms=30 +//! + +#![no_std] +#![no_main] + +use drv_i2c_devices::bmr491::*; + +use core::convert::Infallible; +use idol_runtime::RequestError; +use userlib::{task_slot, RecvMessage, UnwrapLite}; + +task_slot!(I2C, i2c_driver); + +#[export_name = "main"] +fn main() -> ! { + let mut server = ServerImpl {}; + let mut buffer = [0; idl::INCOMING_SIZE]; + + loop { + idol_runtime::dispatch(&mut buffer, &mut server); + } +} + +struct ServerImpl {} + +impl idl::InOrderDrooperImpl for ServerImpl { + fn droop( + &mut self, + _msg: &RecvMessage, + time_ms: u32, + ) -> Result<(), RequestError> { + let (device, rail) = i2c_config::pmbus::v12_sys_a2(I2C.get_task_id()); + let ibc = Bmr491::new(&device, rail); + + // Droop the voltage for the requested time period in ms. + // We pick 9V because it's approximately what we see in the field for mfg-quality#140. + let _ = ibc.set_vout(9); + userlib::hl::sleep_for(time_ms as u64); + + // Restore to 12V. + let _ = ibc.set_vout(12); + + Ok(()) + } +} + +mod idl { + include!(concat!(env!("OUT_DIR"), "/server_stub.rs")); +} + +include!(concat!(env!("OUT_DIR"), "/i2c_config.rs"));