Skip to content

Commit

Permalink
Add API to read BMR491 event log (oxidecomputer#1121)
Browse files Browse the repository at this point in the history
This will let us implement `oxidecomputer/humility#325` without raw I2C, which
in turns lets us (a) call it over the network and (b) plumb it into
`control-plane-agent`.
  • Loading branch information
mkeeter authored Feb 2, 2023
1 parent 4929392 commit 53707f0
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 6 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions build/util/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,6 @@ fn toml_from_env<T: DeserializeOwned>(var: &str) -> Result<Option<T>> {
Ok(c) => c,
};

println!("--- toml for ${} ---", var);
println!("{}", config);
let rval = toml::from_slice(config.as_bytes())
.context("deserializing configuration")?;
Ok(Some(rval))
Expand Down
27 changes: 27 additions & 0 deletions idl/power.idol
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,32 @@ Interface(
),
idempotent: true,
),
"bmr491_event_log_read": (
doc: "reads an event from the BMR491's combined fault and lifecycle event log",
args: {
"index": "u8",
},
reply: Result(
ok: "Bmr491Event",
err: CLike("ResponseCode"),
),
idempotent: true,
),
"bmr491_max_fault_event_index": (
doc: "returns the index of the most recent fault event in the BMR491's event log",
reply: Result(
ok: "u8",
err: CLike("ResponseCode"),
),
idempotent: true,
),
"bmr491_max_lifecycle_event_index": (
doc: "returns the index of the most recent lifecycle event in the BMR491's event log",
reply: Result(
ok: "u8",
err: CLike("ResponseCode"),
),
idempotent: true,
),
},
)
4 changes: 2 additions & 2 deletions task/power-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ serde.workspace = true
static_assertions.workspace = true
zerocopy.workspace = true

drv-i2c-api = { path = "../../drv/i2c-api" }
userlib = { path = "../../sys/userlib" }
drv-i2c-api.path = "../../drv/i2c-api"
userlib.path = "../../sys/userlib"

[build-dependencies]
idol.workspace = true
18 changes: 18 additions & 0 deletions task/power-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub use drv_i2c_api::ResponseCode;
use hubpack::SerializedSize;
use serde::{Deserialize, Serialize};
use userlib::sys_send;
use zerocopy::{AsBytes, FromBytes};

#[derive(Debug, Clone, Copy, Deserialize, Serialize, SerializedSize)]
pub enum Device {
Expand Down Expand Up @@ -127,4 +128,21 @@ impl From<pmbus::units::Percent> for PmbusValue {
}
}

/// Simple wrapper type for the BMR491 event log
///
/// To simplify the implementation, this is the result of a raw PMBus read;
/// this means the first byte is the length of the remaining data (i.e. 23).
#[derive(
Debug,
Clone,
Copy,
Deserialize,
Serialize,
SerializedSize,
AsBytes,
FromBytes,
)]
#[repr(C)]
pub struct Bmr491Event([u8; 24]);

include!(concat!(env!("OUT_DIR"), "/client_stub.rs"));
1 change: 1 addition & 0 deletions task/power/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ hubpack.workspace = true
idol-runtime.workspace = true
num-traits.workspace = true
paste.workspace = true
pmbus.workspace = true
serde.workspace = true
zerocopy.workspace = true

Expand Down
82 changes: 80 additions & 2 deletions task/power/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ use drv_i2c_devices::max5970::*;
use drv_i2c_devices::mwocp68::*;
use drv_i2c_devices::raa229618::*;
use drv_i2c_devices::tps546b24a::*;
use task_power_api::PmbusValue;
use task_power_api::{Bmr491Event, PmbusValue};
use task_sensor_api as sensor_api;
use userlib::units::*;
use userlib::*;

use drv_i2c_api::ResponseCode;
use drv_i2c_api::{I2cDevice, ResponseCode};
use drv_i2c_devices::{
CurrentSensor, InputCurrentSensor, InputVoltageSensor, TempSensor,
VoltageSensor,
Expand Down Expand Up @@ -596,6 +596,20 @@ impl ServerImpl {
}
}
}

/// Find the BMR491 and return an `I2cDevice` handle
///
/// This could be a _little_ inefficient, but means that the code doesn't
/// need to be special-cased for SPs without a BMR491 (and it's the first
/// item in the list anyways).
fn bmr491(&self) -> Result<I2cDevice, ResponseCode> {
let device = CONTROLLER_CONFIG
.iter()
.find(|dev| matches!(dev.device, DeviceType::IBC))
.ok_or(ResponseCode::NoDevice)?;
let (dev, _rail) = (device.builder)(self.i2c_task);
Ok(dev)
}
}

impl idol_runtime::NotificationHandler for ServerImpl {
Expand Down Expand Up @@ -643,6 +657,70 @@ impl idl::InOrderPowerImpl for ServerImpl {

Ok(device.pmbus_read(op)?)
}

fn bmr491_event_log_read(
&mut self,
_msg: &userlib::RecvMessage,
index: u8,
) -> Result<Bmr491Event, idol_runtime::RequestError<ResponseCode>> {
// The BMR491 has 48 event log slots:
// - 0-23 are reserved for faults
// - 24-47 are reserved for lifecycle events
if index >= 48 {
return Err(ResponseCode::BadArg.into());
}

let dev = self.bmr491()?;
dev.write(&[
pmbus::commands::bmr491::CommandCode::MFR_EVENT_INDEX as u8,
index,
])?;

let out = dev.read_reg(
pmbus::commands::bmr491::CommandCode::MFR_READ_EVENT as u8,
)?;

Ok(out)
}

fn bmr491_max_fault_event_index(
&mut self,
_msg: &userlib::RecvMessage,
) -> Result<u8, idol_runtime::RequestError<ResponseCode>> {
let dev = self.bmr491()?;

// 255 is a special value, setting MFR_EVENT_INDEX to the index of the
// newest record in the fault section of the event recorder.
dev.write(&[
pmbus::commands::bmr491::CommandCode::MFR_EVENT_INDEX as u8,
255,
])?;

let out = dev.read_reg(
pmbus::commands::bmr491::CommandCode::MFR_EVENT_INDEX as u8,
)?;
Ok(out)
}

fn bmr491_max_lifecycle_event_index(
&mut self,
_msg: &userlib::RecvMessage,
) -> Result<u8, idol_runtime::RequestError<ResponseCode>> {
let dev = self.bmr491()?;

// 254 is *also* a special value, setting MFR_EVENT_INDEX to the index
// of the newest record in the lifecycle event section of the event
// recorder.
dev.write(&[
pmbus::commands::bmr491::CommandCode::MFR_EVENT_INDEX as u8,
254,
])?;

let out = dev.read_reg(
pmbus::commands::bmr491::CommandCode::MFR_EVENT_INDEX as u8,
)?;
Ok(out)
}
}

/// Claims a mutable buffer of Devices, built from CONTROLLER_CONFIG.
Expand Down

0 comments on commit 53707f0

Please sign in to comment.