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