xref: /openbmc/bmcweb/redfish-core/lib/memory.hpp (revision 262d7d4b)
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                     return;
472                 }
473                 aResp->res.jsonValue["CapacityMiB"] = (*memorySize >> 10);
474             }
475             aResp->res.jsonValue["Status"]["State"] = "Enabled";
476             aResp->res.jsonValue["Status"]["Health"] = "OK";
477 
478             for (const auto& property : properties)
479             {
480                 if (property.first == "MemoryDataWidth")
481                 {
482                     const uint16_t* value =
483                         std::get_if<uint16_t>(&property.second);
484                     if (value == nullptr)
485                     {
486                         continue;
487                     }
488                     aResp->res.jsonValue["DataWidthBits"] = *value;
489                 }
490                 else if (property.first == "PartNumber")
491                 {
492                     const std::string* value =
493                         std::get_if<std::string>(&property.second);
494                     if (value == nullptr)
495                     {
496                         continue;
497                     }
498                     aResp->res.jsonValue["PartNumber"] = *value;
499                 }
500                 else if (property.first == "SerialNumber")
501                 {
502                     const std::string* value =
503                         std::get_if<std::string>(&property.second);
504                     if (value == nullptr)
505                     {
506                         continue;
507                     }
508                     aResp->res.jsonValue["SerialNumber"] = *value;
509                 }
510                 else if (property.first == "Manufacturer")
511                 {
512                     const std::string* value =
513                         std::get_if<std::string>(&property.second);
514                     if (value == nullptr)
515                     {
516                         continue;
517                     }
518                     aResp->res.jsonValue["Manufacturer"] = *value;
519                 }
520                 else if (property.first == "RevisionCode")
521                 {
522                     const uint16_t* value =
523                         std::get_if<uint16_t>(&property.second);
524 
525                     if (value == nullptr)
526                     {
527                         messages::internalError(aResp->res);
528                         BMCWEB_LOG_DEBUG
529                             << "Invalid property type for RevisionCode";
530                         continue;
531                     }
532                     aResp->res.jsonValue["FirmwareRevision"] =
533                         std::to_string(*value);
534                 }
535                 else if (property.first == "MemoryTotalWidth")
536                 {
537                     const uint16_t* value =
538                         std::get_if<uint16_t>(&property.second);
539                     if (value == nullptr)
540                     {
541                         continue;
542                     }
543                     aResp->res.jsonValue["BusWidthBits"] = *value;
544                 }
545                 else if (property.first == "ECC")
546                 {
547                     const std::string* value =
548                         std::get_if<std::string>(&property.second);
549                     if (value == nullptr)
550                     {
551                         messages::internalError(aResp->res);
552                         BMCWEB_LOG_DEBUG << "Invalid property type for ECC";
553                         continue;
554                     }
555                     constexpr const std::array<const char*, 4> values{
556                         "NoECC", "SingleBitECC", "MultiBitECC",
557                         "AddressParity"};
558 
559                     for (const char* v : values)
560                     {
561                         if (boost::ends_with(*value, v))
562                         {
563                             aResp->res.jsonValue["ErrorCorrection"] = v;
564                             break;
565                         }
566                     }
567                 }
568                 else if (property.first == "FormFactor")
569                 {
570                     const std::string* value =
571                         std::get_if<std::string>(&property.second);
572                     if (value == nullptr)
573                     {
574                         messages::internalError(aResp->res);
575                         BMCWEB_LOG_DEBUG
576                             << "Invalid property type for FormFactor";
577                         continue;
578                     }
579                     constexpr const std::array<const char*, 11> values{
580                         "RDIMM",        "UDIMM",        "SO_DIMM",
581                         "LRDIMM",       "Mini_RDIMM",   "Mini_UDIMM",
582                         "SO_RDIMM_72b", "SO_UDIMM_72b", "SO_DIMM_16b",
583                         "SO_DIMM_32b",  "Die"};
584 
585                     for (const char* v : values)
586                     {
587                         if (boost::ends_with(*value, v))
588                         {
589                             aResp->res.jsonValue["BaseModuleType"] = v;
590                             break;
591                         }
592                     }
593                 }
594                 else if (property.first == "AllowedSpeedsMT")
595                 {
596                     const std::vector<uint16_t>* value =
597                         std::get_if<std::vector<uint16_t>>(&property.second);
598                     if (value == nullptr)
599                     {
600                         continue;
601                     }
602                     nlohmann::json& jValue =
603                         aResp->res.jsonValue["AllowedSpeedsMHz"];
604                     jValue = nlohmann::json::array();
605                     for (uint16_t subVal : *value)
606                     {
607                         jValue.push_back(subVal);
608                     }
609                 }
610                 else if (property.first == "MemoryAttributes")
611                 {
612                     const uint8_t* value =
613                         std::get_if<uint8_t>(&property.second);
614 
615                     if (value == nullptr)
616                     {
617                         messages::internalError(aResp->res);
618                         BMCWEB_LOG_DEBUG
619                             << "Invalid property type for MemoryAttributes";
620                         continue;
621                     }
622                     aResp->res.jsonValue["RankCount"] =
623                         static_cast<uint64_t>(*value);
624                 }
625                 else if (property.first == "MemoryConfiguredSpeedInMhz")
626                 {
627                     const uint16_t* value =
628                         std::get_if<uint16_t>(&property.second);
629                     if (value == nullptr)
630                     {
631                         continue;
632                     }
633                     aResp->res.jsonValue["OperatingSpeedMhz"] = *value;
634                 }
635                 else if (property.first == "MemoryType")
636                 {
637                     const auto* value =
638                         std::get_if<std::string>(&property.second);
639                     if (value != nullptr)
640                     {
641                         std::string memoryDeviceType =
642                             translateMemoryTypeToRedfish(*value);
643                         // Values like "Unknown" or "Other" will return empty
644                         // so just leave off
645                         if (!memoryDeviceType.empty())
646                         {
647                             aResp->res.jsonValue["MemoryDeviceType"] =
648                                 memoryDeviceType;
649                         }
650                         if (value->find("DDR") != std::string::npos)
651                         {
652                             aResp->res.jsonValue["MemoryType"] = "DRAM";
653                         }
654                         else if (boost::ends_with(*value, "Logical"))
655                         {
656                             aResp->res.jsonValue["MemoryType"] = "IntelOptane";
657                         }
658                     }
659                 }
660                 // memory location interface
661                 else if (property.first == "Channel" ||
662                          property.first == "MemoryController" ||
663                          property.first == "Slot" || property.first == "Socket")
664                 {
665                     const std::string* value =
666                         std::get_if<std::string>(&property.second);
667                     if (value == nullptr)
668                     {
669                         messages::internalError(aResp->res);
670                         continue;
671                     }
672                     aResp->res.jsonValue["MemoryLocation"][property.first] =
673                         *value;
674                 }
675                 else
676                 {
677                     getPersistentMemoryProperties(aResp, properties);
678                 }
679             }
680         },
681         service, objPath, "org.freedesktop.DBus.Properties", "GetAll", "");
682 }
683 
684 inline void getDimmPartitionData(std::shared_ptr<AsyncResp> aResp,
685                                  const std::string& service,
686                                  const std::string& path)
687 {
688     crow::connections::systemBus->async_method_call(
689         [aResp{std::move(aResp)}](
690             const boost::system::error_code ec,
691             const boost::container::flat_map<
692                 std::string, std::variant<std::string, uint64_t, uint32_t,
693                                           bool>>& properties) {
694             if (ec)
695             {
696                 BMCWEB_LOG_DEBUG << "DBUS response error";
697                 messages::internalError(aResp->res);
698 
699                 return;
700             }
701 
702             nlohmann::json& partition =
703                 aResp->res.jsonValue["Regions"].emplace_back(
704                     nlohmann::json::object());
705             for (const auto& [key, val] : properties)
706             {
707                 if (key == "MemoryClassification")
708                 {
709                     const std::string* value = std::get_if<std::string>(&val);
710                     if (value == nullptr)
711                     {
712                         messages::internalError(aResp->res);
713                         continue;
714                     }
715                     partition[key] = *value;
716                 }
717                 else if (key == "OffsetInKiB")
718                 {
719                     const uint64_t* value = std::get_if<uint64_t>(&val);
720                     if (value == nullptr)
721                     {
722                         messages::internalError(aResp->res);
723                         continue;
724                     }
725 
726                     partition["OffsetMiB"] = (*value >> 10);
727                 }
728                 else if (key == "PartitionId")
729                 {
730                     const std::string* value = std::get_if<std::string>(&val);
731                     if (value == nullptr)
732                     {
733                         messages::internalError(aResp->res);
734                         continue;
735                     }
736                     partition["RegionId"] = *value;
737                 }
738 
739                 else if (key == "PassphraseState")
740                 {
741                     const bool* value = std::get_if<bool>(&val);
742                     if (value == nullptr)
743                     {
744                         messages::internalError(aResp->res);
745                         continue;
746                     }
747                     partition["PassphraseEnabled"] = *value;
748                 }
749                 else if (key == "SizeInKiB")
750                 {
751                     const uint64_t* value = std::get_if<uint64_t>(&val);
752                     if (value == nullptr)
753                     {
754                         messages::internalError(aResp->res);
755                         BMCWEB_LOG_DEBUG
756                             << "Invalid property type for SizeInKiB";
757                         continue;
758                     }
759                     partition["SizeMiB"] = (*value >> 10);
760                 }
761             }
762         },
763 
764         service, path, "org.freedesktop.DBus.Properties", "GetAll",
765         "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition");
766 }
767 
768 inline void getDimmData(std::shared_ptr<AsyncResp> aResp,
769                         const std::string& dimmId)
770 {
771     BMCWEB_LOG_DEBUG << "Get available system dimm resources.";
772     crow::connections::systemBus->async_method_call(
773         [dimmId, aResp{std::move(aResp)}](
774             const boost::system::error_code ec,
775             const boost::container::flat_map<
776                 std::string, boost::container::flat_map<
777                                  std::string, std::vector<std::string>>>&
778                 subtree) {
779             if (ec)
780             {
781                 BMCWEB_LOG_DEBUG << "DBUS response error";
782                 messages::internalError(aResp->res);
783 
784                 return;
785             }
786             bool found = false;
787             for (const auto& [path, object] : subtree)
788             {
789                 if (path.find(dimmId) != std::string::npos)
790                 {
791                     for (const auto& [service, interfaces] : object)
792                     {
793                         if (!found &&
794                             (std::find(
795                                  interfaces.begin(), interfaces.end(),
796                                  "xyz.openbmc_project.Inventory.Item.Dimm") !=
797                              interfaces.end()))
798                         {
799                             getDimmDataByService(aResp, dimmId, service, path);
800                             found = true;
801                         }
802 
803                         // partitions are separate as there can be multiple per
804                         // device, i.e.
805                         // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition1
806                         // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition2
807                         if (std::find(interfaces.begin(), interfaces.end(),
808                                       "xyz.openbmc_project.Inventory.Item."
809                                       "PersistentMemory.Partition") !=
810                             interfaces.end())
811                         {
812                             getDimmPartitionData(aResp, service, path);
813                         }
814                     }
815                 }
816             }
817             // Object not found
818             if (!found)
819             {
820                 messages::resourceNotFound(aResp->res, "Memory", dimmId);
821             }
822             return;
823         },
824         "xyz.openbmc_project.ObjectMapper",
825         "/xyz/openbmc_project/object_mapper",
826         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
827         "/xyz/openbmc_project/inventory", 0,
828         std::array<const char*, 2>{
829             "xyz.openbmc_project.Inventory.Item.Dimm",
830             "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition"});
831 }
832 
833 class MemoryCollection : public Node
834 {
835   public:
836     /*
837      * Default Constructor
838      */
839     MemoryCollection(App& app) : Node(app, "/redfish/v1/Systems/system/Memory/")
840     {
841         entityPrivileges = {
842             {boost::beast::http::verb::get, {{"Login"}}},
843             {boost::beast::http::verb::head, {{"Login"}}},
844             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
845             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
846             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
847             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
848     }
849 
850   private:
851     /**
852      * Functions triggers appropriate requests on DBus
853      */
854     void doGet(crow::Response& res, const crow::Request&,
855                const std::vector<std::string>&) override
856     {
857         res.jsonValue["@odata.type"] = "#MemoryCollection.MemoryCollection";
858         res.jsonValue["Name"] = "Memory Module Collection";
859         res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system/Memory";
860         auto asyncResp = std::make_shared<AsyncResp>(res);
861 
862         collection_util::getCollectionMembers(
863             asyncResp, "/redfish/v1/Systems/system/Memory",
864             {"xyz.openbmc_project.Inventory.Item.Dimm"});
865     }
866 };
867 
868 class Memory : public Node
869 {
870   public:
871     /*
872      * Default Constructor
873      */
874     Memory(App& app) :
875         Node(app, "/redfish/v1/Systems/system/Memory/<str>/", std::string())
876     {
877         entityPrivileges = {
878             {boost::beast::http::verb::get, {{"Login"}}},
879             {boost::beast::http::verb::head, {{"Login"}}},
880             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
881             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
882             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
883             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
884     }
885 
886   private:
887     /**
888      * Functions triggers appropriate requests on DBus
889      */
890     void doGet(crow::Response& res, const crow::Request&,
891                const std::vector<std::string>& params) override
892     {
893         // Check if there is required param, truly entering this shall be
894         // impossible
895         if (params.size() != 1)
896         {
897             messages::internalError(res);
898             res.end();
899             return;
900         }
901         const std::string& dimmId = params[0];
902 
903         res.jsonValue["@odata.type"] = "#Memory.v1_7_0.Memory";
904         res.jsonValue["@odata.id"] =
905             "/redfish/v1/Systems/system/Memory/" + dimmId;
906         auto asyncResp = std::make_shared<AsyncResp>(res);
907 
908         getDimmData(asyncResp, dimmId);
909     }
910 };
911 
912 } // namespace redfish
913