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