xref: /openbmc/bmcweb/features/redfish/lib/memory.hpp (revision ed3982131dcef2b499da36e674d2d21b2289ef29)
1 /*
2 // Copyright (c) 2018 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 #pragma once
17 
18 #include "health.hpp"
19 
20 #include <app.hpp>
21 #include <boost/container/flat_map.hpp>
22 #include <boost/format.hpp>
23 #include <registries/privilege_registry.hpp>
24 #include <utils/collection.hpp>
25 #include <utils/json_utils.hpp>
26 
27 namespace redfish
28 {
29 
30 using DimmProperty =
31     std::variant<std::string, std::vector<uint32_t>, std::vector<uint16_t>,
32                  uint64_t, uint32_t, uint16_t, uint8_t, bool>;
33 
34 using DimmProperties = boost::container::flat_map<std::string, DimmProperty>;
35 
36 inline std::string translateMemoryTypeToRedfish(const std::string& memoryType)
37 {
38     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR")
39     {
40         return "DDR";
41     }
42     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2")
43     {
44         return "DDR2";
45     }
46     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR3")
47     {
48         return "DDR3";
49     }
50     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR4")
51     {
52         return "DDR4";
53     }
54     if (memoryType ==
55         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR4E_SDRAM")
56     {
57         return "DDR4E_SDRAM";
58     }
59     if (memoryType ==
60         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.LPDDR4_SDRAM")
61     {
62         return "LPDDR4_SDRAM";
63     }
64     if (memoryType ==
65         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.LPDDR3_SDRAM")
66     {
67         return "LPDDR3_SDRAM";
68     }
69     if (memoryType ==
70         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2_SDRAM_FB_DIMM")
71     {
72         return "DDR2_SDRAM_FB_DIMM";
73     }
74     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2_"
75                       "SDRAM_FB_DIMM_PROB")
76     {
77         return "DDR2_SDRAM_FB_DIMM_PROBE";
78     }
79     if (memoryType ==
80         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR_SGRAM")
81     {
82         return "DDR_SGRAM";
83     }
84     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.ROM")
85     {
86         return "ROM";
87     }
88     if (memoryType ==
89         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.SDRAM")
90     {
91         return "SDRAM";
92     }
93     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.EDO")
94     {
95         return "EDO";
96     }
97     if (memoryType ==
98         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.FastPageMode")
99     {
100         return "FastPageMode";
101     }
102     if (memoryType ==
103         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.PipelinedNibble")
104     {
105         return "PipelinedNibble";
106     }
107     if (memoryType ==
108         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.Logical")
109     {
110         return "Logical";
111     }
112     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.HBM")
113     {
114         return "HBM";
115     }
116     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.HBM2")
117     {
118         return "HBM2";
119     }
120     // This is values like Other or Unknown
121     // Also D-Bus values:
122     // DRAM
123     // EDRAM
124     // VRAM
125     // SRAM
126     // RAM
127     // FLASH
128     // EEPROM
129     // FEPROM
130     // EPROM
131     // CDRAM
132     // ThreeDRAM
133     // RDRAM
134     // FBD2
135     // LPDDR_SDRAM
136     // LPDDR2_SDRAM
137     return "";
138 }
139 
140 inline void dimmPropToHex(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
141                           const char* key,
142                           const std::pair<std::string, DimmProperty>& property)
143 {
144     const uint16_t* value = std::get_if<uint16_t>(&property.second);
145     if (value == nullptr)
146     {
147         messages::internalError(aResp->res);
148         BMCWEB_LOG_DEBUG << "Invalid property type for " << property.first;
149         return;
150     }
151 
152     aResp->res.jsonValue[key] = (boost::format("0x%04x") % *value).str();
153 }
154 
155 inline void getPersistentMemoryProperties(
156     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
157     const DimmProperties& properties)
158 {
159     for (const auto& property : properties)
160     {
161         if (property.first == "ModuleManufacturerID")
162         {
163             dimmPropToHex(aResp, "ModuleManufacturerID", property);
164         }
165         else if (property.first == "ModuleProductID")
166         {
167             dimmPropToHex(aResp, "ModuleProductID", property);
168         }
169         else if (property.first == "SubsystemVendorID")
170         {
171             dimmPropToHex(aResp, "MemorySubsystemControllerManufacturerID",
172                           property);
173         }
174         else if (property.first == "SubsystemDeviceID")
175         {
176             dimmPropToHex(aResp, "MemorySubsystemControllerProductID",
177                           property);
178         }
179         else if (property.first == "VolatileRegionSizeLimitInKiB")
180         {
181             const uint64_t* value = std::get_if<uint64_t>(&property.second);
182 
183             if (value == nullptr)
184             {
185                 messages::internalError(aResp->res);
186                 BMCWEB_LOG_DEBUG << "Invalid property type for "
187                                     "VolatileRegionSizeLimitKiB";
188                 return;
189             }
190             aResp->res.jsonValue["VolatileRegionSizeLimitMiB"] = (*value) >> 10;
191         }
192         else if (property.first == "PmRegionSizeLimitInKiB")
193         {
194             const uint64_t* value = std::get_if<uint64_t>(&property.second);
195 
196             if (value == nullptr)
197             {
198                 messages::internalError(aResp->res);
199                 BMCWEB_LOG_DEBUG
200                     << "Invalid property type for PmRegioSizeLimitKiB";
201                 return;
202             }
203             aResp->res.jsonValue["PersistentRegionSizeLimitMiB"] =
204                 (*value) >> 10;
205         }
206         else if (property.first == "VolatileSizeInKiB")
207         {
208             const uint64_t* value = std::get_if<uint64_t>(&property.second);
209 
210             if (value == nullptr)
211             {
212                 messages::internalError(aResp->res);
213                 BMCWEB_LOG_DEBUG
214                     << "Invalid property type for VolatileSizeInKiB";
215                 return;
216             }
217             aResp->res.jsonValue["VolatileSizeMiB"] = (*value) >> 10;
218         }
219         else if (property.first == "PmSizeInKiB")
220         {
221             const uint64_t* value = std::get_if<uint64_t>(&property.second);
222             if (value == nullptr)
223             {
224                 messages::internalError(aResp->res);
225                 BMCWEB_LOG_DEBUG << "Invalid property type for PmSizeInKiB";
226                 return;
227             }
228             aResp->res.jsonValue["NonVolatileSizeMiB"] = (*value) >> 10;
229         }
230         else if (property.first == "CacheSizeInKB")
231         {
232             const uint64_t* value = std::get_if<uint64_t>(&property.second);
233             if (value == nullptr)
234             {
235                 messages::internalError(aResp->res);
236                 BMCWEB_LOG_DEBUG << "Invalid property type for CacheSizeInKB";
237                 return;
238             }
239             aResp->res.jsonValue["CacheSizeMiB"] = (*value >> 10);
240         }
241 
242         else if (property.first == "VoltaileRegionMaxSizeInKib")
243         {
244             const uint64_t* value = std::get_if<uint64_t>(&property.second);
245 
246             if (value == nullptr)
247             {
248                 messages::internalError(aResp->res);
249                 BMCWEB_LOG_DEBUG << "Invalid property type for "
250                                     "VolatileRegionMaxSizeInKib";
251                 return;
252             }
253             aResp->res.jsonValue["VolatileRegionSizeMaxMiB"] = (*value) >> 10;
254         }
255         else if (property.first == "PmRegionMaxSizeInKiB")
256         {
257             const uint64_t* value = std::get_if<uint64_t>(&property.second);
258 
259             if (value == nullptr)
260             {
261                 messages::internalError(aResp->res);
262                 BMCWEB_LOG_DEBUG
263                     << "Invalid property type for PmRegionMaxSizeInKiB";
264                 return;
265             }
266             aResp->res.jsonValue["PersistentRegionSizeMaxMiB"] = (*value) >> 10;
267         }
268         else if (property.first == "AllocationIncrementInKiB")
269         {
270             const uint64_t* value = std::get_if<uint64_t>(&property.second);
271 
272             if (value == nullptr)
273             {
274                 messages::internalError(aResp->res);
275                 BMCWEB_LOG_DEBUG << "Invalid property type for "
276                                     "AllocationIncrementInKiB";
277                 return;
278             }
279             aResp->res.jsonValue["AllocationIncrementMiB"] = (*value) >> 10;
280         }
281         else if (property.first == "AllocationAlignmentInKiB")
282         {
283             const uint64_t* value = std::get_if<uint64_t>(&property.second);
284 
285             if (value == nullptr)
286             {
287                 messages::internalError(aResp->res);
288                 BMCWEB_LOG_DEBUG << "Invalid property type for "
289                                     "AllocationAlignmentInKiB";
290                 return;
291             }
292             aResp->res.jsonValue["AllocationAlignmentMiB"] = (*value) >> 10;
293         }
294         else if (property.first == "VolatileRegionNumberLimit")
295         {
296             const uint64_t* value = std::get_if<uint64_t>(&property.second);
297             if (value == nullptr)
298             {
299                 messages::internalError(aResp->res);
300                 return;
301             }
302             aResp->res.jsonValue["VolatileRegionNumberLimit"] = *value;
303         }
304         else if (property.first == "PmRegionNumberLimit")
305         {
306             const uint64_t* value = std::get_if<uint64_t>(&property.second);
307             if (value == nullptr)
308             {
309                 messages::internalError(aResp->res);
310                 return;
311             }
312             aResp->res.jsonValue["PersistentRegionNumberLimit"] = *value;
313         }
314         else if (property.first == "SpareDeviceCount")
315         {
316             const uint64_t* value = std::get_if<uint64_t>(&property.second);
317             if (value == nullptr)
318             {
319                 messages::internalError(aResp->res);
320                 return;
321             }
322             aResp->res.jsonValue["SpareDeviceCount"] = *value;
323         }
324         else if (property.first == "IsSpareDeviceInUse")
325         {
326             const bool* value = std::get_if<bool>(&property.second);
327             if (value == nullptr)
328             {
329                 messages::internalError(aResp->res);
330                 return;
331             }
332             aResp->res.jsonValue["IsSpareDeviceEnabled"] = *value;
333         }
334         else if (property.first == "IsRankSpareEnabled")
335         {
336             const bool* value = std::get_if<bool>(&property.second);
337             if (value == nullptr)
338             {
339                 messages::internalError(aResp->res);
340                 return;
341             }
342             aResp->res.jsonValue["IsRankSpareEnabled"] = *value;
343         }
344         else if (property.first == "MaxAveragePowerLimitmW")
345         {
346             const auto* value =
347                 std::get_if<std::vector<uint32_t>>(&property.second);
348             if (value == nullptr)
349             {
350                 messages::internalError(aResp->res);
351                 BMCWEB_LOG_DEBUG << "Invalid property type for "
352                                     "MaxAveragePowerLimitmW";
353                 return;
354             }
355             aResp->res.jsonValue["MaxTDPMilliWatts"] = *value;
356         }
357         else if (property.first == "ConfigurationLocked")
358         {
359             const bool* value = std::get_if<bool>(&property.second);
360             if (value == nullptr)
361             {
362                 messages::internalError(aResp->res);
363                 return;
364             }
365             aResp->res.jsonValue["ConfigurationLocked"] = *value;
366         }
367         else if (property.first == "AllowedMemoryModes")
368         {
369             const std::string* value =
370                 std::get_if<std::string>(&property.second);
371             if (value == nullptr)
372             {
373                 messages::internalError(aResp->res);
374                 BMCWEB_LOG_DEBUG << "Invalid property type for FormFactor";
375                 return;
376             }
377             constexpr const std::array<const char*, 3> values{"Volatile",
378                                                               "PMEM", "Block"};
379 
380             for (const char* v : values)
381             {
382                 if (boost::ends_with(*value, v))
383                 {
384                     aResp->res.jsonValue["OperatingMemoryModes "] = v;
385                     break;
386                 }
387             }
388         }
389         else if (property.first == "MemoryMedia")
390         {
391             const std::string* value =
392                 std::get_if<std::string>(&property.second);
393             if (value == nullptr)
394             {
395                 messages::internalError(aResp->res);
396                 BMCWEB_LOG_DEBUG << "Invalid property type for MemoryMedia";
397                 return;
398             }
399             constexpr const std::array<const char*, 3> values{"DRAM", "NAND",
400                                                               "Intel3DXPoint"};
401 
402             for (const char* v : values)
403             {
404                 if (boost::ends_with(*value, v))
405                 {
406                     aResp->res.jsonValue["MemoryMedia"] = v;
407                     break;
408                 }
409             }
410         }
411         // PersistantMemory.SecurityCapabilites interface
412         else if (property.first == "ConfigurationLockCapable" ||
413                  property.first == "DataLockCapable" ||
414                  property.first == "PassphraseCapable")
415         {
416             const bool* value = std::get_if<bool>(&property.second);
417             if (value == nullptr)
418             {
419                 messages::internalError(aResp->res);
420                 return;
421             }
422             aResp->res.jsonValue["SecurityCapabilities"][property.first] =
423                 *value;
424         }
425         else if (property.first == "MaxPassphraseCount" ||
426                  property.first == "PassphraseLockLimit")
427         {
428             const uint64_t* value = std::get_if<uint64_t>(&property.second);
429             if (value == nullptr)
430             {
431                 messages::internalError(aResp->res);
432                 return;
433             }
434             aResp->res.jsonValue["SecurityCapabilities"][property.first] =
435                 *value;
436         }
437     }
438 }
439 
440 inline void getDimmDataByService(std::shared_ptr<bmcweb::AsyncResp> aResp,
441                                  const std::string& dimmId,
442                                  const std::string& service,
443                                  const std::string& objPath)
444 {
445     auto health = std::make_shared<HealthPopulate>(aResp);
446     health->selfPath = objPath;
447     health->populate();
448 
449     BMCWEB_LOG_DEBUG << "Get available system components.";
450     crow::connections::systemBus->async_method_call(
451         [dimmId, aResp{std::move(aResp)}](const boost::system::error_code ec,
452                                           const DimmProperties& properties) {
453             if (ec)
454             {
455                 BMCWEB_LOG_DEBUG << "DBUS response error";
456                 messages::internalError(aResp->res);
457 
458                 return;
459             }
460             aResp->res.jsonValue["Id"] = dimmId;
461             aResp->res.jsonValue["Name"] = "DIMM Slot";
462 
463             const auto memorySizeProperty = properties.find("MemorySizeInKB");
464             if (memorySizeProperty != properties.end())
465             {
466                 const uint32_t* memorySize =
467                     std::get_if<uint32_t>(&memorySizeProperty->second);
468                 if (memorySize == nullptr)
469                 {
470                     // Important property not in desired type
471                     messages::internalError(aResp->res);
472                     return;
473                 }
474                 aResp->res.jsonValue["CapacityMiB"] = (*memorySize >> 10);
475             }
476             aResp->res.jsonValue["Status"]["State"] = "Enabled";
477             aResp->res.jsonValue["Status"]["Health"] = "OK";
478 
479             for (const auto& property : properties)
480             {
481                 if (property.first == "MemoryDataWidth")
482                 {
483                     const uint16_t* value =
484                         std::get_if<uint16_t>(&property.second);
485                     if (value == nullptr)
486                     {
487                         continue;
488                     }
489                     aResp->res.jsonValue["DataWidthBits"] = *value;
490                 }
491                 else if (property.first == "PartNumber")
492                 {
493                     const std::string* value =
494                         std::get_if<std::string>(&property.second);
495                     if (value == nullptr)
496                     {
497                         continue;
498                     }
499                     aResp->res.jsonValue["PartNumber"] = *value;
500                 }
501                 else if (property.first == "SerialNumber")
502                 {
503                     const std::string* value =
504                         std::get_if<std::string>(&property.second);
505                     if (value == nullptr)
506                     {
507                         continue;
508                     }
509                     aResp->res.jsonValue["SerialNumber"] = *value;
510                 }
511                 else if (property.first == "Manufacturer")
512                 {
513                     const std::string* value =
514                         std::get_if<std::string>(&property.second);
515                     if (value == nullptr)
516                     {
517                         continue;
518                     }
519                     aResp->res.jsonValue["Manufacturer"] = *value;
520                 }
521                 else if (property.first == "RevisionCode")
522                 {
523                     const uint16_t* value =
524                         std::get_if<uint16_t>(&property.second);
525 
526                     if (value == nullptr)
527                     {
528                         messages::internalError(aResp->res);
529                         BMCWEB_LOG_DEBUG
530                             << "Invalid property type for RevisionCode";
531                         return;
532                     }
533                     aResp->res.jsonValue["FirmwareRevision"] =
534                         std::to_string(*value);
535                 }
536                 else if (property.first == "Present")
537                 {
538                     const bool* value = std::get_if<bool>(&property.second);
539                     if (value == nullptr)
540                     {
541                         messages::internalError(aResp->res);
542                         BMCWEB_LOG_DEBUG
543                             << "Invalid property type for Dimm Presence";
544                         return;
545                     }
546                     if (*value == false)
547                     {
548                         aResp->res.jsonValue["Status"]["State"] = "Absent";
549                     }
550                 }
551                 else if (property.first == "MemoryTotalWidth")
552                 {
553                     const uint16_t* value =
554                         std::get_if<uint16_t>(&property.second);
555                     if (value == nullptr)
556                     {
557                         continue;
558                     }
559                     aResp->res.jsonValue["BusWidthBits"] = *value;
560                 }
561                 else if (property.first == "ECC")
562                 {
563                     const std::string* value =
564                         std::get_if<std::string>(&property.second);
565                     if (value == nullptr)
566                     {
567                         messages::internalError(aResp->res);
568                         BMCWEB_LOG_DEBUG << "Invalid property type for ECC";
569                         return;
570                     }
571                     constexpr const std::array<const char*, 4> values{
572                         "NoECC", "SingleBitECC", "MultiBitECC",
573                         "AddressParity"};
574 
575                     for (const char* v : values)
576                     {
577                         if (boost::ends_with(*value, v))
578                         {
579                             aResp->res.jsonValue["ErrorCorrection"] = v;
580                             break;
581                         }
582                     }
583                 }
584                 else if (property.first == "FormFactor")
585                 {
586                     const std::string* value =
587                         std::get_if<std::string>(&property.second);
588                     if (value == nullptr)
589                     {
590                         messages::internalError(aResp->res);
591                         BMCWEB_LOG_DEBUG
592                             << "Invalid property type for FormFactor";
593                         return;
594                     }
595                     constexpr const std::array<const char*, 11> values{
596                         "RDIMM",        "UDIMM",        "SO_DIMM",
597                         "LRDIMM",       "Mini_RDIMM",   "Mini_UDIMM",
598                         "SO_RDIMM_72b", "SO_UDIMM_72b", "SO_DIMM_16b",
599                         "SO_DIMM_32b",  "Die"};
600 
601                     for (const char* v : values)
602                     {
603                         if (boost::ends_with(*value, v))
604                         {
605                             aResp->res.jsonValue["BaseModuleType"] = v;
606                             break;
607                         }
608                     }
609                 }
610                 else if (property.first == "AllowedSpeedsMT")
611                 {
612                     const std::vector<uint16_t>* value =
613                         std::get_if<std::vector<uint16_t>>(&property.second);
614                     if (value == nullptr)
615                     {
616                         continue;
617                     }
618                     nlohmann::json& jValue =
619                         aResp->res.jsonValue["AllowedSpeedsMHz"];
620                     jValue = nlohmann::json::array();
621                     for (uint16_t subVal : *value)
622                     {
623                         jValue.push_back(subVal);
624                     }
625                 }
626                 else if (property.first == "MemoryAttributes")
627                 {
628                     const uint8_t* value =
629                         std::get_if<uint8_t>(&property.second);
630 
631                     if (value == nullptr)
632                     {
633                         messages::internalError(aResp->res);
634                         BMCWEB_LOG_DEBUG
635                             << "Invalid property type for MemoryAttributes";
636                         return;
637                     }
638                     aResp->res.jsonValue["RankCount"] =
639                         static_cast<uint64_t>(*value);
640                 }
641                 else if (property.first == "MemoryConfiguredSpeedInMhz")
642                 {
643                     const uint16_t* value =
644                         std::get_if<uint16_t>(&property.second);
645                     if (value == nullptr)
646                     {
647                         continue;
648                     }
649                     aResp->res.jsonValue["OperatingSpeedMhz"] = *value;
650                 }
651                 else if (property.first == "MemoryType")
652                 {
653                     const auto* value =
654                         std::get_if<std::string>(&property.second);
655                     if (value != nullptr)
656                     {
657                         std::string memoryDeviceType =
658                             translateMemoryTypeToRedfish(*value);
659                         // Values like "Unknown" or "Other" will return empty
660                         // so just leave off
661                         if (!memoryDeviceType.empty())
662                         {
663                             aResp->res.jsonValue["MemoryDeviceType"] =
664                                 memoryDeviceType;
665                         }
666                         if (value->find("DDR") != std::string::npos)
667                         {
668                             aResp->res.jsonValue["MemoryType"] = "DRAM";
669                         }
670                         else if (boost::ends_with(*value, "Logical"))
671                         {
672                             aResp->res.jsonValue["MemoryType"] = "IntelOptane";
673                         }
674                     }
675                 }
676                 // memory location interface
677                 else if (property.first == "Channel" ||
678                          property.first == "MemoryController" ||
679                          property.first == "Slot" || property.first == "Socket")
680                 {
681                     const std::string* value =
682                         std::get_if<std::string>(&property.second);
683                     if (value == nullptr)
684                     {
685                         messages::internalError(aResp->res);
686                         return;
687                     }
688                     aResp->res.jsonValue["MemoryLocation"][property.first] =
689                         *value;
690                 }
691                 else if (property.first == "SparePartNumber")
692                 {
693                     const std::string* value =
694                         std::get_if<std::string>(&property.second);
695                     if (value == nullptr)
696                     {
697                         messages::internalError(aResp->res);
698                         return;
699                     }
700                     aResp->res.jsonValue["SparePartNumber"] = *value;
701                 }
702                 else if (property.first == "Model")
703                 {
704                     const std::string* value =
705                         std::get_if<std::string>(&property.second);
706                     if (value == nullptr)
707                     {
708                         messages::internalError(aResp->res);
709                         return;
710                     }
711                     aResp->res.jsonValue["Model"] = *value;
712                 }
713                 else if (property.first == "LocationCode")
714                 {
715                     const std::string* value =
716                         std::get_if<std::string>(&property.second);
717                     if (value == nullptr)
718                     {
719                         messages::internalError(aResp->res);
720                         return;
721                     }
722                     aResp->res
723                         .jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
724                         *value;
725                 }
726                 else
727                 {
728                     getPersistentMemoryProperties(aResp, properties);
729                 }
730             }
731         },
732         service, objPath, "org.freedesktop.DBus.Properties", "GetAll", "");
733 }
734 
735 inline void getDimmPartitionData(std::shared_ptr<bmcweb::AsyncResp> aResp,
736                                  const std::string& service,
737                                  const std::string& path)
738 {
739     crow::connections::systemBus->async_method_call(
740         [aResp{std::move(aResp)}](
741             const boost::system::error_code ec,
742             const boost::container::flat_map<
743                 std::string, std::variant<std::string, uint64_t, uint32_t,
744                                           bool>>& properties) {
745             if (ec)
746             {
747                 BMCWEB_LOG_DEBUG << "DBUS response error";
748                 messages::internalError(aResp->res);
749 
750                 return;
751             }
752 
753             nlohmann::json& partition =
754                 aResp->res.jsonValue["Regions"].emplace_back(
755                     nlohmann::json::object());
756             for (const auto& [key, val] : properties)
757             {
758                 if (key == "MemoryClassification")
759                 {
760                     const std::string* value = std::get_if<std::string>(&val);
761                     if (value == nullptr)
762                     {
763                         messages::internalError(aResp->res);
764                         return;
765                     }
766                     partition[key] = *value;
767                 }
768                 else if (key == "OffsetInKiB")
769                 {
770                     const uint64_t* value = std::get_if<uint64_t>(&val);
771                     if (value == nullptr)
772                     {
773                         messages::internalError(aResp->res);
774                         return;
775                     }
776 
777                     partition["OffsetMiB"] = (*value >> 10);
778                 }
779                 else if (key == "PartitionId")
780                 {
781                     const std::string* value = std::get_if<std::string>(&val);
782                     if (value == nullptr)
783                     {
784                         messages::internalError(aResp->res);
785                         return;
786                     }
787                     partition["RegionId"] = *value;
788                 }
789 
790                 else if (key == "PassphraseState")
791                 {
792                     const bool* value = std::get_if<bool>(&val);
793                     if (value == nullptr)
794                     {
795                         messages::internalError(aResp->res);
796                         return;
797                     }
798                     partition["PassphraseEnabled"] = *value;
799                 }
800                 else if (key == "SizeInKiB")
801                 {
802                     const uint64_t* value = std::get_if<uint64_t>(&val);
803                     if (value == nullptr)
804                     {
805                         messages::internalError(aResp->res);
806                         BMCWEB_LOG_DEBUG
807                             << "Invalid property type for SizeInKiB";
808                         return;
809                     }
810                     partition["SizeMiB"] = (*value >> 10);
811                 }
812             }
813         },
814 
815         service, path, "org.freedesktop.DBus.Properties", "GetAll",
816         "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition");
817 }
818 
819 inline void getDimmData(std::shared_ptr<bmcweb::AsyncResp> aResp,
820                         const std::string& dimmId)
821 {
822     BMCWEB_LOG_DEBUG << "Get available system dimm resources.";
823     crow::connections::systemBus->async_method_call(
824         [dimmId, aResp{std::move(aResp)}](
825             const boost::system::error_code ec,
826             const boost::container::flat_map<
827                 std::string, boost::container::flat_map<
828                                  std::string, std::vector<std::string>>>&
829                 subtree) {
830             if (ec)
831             {
832                 BMCWEB_LOG_DEBUG << "DBUS response error";
833                 messages::internalError(aResp->res);
834 
835                 return;
836             }
837             bool found = false;
838             for (const auto& [path, object] : subtree)
839             {
840                 if (path.find(dimmId) != std::string::npos)
841                 {
842                     for (const auto& [service, interfaces] : object)
843                     {
844                         if (!found &&
845                             (std::find(
846                                  interfaces.begin(), interfaces.end(),
847                                  "xyz.openbmc_project.Inventory.Item.Dimm") !=
848                              interfaces.end()))
849                         {
850                             getDimmDataByService(aResp, dimmId, service, path);
851                             found = true;
852                         }
853 
854                         // partitions are separate as there can be multiple per
855                         // device, i.e.
856                         // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition1
857                         // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition2
858                         if (std::find(interfaces.begin(), interfaces.end(),
859                                       "xyz.openbmc_project.Inventory.Item."
860                                       "PersistentMemory.Partition") !=
861                             interfaces.end())
862                         {
863                             getDimmPartitionData(aResp, service, path);
864                         }
865                     }
866                 }
867             }
868             // Object not found
869             if (!found)
870             {
871                 messages::resourceNotFound(aResp->res, "Memory", dimmId);
872             }
873             return;
874         },
875         "xyz.openbmc_project.ObjectMapper",
876         "/xyz/openbmc_project/object_mapper",
877         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
878         "/xyz/openbmc_project/inventory", 0,
879         std::array<const char*, 2>{
880             "xyz.openbmc_project.Inventory.Item.Dimm",
881             "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition"});
882 }
883 
884 inline void requestRoutesMemoryCollection(App& app)
885 {
886     /**
887      * Functions triggers appropriate requests on DBus
888      */
889     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Memory/")
890         .privileges(redfish::privileges::getMemoryCollection)
891         .methods(boost::beast::http::verb::get)(
892             [](const crow::Request&,
893                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
894                 asyncResp->res.jsonValue["@odata.type"] =
895                     "#MemoryCollection.MemoryCollection";
896                 asyncResp->res.jsonValue["Name"] = "Memory Module Collection";
897                 asyncResp->res.jsonValue["@odata.id"] =
898                     "/redfish/v1/Systems/system/Memory";
899 
900                 collection_util::getCollectionMembers(
901                     asyncResp, "/redfish/v1/Systems/system/Memory",
902                     {"xyz.openbmc_project.Inventory.Item.Dimm"});
903             });
904 }
905 
906 inline void requestRoutesMemory(App& app)
907 {
908     /**
909      * Functions triggers appropriate requests on DBus
910      */
911     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Memory/<str>/")
912         .privileges(redfish::privileges::getMemory)
913         .methods(boost::beast::http::verb::get)(
914             [](const crow::Request&,
915                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
916                const std::string& dimmId) {
917                 asyncResp->res.jsonValue["@odata.type"] =
918                     "#Memory.v1_11_0.Memory";
919                 asyncResp->res.jsonValue["@odata.id"] =
920                     "/redfish/v1/Systems/system/Memory/" + dimmId;
921 
922                 getDimmData(asyncResp, dimmId);
923             });
924 }
925 
926 } // namespace redfish
927