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