1 #pragma once
2 
3 #include "async_resp.hpp"
4 #include "dbus_utility.hpp"
5 #include "error_messages.hpp"
6 #include "generated/enums/pcie_device.hpp"
7 #include "generated/enums/pcie_slots.hpp"
8 #include "http/utility.hpp"
9 
10 #include <boost/system/error_code.hpp>
11 #include <boost/url/format.hpp>
12 #include <nlohmann/json.hpp>
13 
14 #include <array>
15 #include <memory>
16 #include <optional>
17 #include <string>
18 #include <string_view>
19 
20 namespace redfish
21 {
22 namespace pcie_util
23 {
24 
25 /**
26  * @brief Populate the PCIe Device list from a GetSubTreePaths search of
27  *        inventory
28  *
29  * @param[i,o] asyncResp  Async response object
30  * @param[i]   Name   Key to store the list of PCIe devices in asyncResp
31  *
32  * @return void
33  */
34 
35 inline void
36     getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
37                       const std::string& name)
38 {
39     static constexpr std::array<std::string_view, 1> pcieDeviceInterface = {
40         "xyz.openbmc_project.Inventory.Item.PCIeDevice"};
41 
42     dbus::utility::getSubTreePaths(
43         "/xyz/openbmc_project/inventory", 0, pcieDeviceInterface,
44         [asyncResp, name](const boost::system::error_code& ec,
45                           const dbus::utility::MapperGetSubTreePathsResponse&
46                               pcieDevicePaths) {
47         if (ec)
48         {
49             BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
50                              << ec.message();
51             // Not an error, system just doesn't have PCIe info
52             return;
53         }
54         nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name];
55         pcieDeviceList = nlohmann::json::array();
56         for (const std::string& pcieDevicePath : pcieDevicePaths)
57         {
58             size_t devStart = pcieDevicePath.rfind('/');
59             if (devStart == std::string::npos)
60             {
61                 continue;
62             }
63 
64             std::string devName = pcieDevicePath.substr(devStart + 1);
65             if (devName.empty())
66             {
67                 continue;
68             }
69             nlohmann::json::object_t pcieDevice;
70             pcieDevice["@odata.id"] = boost::urls::format(
71                 "/redfish/v1/Systems/system/PCIeDevices/{}", devName);
72             pcieDeviceList.emplace_back(std::move(pcieDevice));
73         }
74         asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size();
75         });
76 }
77 
78 inline std::optional<pcie_slots::SlotTypes>
79     dbusSlotTypeToRf(const std::string& slotType)
80 {
81     if (slotType ==
82         "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.FullLength")
83     {
84         return pcie_slots::SlotTypes::FullLength;
85     }
86     if (slotType ==
87         "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.HalfLength")
88     {
89         return pcie_slots::SlotTypes::HalfLength;
90     }
91     if (slotType ==
92         "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.LowProfile")
93     {
94         return pcie_slots::SlotTypes::LowProfile;
95     }
96     if (slotType ==
97         "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.Mini")
98     {
99         return pcie_slots::SlotTypes::Mini;
100     }
101     if (slotType == "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.M_2")
102     {
103         return pcie_slots::SlotTypes::M2;
104     }
105     if (slotType == "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.OEM")
106     {
107         return pcie_slots::SlotTypes::OEM;
108     }
109     if (slotType ==
110         "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.OCP3Small")
111     {
112         return pcie_slots::SlotTypes::OCP3Small;
113     }
114     if (slotType ==
115         "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.OCP3Large")
116     {
117         return pcie_slots::SlotTypes::OCP3Large;
118     }
119     if (slotType == "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.U_2")
120     {
121         return pcie_slots::SlotTypes::U2;
122     }
123     if (slotType ==
124         "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.Unknown")
125     {
126         return pcie_slots::SlotTypes::Invalid;
127     }
128 
129     // Unspecified slotType should return an internal error.
130     return std::nullopt;
131 }
132 
133 inline std::optional<pcie_device::PCIeTypes>
134     redfishPcieGenerationFromDbus(const std::string& generationInUse)
135 {
136     if (generationInUse ==
137         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
138     {
139         return pcie_device::PCIeTypes::Gen1;
140     }
141     if (generationInUse ==
142         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
143     {
144         return pcie_device::PCIeTypes::Gen2;
145     }
146     if (generationInUse ==
147         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
148     {
149         return pcie_device::PCIeTypes::Gen3;
150     }
151     if (generationInUse ==
152         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
153     {
154         return pcie_device::PCIeTypes::Gen4;
155     }
156     if (generationInUse ==
157         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
158     {
159         return pcie_device::PCIeTypes::Gen5;
160     }
161     if (generationInUse.empty() ||
162         generationInUse ==
163             "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
164     {
165         return pcie_device::PCIeTypes::Invalid;
166     }
167 
168     // The value is not unknown or Gen1-5, need return an internal error.
169     return std::nullopt;
170 }
171 
172 } // namespace pcie_util
173 } // namespace redfish
174