From 8d87f58eb55b9c100c81b7ee705ace55fbbb7b0c Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Sun, 21 Sep 2025 12:54:02 -0700 Subject: [PATCH 1/8] cpu_seq: ereports for THERMTRIP/other faults --- drv/cosmo-seq-server/src/main.rs | 89 +++++++++++++++++++++++++++++- drv/cosmo-seq-server/src/vcore.rs | 29 +++++----- drv/gimlet-seq-server/src/main.rs | 60 +++++++++++++++++++- drv/gimlet-seq-server/src/vcore.rs | 57 ++++++++----------- 4 files changed, 179 insertions(+), 56 deletions(-) diff --git a/drv/cosmo-seq-server/src/main.rs b/drv/cosmo-seq-server/src/main.rs index 9f8503483..4553fd111 100644 --- a/drv/cosmo-seq-server/src/main.rs +++ b/drv/cosmo-seq-server/src/main.rs @@ -101,6 +101,14 @@ enum Trace { now: u64, }, UnexpectedInterrupt, + + EreportSent(#[count(children)] EreportClass, usize), + EreportLost( + #[count(children)] EreportClass, + usize, + task_packrat_api::EreportWriteError, + ), + EreportTooBig(#[count(children)] EreportClass), } counted_ringbuf!(Trace, 128, Trace::None); @@ -783,7 +791,17 @@ impl ServerImpl { self.seq.ifr.modify(|h| h.set_thermtrip(false)); ringbuf_entry!(Trace::Thermtrip); action = InternalAction::ThermTrip; - // Great place for an ereport? + let ereport = Ereport { + class: EreportClass::Thermtrip, + version: 0, + refdes: "P0", // host CPU + }; + deliver_ereport( + ereport.class, + ereport, + self.packrat, + self.ereport_buf, + ); } if ifr.a0mapo { @@ -791,14 +809,35 @@ impl ServerImpl { self.seq.ifr.modify(|h| h.set_a0mapo(false)); ringbuf_entry!(Trace::A0MapoInterrupt); action = InternalAction::Mapo; - // Great place for an ereport? + let ereport = Ereport { + class: EreportClass::A0Mapo, + version: 0, + refdes: "U27", // sequencer FPGA + }; + deliver_ereport( + ereport.class, + ereport, + self.packrat, + self.ereport_buf, + ); } if ifr.smerr_assert { self.seq.ifr.modify(|h| h.set_smerr_assert(false)); ringbuf_entry!(Trace::SmerrInterrupt); action = InternalAction::Smerr; - // Great place for an ereport? + + let ereport = Ereport { + class: EreportClass::Smerr, + version: 0, + refdes: "U27", // sequencer FPGA + }; + deliver_ereport( + ereport.class, + ereport, + self.packrat, + self.ereport_buf, + ); } // Fan Fault is unconnected // NIC MAPO is unconnected @@ -831,6 +870,20 @@ impl ServerImpl { ringbuf_entry!(Trace::UnexpectedInterrupt); } }; + + #[derive(serde::Serialize)] + struct Ereport { + #[serde(rename = "k")] + class: EreportClass, + #[serde(rename = "v")] + version: u32, + refdes: &'static str, + // TODO(eliza): eventually, it would be nice to include sequencer + // state registers here, however, we would need to modify the + // `fpga_regmap` codegen to let us get the raw bits out (since + // encoding the `...View` structs as CBOR uses a lot more bytes for + // field names and 8-bit `bool`s...) I'll do this eventually... + } } } @@ -930,6 +983,36 @@ impl NotificationHandler for ServerImpl { //////////////////////////////////////////////////////////////////////////////// +#[derive(Eq, PartialEq, Copy, Clone, serde::Serialize)] +pub(crate) enum EreportClass { + #[serde(rename = "hw.cpu.thermtrip")] + Thermtrip, + #[serde(rename = "hw.seq.smerr")] + Smerr, + #[serde(rename = "hw.seq.a0_map0")] + A0Mapo, + #[serde(rename = "hw.pwr.pmbus.alert")] + PmbusAlert, +} + +pub(crate) fn deliver_ereport( + class: &EreportClass, + ereport: &impl serde::Serialize, + packrat: &Packrat, + buf: &mut [u8], +) { + match packrat.serialize_ereport(ereport, buf) { + Ok(len) => ringbuf_entry!(Trace::EreportSent(class, len)), + Err(task_packrat_api::EreportSerializeError::Packrat { len, err }) => { + ringbuf_entry!(Trace::EreportLost(class, len, err)) + } + Err(task_packrat_api::EreportSerializeError::Serialize(_)) => { + ringbuf_entry!(Trace::EreportTooBig(class)) + } + } +} +//////////////////////////////////////////////////////////////////////////////// + mod idl { use drv_cpu_seq_api::StateChangeReason; include!(concat!(env!("OUT_DIR"), "/server_stub.rs")); diff --git a/drv/cosmo-seq-server/src/vcore.rs b/drv/cosmo-seq-server/src/vcore.rs index cd9824c30..e4f50e4b7 100644 --- a/drv/cosmo-seq-server/src/vcore.rs +++ b/drv/cosmo-seq-server/src/vcore.rs @@ -377,26 +377,21 @@ impl VCore { }; let ereport = Ereport { - k: "hw.pwr.pmbus.alert", - v: 0, + class: crate::EreportClass::PmbusAlert, + version: 0, rail, refdes: device.i2c_device().component_id(), time: now, pmbus_status, pwr_good: power_good, }; - match self.packrat.serialize_ereport(&ereport, ereport_buf) { - Ok(len) => ringbuf_entry!(Trace::EreportSent(rail, len)), - Err(task_packrat_api::EreportSerializeError::Packrat { - len, - err, - }) => { - ringbuf_entry!(Trace::EreportLost(rail, len, err)) - } - Err(task_packrat_api::EreportSerializeError::Serialize(_)) => { - ringbuf_entry!(Trace::EreportTooBig(rail)) - } - } + + crate::deliver_ereport( + ereport.class, + ereport, + self.packrat, + self.ereport_buf, + ); // TODO(eliza): if POWER_GOOD has been deasserted, we should produce a // subsequent ereport for that. @@ -409,8 +404,10 @@ impl VCore { #[derive(Serialize)] struct Ereport { - k: &'static str, - v: usize, + #[serde(rename = "k")] + class: crate::EreportClass, + #[serde(rename = "v")] + version: usize, refdes: &'static str, rail: Rail, time: u64, diff --git a/drv/gimlet-seq-server/src/main.rs b/drv/gimlet-seq-server/src/main.rs index 8b56233a7..d9ecc15df 100644 --- a/drv/gimlet-seq-server/src/main.rs +++ b/drv/gimlet-seq-server/src/main.rs @@ -26,6 +26,7 @@ use drv_spi_api::{SpiDevice, SpiServer}; use drv_stm32xx_sys_api as sys_api; use idol_runtime::{NotificationHandler, RequestError}; use seq_spi::{Addr, Reg}; +use serde::Serialize; use static_assertions::const_assert; use task_jefe_api::Jefe; @@ -153,6 +154,13 @@ enum Trace { retries_remaining: u8, }, StartFailed(#[count(children)] SeqError), + EreportSent(#[count(children)] EreportClass, usize), + EreportLost( + #[count(children)] EreportClass, + usize, + task_packrat_api::EreportWriteError, + ), + EreportTooBig(#[count(children)] EreportClass), } counted_ringbuf!(Trace, 128, Trace::None); @@ -201,6 +209,7 @@ struct ServerImpl { hf: hf_api::HostFlash, vcore: vcore::VCore, deadline: u64, + packrat: Packrat, // Buffer for encoding ereports. This is a static so that it's not on the // stack when handling interrupts. ereport_buf: &'static mut [u8; EREPORT_BUF_LEN], @@ -501,8 +510,9 @@ impl ServerImpl { jefe, hf, deadline: 0, - vcore: vcore::VCore::new(sys, packrat, &device, rail), + vcore: vcore::VCore::new(sys, &device, rail), ereport_buf, + packrat, }; // Power on, unless suppressed by the `stay-in-a2` feature @@ -542,7 +552,8 @@ impl NotificationHandler for ServerImpl { fn handle_notification(&mut self, bits: userlib::NotificationBits) { if bits.check_notification_mask(self.vcore.mask()) { - self.vcore.handle_notification(self.ereport_buf); + self.vcore + .handle_notification(&self.packrat, self.ereport_buf); } if !bits.has_timer_fired(notifications::TIMER_MASK) { @@ -1020,6 +1031,26 @@ impl ServerImpl { if ifr & thermtrip != 0 { self.seq.clear_bytes(Addr::IFR, &[thermtrip]).unwrap_lite(); self.update_state_internal(PowerState::A0Thermtrip); + let ereport = ThermtripEreport { + class: EreportClass::Thermtrip, + version: 0, + refdes: "P0", // host CPU + }; + deliver_ereport( + ereport.class, + &ereport, + &self.packrat, + self.ereport_buf, + ); + } + + #[derive(serde::Serialize)] + struct ThermtripEreport { + #[serde(rename = "k")] + class: EreportClass, + #[serde(rename = "v")] + version: u32, + refdes: &'static str, } } @@ -1279,6 +1310,31 @@ fn read_spd_data_and_load_packrat( Ok(()) } +#[derive(Eq, PartialEq, Copy, Clone, Serialize, Count)] +pub(crate) enum EreportClass { + #[serde(rename = "hw.cpu.thermtrip")] + Thermtrip, + #[serde(rename = "hw.pwr.pmbus.alert")] + PmbusAlert, +} + +pub(crate) fn deliver_ereport( + class: EreportClass, + ereport: &impl Serialize, + packrat: &Packrat, + buf: &mut [u8], +) { + match packrat.serialize_ereport(ereport, buf) { + Ok(len) => ringbuf_entry!(Trace::EreportSent(class, len)), + Err(task_packrat_api::EreportSerializeError::Packrat { len, err }) => { + ringbuf_entry!(Trace::EreportLost(class, len, err)) + } + Err(task_packrat_api::EreportSerializeError::Serialize(_)) => { + ringbuf_entry!(Trace::EreportTooBig(class)) + } + } +} + fn reprogram_fpga( spi: &SpiDevice, sys: &sys_api::Sys, diff --git a/drv/gimlet-seq-server/src/vcore.rs b/drv/gimlet-seq-server/src/vcore.rs index 056c8081d..9ea95eb18 100644 --- a/drv/gimlet-seq-server/src/vcore.rs +++ b/drv/gimlet-seq-server/src/vcore.rs @@ -40,7 +40,6 @@ use userlib::{sys_get_timer, units}; pub struct VCore { device: Raa229618, sys: sys_api::Sys, - packrat: packrat_api::Packrat, } #[derive(Copy, Clone, PartialEq)] @@ -61,9 +60,6 @@ enum Trace { StatusMfrSpecific(Result), Reading { timestamp: u64, volts: units::Volts }, Error(ResponseCode), - EreportSent(usize), - EreportLost(usize, packrat_api::EreportWriteError), - EreportTooBig, } ringbuf!(Trace, 120, Trace::None); @@ -97,16 +93,10 @@ cfg_if::cfg_if! { } impl VCore { - pub fn new( - sys: &sys_api::Sys, - packrat: packrat_api::Packrat, - device: &I2cDevice, - rail: u8, - ) -> Self { + pub fn new(sys: &sys_api::Sys, device: &I2cDevice, rail: u8) -> Self { Self { device: Raa229618::new(device, rail), sys: sys.clone(), - packrat, } } @@ -139,7 +129,11 @@ impl VCore { Ok(()) } - pub fn handle_notification(&self, ereport_buf: &mut [u8]) { + pub fn handle_notification( + &self, + packrat: &packrat_api::Packrat, + ereport_buf: &mut [u8], + ) { let now = sys_get_timer().now; let asserted = self.sys.gpio_read(VCORE_TO_SP_ALERT_L) == 0; @@ -149,7 +143,7 @@ impl VCore { }); if asserted { - self.read_pmbus_status(now, ereport_buf); + self.read_pmbus_status(now, packrat, ereport_buf); // Clear the fault now so that PMALERT_L is reasserted if a // subsequent fault occurs. Note that if the fault *condition* // continues, the fault bits in the status registers will remain @@ -162,7 +156,12 @@ impl VCore { let _ = self.sys.gpio_irq_control(self.mask(), IrqControl::Enable); } - fn read_pmbus_status(&self, now: u64, ereport_buf: &mut [u8]) { + fn read_pmbus_status( + &self, + now: u64, + packrat: &packrat_api::Packrat, + ereport_buf: &mut [u8], + ) { use pmbus::commands::raa229618::STATUS_WORD; // Read PMBus status registers and prepare an ereport. @@ -266,30 +265,16 @@ impl VCore { cml: status_cml.ok(), mfr: status_mfr_specific.ok(), }; - let ereport = Ereport { - k: "hw.pwr.pmbus.alert", - v: 0, + let ereport = PmbusEreport { + class: crate::EreportClass::PmbusAlert, + version: 0, refdes: self.device.i2c_device().component_id(), rail: "VDD_VCORE", time: now, pwr_good, pmbus_status: status, }; - match self - .packrat - .serialize_ereport(&ereport, &mut ereport_buf[..]) - { - Ok(len) => ringbuf_entry!(Trace::EreportSent(len)), - Err(task_packrat_api::EreportSerializeError::Packrat { - len, - err, - }) => { - ringbuf_entry!(Trace::EreportLost(len, err)) - } - Err(task_packrat_api::EreportSerializeError::Serialize(_)) => { - ringbuf_entry!(Trace::EreportTooBig) - } - } + crate::deliver_ereport(ereport.class, &ereport, packrat, ereport_buf); // TODO(eliza): if POWER_GOOD has been deasserted, we should produce a // subsequent ereport for that. @@ -338,9 +323,11 @@ struct PmbusStatus { } #[derive(Serialize)] -struct Ereport { - k: &'static str, - v: usize, +struct PmbusEreport { + #[serde(rename = "k")] + class: crate::EreportClass, + #[serde(rename = "v")] + version: u32, refdes: &'static str, rail: &'static str, time: u64, From 004f28cc2f9d0d0b17dbb77cd9b1c8cf93c2325c Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Mon, 22 Sep 2025 11:10:14 -0700 Subject: [PATCH 2/8] wip --- drv/gimlet-seq-server/src/main.rs | 200 ++++++++++++++++++++++++++---- 1 file changed, 178 insertions(+), 22 deletions(-) diff --git a/drv/gimlet-seq-server/src/main.rs b/drv/gimlet-seq-server/src/main.rs index d9ecc15df..9dcbe8719 100644 --- a/drv/gimlet-seq-server/src/main.rs +++ b/drv/gimlet-seq-server/src/main.rs @@ -84,7 +84,7 @@ enum Trace { A2Status(u8), A2, A0FailureDetails(Addr, u8), - A0Failed(#[count(children)] SeqError), + A0Failed(#[count(children)] A0Failure), A1Status(Result), A1Readbacks(u8), A1OutStatus(u8), @@ -799,7 +799,7 @@ impl ServerImpl { } if sys_get_timer().now > deadline { - return Err(self.a0_failure(SeqError::A1Timeout)); + return Err(self.a0_failure(A0Failure::A1Timeout)); } hl::sleep_for(1); @@ -813,7 +813,7 @@ impl ServerImpl { ringbuf_entry!(Trace::CPUPresent(present)); if !present { - return Err(self.a0_failure(SeqError::CPUNotPresent)); + return Err(self.a0_failure(A0Failure::CPUNotPresent)); } let coretype = sys.gpio_read(CORETYPE) != 0; @@ -857,7 +857,7 @@ impl ServerImpl { } if sys_get_timer().now > deadline { - return Err(self.a0_failure(SeqError::A0TimeoutGroupC)); + return Err(self.a0_failure(A0Failure::A0TimeoutGroupC)); } hl::sleep_for(1); @@ -866,10 +866,10 @@ impl ServerImpl { // // And power up! // - if vcore_soc_on().is_err() { + if let Err(err) = vcore_soc_on() { // Uh-oh, the I2C write failed a bunch of times. Guess I'll // die! - return Err(self.a0_failure(SeqError::I2cFault)); + return Err(self.a0_failure(err)); } ringbuf_entry!(Trace::RailsOn); @@ -890,7 +890,7 @@ impl ServerImpl { } if sys_get_timer().now > deadline { - return Err(self.a0_failure(SeqError::A0Timeout)); + return Err(self.a0_failure(A0Failure::A0Timeout)); } hl::sleep_for(1); @@ -984,12 +984,38 @@ impl ServerImpl { } } - fn a0_failure(&mut self, err: SeqError) -> SeqError { + fn a0_failure(&mut self, err: A0Failure) -> SeqError { + #[derive(Serialize)] + struct Ereport { + #[serde(rename = "k")] + class: EreportClass, + #[serde(rename = "v")] + version: u32, + seq_status: SeqStatus, + refdes: &'static str, + #[serde(skip_serializing_if = "Option::is_none")] + i2c_err: Option, + #[serde(skip_serializing_if = "Option::is_none")] + coretype: Option, + #[serde(skip_serializing_if = "Option::is_none")] + rail: Option<&'static str>, + } + + #[derive(Serialize)] + struct SeqStatus { + ifr: u8, + dbg_max_a0smstatus: u8, + max_groupb_pg: u8, + max_groupc_pg: u8, + flt_a0_smstatus: u8, + flt_groupb_pg: u8, + flt_groupc_pg: u8, + } + let record_reg = |addr| { - ringbuf_entry!(Trace::A0FailureDetails( - addr, - self.seq.read_byte(addr).unwrap_lite(), - )); + let byte = self.seq.read_byte(addr).unwrap_lite(); + ringbuf_entry!(Trace::A0FailureDetails(addr, byte)); + byte }; // @@ -997,13 +1023,15 @@ impl ServerImpl { // buffer to allow this to be debugged. // ringbuf_entry!(Trace::A0Failed(err)); - record_reg(Addr::IFR); - record_reg(Addr::DBG_MAX_A0SMSTATUS); - record_reg(Addr::MAX_GROUPB_PG); - record_reg(Addr::MAX_GROUPC_PG); - record_reg(Addr::FLT_A0_SMSTATUS); - record_reg(Addr::FLT_GROUPB_PG); - record_reg(Addr::FLT_GROUPC_PG); + let seq_status = Seqstatus { + ifr: record_reg(Addr::IFR), + dbg_max_a0smstatus: record_reg(Addr::DBG_MAX_A0SMSTATUS), + max_groupb_pg: record_reg(Addr::MAX_GROUPB_PG), + max_groupc_pg: record_reg(Addr::MAX_GROUPC_PG), + flt_a0_smstatus: record_reg(Addr::FLT_A0_SMSTATUS), + flt_groupb_pg: record_reg(Addr::FLT_GROUPB_PG), + flt_groupc_pg: record_reg(Addr::FLT_GROUPC_PG), + }; // // Now put ourselves back in A2. @@ -1017,6 +1045,88 @@ impl ServerImpl { let _ = vcore_soc_off(); _ = self.hf.set_mux(hf_api::HfMuxState::SP); + let (ereport, err) = match err { + A0Failure::A1Timeout => { + let ereport = Ereport { + class: EreportClass::A1Timeout, + version: 0, + refdes: "", // TODO(eliza): seq + seq_status, + i2c_err: None, + coretype: None, + rail: None, + }; + (ereport, SeqError::A1Timeout) + } + A0Failure::A0Timeout => { + let ereport = Ereport { + class: EreportClass::A0Timeout, + version: 0, + refdes: "", // TODO(eliza): seq + seq_status, + i2c_err: None, + coretype: None, + rail: None, + }; + (ereport, SeqError::A0Timeout) + } + A0Failure::A0TimeoutGroupC => { + let ereport = Ereport { + class: EreportClass::A0TimeoutGroupC, + version: 0, + refdes: "", // TODO(eliza): seq + seq_status, + i2c_err: None, + coretype: None, + rail: None, + }; + (ereport, SeqError::A0TimeoutGroupC) + } + A0Failure::UnrecognizedCPU(coretype) => { + let ereport = Ereport { + class: EreportClass::UnrecognizedCPU, + version: 0, + refdes: "P0", // host CPU + seq_status, + i2c_err: None, + coretype: Some(coretype), + rail: None, + }; + (ereport, SeqError::UnrecognizedCPU) + } + A0Failure::NoCPUPresent => { + let ereport = Ereport { + class: EreportClass::NoCpuPresent, + version: 0, + refdes: "P0", // host CPU + seq_status, + i2c_err: None, + coretype: None, + rail: None, + }; + (ereport, SeqError::NoCPUPresent) + } + A0Failure::I2cFault { refdes, rail, err } => { + let ereport = Ereport { + class: EreportClass::NoCpuPresent, + version: 0, + refdes, // whichever VRM nacked us, basically... + seq_status, + i2c_err: Some(err), + coretype: None, + rail: Some(rail), + }; + (ereport, SeqError::I2cFault) + } + }; + + deliver_ereport( + ereport.class, + &ereport, + &self.packrat, + self.ereport_buf, + ); + err } @@ -1310,12 +1420,48 @@ fn read_spd_data_and_load_packrat( Ok(()) } +#[derive(Copy, Clone, Count, Eq, PartialEq)] +enum A0Failure { + UnrecognizedCPU(Coretype), + NoCPUPresent, + A1Timeout, + A0Timeout, + A0TimeoutGroupC, + I2cFault { + refdes: &'static str, + rail: &'static str, + #[count(children)] + err: i2c::ResponseCode, + }, +} + +#[derive(Copy, Clone, Serialize)] +struct Coretype { + coretype: bool, + sp3r1: bool, + sp3r2: bool, +} + #[derive(Eq, PartialEq, Copy, Clone, Serialize, Count)] pub(crate) enum EreportClass { #[serde(rename = "hw.cpu.thermtrip")] Thermtrip, #[serde(rename = "hw.pwr.pmbus.alert")] PmbusAlert, + + #[serde(rename = "hw.cpu.a0_fail.unknown")] + UnrecognizedCPU, + #[serde(rename = "hw.cpu.a0_fail.no_cpu")] + NoCPUPresent, + + #[serde(rename = "hw.a0_fail.timeout.a1")] + A1Timeout, + #[serde(rename = "hw.a0_fail.timeout.a0")] + A0Timeout, + #[serde(rename = "hw.a0_fail.timeout.groupc")] + A0TimeoutGroupC, + #[serde(rename = "hw.pwr.pmbus.a0_fail.i2c_err")] + I2cFault, } pub(crate) fn deliver_ereport( @@ -1484,7 +1630,7 @@ cfg_if::cfg_if! { Ok(()) } - fn vcore_soc_on() -> Result<(), i2c::ResponseCode> { + fn vcore_soc_on() -> Result<(), A0Failure> { use drv_i2c_devices::raa229618::Raa229618; let i2c = I2C.get_task_id(); @@ -1494,8 +1640,18 @@ cfg_if::cfg_if! { let (device, rail) = i2c_config::pmbus::vddcr_soc(i2c); let mut vddcr_soc = Raa229618::new(&device, rail); - retry_i2c_txn(I2cTxn::VCoreOn, || vdd_vcore.turn_on())?; - retry_i2c_txn(I2cTxn::SocOn, || vddcr_soc.turn_on())?; + retry_i2c_txn(I2cTxn::VCoreOn, || vdd_vcore.turn_on()) + .map_err(|err| A0Failure::I2cFault { + refdes: vdd_vcore.component_id(), + rail: "VDD_VCORE", + err, + })?; + retry_i2c_txn(I2cTxn::SocOn, || vddcr_soc.turn_on()) + .map_err(|err| A0Failure::I2cFault { + refdes: vddcr_soc.component_id(), + rail: "VDDCR_SOC", + err, + })?; Ok(()) } From 196a795baede6bfbd334c0967679e4445bc5163d Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 2 Oct 2025 10:26:09 -0700 Subject: [PATCH 3/8] wip --- drv/gimlet-seq-server/src/main.rs | 288 ++++++++++++----------------- drv/gimlet-seq-server/src/vcore.rs | 20 ++ 2 files changed, 141 insertions(+), 167 deletions(-) diff --git a/drv/gimlet-seq-server/src/main.rs b/drv/gimlet-seq-server/src/main.rs index cdd87265d..89d32249e 100644 --- a/drv/gimlet-seq-server/src/main.rs +++ b/drv/gimlet-seq-server/src/main.rs @@ -11,6 +11,7 @@ mod seq_spi; mod vcore; use counters::*; +use microcbor::StaticCborLen; use ringbuf::*; use userlib::{ hl, set_timer_relative, sys_get_timer, sys_recv_notification, @@ -216,39 +217,40 @@ struct ServerImpl { } const TIMER_INTERVAL: u32 = 10; -const EREPORT_BUF_LEN: usize = as microcbor::StaticCborLen>::MAX_CBOR_LEN; +const EREPORT_BUF_LEN: usize = microcbor::max_cbor_len_for![ + Ereport, + Ereport, + Ereport, +]; -#[derive(microcbor::Encode)] +#[derive(Copy, Clone, Eq, PartialEq, microcbor::Encode, counters::Count)] pub enum EreportClass { + #[cbor(rename = "hw.cpu.thermtrip")] + Thermtrip, #[cbor(rename = "hw.pwr.pmbus.alert")] PmbusAlert, -} -#[derive(microcbor::EncodeFields)] -pub(crate) enum EreportKind { - PmbusAlert { - refdes: fixedstr::FixedStr<{ crate::i2c_config::MAX_COMPONENT_ID_LEN }>, - rail: &'static fixedstr::FixedStr<10>, - time: u64, - pwr_good: Option, - pmbus_status: PmbusStatus, - }, -} + #[cbor(rename = "hw.cpu.a0_fail.unknown")] + UnrecognizedCPU, + #[cbor(rename = "hw.cpu.a0_fail.no_cpu")] + NoCPUPresent, -#[derive(Copy, Clone, Default, microcbor::Encode)] -pub(crate) struct PmbusStatus { - word: Option, - input: Option, - iout: Option, - vout: Option, - temp: Option, - cml: Option, - mfr: Option, + #[cbor(rename = "hw.a0_fail.timeout.a1")] + A1Timeout, + #[cbor(rename = "hw.a0_fail.timeout.a0")] + A0Timeout, + #[cbor(rename = "hw.a0_fail.timeout.groupc")] + A0TimeoutGroupC, + #[cbor(rename = "hw.pwr.pmbus.a0_fail.i2c_err")] + I2cFault, } +// TODO(eliza): can we get this from the `gateway-sp-messages` crate? +static HOST_CPU_DEV_ID: FixedStr<16> =FixedStr::from_str("sp3-host-cpu"); +static HOST_CPU_REFDES: FixedStr< + { crate::i2c_config::MAX_COMPONENT_ID_LEN }, +> = FixedStr::from_str("P0"); + impl ServerImpl { fn init( sys: &sys_api::Sys, @@ -1016,33 +1018,6 @@ impl ServerImpl { } fn a0_failure(&mut self, err: A0Failure) -> SeqError { - #[derive(Serialize)] - struct Ereport { - #[serde(rename = "k")] - class: EreportClass, - #[serde(rename = "v")] - version: u32, - seq_status: SeqStatus, - refdes: &'static str, - #[serde(skip_serializing_if = "Option::is_none")] - i2c_err: Option, - #[serde(skip_serializing_if = "Option::is_none")] - coretype: Option, - #[serde(skip_serializing_if = "Option::is_none")] - rail: Option<&'static str>, - } - - #[derive(Serialize)] - struct SeqStatus { - ifr: u8, - dbg_max_a0smstatus: u8, - max_groupb_pg: u8, - max_groupc_pg: u8, - flt_a0_smstatus: u8, - flt_groupb_pg: u8, - flt_groupc_pg: u8, - } - let record_reg = |addr| { let byte = self.seq.read_byte(addr).unwrap_lite(); ringbuf_entry!(Trace::A0FailureDetails(addr, byte)); @@ -1076,84 +1051,49 @@ impl ServerImpl { let _ = vcore_soc_off(); _ = self.hf.set_mux(hf_api::HfMuxState::SP); - let (ereport, err) = match err { - A0Failure::A1Timeout => { - let ereport = Ereport { - class: EreportClass::A1Timeout, - version: 0, - refdes: "", // TODO(eliza): seq - seq_status, - i2c_err: None, - coretype: None, - rail: None, - }; - (ereport, SeqError::A1Timeout) - } - A0Failure::A0Timeout => { - let ereport = Ereport { - class: EreportClass::A0Timeout, - version: 0, - refdes: "", // TODO(eliza): seq - seq_status, - i2c_err: None, - coretype: None, - rail: None, - }; - (ereport, SeqError::A0Timeout) - } - A0Failure::A0TimeoutGroupC => { - let ereport = Ereport { - class: EreportClass::A0TimeoutGroupC, - version: 0, - refdes: "", // TODO(eliza): seq - seq_status, - i2c_err: None, - coretype: None, - rail: None, - }; - (ereport, SeqError::A0TimeoutGroupC) - } - A0Failure::UnrecognizedCPU(coretype) => { - let ereport = Ereport { - class: EreportClass::UnrecognizedCPU, - version: 0, - refdes: "P0", // host CPU - seq_status, - i2c_err: None, - coretype: Some(coretype), - rail: None, - }; - (ereport, SeqError::UnrecognizedCPU) - } - A0Failure::NoCPUPresent => { - let ereport = Ereport { - class: EreportClass::NoCpuPresent, - version: 0, - refdes: "P0", // host CPU - seq_status, - i2c_err: None, - coretype: None, - rail: None, - }; - (ereport, SeqError::NoCPUPresent) - } - A0Failure::I2cFault { refdes, rail, err } => { - let ereport = Ereport { - class: EreportClass::NoCpuPresent, - version: 0, - refdes, // whichever VRM nacked us, basically... - seq_status, - i2c_err: Some(err), - coretype: None, - rail: Some(rail), - }; - (ereport, SeqError::I2cFault) - } + let (ereport_class, ereport_details, err) = match err { + A0Failure::A1Timeout => ( + EreportClass::A1Timeout, + A0FailureDetails::RefdesOnly { refdes: None }, + SeqError::A1Timeout, + ), + A0Failure::A0Timeout => ( + EreportClass::A0Timeout, + A0FailureDetails::RefdesOnly { refdes: None }, + SeqError::A1Timeout, + ), + A0Failure::A0TimeoutGroupC => ( + EreportClass::A0TimeoutGroupC, + A0FailureDetails::RefdesOnly { refdes: None }, + SeqErr::A0TimeoutGroupC, + ), + A0Failure::UnrecognizedCPU(coretype) => ( + EreportClass::UnrecognizedCPU, + A0FailureDetails::Coretype { + coretype, + refdes: HOST_CPU_REFDES, + dev_id: &HOST_CPU_DEV_ID, + }, + SeqErr::UnrecognizedCPU), + ), + A0Failure::NoCPUPresent => (EreportClass::NoCpuPresent, A0FailureDetails::RefdesDevId { refdes: RefdesDevId { refdes: HOST_CPU_REFDES, + dev_id: &HOST_CPU_DEV_ID, + )}, SeqErr::NoCPUPresent), + A0Failure::I2cFault { refdes, rail, err } => ( + EreportClass::I2cFault, + A0FailureDetails::I2c { refdes: FixedStr::from_str(refdes), rail: FixedStr::from_str(rail), i2c_err: err.into() }, + SeqError::I2cFault(err),), }; deliver_ereport( - ereport.class, - &ereport, + &Ereport { + class: EreportClass, + version: 0, + data: A0FailureEreport { + details, + seq_status, + } + }, &self.packrat, self.ereport_buf, ); @@ -1178,21 +1118,15 @@ impl ServerImpl { refdes: "P0", // host CPU }; deliver_ereport( - ereport.class, - &ereport, + &Ereport { + class: EreportClass::Thermtrip, + version: 0, + data: EreportCl + } &self.packrat, self.ereport_buf, ); } - - #[derive(serde::Serialize)] - struct ThermtripEreport { - #[serde(rename = "k")] - class: EreportClass, - #[serde(rename = "v")] - version: u32, - refdes: &'static str, - } } // @@ -1466,48 +1400,68 @@ enum A0Failure { }, } -#[derive(Copy, Clone, Serialize)] -struct Coretype { - coretype: bool, - sp3r1: bool, - sp3r2: bool, +#[derive(microcbor::Encode)] +struct A0FailureEreport { + seq_status: SeqStatus, + #[cbor(flatten)] + details: A0FailureDetails, } -#[derive(Eq, PartialEq, Copy, Clone, Serialize, Count)] -pub(crate) enum EreportClass { - #[serde(rename = "hw.cpu.thermtrip")] - Thermtrip, - #[serde(rename = "hw.pwr.pmbus.alert")] - PmbusAlert, +#[derive(microcbor::EncodeFields)] +enum A0FailureDetails { + RefdesOnly { + #[cbor(skip_if_nil)] + refdes: Option>, + }, - #[serde(rename = "hw.cpu.a0_fail.unknown")] - UnrecognizedCPU, - #[serde(rename = "hw.cpu.a0_fail.no_cpu")] - NoCPUPresent, + RefdesDevId { + #[cbor(skip_if_nil)] + refdes: FixedStr<{ i2c_config::MAX_COMPONENT_ID_LEN }>, + dev_id: &'static FixedStr<{ 16 }>, + }, + Coretype { + refdes: FixedStr<{ i2c_config::MAX_COMPONENT_ID_LEN }>, + dev_id: &'static FixedStr<{ 16 }>, + #[cbor(flatten)] + coretype: Coretype, + }, + I2c { + refdes: FixedStr<{ i2c_config::MAX_COMPONENT_ID_LEN }>, + rail: &'static FixedStr<{ 16 }>, + i2c_err: u8, + }, +} - #[serde(rename = "hw.a0_fail.timeout.a1")] - A1Timeout, - #[serde(rename = "hw.a0_fail.timeout.a0")] - A0Timeout, - #[serde(rename = "hw.a0_fail.timeout.groupc")] - A0TimeoutGroupC, - #[serde(rename = "hw.pwr.pmbus.a0_fail.i2c_err")] - I2cFault, +#[derive(microcbor::Encode)] +struct SeqStatus { + ifr: u8, + dbg_max_a0smstatus: u8, + max_groupb_pg: u8, + max_groupc_pg: u8, + flt_a0_smstatus: u8, + flt_groupb_pg: u8, + flt_groupc_pg: u8, +} + +#[derive(Copy, Clone, microcbor::EncodeFields)] +struct Coretype { + coretype: bool, + sp3r1: bool, + sp3r2: bool, } -pub(crate) fn deliver_ereport( - class: EreportClass, - ereport: &impl Serialize, +pub(crate) fn deliver_ereport( + ereport: &Ereport, packrat: &Packrat, buf: &mut [u8], ) { match packrat.serialize_ereport(ereport, buf) { - Ok(len) => ringbuf_entry!(Trace::EreportSent(class, len)), + Ok(len) => ringbuf_entry!(Trace::EreportSent(ereport.class, len)), Err(task_packrat_api::EreportSerializeError::Packrat { len, err }) => { - ringbuf_entry!(Trace::EreportLost(class, len, err)) + ringbuf_entry!(Trace::EreportLost(ereport.class, len, err)) } Err(task_packrat_api::EreportSerializeError::Serialize(_)) => { - ringbuf_entry!(Trace::EreportTooBig(class)) + ringbuf_entry!(Trace::EreportTooBig(ereport.class)) } } } diff --git a/drv/gimlet-seq-server/src/vcore.rs b/drv/gimlet-seq-server/src/vcore.rs index 663baaae2..f459e94b2 100644 --- a/drv/gimlet-seq-server/src/vcore.rs +++ b/drv/gimlet-seq-server/src/vcore.rs @@ -42,6 +42,26 @@ pub struct VCore { sys: sys_api::Sys, } +#[derive(microcbor::EncodeFields)] +pub(super) struct PmbusEreport { + refdes: fixedstr::FixedStr<{ crate::i2c_config::MAX_COMPONENT_ID_LEN }>, + rail: &'static fixedstr::FixedStr<10>, + time: u64, + pwr_good: Option, + pmbus_status: PmbusStatus, +} + +#[derive(Copy, Clone, Default, microcbor::Encode)] +struct PmbusStatus { + word: Option, + input: Option, + iout: Option, + vout: Option, + temp: Option, + cml: Option, + mfr: Option, +} + #[derive(Copy, Clone, PartialEq)] enum Trace { None, From 4a7f3d3b469b433c067cc4ffb821e4dfd89924ce Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 3 Oct 2025 10:54:08 -0700 Subject: [PATCH 4/8] wip --- drv/gimlet-seq-server/src/main.rs | 149 ++++++++++++++++++------------ lib/microcbor/src/lib.rs | 15 +++ 2 files changed, 107 insertions(+), 57 deletions(-) diff --git a/drv/gimlet-seq-server/src/main.rs b/drv/gimlet-seq-server/src/main.rs index 0cbded2c5..38d302a15 100644 --- a/drv/gimlet-seq-server/src/main.rs +++ b/drv/gimlet-seq-server/src/main.rs @@ -220,8 +220,8 @@ struct ServerImpl { const TIMER_INTERVAL: u32 = 10; const EREPORT_BUF_LEN: usize = microcbor::max_cbor_len_for![ Ereport, - Ereport, - Ereport, + A0FailureEreport, + Ereport, ]; #[derive(Copy, Clone, Eq, PartialEq, microcbor::Encode, counters::Count)] @@ -247,10 +247,7 @@ pub enum EreportClass { } // TODO(eliza): can we get this from the `gateway-sp-messages` crate? -static HOST_CPU_DEV_ID: FixedStr<16> =FixedStr::from_str("sp3-host-cpu"); -static HOST_CPU_REFDES: FixedStr< - { crate::i2c_config::MAX_COMPONENT_ID_LEN }, -> = FixedStr::from_str("P0"); +static HOST_CPU_DEV_ID: FixedStr<16> = FixedStr::from_str("sp3-host-cpu"); impl ServerImpl { fn init( @@ -1055,45 +1052,53 @@ impl ServerImpl { let (ereport_class, ereport_details, err) = match err { A0Failure::A1Timeout => ( EreportClass::A1Timeout, - A0FailureDetails::RefdesOnly { refdes: None }, + A0FailureDetails::A1Timeout { version: 0 }, SeqError::A1Timeout, ), A0Failure::A0Timeout => ( EreportClass::A0Timeout, - A0FailureDetails::RefdesOnly { refdes: None }, + A0FailureDetails::A0Timeout { version: 0 }, SeqError::A1Timeout, ), A0Failure::A0TimeoutGroupC => ( EreportClass::A0TimeoutGroupC, - A0FailureDetails::RefdesOnly { refdes: None }, - SeqErr::A0TimeoutGroupC, + A0FailureDetails::A0TimeoutGroupC, + SeqError::A0TimeoutGroupC, ), A0Failure::UnrecognizedCPU(coretype) => ( EreportClass::UnrecognizedCPU, - A0FailureDetails::Coretype { + A0FailureDetails::UnrecognizedCPU { + version: 0, coretype, - refdes: HOST_CPU_REFDES, - dev_id: &HOST_CPU_DEV_ID, + refdes: HostCpuRefdes::HOST_CPU_REFDES, }, - SeqErr::UnrecognizedCPU), + SeqError::UnrecognizedCPU, + ), + A0Failure::NoCPUPresent => ( + EreportClass::NoCPUPresent, + A0FailureDetails::NoCpuPresent { + version: 0, + refdes: HostCpuRefdes::HOST_CPU_REFDES, + }, + SeqError::NoCPUPresent, ), - A0Failure::NoCPUPresent => (EreportClass::NoCpuPresent, A0FailureDetails::RefdesDevId { refdes: RefdesDevId { refdes: HOST_CPU_REFDES, - dev_id: &HOST_CPU_DEV_ID, - )}, SeqErr::NoCPUPresent), A0Failure::I2cFault { refdes, rail, err } => ( EreportClass::I2cFault, - A0FailureDetails::I2c { refdes: FixedStr::from_str(refdes), rail: FixedStr::from_str(rail), i2c_err: err.into() }, - SeqError::I2cFault(err),), + A0FailureDetails::I2c { + version: 0, + refdes: FixedStr::from_str(refdes), + rail: FixedStr::try_from_str(rail).ok(), + i2c_err: err.into(), + }, + SeqError::I2cFault(err), + ), }; deliver_ereport( - &Ereport { - class: EreportClass, - version: 0, - data: A0FailureEreport { - details, - seq_status, - } + ereport_class, + &A0FailureEreport { + details: ereport_details, + seq_status, }, &self.packrat, self.ereport_buf, @@ -1113,18 +1118,13 @@ impl ServerImpl { if ifr & thermtrip != 0 { self.seq.clear_bytes(Addr::IFR, &[thermtrip]).unwrap_lite(); self.update_state_internal(PowerState::A0Thermtrip); - let ereport = ThermtripEreport { - class: EreportClass::Thermtrip, - version: 0, - refdes: "P0", // host CPU - }; deliver_ereport( + EreportClass::Thermtrip, &Ereport { class: EreportClass::Thermtrip, version: 0, - data: EreportCl - } - &self.packrat, + data: &HostCpuRefdes::HOST_CPU_REFDES, + } & self.packrat, self.ereport_buf, ); } @@ -1434,33 +1434,54 @@ enum A0Failure { #[derive(microcbor::Encode)] struct A0FailureEreport { - seq_status: SeqStatus, #[cbor(flatten)] details: A0FailureDetails, + seq_status: SeqStatus, } #[derive(microcbor::EncodeFields)] +#[cbor(variant_id = "k")] enum A0FailureDetails { - RefdesOnly { - #[cbor(skip_if_nil)] - refdes: Option>, - }, - - RefdesDevId { - #[cbor(skip_if_nil)] - refdes: FixedStr<{ i2c_config::MAX_COMPONENT_ID_LEN }>, - dev_id: &'static FixedStr<{ 16 }>, - }, - Coretype { - refdes: FixedStr<{ i2c_config::MAX_COMPONENT_ID_LEN }>, - dev_id: &'static FixedStr<{ 16 }>, + #[cbor(rename = "hw.cpu.a0_fail.unknown")] + UnrecognizedCPU { + #[cbor(rename = "v")] + version: u32, + #[cbor(flatten)] + refdes: &'static HostCpuRefdes, #[cbor(flatten)] coretype: Coretype, }, - I2c { - refdes: FixedStr<{ i2c_config::MAX_COMPONENT_ID_LEN }>, - rail: &'static FixedStr<{ 16 }>, - i2c_err: u8, + #[cbor(rename = "hw.cpu.a0_fail.no_cpu")] + NoCPUPresent { + #[cbor(rename = "v")] + version: u32, + #[cbor(flatten)] + refdes: &'static HostCpuRefdes, + }, + #[cbor(rename = "hw.a0_fail.timeout.a1")] + A1Timeout { + #[cbor(rename = "v")] + version: u32, + }, + #[cbor(rename = "hw.a0_fail.timeout.a0")] + A0Timeout { + #[cbor(rename = "v")] + version: u32, + }, + #[cbor(rename = "hw.a0_fail.timeout.groupc")] + A0TimeoutGroupC { + #[cbor(rename = "v")] + version: u32, + }, + #[cbor(rename = "hw.pwr.pmbus.a0_fail.i2c_err")] + I2cErr { + #[cbor(rename = "v")] + version: u32, + refdes: FixedStr<{ i2c_config::MAX_DEVICE_ID_LEN }>, + // TODO(eliza): max rail len... + #[cbor(skip_if_nil)] + rail: Option>, + i2c_err: u32, }, } @@ -1482,18 +1503,32 @@ struct Coretype { sp3r2: bool, } -pub(crate) fn deliver_ereport( - ereport: &Ereport, +#[derive(microcbor::EncodeFields)] +struct HostCpuRefdes { + refdes: FixedStr<2>, + dev_id: FixedStr<16>, +} + +impl HostCpuRefdes { + static HOST_CPU_REFDES: HostCpuRefdes = HostCpuRefdes { + refdes: FixedStr::from("P0"), + dev_id: FixedStr::from("sp3-host-cpu"), + }; +} + +pub(crate) fn deliver_ereport( + class: EreportClass, + ereport: &E, packrat: &Packrat, buf: &mut [u8], ) { match packrat.serialize_ereport(ereport, buf) { - Ok(len) => ringbuf_entry!(Trace::EreportSent(ereport.class, len)), + Ok(len) => ringbuf_entry!(Trace::EreportSent(class, len)), Err(task_packrat_api::EreportSerializeError::Packrat { len, err }) => { - ringbuf_entry!(Trace::EreportLost(ereport.class, len, err)) + ringbuf_entry!(Trace::EreportLost(class, len, err)) } Err(task_packrat_api::EreportSerializeError::Serialize(_)) => { - ringbuf_entry!(Trace::EreportTooBig(ereport.class)) + ringbuf_entry!(Trace::EreportTooBig(class)) } } } diff --git a/lib/microcbor/src/lib.rs b/lib/microcbor/src/lib.rs index ba7858a2c..f61d5dd01 100644 --- a/lib/microcbor/src/lib.rs +++ b/lib/microcbor/src/lib.rs @@ -148,6 +148,21 @@ pub trait EncodeFields { ) -> Result<(), encode::Error>; } +impl EncodeFields for &T +where + T: EncodeFields, +{ + const MAX_FIELDS_LEN: usize = T::MAX_FIELDS_LEN; + + fn encode_fields( + &self, + e: &mut Encoder, + c: &mut C, + ) -> Result<(), encode::Error> { + T::encode_fields(self, e, c) + } +} + #[cfg(feature = "fixedstr")] impl StaticCborLen for fixedstr::FixedStr { const MAX_CBOR_LEN: usize = LEN + usize::MAX_CBOR_LEN; From 578ed4a229c211871ede7e6dee3dbcd7e8bd38ea Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Tue, 7 Oct 2025 11:47:14 -0700 Subject: [PATCH 5/8] okay there we go --- app/gimlet/base.toml | 2 +- drv/gimlet-seq-server/Cargo.toml | 1 - drv/gimlet-seq-server/src/main.rs | 184 +++++++++++++++-------------- drv/gimlet-seq-server/src/vcore.rs | 36 +----- 4 files changed, 101 insertions(+), 122 deletions(-) diff --git a/app/gimlet/base.toml b/app/gimlet/base.toml index b7133df17..0ee610265 100644 --- a/app/gimlet/base.toml +++ b/app/gimlet/base.toml @@ -163,7 +163,7 @@ name = "drv-gimlet-seq-server" features = ["h753"] priority = 4 max-sizes = {flash = 131072, ram = 16384 } -stacksize = 2600 +stacksize = 2912 start = true task-slots = ["sys", "i2c_driver", {spi_driver = "spi2_driver"}, "hf", "jefe", "packrat"] notifications = ["timer", "vcore"] diff --git a/drv/gimlet-seq-server/Cargo.toml b/drv/gimlet-seq-server/Cargo.toml index bef21f575..758813ce9 100644 --- a/drv/gimlet-seq-server/Cargo.toml +++ b/drv/gimlet-seq-server/Cargo.toml @@ -33,7 +33,6 @@ zerocopy-derive = { workspace = true } num-derive = { workspace = true } static_assertions = { workspace = true } spd = { workspace = true } -serde = { workspace = true } pmbus = { workspace = true } [build-dependencies] diff --git a/drv/gimlet-seq-server/src/main.rs b/drv/gimlet-seq-server/src/main.rs index 38d302a15..3dfff115e 100644 --- a/drv/gimlet-seq-server/src/main.rs +++ b/drv/gimlet-seq-server/src/main.rs @@ -11,7 +11,6 @@ mod seq_spi; mod vcore; use counters::*; -use microcbor::StaticCborLen; use ringbuf::*; use userlib::{ hl, set_timer_relative, sys_get_timer, sys_recv_notification, @@ -26,9 +25,9 @@ use drv_ice40_spi_program as ice40; use drv_packrat_vpd_loader::{read_vpd_and_load_packrat, Packrat}; use drv_spi_api::{SpiDevice, SpiServer}; use drv_stm32xx_sys_api as sys_api; +use fixedstr::FixedStr; use idol_runtime::{NotificationHandler, RequestError}; use seq_spi::{Addr, Reg}; -use serde::Serialize; use static_assertions::const_assert; use task_jefe_api::Jefe; @@ -219,11 +218,13 @@ struct ServerImpl { const TIMER_INTERVAL: u32 = 10; const EREPORT_BUF_LEN: usize = microcbor::max_cbor_len_for![ - Ereport, - A0FailureEreport, - Ereport, + Ereport, + Ereport, + Ereport<&'static HostCpuRefdes>, ]; +type Ereport = task_packrat_api::Ereport; + #[derive(Copy, Clone, Eq, PartialEq, microcbor::Encode, counters::Count)] pub enum EreportClass { #[cbor(rename = "hw.cpu.thermtrip")] @@ -246,9 +247,6 @@ pub enum EreportClass { I2cFault, } -// TODO(eliza): can we get this from the `gateway-sp-messages` crate? -static HOST_CPU_DEV_ID: FixedStr<16> = FixedStr::from_str("sp3-host-cpu"); - impl ServerImpl { fn init( sys: &sys_api::Sys, @@ -844,7 +842,7 @@ impl ServerImpl { ringbuf_entry!(Trace::CPUPresent(present)); if !present { - return Err(self.a0_failure(A0Failure::CPUNotPresent)); + return Err(self.a0_failure(A0Failure::NoCPUPresent)); } let coretype = sys.gpio_read(CORETYPE) != 0; @@ -864,7 +862,13 @@ impl ServerImpl { // to be low (VSS on Type-0/Type-1/Type-2). // if !coretype || !sp3r1 || sp3r2 { - return Err(self.a0_failure(SeqError::UnrecognizedCPU)); + return Err(self.a0_failure(A0Failure::UnrecognizedCPU( + Coretype { + coretype, + sp3r1, + sp3r2, + }, + ))); } // @@ -1027,7 +1031,7 @@ impl ServerImpl { // buffer to allow this to be debugged. // ringbuf_entry!(Trace::A0Failed(err)); - let seq_status = Seqstatus { + let seq_status = SeqStatus { ifr: record_reg(Addr::IFR), dbg_max_a0smstatus: record_reg(Addr::DBG_MAX_A0SMSTATUS), max_groupb_pg: record_reg(Addr::MAX_GROUPB_PG), @@ -1049,60 +1053,87 @@ impl ServerImpl { let _ = vcore_soc_off(); _ = self.hf.set_mux(hf_api::HfMuxState::SP); - let (ereport_class, ereport_details, err) = match err { + let (ereport, err) = match err { A0Failure::A1Timeout => ( - EreportClass::A1Timeout, - A0FailureDetails::A1Timeout { version: 0 }, + Ereport { + class: EreportClass::A1Timeout, + version: 0, + report: A0FailureEreport { + seq_status, + details: None, + }, + }, SeqError::A1Timeout, ), A0Failure::A0Timeout => ( - EreportClass::A0Timeout, - A0FailureDetails::A0Timeout { version: 0 }, + Ereport { + class: EreportClass::A0Timeout, + version: 0, + report: A0FailureEreport { + seq_status, + details: None, + }, + }, SeqError::A1Timeout, ), A0Failure::A0TimeoutGroupC => ( - EreportClass::A0TimeoutGroupC, - A0FailureDetails::A0TimeoutGroupC, + Ereport { + class: EreportClass::A0TimeoutGroupC, + version: 0, + report: A0FailureEreport { + seq_status, + details: None, + }, + }, SeqError::A0TimeoutGroupC, ), A0Failure::UnrecognizedCPU(coretype) => ( - EreportClass::UnrecognizedCPU, - A0FailureDetails::UnrecognizedCPU { + Ereport { + class: EreportClass::A1Timeout, version: 0, - coretype, - refdes: HostCpuRefdes::HOST_CPU_REFDES, + report: A0FailureEreport { + seq_status, + details: Some(A0FailureDetails::UnrecognizedCPU { + coretype, + refdes: &HOST_CPU_REFDES, + }), + }, }, SeqError::UnrecognizedCPU, ), A0Failure::NoCPUPresent => ( - EreportClass::NoCPUPresent, - A0FailureDetails::NoCpuPresent { + Ereport { + class: EreportClass::A1Timeout, version: 0, - refdes: HostCpuRefdes::HOST_CPU_REFDES, + report: A0FailureEreport { + seq_status, + details: Some(A0FailureDetails::NoCPUPresent { + refdes: &HOST_CPU_REFDES, + }), + }, }, - SeqError::NoCPUPresent, + SeqError::CPUNotPresent, ), A0Failure::I2cFault { refdes, rail, err } => ( - EreportClass::I2cFault, - A0FailureDetails::I2c { + Ereport { + class: EreportClass::I2cFault, version: 0, - refdes: FixedStr::from_str(refdes), - rail: FixedStr::try_from_str(rail).ok(), - i2c_err: err.into(), + report: A0FailureEreport { + seq_status, + details: Some(A0FailureDetails::I2cErr { + i2c_err: err.into(), + // refdes is guaranteed to be <= + // MAX_COMPONENT_ID_LEN, so this will never panic. + refdes: FixedStr::from_str(refdes), + rail: FixedStr::try_from_str(rail).ok(), + }), + }, }, - SeqError::I2cFault(err), + SeqError::I2cFault, ), }; - deliver_ereport( - ereport_class, - &A0FailureEreport { - details: ereport_details, - seq_status, - }, - &self.packrat, - self.ereport_buf, - ); + deliver_ereport(&ereport, &self.packrat, self.ereport_buf); err } @@ -1119,12 +1150,12 @@ impl ServerImpl { self.seq.clear_bytes(Addr::IFR, &[thermtrip]).unwrap_lite(); self.update_state_internal(PowerState::A0Thermtrip); deliver_ereport( - EreportClass::Thermtrip, &Ereport { class: EreportClass::Thermtrip, version: 0, - data: &HostCpuRefdes::HOST_CPU_REFDES, - } & self.packrat, + report: &HOST_CPU_REFDES, + }, + &self.packrat, self.ereport_buf, ); } @@ -1432,52 +1463,27 @@ enum A0Failure { }, } -#[derive(microcbor::Encode)] +#[derive(microcbor::EncodeFields)] struct A0FailureEreport { #[cbor(flatten)] - details: A0FailureDetails, + details: Option, seq_status: SeqStatus, } #[derive(microcbor::EncodeFields)] -#[cbor(variant_id = "k")] enum A0FailureDetails { - #[cbor(rename = "hw.cpu.a0_fail.unknown")] UnrecognizedCPU { - #[cbor(rename = "v")] - version: u32, #[cbor(flatten)] refdes: &'static HostCpuRefdes, #[cbor(flatten)] coretype: Coretype, }, - #[cbor(rename = "hw.cpu.a0_fail.no_cpu")] NoCPUPresent { - #[cbor(rename = "v")] - version: u32, #[cbor(flatten)] refdes: &'static HostCpuRefdes, }, - #[cbor(rename = "hw.a0_fail.timeout.a1")] - A1Timeout { - #[cbor(rename = "v")] - version: u32, - }, - #[cbor(rename = "hw.a0_fail.timeout.a0")] - A0Timeout { - #[cbor(rename = "v")] - version: u32, - }, - #[cbor(rename = "hw.a0_fail.timeout.groupc")] - A0TimeoutGroupC { - #[cbor(rename = "v")] - version: u32, - }, - #[cbor(rename = "hw.pwr.pmbus.a0_fail.i2c_err")] I2cErr { - #[cbor(rename = "v")] - version: u32, - refdes: FixedStr<{ i2c_config::MAX_DEVICE_ID_LEN }>, + refdes: FixedStr<{ i2c_config::MAX_COMPONENT_ID_LEN }>, // TODO(eliza): max rail len... #[cbor(skip_if_nil)] rail: Option>, @@ -1496,7 +1502,7 @@ struct SeqStatus { flt_groupc_pg: u8, } -#[derive(Copy, Clone, microcbor::EncodeFields)] +#[derive(Copy, Clone, Eq, PartialEq, microcbor::EncodeFields)] struct Coretype { coretype: bool, sp3r1: bool, @@ -1509,26 +1515,24 @@ struct HostCpuRefdes { dev_id: FixedStr<16>, } -impl HostCpuRefdes { - static HOST_CPU_REFDES: HostCpuRefdes = HostCpuRefdes { - refdes: FixedStr::from("P0"), - dev_id: FixedStr::from("sp3-host-cpu"), - }; -} +static HOST_CPU_REFDES: HostCpuRefdes = HostCpuRefdes { + refdes: FixedStr::from_str("P0"), + // TODO(eliza): can we get this from the `gateway-sp-messages` crate? + dev_id: FixedStr::from_str("sp3-host-cpu"), +}; -pub(crate) fn deliver_ereport( - class: EreportClass, - ereport: &E, +pub(crate) fn deliver_ereport>( + ereport: &Ereport, packrat: &Packrat, buf: &mut [u8], ) { - match packrat.serialize_ereport(ereport, buf) { - Ok(len) => ringbuf_entry!(Trace::EreportSent(class, len)), - Err(task_packrat_api::EreportSerializeError::Packrat { len, err }) => { - ringbuf_entry!(Trace::EreportLost(class, len, err)) + match packrat.encode_ereport(ereport, buf) { + Ok(len) => ringbuf_entry!(Trace::EreportSent(ereport.class, len)), + Err(task_packrat_api::EreportEncodeError::Packrat { len, err }) => { + ringbuf_entry!(Trace::EreportLost(ereport.class, len, err)) } - Err(task_packrat_api::EreportSerializeError::Serialize(_)) => { - ringbuf_entry!(Trace::EreportTooBig(class)) + Err(task_packrat_api::EreportEncodeError::Encoder(_)) => { + ringbuf_entry!(Trace::EreportTooBig(ereport.class)) } } } @@ -1694,13 +1698,13 @@ cfg_if::cfg_if! { retry_i2c_txn(I2cTxn::VCoreOn, || vdd_vcore.turn_on()) .map_err(|err| A0Failure::I2cFault { - refdes: vdd_vcore.component_id(), + refdes: vdd_vcore.i2c_device().component_id(), rail: "VDD_VCORE", err, })?; retry_i2c_txn(I2cTxn::SocOn, || vddcr_soc.turn_on()) .map_err(|err| A0Failure::I2cFault { - refdes: vddcr_soc.component_id(), + refdes: vddcr_soc.i2c_device().component_id(), rail: "VDDCR_SOC", err, })?; diff --git a/drv/gimlet-seq-server/src/vcore.rs b/drv/gimlet-seq-server/src/vcore.rs index f459e94b2..d42c9e4df 100644 --- a/drv/gimlet-seq-server/src/vcore.rs +++ b/drv/gimlet-seq-server/src/vcore.rs @@ -44,8 +44,8 @@ pub struct VCore { #[derive(microcbor::EncodeFields)] pub(super) struct PmbusEreport { - refdes: fixedstr::FixedStr<{ crate::i2c_config::MAX_COMPONENT_ID_LEN }>, - rail: &'static fixedstr::FixedStr<10>, + refdes: FixedStr<{ crate::i2c_config::MAX_COMPONENT_ID_LEN }>, + rail: &'static FixedStr<10>, time: u64, pwr_good: Option, pmbus_status: PmbusStatus, @@ -180,7 +180,6 @@ impl VCore { &self, now: u64, packrat: &packrat_api::Packrat, - ereport_buf: &mut [u8], ereport_buf: &mut [u8; crate::EREPORT_BUF_LEN], ) { use pmbus::commands::raa229618::STATUS_WORD; @@ -277,7 +276,7 @@ impl VCore { .map(|s| s.0); ringbuf_entry!(Trace::StatusMfrSpecific(status_mfr_specific)); - let status = super::PmbusStatus { + let status = PmbusStatus { word: status_word.map(|s| s.0).ok(), input: status_input.ok(), vout: status_vout.ok(), @@ -288,10 +287,10 @@ impl VCore { }; static RAIL: FixedStr<10> = FixedStr::from_str("VDD_VCORE"); - let ereport = packrat_api::Ereport { + let ereport = crate::Ereport { class: crate::EreportClass::PmbusAlert, version: 0, - report: crate::EreportKind::PmbusAlert { + report: PmbusEreport { refdes: FixedStr::from_str( self.device.i2c_device().component_id(), ), @@ -301,6 +300,7 @@ impl VCore { pmbus_status: status, }, }; + crate::deliver_ereport(&ereport, packrat, ereport_buf); // TODO(eliza): if POWER_GOOD has been deasserted, we should produce a // subsequent ereport for that. @@ -337,27 +337,3 @@ impl VCore { } } } - -#[derive(Copy, Clone, Default, Serialize)] -struct PmbusStatus { - word: Option, - input: Option, - iout: Option, - vout: Option, - temp: Option, - cml: Option, - mfr: Option, -} - -#[derive(Serialize)] -struct PmbusEreport { - #[serde(rename = "k")] - class: crate::EreportClass, - #[serde(rename = "v")] - version: u32, - refdes: &'static str, - rail: &'static str, - time: u64, - pwr_good: Option, - pmbus_status: PmbusStatus, -} From ac09bc0d3887b3bd53a82b4098fa995f17630295 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Tue, 7 Oct 2025 13:39:11 -0700 Subject: [PATCH 6/8] cosmo --- Cargo.lock | 2 + drv/cosmo-seq-server/Cargo.toml | 4 +- drv/cosmo-seq-server/src/main.rs | 196 +++++++++++++++++++----------- drv/cosmo-seq-server/src/vcore.rs | 50 ++++---- 4 files changed, 155 insertions(+), 97 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b094c9ff3..dd63387fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1115,9 +1115,11 @@ dependencies = [ "drv-spartan7-loader-api", "drv-spi-api", "drv-stm32xx-sys-api", + "fixedstr", "gnarle", "idol", "idol-runtime", + "microcbor", "num-traits", "pmbus", "ringbuf", diff --git a/drv/cosmo-seq-server/Cargo.toml b/drv/cosmo-seq-server/Cargo.toml index 9e96d4628..f476111b7 100644 --- a/drv/cosmo-seq-server/Cargo.toml +++ b/drv/cosmo-seq-server/Cargo.toml @@ -16,11 +16,13 @@ drv-packrat-vpd-loader = { path = "../packrat-vpd-loader" } drv-spartan7-loader-api = { path = "../spartan7-loader-api" } drv-spi-api = { path = "../spi-api" } drv-stm32xx-sys-api = { path = "../stm32xx-sys-api" } +fixedstr = { path = "../../lib/fixedstr", features = ["microcbor"] } gnarle = { path = "../../lib/gnarle" } ringbuf = { path = "../../lib/ringbuf" } +microcbor = { path = "../../lib/microcbor" } userlib = { path = "../../sys/userlib", features = ["panic-messages"] } task-jefe-api = { path = "../../task/jefe-api" } -task-packrat-api = { path = "../../task/packrat-api", features = ["serde"] } +task-packrat-api = { path = "../../task/packrat-api", features = ["microcbor"] } static-cell = { path = "../../lib/static-cell" } cfg-if = { workspace = true } diff --git a/drv/cosmo-seq-server/src/main.rs b/drv/cosmo-seq-server/src/main.rs index 432c6ed37..ca4321337 100644 --- a/drv/cosmo-seq-server/src/main.rs +++ b/drv/cosmo-seq-server/src/main.rs @@ -10,21 +10,21 @@ use drv_cpu_seq_api::{ PowerState, SeqError as CpuSeqError, StateChangeReason, Transition, }; +use drv_hf_api::HostFlash; use drv_ice40_spi_program as ice40; use drv_packrat_vpd_loader::{read_vpd_and_load_packrat, Packrat}; use drv_spartan7_loader_api::Spartan7Loader; use drv_spi_api::{SpiDevice, SpiServer}; use drv_stm32xx_sys_api::{self as sys_api, Sys}; +use fixedstr::FixedStr; use idol_runtime::{NotificationHandler, RequestError}; +use ringbuf::{counted_ringbuf, ringbuf_entry, Count}; use task_jefe_api::Jefe; use userlib::{ hl, set_timer_relative, sys_get_timer, sys_recv_notification, task_slot, RecvMessage, }; -use drv_hf_api::HostFlash; -use ringbuf::{counted_ringbuf, ringbuf_entry, Count}; - include!(concat!(env!("OUT_DIR"), "/i2c_config.rs")); mod vcore; @@ -386,12 +386,18 @@ struct ServerImpl { seq: fmc_sequencer::Sequencer, espi: fmc_periph::espi::Espi, vcore: VCore, + packrat: Packrat, /// Static buffer for encoding ereports. This is a static so that we don't /// have it on the stack when encoding ereports. ereport_buf: &'static mut [u8; EREPORT_BUF_LEN], } -const EREPORT_BUF_LEN: usize = 256; +const EREPORT_BUF_LEN: usize = microcbor::max_cbor_len_for![ + Ereport, + Ereport, + // For FPGA MAPO/SMERR ereports + Ereport<&'static SeqFpgaRefdes>, +]; impl ServerImpl { fn new( @@ -429,7 +435,8 @@ impl ServerImpl { hf: HostFlash::from(HF.get_task_id()), seq, espi, - vcore: VCore::new(I2C.get_task_id(), packrat), + vcore: VCore::new(I2C.get_task_id()), + packrat, ereport_buf, } } @@ -545,26 +552,42 @@ impl ServerImpl { }); // From sp5-mobo-guide-56870_1.1.pdf table 72 - match (coretype0, coretype1, coretype2) { + let coretype_ok = match (coretype0, coretype1, coretype2) { // These correspond to Type-2 and Type-3 - (true, false, true) | (true, false, false) => (), + (true, false, true) | (true, false, false) => true, // Reject all other combos and return to A0 - _ => { - self.seq.power_ctrl.modify(|m| m.set_a0_en(false)); - return Err(CpuSeqError::UnrecognizedCPU); - } + _ => false, }; // From sp5-mobo-guide-56870_1.1.pdf table 73 - match (sp5r1, sp5r2, sp5r3, sp5r4) { + let sp5r_ok = match (sp5r1, sp5r2, sp5r3, sp5r4) { // There is only combo we accept here - (true, false, false, false) => (), + (true, false, false, false) => true, // Reject all other combos and return to A0 - _ => { - self.seq.power_ctrl.modify(|m| m.set_a0_en(false)); - return Err(CpuSeqError::UnrecognizedCPU); - } + _ => false, }; + + if !(coretype_ok && sp5r_ok) { + // Looks weird! + self.seq.power_ctrl.modify(|m| m.set_a0_en(false)); + let ereport = Ereport { + class: EreportClass::UnrecognizedCPU, + version: 0, + report: UnrecognizedCPU { + refdes: &HOST_CPU_REFDES, + coretype0, + coretype1, + coretype2, + sp5r1, + sp5r2, + sp5r3, + sp5r4, + }, + }; + deliver_ereport(&ereport, &self.packrat, self.ereport_buf); + return Err(CpuSeqError::UnrecognizedCPU); + } + // Turn on the voltage regulator undervolt alerts. self.enable_sequencer_interrupts(); @@ -766,8 +789,12 @@ impl ServerImpl { vddcr_cpu0: ifr.pwr_cont1_to_fpga1_alert, vddcr_cpu1: ifr.pwr_cont2_to_fpga1_alert, }; - self.vcore - .handle_pmbus_alert(which_rails, now, self.ereport_buf); + self.vcore.handle_pmbus_alert( + which_rails, + now, + &self.packrat, + self.ereport_buf, + ); // We need not instruct the sequencer to reset. PMBus alerts from // the RAA229620As are divided into two categories, "warnings" and @@ -798,14 +825,14 @@ impl ServerImpl { let ereport = Ereport { class: EreportClass::Thermtrip, version: 0, - refdes: "P0", // host CPU + report: &HOST_CPU_REFDES, + // TODO(eliza): eventually, it would be nice to include sequencer + // state registers here, however, we would need to modify the + // `fpga_regmap` codegen to let us get the raw bits out (since + // encoding the `...View` structs as CBOR uses a lot more bytes for + // field names and 8-bit `bool`s...) I'll do this eventually... }; - deliver_ereport( - ereport.class, - ereport, - self.packrat, - self.ereport_buf, - ); + deliver_ereport(&ereport, &self.packrat, self.ereport_buf); } if ifr.a0mapo { @@ -813,17 +840,18 @@ impl ServerImpl { self.seq.ifr.modify(|h| h.set_a0mapo(false)); ringbuf_entry!(Trace::A0MapoInterrupt); action = InternalAction::Mapo; + let ereport = Ereport { class: EreportClass::A0Mapo, version: 0, - refdes: "U27", // sequencer FPGA + report: &SEQ_FPGA_REFDES, + // TODO(eliza): eventually, it would be nice to include sequencer + // state registers here, however, we would need to modify the + // `fpga_regmap` codegen to let us get the raw bits out (since + // encoding the `...View` structs as CBOR uses a lot more bytes for + // field names and 8-bit `bool`s...) I'll do this eventually... }; - deliver_ereport( - ereport.class, - ereport, - self.packrat, - self.ereport_buf, - ); + deliver_ereport(&ereport, &self.packrat, self.ereport_buf); } if ifr.smerr_assert { @@ -834,14 +862,14 @@ impl ServerImpl { let ereport = Ereport { class: EreportClass::Smerr, version: 0, - refdes: "U27", // sequencer FPGA + report: &SEQ_FPGA_REFDES, + // TODO(eliza): eventually, it would be nice to include sequencer + // state registers here, however, we would need to modify the + // `fpga_regmap` codegen to let us get the raw bits out (since + // encoding the `...View` structs as CBOR uses a lot more bytes for + // field names and 8-bit `bool`s...) I'll do this eventually... }; - deliver_ereport( - ereport.class, - ereport, - self.packrat, - self.ereport_buf, - ); + deliver_ereport(&ereport, &self.packrat, self.ereport_buf); } // Fan Fault is unconnected // NIC MAPO is unconnected @@ -874,20 +902,6 @@ impl ServerImpl { ringbuf_entry!(Trace::UnexpectedInterrupt); } }; - - #[derive(serde::Serialize)] - struct Ereport { - #[serde(rename = "k")] - class: EreportClass, - #[serde(rename = "v")] - version: u32, - refdes: &'static str, - // TODO(eliza): eventually, it would be nice to include sequencer - // state registers here, however, we would need to modify the - // `fpga_regmap` codegen to let us get the raw bits out (since - // encoding the `...View` structs as CBOR uses a lot more bytes for - // field names and 8-bit `bool`s...) I'll do this eventually... - } } } @@ -1012,31 +1026,77 @@ impl NotificationHandler for ServerImpl { //////////////////////////////////////////////////////////////////////////////// -#[derive(Eq, PartialEq, Copy, Clone, serde::Serialize)] +#[derive(Eq, PartialEq, Copy, Clone, microcbor::Encode, counters::Count)] pub(crate) enum EreportClass { - #[serde(rename = "hw.cpu.thermtrip")] + // + // Interrupts + // + #[cbor(rename = "hw.cpu.thermtrip")] Thermtrip, - #[serde(rename = "hw.seq.smerr")] + #[cbor(rename = "hw.seq.smerr")] Smerr, - #[serde(rename = "hw.seq.a0_map0")] + #[cbor(rename = "hw.seq.a0_map0")] A0Mapo, - #[serde(rename = "hw.pwr.pmbus.alert")] + #[cbor(rename = "hw.pwr.pmbus.alert")] PmbusAlert, + + // + // Initialization failures + // + #[cbor(rename = "hw.cpu.a0_fail.unknown")] + UnrecognizedCPU, + #[cbor(rename = "hw.cpu.a0_fail.no_cpu")] + NoCPUPresent, +} + +pub(crate) type Ereport = task_packrat_api::Ereport; + +#[derive(microcbor::EncodeFields)] +pub(crate) struct UnrecognizedCPU { + #[cbor(flatten)] + refdes: &'static HostCpuRefdes, + coretype0: bool, + coretype1: bool, + coretype2: bool, + sp5r1: bool, + sp5r2: bool, + sp5r3: bool, + sp5r4: bool, } -pub(crate) fn deliver_ereport( - class: &EreportClass, - ereport: &impl serde::Serialize, +#[derive(microcbor::EncodeFields)] +struct HostCpuRefdes { + refdes: FixedStr<2>, + dev_id: FixedStr<16>, +} + +#[derive(microcbor::EncodeFields)] +struct SeqFpgaRefdes { + refdes: FixedStr<3>, +} + +static SEQ_FPGA_REFDES: SeqFpgaRefdes = SeqFpgaRefdes { + refdes: FixedStr::from_str("U27"), +}; + +static HOST_CPU_REFDES: HostCpuRefdes = HostCpuRefdes { + refdes: FixedStr::from_str("P0"), + // TODO(eliza): can we get this from the `gateway-sp-messages` crate? + dev_id: FixedStr::from_str("sp5-host-cpu"), +}; + +pub(crate) fn deliver_ereport>( + ereport: &Ereport, packrat: &Packrat, buf: &mut [u8], ) { - match packrat.serialize_ereport(ereport, buf) { - Ok(len) => ringbuf_entry!(Trace::EreportSent(class, len)), - Err(task_packrat_api::EreportSerializeError::Packrat { len, err }) => { - ringbuf_entry!(Trace::EreportLost(class, len, err)) + match packrat.encode_ereport(ereport, buf) { + Ok(len) => ringbuf_entry!(Trace::EreportSent(ereport.class, len)), + Err(task_packrat_api::EreportEncodeError::Packrat { len, err }) => { + ringbuf_entry!(Trace::EreportLost(ereport.class, len, err)) } - Err(task_packrat_api::EreportSerializeError::Serialize(_)) => { - ringbuf_entry!(Trace::EreportTooBig(class)) + Err(task_packrat_api::EreportEncodeError::Encoder(_)) => { + ringbuf_entry!(Trace::EreportTooBig(ereport.class)) } } } diff --git a/drv/cosmo-seq-server/src/vcore.rs b/drv/cosmo-seq-server/src/vcore.rs index e4f50e4b7..ab2d1c820 100644 --- a/drv/cosmo-seq-server/src/vcore.rs +++ b/drv/cosmo-seq-server/src/vcore.rs @@ -13,10 +13,11 @@ //! use super::i2c_config; +use super::Ereport; use drv_i2c_api::ResponseCode; use drv_i2c_devices::raa229620a::{self, Raa229620A}; +use fixedstr::FixedStr; use ringbuf::*; -use serde::Serialize; use userlib::{sys_get_timer, units, TaskId}; pub(super) struct VCore { @@ -24,13 +25,13 @@ pub(super) struct VCore { vddcr_cpu0: Raa229620A, /// `PWR_CONT2`: This regulator controls `VDDCR_CPU1` and `VDDIO_SP5` rails. vddcr_cpu1: Raa229620A, - packrat: task_packrat_api::Packrat, } -#[derive(Copy, Clone, PartialEq, Serialize)] -#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +#[derive(Copy, Clone, PartialEq, microcbor::Encode)] enum Rail { + #[cbor(rename = "VDDCR_CPU0")] VddcrCpu0, + #[cbor(rename = "VDDCR_CPU1")] VddcrCpu1, } @@ -71,9 +72,6 @@ enum Trace { StatusCml(Rail, Result), StatusMfrSpecific(Rail, Result), I2cError(Rail, PmbusCmd, raa229620a::Error), - EreportSent(Rail, usize), - EreportLost(Rail, usize, task_packrat_api::EreportWriteError), - EreportTooBig(Rail), } #[derive(Copy, Clone, PartialEq)] @@ -104,7 +102,7 @@ const VCORE_UV_WARN_LIMIT: units::Volts = units::Volts(11.75); const VCORE_NSAMPLES: usize = 25; impl VCore { - pub fn new(i2c: TaskId, packrat: task_packrat_api::Packrat) -> Self { + pub fn new(i2c: TaskId) -> Self { let (device, rail) = i2c_config::pmbus::vddcr_cpu0_a0(i2c); let vddcr_cpu0 = Raa229620A::new(&device, rail); @@ -113,7 +111,6 @@ impl VCore { Self { vddcr_cpu0, vddcr_cpu1, - packrat, } } @@ -165,6 +162,7 @@ impl VCore { &self, mut rails: Rails, now: u64, + packrat: &task_packrat_api::Packrat, ereport_buf: &mut [u8], ) { ringbuf_entry!(Trace::PmbusAlert { @@ -176,6 +174,7 @@ impl VCore { now, Rail::VddcrCpu0, rails.vddcr_cpu0, + packrat, ereport_buf, ); rails.vddcr_cpu0 |= cpu0_state.faulted; @@ -184,6 +183,7 @@ impl VCore { now, Rail::VddcrCpu1, rails.vddcr_cpu1, + packrat, ereport_buf, ); rails.vddcr_cpu1 |= cpu1_state.faulted; @@ -258,6 +258,7 @@ impl VCore { now: u64, rail: Rail, alerted: bool, + packrat: &task_packrat_api::Packrat, ereport_buf: &mut [u8], ) -> RegulatorState { use pmbus::commands::raa229620a::STATUS_WORD; @@ -379,19 +380,16 @@ impl VCore { let ereport = Ereport { class: crate::EreportClass::PmbusAlert, version: 0, - rail, - refdes: device.i2c_device().component_id(), - time: now, - pmbus_status, - pwr_good: power_good, + report: PmbusEreport { + rail, + refdes: FixedStr::from_str(device.i2c_device().component_id()), + time: now, + pmbus_status, + pwr_good: power_good, + }, }; - crate::deliver_ereport( - ereport.class, - ereport, - self.packrat, - self.ereport_buf, - ); + crate::deliver_ereport(&ereport, packrat, ereport_buf); // TODO(eliza): if POWER_GOOD has been deasserted, we should produce a // subsequent ereport for that. @@ -402,20 +400,16 @@ impl VCore { } } -#[derive(Serialize)] -struct Ereport { - #[serde(rename = "k")] - class: crate::EreportClass, - #[serde(rename = "v")] - version: usize, - refdes: &'static str, +#[derive(microcbor::EncodeFields)] +pub(crate) struct PmbusEreport { + refdes: FixedStr<{ crate::i2c_config::MAX_COMPONENT_ID_LEN }>, rail: Rail, time: u64, pwr_good: Option, pmbus_status: PmbusStatus, } -#[derive(Copy, Clone, Default, Serialize)] +#[derive(Copy, Clone, Default, microcbor::Encode)] struct PmbusStatus { word: Option, input: Option, From e3ded7c0fbdc43c772a14fb43fbb4ad065eaaa06 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Tue, 7 Oct 2025 14:14:57 -0700 Subject: [PATCH 7/8] reticulating cosmo --- drv/cosmo-seq-server/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drv/cosmo-seq-server/src/main.rs b/drv/cosmo-seq-server/src/main.rs index ca4321337..28856340d 100644 --- a/drv/cosmo-seq-server/src/main.rs +++ b/drv/cosmo-seq-server/src/main.rs @@ -1035,7 +1035,7 @@ pub(crate) enum EreportClass { Thermtrip, #[cbor(rename = "hw.seq.smerr")] Smerr, - #[cbor(rename = "hw.seq.a0_map0")] + #[cbor(rename = "hw.seq.a0_mapo")] A0Mapo, #[cbor(rename = "hw.pwr.pmbus.alert")] PmbusAlert, @@ -1045,8 +1045,8 @@ pub(crate) enum EreportClass { // #[cbor(rename = "hw.cpu.a0_fail.unknown")] UnrecognizedCPU, - #[cbor(rename = "hw.cpu.a0_fail.no_cpu")] - NoCPUPresent, + #[cbor(rename = "hw.a0_fail")] + A0Failure, } pub(crate) type Ereport = task_packrat_api::Ereport; From 5a93d7842a615470235da2adb2f219096176a468 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Wed, 8 Oct 2025 10:42:57 -0700 Subject: [PATCH 8/8] -dead code --- drv/cosmo-seq-server/src/main.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/drv/cosmo-seq-server/src/main.rs b/drv/cosmo-seq-server/src/main.rs index 28856340d..f6c7d13c0 100644 --- a/drv/cosmo-seq-server/src/main.rs +++ b/drv/cosmo-seq-server/src/main.rs @@ -1045,8 +1045,6 @@ pub(crate) enum EreportClass { // #[cbor(rename = "hw.cpu.a0_fail.unknown")] UnrecognizedCPU, - #[cbor(rename = "hw.a0_fail")] - A0Failure, } pub(crate) type Ereport = task_packrat_api::Ereport;