From 2b2b99144982fe25474f53c2002a40669b61a445 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Tue, 9 Sep 2025 11:33:39 -0700 Subject: [PATCH 1/9] wip --- Cargo.lock | 581 +++++++++--------- Cargo.toml | 2 +- build/i2c/src/lib.rs | 37 +- task/control-plane-agent/Cargo.toml | 5 +- task/control-plane-agent/build.rs | 6 + task/control-plane-agent/src/inventory.rs | 49 +- .../src/mgs_compute_sled.rs | 2 +- task/validate-api/Cargo.toml | 3 +- task/validate-api/build.rs | 59 +- task/validate-api/src/lib.rs | 28 +- 10 files changed, 460 insertions(+), 312 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a97dce8ece..99ec7fea58 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,11 +6,11 @@ version = 4 name = "abi" version = "0.1.0" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "byteorder", "phash", "serde", - "zerocopy 0.8.26", + "zerocopy 0.8.27", ] [[package]] @@ -178,8 +178,8 @@ dependencies = [ "num-traits", "serde", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -271,9 +271,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "bitvec" @@ -337,7 +337,7 @@ dependencies = [ name = "build-kconfig" version = "0.1.0" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "serde", ] @@ -1007,8 +1007,8 @@ dependencies = [ "sha3", "tlvc", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1026,8 +1026,8 @@ dependencies = [ "stm32h7", "tlvc", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1069,8 +1069,8 @@ dependencies = [ "serde", "stm32h7", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1106,8 +1106,8 @@ dependencies = [ "task-jefe-api", "task-packrat-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1117,8 +1117,8 @@ dependencies = [ "counters", "num-traits", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1132,8 +1132,8 @@ dependencies = [ "idol-runtime", "num-traits", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1148,8 +1148,8 @@ dependencies = [ "idol-runtime", "num-traits", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1165,8 +1165,8 @@ dependencies = [ "sha3", "tlvc", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1183,7 +1183,7 @@ dependencies = [ "num-traits", "ringbuf", "userlib", - "zerocopy 0.8.26", + "zerocopy 0.8.27", ] [[package]] @@ -1206,8 +1206,8 @@ dependencies = [ "num-traits", "ringbuf", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1217,8 +1217,8 @@ dependencies = [ "drv-fpga-api", "num-traits", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1237,8 +1237,8 @@ dependencies = [ "serde", "stm32h7", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1279,8 +1279,8 @@ dependencies = [ "task-jefe-api", "task-packrat-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1303,8 +1303,8 @@ dependencies = [ "task-jefe-api", "task-packrat-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1317,8 +1317,8 @@ dependencies = [ "idol-runtime", "num-traits", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1336,8 +1336,8 @@ dependencies = [ "num-traits", "serde", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1348,8 +1348,8 @@ dependencies = [ "counters", "drv-i2c-types", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1367,8 +1367,8 @@ dependencies = [ "smbus-pec", "task-power-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1413,8 +1413,8 @@ dependencies = [ "serde", "static_assertions", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1432,8 +1432,8 @@ dependencies = [ "mutable-statics", "num-traits", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1451,8 +1451,8 @@ dependencies = [ "num-traits", "ringbuf", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1465,8 +1465,8 @@ dependencies = [ "drv-oxide-vpd", "idol", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1489,8 +1489,8 @@ dependencies = [ "num-traits", "serde", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1507,8 +1507,8 @@ dependencies = [ "num-traits", "serde", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1521,8 +1521,8 @@ dependencies = [ "lpc55-pac", "num-traits", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1539,8 +1539,8 @@ dependencies = [ "rand_chacha", "rand_core", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1560,8 +1560,8 @@ dependencies = [ "lpc55-pac", "num-traits", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1579,8 +1579,8 @@ dependencies = [ "ringbuf", "serde", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1614,8 +1614,8 @@ dependencies = [ "static_assertions", "task-jefe-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1624,7 +1624,7 @@ version = "0.1.0" dependencies = [ "anyhow", "attest-api", - "bitflags 2.9.1", + "bitflags 2.9.4", "build-lpc55pins", "build-util", "call_rustfmt", @@ -1648,8 +1648,8 @@ dependencies = [ "serde", "static_assertions", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1664,8 +1664,8 @@ dependencies = [ "num-traits", "task-jefe-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1677,8 +1677,8 @@ dependencies = [ "idol", "num-traits", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1697,8 +1697,8 @@ dependencies = [ "serde", "stage0-handoff", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1716,15 +1716,15 @@ dependencies = [ "nb 1.0.0", "serde", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] name = "drv-mb85rsxx-fram" version = "0.1.0" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "counters", "drv-spi-api", ] @@ -1742,8 +1742,8 @@ dependencies = [ "idol-runtime", "num-traits", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1755,8 +1755,8 @@ dependencies = [ "idol", "num-traits", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1772,8 +1772,8 @@ dependencies = [ "num-traits", "serde", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1800,8 +1800,8 @@ dependencies = [ "ringbuf", "serde", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1818,8 +1818,8 @@ dependencies = [ "num-traits", "ringbuf", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1837,8 +1837,8 @@ dependencies = [ "num-traits", "serde", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1862,8 +1862,8 @@ dependencies = [ "serde", "serde_json", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1879,8 +1879,8 @@ dependencies = [ "num-traits", "serde", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1894,8 +1894,8 @@ dependencies = [ "num-traits", "task-jefe-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1912,8 +1912,8 @@ dependencies = [ "userlib", "vsc7448", "vsc85xx", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1922,8 +1922,8 @@ version = "0.1.0" dependencies = [ "num-traits", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1933,8 +1933,8 @@ dependencies = [ "drv-onewire", "num-traits", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -1946,8 +1946,8 @@ dependencies = [ "idol", "ringbuf", "tlvc", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2016,8 +2016,8 @@ dependencies = [ "num-traits", "rand_core", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2036,8 +2036,8 @@ dependencies = [ "num-traits", "ringbuf", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2051,8 +2051,8 @@ dependencies = [ "idol", "num-traits", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2076,8 +2076,8 @@ dependencies = [ "userlib", "vsc7448-pac", "vsc85xx", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2100,8 +2100,8 @@ dependencies = [ "serde", "serde_json", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2128,8 +2128,8 @@ dependencies = [ "num-traits", "serde", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2157,8 +2157,8 @@ dependencies = [ "ringbuf", "serde", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2171,8 +2171,8 @@ dependencies = [ "idol-runtime", "num-traits", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2193,8 +2193,8 @@ dependencies = [ "ringbuf", "task-config", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2206,8 +2206,8 @@ dependencies = [ "idol-runtime", "num-traits", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2236,8 +2236,8 @@ dependencies = [ "num-traits", "serde", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2268,8 +2268,8 @@ dependencies = [ "tlvc", "unwrap-lite", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2280,8 +2280,8 @@ dependencies = [ "stm32f3", "stm32f4", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2293,8 +2293,8 @@ dependencies = [ "stm32f3", "stm32f4", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2308,8 +2308,8 @@ dependencies = [ "num-traits", "stm32g0", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2356,8 +2356,8 @@ dependencies = [ "stm32h7", "userlib", "vcell", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2375,8 +2375,8 @@ dependencies = [ "num-traits", "stm32h7", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2387,8 +2387,8 @@ dependencies = [ "stm32h7", "userlib", "vcell", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2405,8 +2405,8 @@ dependencies = [ "stm32h7", "task-packrat-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2417,8 +2417,8 @@ dependencies = [ "ringbuf", "stm32h7", "vcell", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2433,8 +2433,8 @@ dependencies = [ "idol-runtime", "num-traits", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2464,7 +2464,7 @@ dependencies = [ "stm32h7", "syn 2.0.98", "userlib", - "zerocopy 0.8.26", + "zerocopy 0.8.27", ] [[package]] @@ -2491,8 +2491,8 @@ dependencies = [ "ssmarshal", "static-cell", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2519,8 +2519,8 @@ dependencies = [ "serde", "stage0-handoff", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2541,8 +2541,8 @@ dependencies = [ "stm32g0", "stm32h7", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2560,8 +2560,8 @@ dependencies = [ "stm32g0", "stm32h7", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2589,7 +2589,7 @@ dependencies = [ name = "drv-stm32xx-sys" version = "0.1.0" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "build-stm32xx-sys", "build-util", "cfg-if", @@ -2605,8 +2605,8 @@ dependencies = [ "stm32h7", "task-jefe-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2623,8 +2623,8 @@ dependencies = [ "num-traits", "serde", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2648,8 +2648,8 @@ dependencies = [ "task-sensor-api", "transceiver-messages", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2682,8 +2682,8 @@ dependencies = [ "task-thermal-api", "transceiver-messages", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2700,8 +2700,8 @@ dependencies = [ "ringbuf", "serde", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2722,8 +2722,8 @@ dependencies = [ "stm32f4", "task-config", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2735,8 +2735,8 @@ dependencies = [ "idol", "num-traits", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2753,8 +2753,8 @@ dependencies = [ "num-traits", "serde", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2770,8 +2770,8 @@ dependencies = [ "num-traits", "serde", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -2859,7 +2859,7 @@ name = "endoscope-abi" version = "0.1.0" dependencies = [ "sha3", - "zerocopy 0.8.26", + "zerocopy 0.8.27", ] [[package]] @@ -3004,17 +3004,17 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "gateway-ereport-messages" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/management-gateway-service#57ffd1c24f3ad1919fb4a605d5a501f2c5deb54c" +source = "git+https://github.com/oxidecomputer/management-gateway-service#f3a3cad67fa3099883b8fb7e69b7677498b0eefe" dependencies = [ - "zerocopy 0.8.26", + "zerocopy 0.8.27", ] [[package]] name = "gateway-messages" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/management-gateway-service#83fe1885c9916cebbee261c47a09d832d75b7df0" +source = "git+https://github.com/oxidecomputer/management-gateway-service?branch=eliza%2Fvpd#dc297c9a94674d13db3f2faf7536af70a8671e8c" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "hubpack", "serde", "serde-big-array 0.5.1", @@ -3024,7 +3024,7 @@ dependencies = [ "strum", "strum_macros", "uuid", - "zerocopy 0.8.26", + "zerocopy 0.8.27", ] [[package]] @@ -3246,7 +3246,7 @@ dependencies = [ name = "host-sp-messages" version = "0.1.0" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "counters", "drv-i2c-types", "fletcher", @@ -3260,8 +3260,8 @@ dependencies = [ "serde_repr", "static_assertions", "unwrap-lite", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -3330,8 +3330,8 @@ dependencies = [ "serde", "serde-big-array 0.5.1", "static_assertions", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -3387,7 +3387,7 @@ source = "git+https://github.com/oxidecomputer/idolatry.git#b9fb439a8b6d77d10c92 dependencies = [ "counters", "userlib", - "zerocopy 0.8.26", + "zerocopy 0.8.27", ] [[package]] @@ -3492,7 +3492,7 @@ dependencies = [ "abi", "anyhow", "armv8-m-mpu", - "bitflags 2.9.1", + "bitflags 2.9.4", "build-kconfig", "build-util", "byteorder", @@ -3510,8 +3510,8 @@ dependencies = [ "ssmarshal", "syn 2.0.98", "unwrap-lite", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -3565,8 +3565,8 @@ dependencies = [ "static_assertions", "unwrap-lite", "vcell", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", "zeroize", ] @@ -3630,8 +3630,8 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -3687,8 +3687,8 @@ dependencies = [ "static_assertions", "toml", "unwrap-lite", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", "zeroize", ] @@ -3719,8 +3719,8 @@ dependencies = [ "task-jefe-api", "tlvc", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -4140,7 +4140,7 @@ version = "0.1.0" dependencies = [ "hubpack", "serde", - "zerocopy 0.8.26", + "zerocopy 0.8.27", ] [[package]] @@ -5168,8 +5168,8 @@ dependencies = [ "serde", "stm32h7", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5180,20 +5180,19 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strum" -version = "0.27.1" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" [[package]] name = "strum_macros" -version = "0.27.1" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "rustversion", "syn 2.0.98", ] @@ -5254,8 +5253,8 @@ dependencies = [ "static-cell", "unwrap-lite", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5275,6 +5274,7 @@ name = "task-control-plane-agent" version = "0.1.0" dependencies = [ "anyhow", + "build-i2c", "build-util", "cfg-if", "counters", @@ -5283,6 +5283,8 @@ dependencies = [ "drv-caboose-pos", "drv-cpu-seq-api", "drv-hf-api", + "drv-i2c-api", + "drv-i2c-devices", "drv-ignition-api", "drv-lpc55-update-api", "drv-monorail-api", @@ -5321,8 +5323,8 @@ dependencies = [ "task-vpd-api", "update-buffer", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5339,8 +5341,8 @@ dependencies = [ "serde", "ssmarshal", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5362,8 +5364,8 @@ dependencies = [ "task-packrat-api", "task-sensor-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5389,8 +5391,8 @@ dependencies = [ "task-jefe-api", "task-net-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5409,8 +5411,8 @@ dependencies = [ "ringbuf", "serde", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5425,8 +5427,8 @@ dependencies = [ "ringbuf", "task-packrat-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5509,8 +5511,8 @@ dependencies = [ "static-cell", "test-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5557,8 +5559,8 @@ dependencies = [ "task-sensor-api", "tlvc", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5573,8 +5575,8 @@ dependencies = [ "num-traits", "ssmarshal", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5606,8 +5608,8 @@ dependencies = [ "ssmarshal", "task-jefe-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5625,8 +5627,8 @@ dependencies = [ "serde", "ssmarshal", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5656,8 +5658,8 @@ dependencies = [ "vsc7448", "vsc7448-pac", "vsc85xx", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5704,8 +5706,8 @@ dependencies = [ "userlib", "vsc7448-pac", "vsc85xx", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5727,8 +5729,8 @@ dependencies = [ "smoltcp", "task-packrat-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5771,8 +5773,8 @@ dependencies = [ "static_assertions", "task-packrat-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5789,8 +5791,8 @@ dependencies = [ "num-traits", "oxide-barcode", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5842,8 +5844,8 @@ dependencies = [ "task-power-api", "task-sensor-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5861,8 +5863,8 @@ dependencies = [ "static_assertions", "task-sensor-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5885,8 +5887,8 @@ dependencies = [ "serde", "task-sensor-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5906,8 +5908,8 @@ dependencies = [ "num-traits", "serde", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5924,8 +5926,8 @@ dependencies = [ "ringbuf", "task-sensor-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5941,8 +5943,8 @@ dependencies = [ "task-net-api", "task-packrat-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -5972,7 +5974,7 @@ name = "task-thermal" version = "0.1.0" dependencies = [ "anyhow", - "bitflags 2.9.1", + "bitflags 2.9.4", "build-i2c", "build-util", "cortex-m", @@ -5994,8 +5996,8 @@ dependencies = [ "task-sensor-api", "task-thermal-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -6013,8 +6015,8 @@ dependencies = [ "serde", "task-sensor-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -6045,8 +6047,8 @@ dependencies = [ "task-net-api", "task-packrat-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -6070,8 +6072,8 @@ dependencies = [ "idol", "task-net-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -6093,8 +6095,8 @@ dependencies = [ "serde", "task-validate-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -6106,6 +6108,7 @@ dependencies = [ "counters", "derive-idol-err", "drv-i2c-api", + "drv-i2c-devices", "gateway-messages", "hubpack", "idol", @@ -6114,8 +6117,8 @@ dependencies = [ "serde", "task-sensor-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -6135,8 +6138,8 @@ dependencies = [ "ringbuf", "task-vpd-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -6150,8 +6153,8 @@ dependencies = [ "idol-runtime", "num-traits", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -6180,8 +6183,8 @@ dependencies = [ "build-util", "num-traits", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -6194,8 +6197,8 @@ dependencies = [ "num-traits", "test-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -6210,8 +6213,8 @@ dependencies = [ "serde", "ssmarshal", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -6226,8 +6229,8 @@ dependencies = [ "ssmarshal", "test-idol-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -6243,8 +6246,8 @@ dependencies = [ "ringbuf", "test-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -6264,8 +6267,8 @@ dependencies = [ "test-api", "test-idol-api", "userlib", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -6495,7 +6498,7 @@ name = "transceiver-messages" version = "0.1.1" source = "git+https://github.com/oxidecomputer/transceiver-control/#c5564eb96ddc7887a02596cc039662c87e906d0c" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "hubpack", "serde", ] @@ -6553,8 +6556,8 @@ dependencies = [ "ssmarshal", "unwrap-lite", "volatile-const", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -6643,8 +6646,8 @@ dependencies = [ "userlib", "vsc-err", "vsc7448-pac", - "zerocopy 0.8.26", - "zerocopy-derive 0.8.26", + "zerocopy 0.8.27", + "zerocopy-derive 0.8.27", ] [[package]] @@ -7032,7 +7035,7 @@ dependencies = [ "toml-task", "toml_edit", "walkdir", - "zerocopy 0.8.26", + "zerocopy 0.8.27", "zip", ] @@ -7058,11 +7061,11 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ - "zerocopy-derive 0.8.26", + "zerocopy-derive 0.8.27", ] [[package]] @@ -7089,9 +7092,9 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index bdf1031473..084c24d282 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -145,7 +145,7 @@ zip = { version = "0.6", default-features = false, features = ["bzip2", "deflate # Oxide forks and repos attest-data = { git = "https://github.com/oxidecomputer/dice-util", default-features = false, version = "0.4.0" } dice-mfg-msgs = { git = "https://github.com/oxidecomputer/dice-util", default-features = false, version = "0.2.1" } -gateway-messages = { git = "https://github.com/oxidecomputer/management-gateway-service", default-features = false, features = ["smoltcp"] } +gateway-messages = { git = "https://github.com/oxidecomputer/management-gateway-service", default-features = false, features = ["smoltcp"], branch = "eliza/vpd" } gateway-ereport-messages = { git = "https://github.com/oxidecomputer/management-gateway-service", default-features = false } gimlet-inspector-protocol = { git = "https://github.com/oxidecomputer/gimlet-inspector-protocol", version = "0.1.0" } hif = { git = "https://github.com/oxidecomputer/hif", default-features = false } diff --git a/build/i2c/src/lib.rs b/build/i2c/src/lib.rs index d2618ce240..991f4a7bdc 100644 --- a/build/i2c/src/lib.rs +++ b/build/i2c/src/lib.rs @@ -108,6 +108,9 @@ struct I2cDevice { /// device is removable #[serde(default)] removable: bool, + + /// how to read FRUID VPD from the device, if any + fruid: Option, } impl I2cDevice { @@ -224,11 +227,18 @@ struct I2cSensors { #[derive(Clone, Debug, Deserialize, Hash, PartialOrd, PartialEq, Eq, Ord)] #[serde(untagged)] -enum Refdes { +pub enum Refdes { Component(String), Path(Vec), } +#[derive(Clone, Debug, Deserialize, PartialOrd, Ord, Eq, PartialEq)] +pub enum FruidMode { + SingleBarcode, + NestedBarcode, + Pmbus, +} + impl I2cSensors { /// Checks whether two sensor sets are compatible /// @@ -1775,8 +1785,9 @@ pub struct I2cDeviceDescription { pub device: String, pub description: String, pub sensors: Vec, - pub device_id: Option, + pub device_id: Option, pub name: Option, + pub fruid: Option, } /// @@ -1794,15 +1805,13 @@ pub fn device_descriptions() -> impl Iterator { // Matches the ordering of the `match` produced by `generate_validation()` // above; if we change the order here, it must change there as well. g.devices.into_iter().zip(sensors.device_sensors).map( - |(device, sensors)| { - let device_id = device.refdes.as_ref().map(Refdes::to_component_id); - I2cDeviceDescription { - device: device.device, - description: device.description, - sensors, - device_id, - name: device.name, - } + |(device, sensors)| I2cDeviceDescription { + device: device.device, + description: device.description, + sensors, + device_id: device.refdes.clone(), + fruid: device.fruid, + name: device.name, }, ) } @@ -1838,15 +1847,15 @@ where } impl Refdes { - fn to_component_id(&self) -> String { + pub fn to_component_id(&self) -> String { self.join_with_case(str::make_ascii_uppercase, "/") } - fn to_upper_ident(&self) -> String { + pub fn to_upper_ident(&self) -> String { self.join_with_case(str::make_ascii_uppercase, "_") } - fn to_lower_ident(&self) -> String { + pub fn to_lower_ident(&self) -> String { self.join_with_case(str::make_ascii_lowercase, "_") } diff --git a/task/control-plane-agent/Cargo.toml b/task/control-plane-agent/Cargo.toml index 519193ceac..ccb18274d3 100644 --- a/task/control-plane-agent/Cargo.toml +++ b/task/control-plane-agent/Cargo.toml @@ -25,6 +25,8 @@ drv-caboose = { path = "../../drv/caboose" } drv-caboose-pos = { path = "../../drv/caboose-pos" } drv-hf-api = { path = "../../drv/hf-api", optional = true } drv-cpu-seq-api = { path = "../../drv/cpu-seq-api", optional = true } +drv-i2c-api = { path = "../../drv/i2c-api" } +drv-i2c-devices = { path = "../../drv/i2c-devices" } drv-ignition-api = { path = "../../drv/ignition-api", optional = true } drv-lpc55-update-api = { path = "../../drv/lpc55-update-api" } drv-monorail-api = { path = "../../drv/monorail-api", optional = true } @@ -47,13 +49,14 @@ task-jefe-api = { path = "../jefe-api" } task-net-api = { path = "../net-api", features = ["use-smoltcp"] } task-packrat-api = { path = "../packrat-api" } task-sensor-api = { path = "../sensor-api" } -task-validate-api = { path = "../validate-api" } +task-validate-api = { path = "../validate-api", features = ["fruid"] } update-buffer = { path = "../../lib/update-buffer" } userlib = { path = "../../sys/userlib", features = ["panic-messages"] } static-cell = { path = "../../lib/static-cell" } [build-dependencies] build-util = { path = "../../build/util" } +build-i2c = { path = "../../build/i2c" } anyhow = { workspace = true } idol = { workspace = true } serde = { workspace = true } diff --git a/task/control-plane-agent/build.rs b/task/control-plane-agent/build.rs index fe7368fded..89bac9dcb3 100644 --- a/task/control-plane-agent/build.rs +++ b/task/control-plane-agent/build.rs @@ -35,6 +35,12 @@ fn main() -> Result<(), Box> { if let Some(cfg) = cfg { write_keys(cfg)?; } + + let disposition = build_i2c::Disposition::Devices; + if let Err(e) = build_i2c::codegen(disposition) { + println!("cargo::error=I2C code generation failed: {e}"); + std::process::exit(1); + } Ok(()) } diff --git a/task/control-plane-agent/src/inventory.rs b/task/control-plane-agent/src/inventory.rs index 0832192500..069585ba1c 100644 --- a/task/control-plane-agent/src/inventory.rs +++ b/task/control-plane-agent/src/inventory.rs @@ -11,18 +11,54 @@ use gateway_messages::{ }; use task_sensor_api::Sensor as SensorTask; use task_sensor_api::SensorError; +use task_validate_api::FruidMode; use task_validate_api::{Sensor, DEVICES as VALIDATE_DEVICES}; use task_validate_api::{Validate, ValidateError, ValidateOk}; use userlib::UnwrapLite; userlib::task_slot!(VALIDATE, validate); userlib::task_slot!(SENSOR, sensor); +userlib::task_slot!(I2C, i2c); pub(crate) struct Inventory { validate_task: Validate, sensor_task: SensorTask, } +pub(crate) struct FixedStr { + buf: [u8; 32], + len: usize, +} + +impl FixedStr { + pub fn copy_from_slice(slice: &[u8]) -> Result { + core::str::from_utf8(slice)?; + let mut buf = [0u8; 32]; + buf[..slice.len()].copy_from_slice(slice); + Ok(Self { + buf, + len: slice.len(), + }) + } + + pub fn from_buf( + bytes: [u8; 32], + len: usize, + ) -> Result { + core::str::from_utf8(&bytes[..len])?; + Ok(Self { buf: bytes, len }) + } +} + +impl AsRef for FixedStr { + fn as_ref(&self) -> &str { + unsafe { + // SAFETY: This is checked when constructing the FixedStr. + core::str::from_utf8_unchecked(&self.buf[..self.len]) + } + } +} + impl Inventory { pub(crate) fn new() -> Self { let () = devices_with_static_validation::ASSERT_EACH_DEVICE_FITS_IN_ONE_PACKET; @@ -44,7 +80,15 @@ impl Inventory { match Index::try_from(component)? { Index::OurDevice(_) => Ok(0), Index::ValidateDevice(i) => { - Ok(VALIDATE_DEVICES[i].sensors.len() as u32) + let dev = &VALIDATE_DEVICES[i]; + let nsensors = dev.sensors.len() as u32; + let nfruid = match dev.fruid { + Some(FruidMode::At24Csw080Barcode(_)) => 1, + Some(FruidMode::At24Csw080Nested(_)) => 0, // TODO(eliza): implement nested SASY barcodes + Some(FruidMode::Tmp117(_)) => 1, + None => 0, + }; + Ok(nsensors + nfruid) } } } @@ -53,7 +97,7 @@ impl Inventory { &self, component: &SpComponent, component_index: BoundsChecked, - ) -> ComponentDetails { + ) -> ComponentDetails { // `component_index` is guaranteed to be in the range // `0..num_component_details(component)`, and we only return a value // greater than 0 from that method for indices in the VALIDATE_DEVICES @@ -270,6 +314,7 @@ mod devices_with_static_validation { // Fine to assume this is always present; if it isn't, we can't respond // to MGS messages anyway! presence: DevicePresence::Present, + fruid: None, }, #[cfg(any( feature = "gimlet", diff --git a/task/control-plane-agent/src/mgs_compute_sled.rs b/task/control-plane-agent/src/mgs_compute_sled.rs index 25d59bf969..b9e0e06f42 100644 --- a/task/control-plane-agent/src/mgs_compute_sled.rs +++ b/task/control-plane-agent/src/mgs_compute_sled.rs @@ -913,7 +913,7 @@ impl SpHandler for MgsHandler { &mut self, component: SpComponent, index: BoundsChecked, - ) -> ComponentDetails { + ) -> ComponentDetails { self.common.inventory().component_details(&component, index) } diff --git a/task/validate-api/Cargo.toml b/task/validate-api/Cargo.toml index a11dddbaf5..29d071c4e3 100644 --- a/task/validate-api/Cargo.toml +++ b/task/validate-api/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [features] - +fruid = [] [dependencies] idol-runtime.workspace = true @@ -17,6 +17,7 @@ serde.workspace = true counters = { path = "../../lib/counters" } derive-idol-err = { path = "../../lib/derive-idol-err" } drv-i2c-api = { path = "../../drv/i2c-api" } +drv-i2c-devices = { path = "../../drv/i2c-devices", optional = true } task-sensor-api = { path = "../sensor-api" } userlib = { path = "../../sys/userlib" } diff --git a/task/validate-api/build.rs b/task/validate-api/build.rs index 869ef1c4dc..c4d7efbb13 100644 --- a/task/validate-api/build.rs +++ b/task/validate-api/build.rs @@ -11,6 +11,13 @@ fn main() -> Result<(), Box> { "../../idl/validate.idol", "client_stub.rs", )?; + + #[cfg(feature = "fruid")] + if let Err(e) = build_i2c::codegen(build_i2c::Disposition::Devices) { + println!("cargo::error=failed to generate I2C devices: {e}"); + std::process::exit(1); + } + Ok(()) } @@ -50,6 +57,7 @@ fn write_pub_device_descriptions() -> anyhow::Result<()> { let mut missing_ids = 0; let mut duplicate_ids = 0; let mut ids_too_long = 0; + let mut bad_fruids = 0; // // The DEVICE_INDICES_BY_SORTED_ID array is used to look up indices by ID // using a binary search, so it must be sorted by ID. This map is used to @@ -62,7 +70,8 @@ fn write_pub_device_descriptions() -> anyhow::Result<()> { writeln!(file, " DeviceDescription {{")?; writeln!(file, " device: {:?},", dev.device)?; writeln!(file, " description: {:?},", dev.description)?; - if let Some(id) = dev.device_id { + if let Some(id) = dev.device_id.as_ref() { + let id = id.to_component_id(); if let Ok(component) = SpComponent::try_from(id.as_ref()) { write!(file, " id: {:?},", component.id)?; if id2idx.insert(component.id, idx).is_some() { @@ -92,6 +101,49 @@ fn write_pub_device_descriptions() -> anyhow::Result<()> { writeln!(file, " }},")?; } writeln!(file, " ],")?; + #[cfg(feature = "fruid")] + { + let mode = match (dev.fruid, dev.device.as_ref()) { + (Some(build_i2c::FruidMode::SingleBarcode), "at24csw080") => { + Some("FruidMode::At24Csw080Barcode") + } + (Some(build_i2c::FruidMode::NestedBarcode), "at24csw080") => { + Some("FruidMode::At24Csw080NestedBarcode") + } + (None, "tmp117") => Some("FruidMode::Tmp117"), + // TODO(eliza): PMBus + (Some(mode), device) => { + println!("cargo::error=FRUID mode {mode:?} not supported for {device}"); + bad_fruids += 1; + None + } + (None, _) => None, + }; + match (mode, dev.device_id.as_ref()) { + (Some(mode), Some(id)) => { + let devname = format!( + "i2c_config::devices::{}_{} as fn(_) -> _", + &dev.device, + id.to_lower_ident() + ); + writeln!( + file, + " fruid: Some({mode}({devname}))," + )?; + } + (None, _) => { + writeln!(file, " fruid: None,")?; + } + (Some(mode), None) => { + println!( + "cargo::error=devices with a FRUID mode must have \ + refdes, but device {idx} (mode: {mode:?}) does not\ + have one", + ); + bad_fruids += 1; + } + } + } writeln!(file, " }},")?; } @@ -127,5 +179,10 @@ fn write_pub_device_descriptions() -> anyhow::Result<()> { SpComponent::MAX_ID_LENGTH, ); + anyhow::ensure!( + bad_fruids == 0, + "{bad_fruids} devices have invalid FRUID configs!" + ); + Ok(()) } diff --git a/task/validate-api/src/lib.rs b/task/validate-api/src/lib.rs index 3884406f07..ed3ccc1a94 100644 --- a/task/validate-api/src/lib.rs +++ b/task/validate-api/src/lib.rs @@ -7,7 +7,7 @@ #![no_std] use derive_idol_err::IdolError; -use drv_i2c_api::ResponseCode; +use drv_i2c_api::{I2cDevice, ResponseCode}; use userlib::*; use zerocopy::{Immutable, IntoBytes, KnownLayout}; @@ -69,12 +69,36 @@ pub struct SensorDescription { pub id: SensorId, } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug)] pub struct DeviceDescription { pub device: &'static str, pub description: &'static str, pub sensors: &'static [SensorDescription], pub id: [u8; MAX_ID_LENGTH], + #[cfg(feature = "fruid")] + pub fruid: Option, +} + +#[cfg(feature = "fruid")] +#[derive(Copy, Clone)] +pub enum FruidMode { + At24Csw080Barcode(fn(TaskId) -> I2cDevice), + At24Csw080Nested(fn(TaskId) -> I2cDevice), + Tmp117(fn(TaskId) -> I2cDevice), +} + +#[cfg(feature = "fruid")] +impl core::fmt::Debug for FruidMode { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + FruidMode::At24Csw080Barcode(_) => write!(f, "At24Csw080Barcode"), + FruidMode::At24Csw080Nested(_) => write!(f, "At24Csw080Nested"), + FruidMode::Tmp117(_) => write!(f, "Tmp117"), + } + } } include!(concat!(env!("OUT_DIR"), "/device_descriptions.rs")); + +#[cfg(feature = "fruid")] +include!(concat!(env!("OUT_DIR"), "/i2c_config.rs")); From e85ae132971d1a2ef30e28d8a2f69e1e07f1eb75 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Tue, 9 Sep 2025 12:01:24 -0700 Subject: [PATCH 2/9] wip --- app/gimlet/base.toml | 1 + task/control-plane-agent/src/inventory.rs | 121 ++++++++++-------- task/control-plane-agent/src/mgs_common.rs | 13 +- .../src/mgs_compute_sled.rs | 4 +- task/validate-api/build.rs | 2 + 5 files changed, 86 insertions(+), 55 deletions(-) diff --git a/app/gimlet/base.toml b/app/gimlet/base.toml index 20ebe24b20..ab10394685 100644 --- a/app/gimlet/base.toml +++ b/app/gimlet/base.toml @@ -287,6 +287,7 @@ task-slots = [ "packrat", "user_leds", "vpd", + "i2c_driver", ] features = [ "gimlet", diff --git a/task/control-plane-agent/src/inventory.rs b/task/control-plane-agent/src/inventory.rs index 069585ba1c..2b125fea35 100644 --- a/task/control-plane-agent/src/inventory.rs +++ b/task/control-plane-agent/src/inventory.rs @@ -2,6 +2,7 @@ // 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/. +use drv_i2c_devices::at24csw080::At24Csw080; use gateway_messages::measurement::{ Measurement, MeasurementError, MeasurementKind, }; @@ -18,54 +19,56 @@ use userlib::UnwrapLite; userlib::task_slot!(VALIDATE, validate); userlib::task_slot!(SENSOR, sensor); -userlib::task_slot!(I2C, i2c); +userlib::task_slot!(I2C, i2c_driver); pub(crate) struct Inventory { validate_task: Validate, sensor_task: SensorTask, + fruid_buf: &'static mut [u8], } -pub(crate) struct FixedStr { - buf: [u8; 32], - len: usize, -} - -impl FixedStr { - pub fn copy_from_slice(slice: &[u8]) -> Result { - core::str::from_utf8(slice)?; - let mut buf = [0u8; 32]; - buf[..slice.len()].copy_from_slice(slice); - Ok(Self { - buf, - len: slice.len(), - }) - } - - pub fn from_buf( - bytes: [u8; 32], - len: usize, - ) -> Result { - core::str::from_utf8(&bytes[..len])?; - Ok(Self { buf: bytes, len }) - } -} - -impl AsRef for FixedStr { - fn as_ref(&self) -> &str { - unsafe { - // SAFETY: This is checked when constructing the FixedStr. - core::str::from_utf8_unchecked(&self.buf[..self.len]) - } - } -} +// pub(crate) struct FixedStr { +// buf: [u8; 32], +// len: usize, +// } + +// impl FixedStr { +// pub fn copy_from_slice(slice: &[u8]) -> Result { +// core::str::from_utf8(slice)?; +// let mut buf = [0u8; 32]; +// buf[..slice.len()].copy_from_slice(slice); +// Ok(Self { +// buf, +// len: slice.len(), +// }) +// } + +// pub fn from_buf( +// bytes: [u8; 32], +// len: usize, +// ) -> Result { +// core::str::from_utf8(&bytes[..len])?; +// Ok(Self { buf: bytes, len }) +// } +// } + +// impl AsRef for FixedStr { +// fn as_ref(&self) -> &str { +// unsafe { +// // SAFETY: This is checked when constructing the FixedStr. +// core::str::from_utf8_unchecked(&self.buf[..self.len]) +// } +// } +// } impl Inventory { - pub(crate) fn new() -> Self { + pub(crate) fn new(fruid_buf: &'static mut [u8]) -> Self { let () = devices_with_static_validation::ASSERT_EACH_DEVICE_FITS_IN_ONE_PACKET; Self { validate_task: Validate::from(VALIDATE.get_task_id()), sensor_task: SensorTask::from(SENSOR.get_task_id()), + fruid_buf, } } @@ -93,11 +96,11 @@ impl Inventory { } } - pub(crate) fn component_details( - &self, + pub(crate) fn component_details<'buf>( + &'buf mut self, component: &SpComponent, component_index: BoundsChecked, - ) -> ComponentDetails { + ) -> ComponentDetails<&'buf str> { // `component_index` is guaranteed to be in the range // `0..num_component_details(component)`, and we only return a value // greater than 0 from that method for indices in the VALIDATE_DEVICES @@ -108,20 +111,38 @@ impl Inventory { Ok(Index::ValidateDevice(i)) => i, Ok(Index::OurDevice(_)) | Err(_) => panic!(), }; + let device = &VALIDATE_DEVICES[val_device_index]; + // First, measurement channels... + if let Some(sensor_description) = + device.sensors.get(component_index.0 as usize) + { + let value = self + .sensor_task + .get(sensor_description.id) + .map_err(|err| SensorErrorConvert(err).into()); + + return ComponentDetails::Measurement(Measurement { + name: sensor_description.name.unwrap_or(""), + kind: MeasurementKindConvert(sensor_description.kind).into(), + value, + }); + } - let sensor_description = &VALIDATE_DEVICES[val_device_index].sensors - [component_index.0 as usize]; - - let value = self - .sensor_task - .get(sensor_description.id) - .map_err(|err| SensorErrorConvert(err).into()); + // If the index is greater than the maximum number of measurement + // channels, it must be a FRUID. + let Some(fruid) = device.fruid else { + // Index is bounds-checked. + unreachable!() + }; - ComponentDetails::Measurement(Measurement { - name: sensor_description.name.unwrap_or(""), - kind: MeasurementKindConvert(sensor_description.kind).into(), - value, - }) + match fruid { + FruidMode::At24Csw080Barcode(f) => { + let dev = f(I2C.get_task_id()); + todo!() + } + FruidMode::At24Csw080Nested(_) => todo!(), + FruidMode::Tmp117(_) => todo!(), + } } pub(crate) fn device_description( diff --git a/task/control-plane-agent/src/mgs_common.rs b/task/control-plane-agent/src/mgs_common.rs index 1ef23dc778..298e09720b 100644 --- a/task/control-plane-agent/src/mgs_common.rs +++ b/task/control-plane-agent/src/mgs_common.rs @@ -57,7 +57,7 @@ pub(crate) struct MgsCommon { dump_state: DumpState, reset_component_requested: Option, - inventory: Inventory, + pub inventory: Inventory, base_mac_address: MacAddress, packrat: Packrat, sprot: SpRot, @@ -65,15 +65,22 @@ pub(crate) struct MgsCommon { sensor: Sensor, } +const FRUID_BUF_SIZE: usize = 256; + impl MgsCommon { pub(crate) fn claim_static_resources(base_mac_address: MacAddress) -> Self { + use static_cell::ClaimOnceCell; + let fruid_buf = { + static BUF: ClaimOnceCell<[u8; FRUID_BUF_SIZE]> = + ClaimOnceCell::new([0; FRUID_BUF_SIZE]); + BUF.claim() + }; Self { sp_update: SpUpdate::new(), rot_update: RotUpdate::new(), dump_state: DumpState::new(), - reset_component_requested: None, - inventory: Inventory::new(), + inventory: Inventory::new(fruid_buf), base_mac_address, packrat: Packrat::from(PACKRAT.get_task_id()), sprot: SpRot::from(SPROT.get_task_id()), diff --git a/task/control-plane-agent/src/mgs_compute_sled.rs b/task/control-plane-agent/src/mgs_compute_sled.rs index b9e0e06f42..a10b8cad98 100644 --- a/task/control-plane-agent/src/mgs_compute_sled.rs +++ b/task/control-plane-agent/src/mgs_compute_sled.rs @@ -913,8 +913,8 @@ impl SpHandler for MgsHandler { &mut self, component: SpComponent, index: BoundsChecked, - ) -> ComponentDetails { - self.common.inventory().component_details(&component, index) + ) -> ComponentDetails<&str> { + self.common.inventory.component_details(&component, index) } fn component_get_active_slot( diff --git a/task/validate-api/build.rs b/task/validate-api/build.rs index c4d7efbb13..bcb4c9bc3c 100644 --- a/task/validate-api/build.rs +++ b/task/validate-api/build.rs @@ -57,6 +57,7 @@ fn write_pub_device_descriptions() -> anyhow::Result<()> { let mut missing_ids = 0; let mut duplicate_ids = 0; let mut ids_too_long = 0; + #[cfg(feature = "fruid")] let mut bad_fruids = 0; // // The DEVICE_INDICES_BY_SORTED_ID array is used to look up indices by ID @@ -179,6 +180,7 @@ fn write_pub_device_descriptions() -> anyhow::Result<()> { SpComponent::MAX_ID_LENGTH, ); + #[cfg(feature = "fruid")] anyhow::ensure!( bad_fruids == 0, "{bad_fruids} devices have invalid FRUID configs!" From 39d145035d721c5f335bb595a3123a72ba88d55e Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 11 Sep 2025 10:12:38 -0700 Subject: [PATCH 3/9] janky working sharkfin vpd --- Cargo.lock | 5 +- app/gimlet/base.toml | 11 +++++ build/i2c/src/lib.rs | 1 + task/control-plane-agent/Cargo.toml | 3 ++ task/control-plane-agent/src/inventory.rs | 57 ++++++++++++++++++++++- task/validate-api/build.rs | 7 +-- 6 files changed, 76 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 99ec7fea58..38ae6723b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3012,7 +3012,7 @@ dependencies = [ [[package]] name = "gateway-messages" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/management-gateway-service?branch=eliza%2Fvpd#dc297c9a94674d13db3f2faf7536af70a8671e8c" +source = "git+https://github.com/oxidecomputer/management-gateway-service?branch=eliza%2Fvpd#4f5a721d43610fe8c637c2f45ff58ebbff2235ff" dependencies = [ "bitflags 2.9.4", "hubpack", @@ -5288,6 +5288,7 @@ dependencies = [ "drv-ignition-api", "drv-lpc55-update-api", "drv-monorail-api", + "drv-oxide-vpd", "drv-rng-api", "drv-sidecar-seq-api", "drv-sprot-api", @@ -5306,6 +5307,7 @@ dependencies = [ "idol-runtime", "lpc55-rom-data", "num-traits", + "oxide-barcode", "p256", "ringbuf", "serde", @@ -5321,6 +5323,7 @@ dependencies = [ "task-sensor-api", "task-validate-api", "task-vpd-api", + "tlvc", "update-buffer", "userlib", "zerocopy 0.8.27", diff --git a/app/gimlet/base.toml b/app/gimlet/base.toml index ab10394685..a31f399474 100644 --- a/app/gimlet/base.toml +++ b/app/gimlet/base.toml @@ -490,6 +490,7 @@ description = "U.2 Sharkfin A VPD" name = "sharkfin_a_vpd" refdes = ["J206", "U7"] removable = true +fruid = "single-barcode" [[config.i2c.devices]] bus = "front" @@ -526,6 +527,7 @@ description = "U.2 Sharkfin B VPD" name = "sharkfin_b_vpd" refdes = ["J207", "U7"] removable = true +fruid = "single-barcode" [[config.i2c.devices]] bus = "front" @@ -562,6 +564,7 @@ description = "U.2 Sharkfin C VPD" name = "sharkfin_c_vpd" refdes = ["J208", "U7"] removable = true +fruid = "single-barcode" [[config.i2c.devices]] bus = "front" @@ -598,6 +601,7 @@ description = "U.2 Sharkfin D VPD" name = "sharkfin_d_vpd" refdes = ["J209", "U7"] removable = true +fruid = "single-barcode" [[config.i2c.devices]] bus = "front" @@ -634,6 +638,7 @@ description = "U.2 Sharkfin E VPD" name = "sharkfin_e_vpd" refdes = ["J210", "U7"] removable = true +fruid = "single-barcode" [[config.i2c.devices]] bus = "front" @@ -670,6 +675,7 @@ description = "U.2 Sharkfin F VPD" name = "sharkfin_f_vpd" refdes = ["J211", "U7"] removable = true +fruid = "single-barcode" [[config.i2c.devices]] bus = "front" @@ -706,6 +712,7 @@ description = "U.2 Sharkfin G VPD" name = "sharkfin_g_vpd" refdes = ["J212", "U7"] removable = true +fruid = "single-barcode" [[config.i2c.devices]] bus = "front" @@ -742,6 +749,7 @@ description = "U.2 Sharkfin H VPD" name = "sharkfin_h_vpd" refdes = ["J213", "U7"] removable = true +fruid = "single-barcode" [[config.i2c.devices]] bus = "front" @@ -778,6 +786,7 @@ description = "U.2 Sharkfin I VPD" name = "sharkfin_i_vpd" refdes = ["J214", "U7"] removable = true +fruid = "single-barcode" [[config.i2c.devices]] bus = "front" @@ -814,6 +823,7 @@ description = "U.2 Sharkfin J VPD" name = "sharkfin_j_vpd" refdes = ["J215", "U7"] removable = true +fruid = "single-barcode" [[config.i2c.devices]] bus = "front" @@ -849,6 +859,7 @@ device = "at24csw080" name = "local_vpd" description = "Gimlet VPD" refdes = "U615" +fruid = "single-barcode" # # M.2 NVMe bus mux. Segments: diff --git a/build/i2c/src/lib.rs b/build/i2c/src/lib.rs index 991f4a7bdc..74a3e66ea4 100644 --- a/build/i2c/src/lib.rs +++ b/build/i2c/src/lib.rs @@ -233,6 +233,7 @@ pub enum Refdes { } #[derive(Clone, Debug, Deserialize, PartialOrd, Ord, Eq, PartialEq)] +#[serde(rename_all = "kebab-case")] pub enum FruidMode { SingleBarcode, NestedBarcode, diff --git a/task/control-plane-agent/Cargo.toml b/task/control-plane-agent/Cargo.toml index ccb18274d3..18582a2eda 100644 --- a/task/control-plane-agent/Cargo.toml +++ b/task/control-plane-agent/Cargo.toml @@ -14,6 +14,7 @@ num-traits.workspace = true serde.workspace = true ssmarshal.workspace = true static_assertions.workspace = true +tlvc.workspace = true zerocopy.workspace = true zerocopy-derive.workspace = true @@ -30,6 +31,7 @@ drv-i2c-devices = { path = "../../drv/i2c-devices" } drv-ignition-api = { path = "../../drv/ignition-api", optional = true } drv-lpc55-update-api = { path = "../../drv/lpc55-update-api" } drv-monorail-api = { path = "../../drv/monorail-api", optional = true } +drv-oxide-vpd = { path = "../../drv/oxide-vpd" } drv-sidecar-seq-api = { path = "../../drv/sidecar-seq-api", optional = true } drv-sprot-api = { path = "../../drv/sprot-api" } drv-stm32h7-update-api = { path = "../../drv/stm32h7-update-api" } @@ -42,6 +44,7 @@ dump-agent-api = { path = "../dump-agent-api" } task-vpd-api = { path = "../../task/vpd-api", optional = true } host-sp-messages = { path = "../../lib/host-sp-messages" } lpc55-rom-data = { path = "../../lib/lpc55-rom-data" } +oxide-barcode = { path = "../../lib/oxide-barcode" } ringbuf = { path = "../../lib/ringbuf" } counters = { path = "../../lib/counters" } task-control-plane-agent-api = { path = "../control-plane-agent-api" } diff --git a/task/control-plane-agent/src/inventory.rs b/task/control-plane-agent/src/inventory.rs index 2b125fea35..66be6bb6a7 100644 --- a/task/control-plane-agent/src/inventory.rs +++ b/task/control-plane-agent/src/inventory.rs @@ -2,13 +2,16 @@ // 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/. +use drv_i2c_api::{self as i2c, I2cDevice}; use drv_i2c_devices::at24csw080::At24Csw080; use gateway_messages::measurement::{ Measurement, MeasurementError, MeasurementKind, }; use gateway_messages::sp_impl::{BoundsChecked, DeviceDescription}; +use gateway_messages::vpd::{OxideVpd, Vpd}; use gateway_messages::{ ComponentDetails, DeviceCapabilities, DevicePresence, SpComponent, SpError, + VpdError, }; use task_sensor_api::Sensor as SensorTask; use task_sensor_api::SensorError; @@ -88,7 +91,7 @@ impl Inventory { let nfruid = match dev.fruid { Some(FruidMode::At24Csw080Barcode(_)) => 1, Some(FruidMode::At24Csw080Nested(_)) => 0, // TODO(eliza): implement nested SASY barcodes - Some(FruidMode::Tmp117(_)) => 1, + Some(FruidMode::Tmp117(_)) => 0, // TODO(eliza): implement tmp117 fruid None => 0, }; Ok(nsensors + nfruid) @@ -138,7 +141,18 @@ impl Inventory { match fruid { FruidMode::At24Csw080Barcode(f) => { let dev = f(I2C.get_task_id()); - todo!() + match read_one_barcode(dev, &[(*b"BARC", 0)]) { + Ok(oxide_barcode::VpdIdentity { + revision, + serial, + part_number, + }) => ComponentDetails::Vpd(Vpd::Oxide(OxideVpd { + rev: revision, + serial, + part_number, + })), + Err(err) => panic!(), // TODO(eliza): figure out this + } } FruidMode::At24Csw080Nested(_) => todo!(), FruidMode::Tmp117(_) => todo!(), @@ -179,6 +193,9 @@ impl Inventory { if !device.sensors.is_empty() { capabilities |= DeviceCapabilities::HAS_MEASUREMENT_CHANNELS; } + if device.fruid.is_some() { + capabilities |= DeviceCapabilities::HAS_VPD; + } DeviceDescription { component: SpComponent { id: device.id }, device: device.device, @@ -245,6 +262,42 @@ impl TryFrom<&'_ SpComponent> for Index { } } +/// Free function to read a nested barcode, translating errors appropriately +fn read_one_barcode( + dev: I2cDevice, + path: &[([u8; 4], usize)], +) -> Result { + let eeprom = At24Csw080::new(dev); + let mut barcode = [0; 32]; + match drv_oxide_vpd::read_config_nested_from_into( + eeprom, + path, + &mut barcode, + ) { + Ok(n) => { + // extract barcode! + let identity = oxide_barcode::VpdIdentity::parse(&barcode[..n]) + .map_err(|_| VpdError::DeviceError)?; + Ok(identity) + } + Err( + drv_oxide_vpd::VpdError::ErrorOnBegin(err) + | drv_oxide_vpd::VpdError::ErrorOnRead(err) + | drv_oxide_vpd::VpdError::ErrorOnNext(err) + | drv_oxide_vpd::VpdError::InvalidChecksum(err), + ) if err + == tlvc::TlvcReadError::User( + drv_i2c_devices::at24csw080::Error::I2cError( + i2c::ResponseCode::NoDevice, + ), + ) => + { + Err(VpdError::NotPresent) + } + Err(..) => Err(VpdError::DeviceError), + } +} + use devices_with_static_validation::OUR_DEVICES; // We tag this with module `#[allow(dead_code)]` to prevent warnings about the // contents of this module not being used; it contains constants used in static diff --git a/task/validate-api/build.rs b/task/validate-api/build.rs index bcb4c9bc3c..bd0ee6c5d3 100644 --- a/task/validate-api/build.rs +++ b/task/validate-api/build.rs @@ -127,13 +127,10 @@ fn write_pub_device_descriptions() -> anyhow::Result<()> { &dev.device, id.to_lower_ident() ); - writeln!( - file, - " fruid: Some({mode}({devname}))," - )?; + writeln!(file, " fruid: Some({mode}({devname})),")?; } (None, _) => { - writeln!(file, " fruid: None,")?; + writeln!(file, " fruid: None,")?; } (Some(mode), None) => { println!( From 5981469fda3737ba82cdd49e13279566a02aa742 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 11 Sep 2025 11:32:19 -0700 Subject: [PATCH 4/9] add tmp117 --- Cargo.lock | 2 +- task/control-plane-agent/src/inventory.rs | 24 +++++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 38ae6723b4..62fa740489 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3012,7 +3012,7 @@ dependencies = [ [[package]] name = "gateway-messages" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/management-gateway-service?branch=eliza%2Fvpd#4f5a721d43610fe8c637c2f45ff58ebbff2235ff" +source = "git+https://github.com/oxidecomputer/management-gateway-service?branch=eliza%2Fvpd#206fd606bcea437f9b6b243788d2d17677746748" dependencies = [ "bitflags 2.9.4", "hubpack", diff --git a/task/control-plane-agent/src/inventory.rs b/task/control-plane-agent/src/inventory.rs index 66be6bb6a7..b2a9a73887 100644 --- a/task/control-plane-agent/src/inventory.rs +++ b/task/control-plane-agent/src/inventory.rs @@ -91,7 +91,7 @@ impl Inventory { let nfruid = match dev.fruid { Some(FruidMode::At24Csw080Barcode(_)) => 1, Some(FruidMode::At24Csw080Nested(_)) => 0, // TODO(eliza): implement nested SASY barcodes - Some(FruidMode::Tmp117(_)) => 0, // TODO(eliza): implement tmp117 fruid + Some(FruidMode::Tmp117(_)) => 1, None => 0, }; Ok(nsensors + nfruid) @@ -155,7 +155,13 @@ impl Inventory { } } FruidMode::At24Csw080Nested(_) => todo!(), - FruidMode::Tmp117(_) => todo!(), + FruidMode::Tmp117(dev) => { + let dev = f(I2C.get_task_id()); + match read_tmp117_fruid(dev) { + Ok(vpd) => ComponentDetails::Vpd(Vpd::Tmp117(vpd)), + Err(err) => panic!(), // TODO(eliza): figure out this + } + } } } @@ -298,6 +304,20 @@ fn read_one_barcode( } } +/// Read FRUID data from a TMP117 temperature sensor. +fn read_tmp117_fruid(dev: I2cDevice) -> Result { + let id = dev.read_reg(0x0Fu8)?; + let eeprom1 = dev.read_reg(0x05u8)?; + let eeprom2 = dev.read_reg(0x06u8)?; + let eeprom3 = dev.read_reg(0x08u8)?; + Ok(Tmp117Vpd { + id, + eeprom1, + eeprom2, + eeprom3, + }) +} + use devices_with_static_validation::OUR_DEVICES; // We tag this with module `#[allow(dead_code)]` to prevent warnings about the // contents of this module not being used; it contains constants used in static From a457546241a7759a7a7c2b8bc7a73869ef379304 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 11 Sep 2025 11:34:42 -0700 Subject: [PATCH 5/9] add tmp117 vpd actually works version --- task/control-plane-agent/src/inventory.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/task/control-plane-agent/src/inventory.rs b/task/control-plane-agent/src/inventory.rs index b2a9a73887..99112bef54 100644 --- a/task/control-plane-agent/src/inventory.rs +++ b/task/control-plane-agent/src/inventory.rs @@ -8,7 +8,7 @@ use gateway_messages::measurement::{ Measurement, MeasurementError, MeasurementKind, }; use gateway_messages::sp_impl::{BoundsChecked, DeviceDescription}; -use gateway_messages::vpd::{OxideVpd, Vpd}; +use gateway_messages::vpd::{OxideVpd, Tmp117Vpd, Vpd}; use gateway_messages::{ ComponentDetails, DeviceCapabilities, DevicePresence, SpComponent, SpError, VpdError, @@ -155,7 +155,7 @@ impl Inventory { } } FruidMode::At24Csw080Nested(_) => todo!(), - FruidMode::Tmp117(dev) => { + FruidMode::Tmp117(f) => { let dev = f(I2C.get_task_id()); match read_tmp117_fruid(dev) { Ok(vpd) => ComponentDetails::Vpd(Vpd::Tmp117(vpd)), @@ -305,11 +305,11 @@ fn read_one_barcode( } /// Read FRUID data from a TMP117 temperature sensor. -fn read_tmp117_fruid(dev: I2cDevice) -> Result { - let id = dev.read_reg(0x0Fu8)?; - let eeprom1 = dev.read_reg(0x05u8)?; - let eeprom2 = dev.read_reg(0x06u8)?; - let eeprom3 = dev.read_reg(0x08u8)?; +fn read_tmp117_fruid(dev: I2cDevice) -> Result { + let id: u16 = dev.read_reg(0x0Fu8)?; + let eeprom1: u16 = dev.read_reg(0x05u8)?; + let eeprom2: u16 = dev.read_reg(0x06u8)?; + let eeprom3: u16 = dev.read_reg(0x08u8)?; Ok(Tmp117Vpd { id, eeprom1, From 4a25c49ea6fb77148f08ef60e4bde64074fc0ec4 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 12 Sep 2025 12:36:36 -0700 Subject: [PATCH 6/9] pick up errors --- Cargo.lock | 2 +- task/control-plane-agent/src/inventory.rs | 54 ++++++++++++++--------- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 62fa740489..6975d286c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3012,7 +3012,7 @@ dependencies = [ [[package]] name = "gateway-messages" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/management-gateway-service?branch=eliza%2Fvpd#206fd606bcea437f9b6b243788d2d17677746748" +source = "git+https://github.com/oxidecomputer/management-gateway-service?branch=eliza%2Fvpd#0017c81be552980b9efbd5041ac72ce3dd061019" dependencies = [ "bitflags 2.9.4", "hubpack", diff --git a/task/control-plane-agent/src/inventory.rs b/task/control-plane-agent/src/inventory.rs index 99112bef54..491939413f 100644 --- a/task/control-plane-agent/src/inventory.rs +++ b/task/control-plane-agent/src/inventory.rs @@ -8,10 +8,9 @@ use gateway_messages::measurement::{ Measurement, MeasurementError, MeasurementKind, }; use gateway_messages::sp_impl::{BoundsChecked, DeviceDescription}; -use gateway_messages::vpd::{OxideVpd, Tmp117Vpd, Vpd}; +use gateway_messages::vpd::{OxideVpd, Tmp117Vpd, Vpd, VpdReadError}; use gateway_messages::{ ComponentDetails, DeviceCapabilities, DevicePresence, SpComponent, SpError, - VpdError, }; use task_sensor_api::Sensor as SensorTask; use task_sensor_api::SensorError; @@ -151,7 +150,7 @@ impl Inventory { serial, part_number, })), - Err(err) => panic!(), // TODO(eliza): figure out this + Err(err) => ComponentDetails::Vpd(Vpd::Err(err)), } } FruidMode::At24Csw080Nested(_) => todo!(), @@ -159,7 +158,7 @@ impl Inventory { let dev = f(I2C.get_task_id()); match read_tmp117_fruid(dev) { Ok(vpd) => ComponentDetails::Vpd(Vpd::Tmp117(vpd)), - Err(err) => panic!(), // TODO(eliza): figure out this + Err(err) => ComponentDetails::Vpd(Vpd::Err(err)), } } } @@ -272,7 +271,7 @@ impl TryFrom<&'_ SpComponent> for Index { fn read_one_barcode( dev: I2cDevice, path: &[([u8; 4], usize)], -) -> Result { +) -> Result { let eeprom = At24Csw080::new(dev); let mut barcode = [0; 32]; match drv_oxide_vpd::read_config_nested_from_into( @@ -283,33 +282,39 @@ fn read_one_barcode( Ok(n) => { // extract barcode! let identity = oxide_barcode::VpdIdentity::parse(&barcode[..n]) - .map_err(|_| VpdError::DeviceError)?; + .map_err(|_| VpdReadError::InvalidContents)?; Ok(identity) } + Err( + drv_oxide_vpd::VpdError::NoRootChunk + | drv_oxide_vpd::VpdError::NoSuchChunk(_) + | drv_oxide_vpd::VpdError::InvalidChunkSize, + ) => Err(VpdReadError::InvalidContents), Err( drv_oxide_vpd::VpdError::ErrorOnBegin(err) | drv_oxide_vpd::VpdError::ErrorOnRead(err) | drv_oxide_vpd::VpdError::ErrorOnNext(err) | drv_oxide_vpd::VpdError::InvalidChecksum(err), - ) if err - == tlvc::TlvcReadError::User( - drv_i2c_devices::at24csw080::Error::I2cError( - i2c::ResponseCode::NoDevice, - ), - ) => - { - Err(VpdError::NotPresent) - } - Err(..) => Err(VpdError::DeviceError), + ) => match err { + // If the underlying error is an I2C error, indicate that. + tlvc::TlvcReadError::User( + drv_i2c_devices::at24csw080::Error::I2cError(e), + ) => Err(i2c_vpd_error(e)), + // Other user errors indicate we tried to read a bad address or + // similar. + tlvc::TlvcReadError::User(_) => Err(VpdReadError::BadRead), + // Otherwise, indicate that the contents are invalid TLV-c. + _ => Err(VpdReadError::InvalidContents), + }, } } /// Read FRUID data from a TMP117 temperature sensor. -fn read_tmp117_fruid(dev: I2cDevice) -> Result { - let id: u16 = dev.read_reg(0x0Fu8)?; - let eeprom1: u16 = dev.read_reg(0x05u8)?; - let eeprom2: u16 = dev.read_reg(0x06u8)?; - let eeprom3: u16 = dev.read_reg(0x08u8)?; +fn read_tmp117_fruid(dev: I2cDevice) -> Result { + let id: u16 = dev.read_reg(0x0Fu8).map_err(i2c_vpd_error)?; + let eeprom1: u16 = dev.read_reg(0x05u8).map_err(i2c_vpd_error)?; + let eeprom2: u16 = dev.read_reg(0x06u8).map_err(i2c_vpd_error)?; + let eeprom3: u16 = dev.read_reg(0x08u8).map_err(i2c_vpd_error)?; Ok(Tmp117Vpd { id, eeprom1, @@ -318,6 +323,13 @@ fn read_tmp117_fruid(dev: I2cDevice) -> Result { }) } +fn i2c_vpd_error(e: i2c::ResponseCode) -> VpdReadError { + match e { + i2c::ResponseCode::NoDevice => VpdReadError::DeviceNotPresent, + _ => VpdReadError::I2cError, + } +} + use devices_with_static_validation::OUR_DEVICES; // We tag this with module `#[allow(dead_code)]` to prevent warnings about the // contents of this module not being used; it contains constants used in static From 0af70d96d0675d130ce8f3f1efcf0810c3840409 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Sat, 13 Sep 2025 13:04:11 -0700 Subject: [PATCH 7/9] wip pmbus --- Cargo.lock | 1 + app/psc/base.toml | 6 ++ drv/i2c-devices/Cargo.toml | 1 + drv/i2c-devices/src/lib.rs | 101 ++++++++++++++++++++ drv/i2c-devices/src/mwocp68.rs | 7 +- task/control-plane-agent/src/inventory.rs | 39 +++++++- task/control-plane-agent/src/main.rs | 5 + task/control-plane-agent/src/mgs_psc.rs | 4 +- task/control-plane-agent/src/mgs_sidecar.rs | 4 +- task/validate-api/Cargo.toml | 2 +- task/validate-api/build.rs | 6 +- task/validate-api/src/lib.rs | 6 +- 12 files changed, 171 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6975d286c4..aadb682102 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1357,6 +1357,7 @@ name = "drv-i2c-devices" version = "0.1.0" dependencies = [ "bitfield 0.13.2", + "counters", "derive-idol-err", "drv-i2c-api", "drv-onewire", diff --git a/app/psc/base.toml b/app/psc/base.toml index cb69afe472..6429ec6d6a 100644 --- a/app/psc/base.toml +++ b/app/psc/base.toml @@ -219,6 +219,7 @@ task-slots = [ "packrat", "user_leds", "vpd", + "i2c_driver", ] features = ["psc", "vlan", "vpd"] notifications = ["usart-irq", "socket", "timer"] @@ -410,6 +411,7 @@ description = "PSU 0 MCU" power = { rails = [ "V54_PSU0", "V12_PSU0" ], sensors = ["voltage", "current", "input-voltage", "input-current"] } sensors = { input-voltage = 2, input-current = 2, voltage = 2, current = 2, temperature = 3, speed = 2 } refdes = "PSU0" +fruid = "pmbus" [[config.i2c.devices]] bus = "backplane" @@ -428,6 +430,7 @@ description = "PSU 1 MCU" power = { rails = [ "V54_PSU1", "V12_PSU1" ], sensors = ["voltage", "current", "input-voltage", "input-current"] } sensors = { input-voltage = 2, input-current = 2, voltage = 2, current = 2, temperature = 3, speed = 2 } refdes = "PSU1" +fruid = "pmbus" [[config.i2c.devices]] bus = "backplane" @@ -446,6 +449,7 @@ description = "PSU 2 MCU" power = { rails = [ "V54_PSU2", "V12_PSU2" ], sensors = ["voltage", "current", "input-voltage", "input-current"] } sensors = { input-voltage = 2, input-current = 2, voltage = 2, current = 2, temperature = 3, speed = 2 } refdes = "PSU2" +fruid = "pmbus" [[config.i2c.devices]] bus = "backplane" @@ -464,6 +468,7 @@ description = "PSU 3 MCU" power = { rails = [ "V54_PSU3", "V12_PSU3" ], sensors = ["voltage", "current", "input-voltage", "input-current"] } sensors = { input-voltage = 2, input-current = 2, voltage = 2, current = 2, temperature = 3, speed = 2 } refdes = "PSU3" +fruid = "pmbus" [[config.i2c.devices]] bus = "backplane" @@ -500,6 +505,7 @@ description = "PSU 5 MCU" power = { rails = [ "V54_PSU5", "V12_PSU5" ], sensors = ["voltage", "current", "input-voltage", "input-current"] } sensors = { input-voltage = 2, input-current = 2, voltage = 2, current = 2, temperature = 3, speed = 2 } refdes = "PSU5" +fruid = "pmbus" [config.spi.spi2] controller = 2 diff --git a/drv/i2c-devices/Cargo.toml b/drv/i2c-devices/Cargo.toml index bcd62bcda9..91752b97fe 100644 --- a/drv/i2c-devices/Cargo.toml +++ b/drv/i2c-devices/Cargo.toml @@ -16,6 +16,7 @@ derive-idol-err = { path = "../../lib/derive-idol-err" } drv-i2c-api = { path = "../i2c-api" } drv-onewire = { path = "../onewire" } ringbuf = { path = "../../lib/ringbuf" } +counters = { path = "../../lib/counters" } task-power-api = { path = "../../task/power-api" } userlib = { path = "../../sys/userlib" } diff --git a/drv/i2c-devices/src/lib.rs b/drv/i2c-devices/src/lib.rs index 1a320122ce..dd51d60c24 100644 --- a/drv/i2c-devices/src/lib.rs +++ b/drv/i2c-devices/src/lib.rs @@ -233,6 +233,107 @@ pub trait Validate> { } } +#[derive(Copy, Clone, Eq, PartialEq, counters::Count)] +pub enum PmbusVpdError { + I2c { + cmd: PmbusVpdCmd, + #[count(children)] + err: drv_i2c_api::ResponseCode, + }, + InvalidStr { + cmd: PmbusVpdCmd, + }, + BufferTooSmall { + cmd: PmbusVpdCmd, + }, +} + +#[derive( + Copy, + Clone, + Eq, + PartialEq, + zerocopy_derive::IntoBytes, + zerocopy_derive::Immutable, + counters::Count, +)] +#[repr(u8)] +pub enum PmbusVpdCmd { + MfrId = pmbus::CommandCode::MFR_ID as u8, + MfrModel = pmbus::CommandCode::MFR_MODEL as u8, + MfrRevision = pmbus::CommandCode::MFR_REVISION as u8, + MfrSerial = pmbus::CommandCode::MFR_SERIAL as u8, +} + +pub struct PmbusVpd<'buf> { + pub mfr: &'buf str, + pub mpn: &'buf str, + pub rev: &'buf str, + pub serial: &'buf str, +} + +impl<'buf> PmbusVpd<'buf> { + pub fn read_from( + dev: &I2cDevice, + buf: &'buf mut [u8], + ) -> Result { + use core::ops::Range; + + fn read( + dev: &drv_i2c_api::I2cDevice, + cmd: PmbusVpdCmd, + buf: &mut [u8], + off: &mut usize, + ) -> Result, PmbusVpdError> { + // if *off + len > buf.len() { + // return Err(PmbusVpdError::BufferTooSmall { cmd }); + // } + + // PMBus block reads may not be longer than 32 bytes. Clamp this + // down as `drv_i2c_api` gets mad if it sees a lease of >255B. + let rdlen = core::cmp::min(buf.len(), off + 32); + let len = dev + .read_block(cmd as u8, &mut buf[*off..rdlen]) + .map_err(|err| PmbusVpdError::I2c { cmd, err })?; + let range = *off..*off + len; + *off += len; + Ok(range) + } + let mut off = 0; + let mfr_range = read(dev, PmbusVpdCmd::MfrId, buf, &mut off)?; + let mpn_range = read(dev, PmbusVpdCmd::MfrModel, buf, &mut off)?; + let rev_range = read(dev, PmbusVpdCmd::MfrRevision, buf, &mut off)?; + let serial_range = read(dev, PmbusVpdCmd::MfrSerial, buf, &mut off)?; + let mfr = core::str::from_utf8(&buf[mfr_range]).map_err(|_| { + PmbusVpdError::InvalidStr { + cmd: PmbusVpdCmd::MfrId, + } + })?; + let mpn = core::str::from_utf8(&buf[mpn_range]).map_err(|_| { + PmbusVpdError::InvalidStr { + cmd: PmbusVpdCmd::MfrModel, + } + })?; + let rev = core::str::from_utf8(&buf[rev_range]).map_err(|_| { + PmbusVpdError::InvalidStr { + cmd: PmbusVpdCmd::MfrRevision, + } + })?; + let serial = + core::str::from_utf8(&buf[serial_range]).map_err(|_| { + PmbusVpdError::InvalidStr { + cmd: PmbusVpdCmd::MfrSerial, + } + })?; + Ok(Self { + mfr, + mpn, + rev, + serial, + }) + } +} + pub mod adm1272; pub mod adt7420; pub mod at24csw080; diff --git a/drv/i2c-devices/src/mwocp68.rs b/drv/i2c-devices/src/mwocp68.rs index 516612014d..f7f85e896c 100644 --- a/drv/i2c-devices/src/mwocp68.rs +++ b/drv/i2c-devices/src/mwocp68.rs @@ -31,7 +31,10 @@ pub struct Mwocp68 { pub struct FirmwareRev(pub [u8; 4]); #[derive(Copy, Clone, PartialEq, Default)] -pub struct SerialNumber(pub [u8; 12]); +pub struct SerialNumber(pub [u8; SERIAL_LEN]); + +const SERIAL_LEN: usize = 12; +const REVISION_LEN: usize = 14; // // The boot loader command -- sent via BOOT_LOADER_CMD -- is unfortunately odd @@ -481,8 +484,6 @@ impl Mwocp68 { /// Returns the firmware revision of the primary MCU (AC input side). /// pub fn firmware_revision(&self) -> Result { - const REVISION_LEN: usize = 14; - let mut data = [0u8; REVISION_LEN]; let expected = b"XXXX-YYYY-0000"; diff --git a/task/control-plane-agent/src/inventory.rs b/task/control-plane-agent/src/inventory.rs index 491939413f..95dea19dd8 100644 --- a/task/control-plane-agent/src/inventory.rs +++ b/task/control-plane-agent/src/inventory.rs @@ -8,10 +8,11 @@ use gateway_messages::measurement::{ Measurement, MeasurementError, MeasurementKind, }; use gateway_messages::sp_impl::{BoundsChecked, DeviceDescription}; -use gateway_messages::vpd::{OxideVpd, Tmp117Vpd, Vpd, VpdReadError}; +use gateway_messages::vpd::{MfgVpd, OxideVpd, Tmp117Vpd, Vpd, VpdReadError}; use gateway_messages::{ ComponentDetails, DeviceCapabilities, DevicePresence, SpComponent, SpError, }; +use ringbuf::ringbuf_entry_root; use task_sensor_api::Sensor as SensorTask; use task_sensor_api::SensorError; use task_validate_api::FruidMode; @@ -91,6 +92,7 @@ impl Inventory { Some(FruidMode::At24Csw080Barcode(_)) => 1, Some(FruidMode::At24Csw080Nested(_)) => 0, // TODO(eliza): implement nested SASY barcodes Some(FruidMode::Tmp117(_)) => 1, + Some(FruidMode::Pmbus(_)) => 1, None => 0, }; Ok(nsensors + nfruid) @@ -161,6 +163,41 @@ impl Inventory { Err(err) => ComponentDetails::Vpd(Vpd::Err(err)), } } + FruidMode::Pmbus(f) => { + use drv_i2c_devices::{PmbusVpd, PmbusVpdError}; + let dev = f(I2C.get_task_id()); + + match drv_i2c_devices::PmbusVpd::read_from(&dev, self.fruid_buf) + { + Ok(PmbusVpd { + mpn, + mfr, + serial, + rev, + }) => ComponentDetails::Vpd(Vpd::Mfg(MfgVpd { + mpn, + mfg: mfr, + serial, + mfg_rev: rev, + })), + Err(err) => { + ringbuf_entry_root!(crate::Log::PmbusVpdError { + dev: *component, + err, + }); + let rsp = match err { + PmbusVpdError::BufferTooSmall { .. } => { + VpdReadError::BadRead + } + PmbusVpdError::InvalidStr { .. } => { + VpdReadError::InvalidContents + } + PmbusVpdError::I2c { .. } => VpdReadError::I2cError, + }; + ComponentDetails::Vpd(Vpd::Err(rsp)) + } + } + } } } diff --git a/task/control-plane-agent/src/main.rs b/task/control-plane-agent/src/main.rs index c9c4eb823e..44a3f381dd 100644 --- a/task/control-plane-agent/src/main.rs +++ b/task/control-plane-agent/src/main.rs @@ -81,6 +81,11 @@ enum Log { ReadRotPage, IpcRequest(#[count(children)] IpcRequest), VpdLockStatus, + PmbusVpdError { + dev: SpComponent, + #[count(children)] + err: drv_i2c_devices::PmbusVpdError, + }, } // This enum does not define the actual MGS protocol - it is only used in the diff --git a/task/control-plane-agent/src/mgs_psc.rs b/task/control-plane-agent/src/mgs_psc.rs index fdf45de984..8f512aaaf5 100644 --- a/task/control-plane-agent/src/mgs_psc.rs +++ b/task/control-plane-agent/src/mgs_psc.rs @@ -451,8 +451,8 @@ impl SpHandler for MgsHandler { &mut self, component: SpComponent, index: BoundsChecked, - ) -> ComponentDetails { - self.common.inventory().component_details(&component, index) + ) -> ComponentDetails<&str> { + self.common.inventory.component_details(&component, index) } fn component_get_active_slot( diff --git a/task/control-plane-agent/src/mgs_sidecar.rs b/task/control-plane-agent/src/mgs_sidecar.rs index 4a5e14ed64..f5b315f678 100644 --- a/task/control-plane-agent/src/mgs_sidecar.rs +++ b/task/control-plane-agent/src/mgs_sidecar.rs @@ -923,12 +923,12 @@ impl SpHandler for MgsHandler { &mut self, component: SpComponent, index: BoundsChecked, - ) -> ComponentDetails { + ) -> ComponentDetails<&str> { match component { SpComponent::MONORAIL => ComponentDetails::PortStatus( monorail_port_status::port_status(&self.monorail, index), ), - _ => self.common.inventory().component_details(&component, index), + _ => self.common.inventory.component_details(&component, index), } } diff --git a/task/validate-api/Cargo.toml b/task/validate-api/Cargo.toml index 29d071c4e3..07714de23a 100644 --- a/task/validate-api/Cargo.toml +++ b/task/validate-api/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [features] -fruid = [] +fruid = ["drv-i2c-devices"] [dependencies] idol-runtime.workspace = true diff --git a/task/validate-api/build.rs b/task/validate-api/build.rs index bd0ee6c5d3..254b7175f6 100644 --- a/task/validate-api/build.rs +++ b/task/validate-api/build.rs @@ -112,7 +112,11 @@ fn write_pub_device_descriptions() -> anyhow::Result<()> { Some("FruidMode::At24Csw080NestedBarcode") } (None, "tmp117") => Some("FruidMode::Tmp117"), - // TODO(eliza): PMBus + (Some(build_i2c::FruidMode::Pmbus), _) => { + // TODO(elize): this should check that the device is a PMBus + // device and error if it isn't... + Some("FruidMode::Pmbus") + } (Some(mode), device) => { println!("cargo::error=FRUID mode {mode:?} not supported for {device}"); bad_fruids += 1; diff --git a/task/validate-api/src/lib.rs b/task/validate-api/src/lib.rs index ed3ccc1a94..fd8b5214ae 100644 --- a/task/validate-api/src/lib.rs +++ b/task/validate-api/src/lib.rs @@ -7,7 +7,9 @@ #![no_std] use derive_idol_err::IdolError; -use drv_i2c_api::{I2cDevice, ResponseCode}; +#[cfg(feature = "fruid")] +use drv_i2c_api::I2cDevice; +use drv_i2c_api::ResponseCode; use userlib::*; use zerocopy::{Immutable, IntoBytes, KnownLayout}; @@ -85,6 +87,7 @@ pub enum FruidMode { At24Csw080Barcode(fn(TaskId) -> I2cDevice), At24Csw080Nested(fn(TaskId) -> I2cDevice), Tmp117(fn(TaskId) -> I2cDevice), + Pmbus(fn(TaskId) -> I2cDevice), } #[cfg(feature = "fruid")] @@ -94,6 +97,7 @@ impl core::fmt::Debug for FruidMode { FruidMode::At24Csw080Barcode(_) => write!(f, "At24Csw080Barcode"), FruidMode::At24Csw080Nested(_) => write!(f, "At24Csw080Nested"), FruidMode::Tmp117(_) => write!(f, "Tmp117"), + FruidMode::Pmbus(_) => write!(f, "Pmbus"), } } } From 4069a8ed8bc45723f6233641e3cdfade4d799855 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Mon, 15 Sep 2025 09:35:06 -0700 Subject: [PATCH 8/9] refactoring --- task/control-plane-agent/src/inventory.rs | 22 ++++++++++++++++++++-- task/control-plane-agent/src/mgs_common.rs | 10 +--------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/task/control-plane-agent/src/inventory.rs b/task/control-plane-agent/src/inventory.rs index 95dea19dd8..ae29a610fa 100644 --- a/task/control-plane-agent/src/inventory.rs +++ b/task/control-plane-agent/src/inventory.rs @@ -27,9 +27,18 @@ userlib::task_slot!(I2C, i2c_driver); pub(crate) struct Inventory { validate_task: Validate, sensor_task: SensorTask, - fruid_buf: &'static mut [u8], + fruid_buf: &'static mut [u8; FRUID_BUF_SIZE], } +/// At present, this buffer must be large enough to store a complete set of +/// PMBus FRUID values (`MFR_ID`, `MFR_MODEL`, `MFR_REVISION`, `MFR_SERIAL`). +/// Each of these four values is a SMBus "block read", which may be up to 32 +/// bytes. So, a 128-byte buffer is sufficient. +/// +/// If we want to read more FRUID values in the future, this will need to be +/// embiggened. +const FRUID_BUF_SIZE: usize = 32 * 4; + // pub(crate) struct FixedStr { // buf: [u8; 32], // len: usize, @@ -63,11 +72,20 @@ pub(crate) struct Inventory { // } // } // } +// +// impl Inventory { - pub(crate) fn new(fruid_buf: &'static mut [u8]) -> Self { + pub(crate) fn new() -> Self { let () = devices_with_static_validation::ASSERT_EACH_DEVICE_FITS_IN_ONE_PACKET; + let fruid_buf = { + use static_cell::ClaimOnceCell; + static BUF: ClaimOnceCell<[u8; FRUID_BUF_SIZE]> = + ClaimOnceCell::new([0; FRUID_BUF_SIZE]); + BUF.claim() + }; + Self { validate_task: Validate::from(VALIDATE.get_task_id()), sensor_task: SensorTask::from(SENSOR.get_task_id()), diff --git a/task/control-plane-agent/src/mgs_common.rs b/task/control-plane-agent/src/mgs_common.rs index 298e09720b..3c7067f66d 100644 --- a/task/control-plane-agent/src/mgs_common.rs +++ b/task/control-plane-agent/src/mgs_common.rs @@ -65,22 +65,14 @@ pub(crate) struct MgsCommon { sensor: Sensor, } -const FRUID_BUF_SIZE: usize = 256; - impl MgsCommon { pub(crate) fn claim_static_resources(base_mac_address: MacAddress) -> Self { - use static_cell::ClaimOnceCell; - let fruid_buf = { - static BUF: ClaimOnceCell<[u8; FRUID_BUF_SIZE]> = - ClaimOnceCell::new([0; FRUID_BUF_SIZE]); - BUF.claim() - }; Self { sp_update: SpUpdate::new(), rot_update: RotUpdate::new(), dump_state: DumpState::new(), reset_component_requested: None, - inventory: Inventory::new(fruid_buf), + inventory: Inventory::new(), base_mac_address, packrat: Packrat::from(PACKRAT.get_task_id()), sprot: SpRot::from(SPROT.get_task_id()), From 5d2586438d432942be22896ac521a90cd171be5f Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Mon, 15 Sep 2025 09:45:34 -0700 Subject: [PATCH 9/9] more pmbus tidiness --- drv/i2c-devices/src/lib.rs | 30 ++++++++----- task/control-plane-agent/src/inventory.rs | 52 ++--------------------- 2 files changed, 24 insertions(+), 58 deletions(-) diff --git a/drv/i2c-devices/src/lib.rs b/drv/i2c-devices/src/lib.rs index dd51d60c24..4958eff323 100644 --- a/drv/i2c-devices/src/lib.rs +++ b/drv/i2c-devices/src/lib.rs @@ -273,6 +273,16 @@ pub struct PmbusVpd<'buf> { } impl<'buf> PmbusVpd<'buf> { + /// SMBus block reads may not be longer than 32 bytes. + const BLOCK_LEN: usize = 32; + /// Maximum length currently required to read a complete set of VPD + /// registers from a PMBus device. + /// + /// Currently, this is 4 32-byte blocks (`MFR_ID`, `MFR_MODEL`, + /// `MFR_REVISION`, and `MFR_SERIAL`). If more values are added in the + /// future, this will need to be embiggened. + pub const MAX_LEN: usize = Self::BLOCK_LEN * 4; + pub fn read_from( dev: &I2cDevice, buf: &'buf mut [u8], @@ -283,22 +293,22 @@ impl<'buf> PmbusVpd<'buf> { dev: &drv_i2c_api::I2cDevice, cmd: PmbusVpdCmd, buf: &mut [u8], - off: &mut usize, + curr_off: &mut usize, ) -> Result, PmbusVpdError> { - // if *off + len > buf.len() { - // return Err(PmbusVpdError::BufferTooSmall { cmd }); - // } - + let off = *curr_off; // PMBus block reads may not be longer than 32 bytes. Clamp this // down as `drv_i2c_api` gets mad if it sees a lease of >255B. - let rdlen = core::cmp::min(buf.len(), off + 32); + let Some(block) = buf.get_mut(off..off + PmbusVpd::BLOCK_LEN) + else { + return Err(PmbusVpdError::BufferTooSmall { cmd }); + }; let len = dev - .read_block(cmd as u8, &mut buf[*off..rdlen]) + .read_block(cmd, block) .map_err(|err| PmbusVpdError::I2c { cmd, err })?; - let range = *off..*off + len; - *off += len; - Ok(range) + *curr_off += len; + Ok(off..*curr_off) } + let mut off = 0; let mfr_range = read(dev, PmbusVpdCmd::MfrId, buf, &mut off)?; let mpn_range = read(dev, PmbusVpdCmd::MfrModel, buf, &mut off)?; diff --git a/task/control-plane-agent/src/inventory.rs b/task/control-plane-agent/src/inventory.rs index ae29a610fa..78b634ca03 100644 --- a/task/control-plane-agent/src/inventory.rs +++ b/task/control-plane-agent/src/inventory.rs @@ -4,6 +4,7 @@ use drv_i2c_api::{self as i2c, I2cDevice}; use drv_i2c_devices::at24csw080::At24Csw080; +use drv_i2c_devices::PmbusVpd; use gateway_messages::measurement::{ Measurement, MeasurementError, MeasurementKind, }; @@ -27,62 +28,17 @@ userlib::task_slot!(I2C, i2c_driver); pub(crate) struct Inventory { validate_task: Validate, sensor_task: SensorTask, - fruid_buf: &'static mut [u8; FRUID_BUF_SIZE], + fruid_buf: &'static mut [u8; PmbusVpd::MAX_LEN], } -/// At present, this buffer must be large enough to store a complete set of -/// PMBus FRUID values (`MFR_ID`, `MFR_MODEL`, `MFR_REVISION`, `MFR_SERIAL`). -/// Each of these four values is a SMBus "block read", which may be up to 32 -/// bytes. So, a 128-byte buffer is sufficient. -/// -/// If we want to read more FRUID values in the future, this will need to be -/// embiggened. -const FRUID_BUF_SIZE: usize = 32 * 4; - -// pub(crate) struct FixedStr { -// buf: [u8; 32], -// len: usize, -// } - -// impl FixedStr { -// pub fn copy_from_slice(slice: &[u8]) -> Result { -// core::str::from_utf8(slice)?; -// let mut buf = [0u8; 32]; -// buf[..slice.len()].copy_from_slice(slice); -// Ok(Self { -// buf, -// len: slice.len(), -// }) -// } - -// pub fn from_buf( -// bytes: [u8; 32], -// len: usize, -// ) -> Result { -// core::str::from_utf8(&bytes[..len])?; -// Ok(Self { buf: bytes, len }) -// } -// } - -// impl AsRef for FixedStr { -// fn as_ref(&self) -> &str { -// unsafe { -// // SAFETY: This is checked when constructing the FixedStr. -// core::str::from_utf8_unchecked(&self.buf[..self.len]) -// } -// } -// } -// -// - impl Inventory { pub(crate) fn new() -> Self { let () = devices_with_static_validation::ASSERT_EACH_DEVICE_FITS_IN_ONE_PACKET; let fruid_buf = { use static_cell::ClaimOnceCell; - static BUF: ClaimOnceCell<[u8; FRUID_BUF_SIZE]> = - ClaimOnceCell::new([0; FRUID_BUF_SIZE]); + static BUF: ClaimOnceCell<[u8; PmbusVpd::MAX_LEN]> = + ClaimOnceCell::new([0; PmbusVpd::MAX_LEN]); BUF.claim() };