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