ipmbsensor: add support for an Ampere SMPro on an IPMB
On ADLINK systems, the SMPro can be reached via the MMC (Module
Management Controller), which is a second BMC. It sits on an IPMB
bus.
Add support for reading power, voltage, current and temperature values
from the SMPro.
Tested: built ipmbsensor and ran new ipmb unit tests.
Change-Id: Ib9862486a18f77fb58d3acd59de7686750029b56
Signed-off-by: Rebecca Cran <rebecca@bsdio.com>
diff --git a/src/IpmbSensor.cpp b/src/IpmbSensor.cpp
index 30531bf..fbc4b7d 100644
--- a/src/IpmbSensor.cpp
+++ b/src/IpmbSensor.cpp
@@ -249,6 +249,33 @@
0x02, 0x00, 0x00, 0x00};
readingFormat = ReadingFormat::byte3;
}
+ else if (type == IpmbType::SMPro)
+ {
+ // This is an Ampere SMPro reachable via a BMC. For example,
+ // this architecture is used on ADLINK Ampere Altra systems.
+ // See the Ampere Family SoC BMC Interface Specification at
+ // https://amperecomputing.com/customer-connect/products/altra-family-software---firmware
+ // for details of the sensors.
+ commandAddress = 0;
+ netfn = 0x30;
+ command = 0x31;
+ commandData = {0x9e, deviceAddress};
+ switch (subType)
+ {
+ case IpmbSubType::temp:
+ readingFormat = ReadingFormat::nineBit;
+ break;
+ case IpmbSubType::power:
+ readingFormat = ReadingFormat::tenBit;
+ break;
+ case IpmbSubType::curr:
+ case IpmbSubType::volt:
+ readingFormat = ReadingFormat::fifteenBit;
+ break;
+ default:
+ throw std::runtime_error("Invalid sensor type");
+ }
+ }
else
{
throw std::runtime_error("Invalid sensor type");
@@ -296,6 +323,51 @@
resp = data[3];
return true;
}
+ case (ReadingFormat::nineBit):
+ case (ReadingFormat::tenBit):
+ case (ReadingFormat::fifteenBit):
+ {
+ if (data.size() != 2)
+ {
+ if (errCount == 0U)
+ {
+ std::cerr << "Invalid data length returned\n";
+ }
+ return false;
+ }
+
+ // From the Altra Family SoC BMC Interface Specification:
+ // 0xFFFF – This sensor data is either missing or is not supported
+ // by the device.
+ if ((data[0] == 0xff) && (data[1] == 0xff))
+ {
+ return false;
+ }
+
+ if (readingFormat == ReadingFormat::nineBit)
+ {
+ int16_t value = data[0];
+ if ((data[1] & 0x1) != 0)
+ {
+ // Sign extend to 16 bits
+ value |= 0xFF00;
+ }
+ resp = value;
+ }
+ else if (readingFormat == ReadingFormat::tenBit)
+ {
+ uint16_t value = ((data[1] & 0x3) << 8) + data[0];
+ resp = value;
+ }
+ else if (readingFormat == ReadingFormat::fifteenBit)
+ {
+ uint16_t value = ((data[1] & 0x7F) << 8) + data[0];
+ // Convert mV to V
+ resp = value / 1000.0;
+ }
+
+ return true;
+ }
case (ReadingFormat::elevenBit):
{
if (data.size() < 5)
@@ -464,6 +536,10 @@
{
type = IpmbType::meSensor;
}
+ else if (sensorClass == "SMPro")
+ {
+ type = IpmbType::SMPro;
+ }
else
{
std::cerr << "Invalid class " << sensorClass << "\n";