diff --git a/Cargo.lock b/Cargo.lock index 19b984cebb..ece9f7bd9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3146,7 +3146,7 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "gateway-ereport-messages" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/management-gateway-service#177c9c719e12896c566a1b6b5416c9bc686531d3" +source = "git+https://github.com/oxidecomputer/management-gateway-service#745a508cb97b7ca9b4c10ec9592c980eb769b10d" dependencies = [ "zerocopy 0.8.27", ] @@ -3154,7 +3154,7 @@ dependencies = [ [[package]] name = "gateway-messages" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/management-gateway-service#177c9c719e12896c566a1b6b5416c9bc686531d3" +source = "git+https://github.com/oxidecomputer/management-gateway-service#745a508cb97b7ca9b4c10ec9592c980eb769b10d" dependencies = [ "bitflags 2.9.4", "hubpack", diff --git a/build/i2c/src/lib.rs b/build/i2c/src/lib.rs index 6774116bd7..4305f8ccf2 100644 --- a/build/i2c/src/lib.rs +++ b/build/i2c/src/lib.rs @@ -1782,6 +1782,27 @@ pub struct I2cDeviceDescription { pub sensors: Vec, pub device_id: Option, pub name: Option, + /// If this is a PMBus device, this field contains additional data about the + /// PMBus device to be used for generating PMBus-y code. + pub pmbus: Option, +} + +#[derive(Debug, Clone)] +pub struct PmbusDeviceDescription { + pub rails: Vec, +} + +#[derive(Debug, Clone)] +pub struct PmbusRailDescription { + pub name: String, + pub phases: Vec, +} + +impl I2cDeviceDescription { + /// Returns `true` if this device is a PMBus device. + pub fn is_pmbus(&self) -> bool { + self.pmbus.is_some() + } } /// @@ -1801,12 +1822,59 @@ pub fn device_descriptions() -> impl Iterator { g.devices.into_iter().zip(sensors.device_sensors).map( |(device, sensors)| { let device_id = device.refdes.as_ref().map(Refdes::to_component_id); + let pmbus = device.power.as_ref().and_then(|power| { + if !power.pmbus { + return None; + } + + let rails = match (power.rails.as_ref(), power.phases.as_ref()) + { + (Some(rails), Some(phases)) => { + assert_eq!( + rails.len(), + phases.len(), + "invalid config: PMBus device {device_id:?}'s \ + `power.rails` and `power.phases` lists are not \ + the same length" + ); + rails + .iter() + .cloned() + .zip(phases.iter().cloned()) + .map(|(name, phases)| PmbusRailDescription { + name, + phases, + }) + .collect() + } + (Some(rails), None) => rails + .iter() + .cloned() + .map(|name| PmbusRailDescription { + name, + phases: Vec::new(), + }) + .collect(), + (None, Some(_)) => { + panic!( + "invalid config: PMBus device {device_id:?} \ + defines a `power.phases` list, but not a \ + `power.rails` list" + ); + } + (None, None) => Vec::new(), + }; + + Some(PmbusDeviceDescription { rails }) + }); + I2cDeviceDescription { device: device.device, description: device.description, sensors, device_id, name: device.name, + pmbus, } }, ) diff --git a/task/control-plane-agent/src/inventory.rs b/task/control-plane-agent/src/inventory.rs index f9bead6fa2..1ccc860bda 100644 --- a/task/control-plane-agent/src/inventory.rs +++ b/task/control-plane-agent/src/inventory.rs @@ -123,6 +123,9 @@ impl Inventory { }; let mut capabilities = DeviceCapabilities::empty(); + if device.is_pmbus { + capabilities |= DeviceCapabilities::IS_PMBUS; + } if !device.sensors.is_empty() { capabilities |= DeviceCapabilities::HAS_MEASUREMENT_CHANNELS; } diff --git a/task/validate-api/build.rs b/task/validate-api/build.rs index 869ef1c4dc..4f0d3c8b40 100644 --- a/task/validate-api/build.rs +++ b/task/validate-api/build.rs @@ -59,12 +59,13 @@ fn write_pub_device_descriptions() -> anyhow::Result<()> { let mut id2idx = std::collections::BTreeMap::new(); for (idx, dev) in devices.into_iter().enumerate() { + let is_pmbus = dev.is_pmbus(); writeln!(file, " DeviceDescription {{")?; writeln!(file, " device: {:?},", dev.device)?; writeln!(file, " description: {:?},", dev.description)?; if let Some(id) = dev.device_id { if let Ok(component) = SpComponent::try_from(id.as_ref()) { - write!(file, " id: {:?},", component.id)?; + writeln!(file, " id: {:?},", component.id)?; if id2idx.insert(component.id, idx).is_some() { println!("cargo::error=duplicate device id {id:?}",); duplicate_ids += 1; @@ -83,6 +84,7 @@ fn write_pub_device_descriptions() -> anyhow::Result<()> { ); missing_ids += 1; }; + writeln!(file, " is_pmbus: {is_pmbus:?},")?; writeln!(file, " sensors: &[")?; for s in dev.sensors { writeln!(file, " SensorDescription {{")?; diff --git a/task/validate-api/src/lib.rs b/task/validate-api/src/lib.rs index 3884406f07..b55d93cd14 100644 --- a/task/validate-api/src/lib.rs +++ b/task/validate-api/src/lib.rs @@ -75,6 +75,7 @@ pub struct DeviceDescription { pub description: &'static str, pub sensors: &'static [SensorDescription], pub id: [u8; MAX_ID_LENGTH], + pub is_pmbus: bool, } include!(concat!(env!("OUT_DIR"), "/device_descriptions.rs"));