1 #include "fru_oem_ibm.hpp"
2 
3 #include <phosphor-logging/lg2.hpp>
4 
5 #include <ranges>
6 
7 PHOSPHOR_LOG2_USING;
8 
9 namespace pldm
10 {
11 namespace responder
12 {
13 namespace oem_ibm_fru
14 {
15 
16 void pldm::responder::oem_ibm_fru::Handler::setIBMFruHandler(
17     pldm::responder::fru::Handler* handler)
18 {
19     fruHandler = handler;
20 }
21 
22 int pldm::responder::oem_ibm_fru::Handler::processOEMFRUTable(
23     const std::vector<uint8_t>& fruData)
24 {
25     uint8_t dataSize = 0;
26     const uint8_t* data = fruData.data();
27 
28     while (dataSize < fruData.size())
29     {
30         auto record =
31             reinterpret_cast<const pldm_fru_record_data_format*>(data);
32         if (!record)
33         {
34             return PLDM_ERROR_INVALID_DATA;
35         }
36 
37         auto& entityAssociationMap = getAssociateEntityMap();
38         uint16_t fruRSI = le16toh(record->record_set_id);
39 
40         dataSize += sizeof(pldm_fru_record_data_format) -
41                     sizeof(pldm_fru_record_tlv);
42         data += dataSize;
43 
44         for ([[maybe_unused]] const auto& i :
45              std::views::iota(0, (int)record->num_fru_fields))
46         {
47             auto tlv = reinterpret_cast<const pldm_fru_record_tlv*>(data);
48             if (!tlv)
49             {
50                 return PLDM_ERROR_INVALID_DATA;
51             }
52 
53             if (tlv->type == PLDM_OEM_FRU_FIELD_TYPE_PCIE_CONFIG_SPACE_DATA)
54             {
55                 auto pcieData =
56                     reinterpret_cast<const PcieConfigSpaceData*>(tlv->value);
57 
58                 if (!pcieData)
59                 {
60                     return PLDM_ERROR_INVALID_DATA;
61                 }
62                 auto vendorId = std::to_string(htole16(pcieData->vendorId));
63                 auto deviceId = std::to_string(htole16(pcieData->deviceId));
64                 auto revisionId = std::to_string(pcieData->revisionId);
65 
66                 std::stringstream ss;
67 
68                 for (const auto& ele : pcieData->classCode)
69                 {
70                     ss << std::setfill('0') << std::setw(2) << std::hex << ele;
71                 }
72                 std::string classCode = ss.str();
73 
74                 auto subSystemVendorId =
75                     std::to_string(htole16(pcieData->subSystemVendorId));
76                 auto subSystemId =
77                     std::to_string(htole16(pcieData->subSystemId));
78 
79                 updateDBusProperty(fruRSI, entityAssociationMap, vendorId,
80                                    deviceId, revisionId, classCode,
81                                    subSystemVendorId, subSystemId);
82             }
83             // length of tlv is removed from the structure pldm_fru_record_tlv
84             // and the new tlv length is added back.
85             dataSize += sizeof(pldm_fru_record_tlv) - sizeof(uint8_t) +
86                         tlv->length;
87             data += dataSize;
88         }
89     }
90 
91     return PLDM_SUCCESS;
92 }
93 
94 void Handler::updateDBusProperty(
95     uint16_t fruRSI, const AssociatedEntityMap& fruAssociationMap,
96     const std::string& vendorId, const std::string& deviceId,
97     const std::string& revisionId, const std::string& classCode,
98     const std::string& subSystemVendorId, const std::string& subSystemId)
99 {
100     uint16_t entityType{};
101     uint16_t entityInstanceNum{};
102     uint16_t containerId{};
103     uint16_t terminusHandle{};
104     const pldm_pdr_record* record{};
105 
106     record = pldm_pdr_fru_record_set_find_by_rsi(
107         pdrRepo, fruRSI, &terminusHandle, &entityType, &entityInstanceNum,
108         &containerId);
109 
110     if (record)
111     {
112         for (const auto& [key, value] : fruAssociationMap)
113         {
114             if (entityInstanceNum == value.entity_instance_num &&
115                 entityType == value.entity_type &&
116                 containerId == value.entity_container_id)
117             {
118                 dbus_map_update(key, "Function0VendorId", vendorId);
119                 dbus_map_update(key, "Function0DeviceId", deviceId);
120                 dbus_map_update(key, "Function0RevisionId", revisionId);
121                 dbus_map_update(key, "Function0ClassCode", classCode);
122                 dbus_map_update(key, "Function0SubsystemVendorId",
123                                 subSystemVendorId);
124                 dbus_map_update(key, "Function0SubsystemId", subSystemId);
125             }
126         }
127     }
128 }
129 
130 void Handler::dbus_map_update(const std::string& adapterObjPath,
131                               const std::string& propertyName,
132                               const std::string& propValue)
133 {
134     pldm::utils::PropertyValue value = propValue;
135     pldm::utils::DBusMapping dbusMapping;
136     dbusMapping.objectPath = adapterObjPath;
137     dbusMapping.interface = "xyz.openbmc_project.Inventory.Item.PCIeDevice";
138     dbusMapping.propertyName = propertyName;
139     dbusMapping.propertyType = "string";
140     try
141     {
142         pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
143     }
144     catch (const std::exception& e)
145     {
146         error("Failed to set '{PROPERTY}' property: {ERROR}", "PROPERTY",
147               propertyName, "ERROR", e);
148     }
149 }
150 } // namespace oem_ibm_fru
151 } // namespace responder
152 } // namespace pldm
153