Support "GenerationInUse" PCIe device property
This commit adds support for PCIe device property "GenerationInUse",
and let management APIs like redfish can expose the information.
New property:
GenerationInUse : The PCIe interface generation in use by the device.
Tested:
Ensure DBus is created and the value is correct of new property.
Dbus Sample output:
NAME TYPE SIGNATURE RESULT/VALUE FLAGS
[...]
xyz.openbmc_project.PCIe.Device interface - - -
.DeviceType property s "SingleFunction" emits-change
.Function0ClassCode property s "0x060400" emits-change
[...]
.GenerationInUse property s "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2" emits-change
Signed-off-by: Spencer Ku <Spencer.Ku@quantatw.com>
Change-Id: I2273b9529a16ca0229c5d0ad17befcd3f764a188
diff --git a/include/peci_pcie.hpp b/include/peci_pcie.hpp
index 74ea2da..1e10b46 100644
--- a/include/peci_pcie.hpp
+++ b/include/peci_pcie.hpp
@@ -33,4 +33,25 @@
static constexpr const int peciCheckInterval = 10;
static constexpr const int osStandbyDelaySeconds = 10;
+
+static constexpr const int pointToCapStruct = 0x34;
+static constexpr const int maskOfCLS = 0x0F;
+
+static constexpr const int capPointerOffset = 1;
+static constexpr const int linkStatusOffset = 18;
+
+// PCIe version
+// GEN1 : 0001b : transfer rate 2.5GB
+// GEN2 : 0010b : transfer rate 5GB
+// GEN3 : 0011b : transfer rate 8GB
+// GEN4 : 0100b : transfer rate 16GB
+// GEN5 : 0101b : transfer rate 32GB
+enum GenerationInUse : int
+{
+ pcieGen1 = 1,
+ pcieGen2,
+ pcieGen3,
+ pcieGen4,
+ pcieGen5
+};
} // namespace peci_pcie
diff --git a/src/peci_pcie.cpp b/src/peci_pcie.cpp
index ea75c9d..3183e6e 100644
--- a/src/peci_pcie.cpp
+++ b/src/peci_pcie.cpp
@@ -68,6 +68,7 @@
enum class resCode
{
resOk,
+ resSkip,
resErr
};
@@ -258,6 +259,109 @@
return resCode::resOk;
}
+static resCode getCapReading(const int& clientAddr, const int& bus,
+ const int& dev, uint32_t& capReading,
+ const int compareCapID, const int offsetAddress,
+ const int offsetLength)
+{
+ resCode error;
+ uint32_t capAddress = 0;
+ uint32_t capabilityID;
+ uint32_t nextCapPointer = peci_pcie::pointToCapStruct;
+
+ do
+ {
+ // Get capability address
+ error = getDataFromPCIeConfig(clientAddr, bus, dev, 0, nextCapPointer,
+ 1, capAddress);
+ if (error != resCode::resOk)
+ {
+ return error;
+ }
+ // Capability struct address is a pointer which point to next capability
+ // struct, so if capability struct address is 0 means it doesn't have
+ // next capability struct.
+ if (capAddress == 0)
+ {
+ return resCode::resSkip;
+ }
+ // Get capability ID
+ error = getDataFromPCIeConfig(clientAddr, bus, dev, 0, capAddress, 1,
+ capabilityID);
+ if (error != resCode::resOk)
+ {
+ return error;
+ }
+ nextCapPointer = capAddress + peci_pcie::capPointerOffset;
+
+ } while (capabilityID != compareCapID);
+ // Get capability reading.
+ error = getDataFromPCIeConfig(clientAddr, bus, dev, 0,
+ capAddress + offsetAddress, offsetLength,
+ capReading);
+ if (error != resCode::resOk)
+ {
+ return error;
+ }
+ return resCode::resOk;
+}
+
+static resCode getGenerationInUse(const int& clientAddr, const int& bus,
+ const int& dev, std::string& generationInUse)
+{
+ resCode error;
+ std::string res;
+ uint32_t capReading = 0;
+
+ // Capability ID 0x10(16) is PCI Express
+ constexpr int pcieCapID = 16;
+ constexpr int capLength = 2;
+ uint32_t linkStatus;
+
+ error = getCapReading(clientAddr, bus, dev, linkStatus, pcieCapID,
+ peci_pcie::linkStatusOffset, capLength);
+ if (error != resCode::resOk)
+ {
+ return error;
+ }
+
+ uint32_t linkSpeed = linkStatus & peci_pcie::maskOfCLS;
+
+ switch (linkSpeed)
+ {
+ case peci_pcie::pcieGen1:
+ generationInUse = "xyz.openbmc_project.Inventory.Item."
+ "PCIeSlot.Generations.Gen1";
+ error = resCode::resOk;
+ break;
+ case peci_pcie::pcieGen2:
+ generationInUse = "xyz.openbmc_project.Inventory.Item."
+ "PCIeSlot.Generations.Gen2";
+ error = resCode::resOk;
+ break;
+ case peci_pcie::pcieGen3:
+ generationInUse = "xyz.openbmc_project.Inventory.Item."
+ "PCIeSlot.Generations.Gen3";
+ error = resCode::resOk;
+ break;
+ case peci_pcie::pcieGen4:
+ generationInUse = "xyz.openbmc_project.Inventory.Item."
+ "PCIeSlot.Generations.Gen4";
+ error = resCode::resOk;
+ break;
+ case peci_pcie::pcieGen5:
+ generationInUse = "xyz.openbmc_project.Inventory.Item."
+ "PCIeSlot.Generations.Gen5";
+ error = resCode::resOk;
+ break;
+ default:
+ std::cerr << "Link speed : " << linkSpeed
+ << " can not mapping to PCIe type list.\n";
+ error = resCode::resSkip;
+ }
+ return error;
+}
+
static resCode isMultiFunction(const int& clientAddr, const int& bus,
const int& dev, bool& res)
{
@@ -415,6 +519,24 @@
{
setPCIeProperty(clientAddr, bus, dev, deviceTypeName, "SingleFunction");
}
+
+ // Set PCIe Generation
+ constexpr char const* generationInUseName = "GenerationInUse";
+ std::string generationInUse;
+ error = getGenerationInUse(clientAddr, bus, dev, generationInUse);
+ if (error == resCode::resErr)
+ {
+ return error;
+ }
+ // "resSkip" status means it can't get the capability reading, such like
+ // this device is not PCI Express.
+ if (error == resCode::resSkip)
+ {
+ setPCIeProperty(clientAddr, bus, dev, generationInUseName, "");
+ return resCode::resOk;
+ }
+ setPCIeProperty(clientAddr, bus, dev, generationInUseName, generationInUse);
+
return resCode::resOk;
}