xref: /openbmc/bmcweb/redfish-core/lib/memory.hpp (revision 852432ac)
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 <nlohmann/json.hpp>
23 #include <query.hpp>
24 #include <registries/privilege_registry.hpp>
25 #include <utils/collection.hpp>
26 #include <utils/hex_utils.hpp>
27 #include <utils/json_utils.hpp>
28 
29 namespace redfish
30 {
31 
32 inline std::string translateMemoryTypeToRedfish(const std::string& memoryType)
33 {
34     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR")
35     {
36         return "DDR";
37     }
38     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2")
39     {
40         return "DDR2";
41     }
42     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR3")
43     {
44         return "DDR3";
45     }
46     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR4")
47     {
48         return "DDR4";
49     }
50     if (memoryType ==
51         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR4E_SDRAM")
52     {
53         return "DDR4E_SDRAM";
54     }
55     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR5")
56     {
57         return "DDR5";
58     }
59     if (memoryType ==
60         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.LPDDR4_SDRAM")
61     {
62         return "LPDDR4_SDRAM";
63     }
64     if (memoryType ==
65         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.LPDDR3_SDRAM")
66     {
67         return "LPDDR3_SDRAM";
68     }
69     if (memoryType ==
70         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2_SDRAM_FB_DIMM")
71     {
72         return "DDR2_SDRAM_FB_DIMM";
73     }
74     if (memoryType ==
75         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2_SDRAM_FB_DIMM_PROB")
76     {
77         return "DDR2_SDRAM_FB_DIMM_PROBE";
78     }
79     if (memoryType ==
80         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR_SGRAM")
81     {
82         return "DDR_SGRAM";
83     }
84     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.ROM")
85     {
86         return "ROM";
87     }
88     if (memoryType ==
89         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.SDRAM")
90     {
91         return "SDRAM";
92     }
93     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.EDO")
94     {
95         return "EDO";
96     }
97     if (memoryType ==
98         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.FastPageMode")
99     {
100         return "FastPageMode";
101     }
102     if (memoryType ==
103         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.PipelinedNibble")
104     {
105         return "PipelinedNibble";
106     }
107     if (memoryType ==
108         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.Logical")
109     {
110         return "Logical";
111     }
112     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.HBM")
113     {
114         return "HBM";
115     }
116     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.HBM2")
117     {
118         return "HBM2";
119     }
120     // This is values like Other or Unknown
121     // Also D-Bus values:
122     // DRAM
123     // EDRAM
124     // VRAM
125     // SRAM
126     // RAM
127     // FLASH
128     // EEPROM
129     // FEPROM
130     // EPROM
131     // CDRAM
132     // ThreeDRAM
133     // RDRAM
134     // FBD2
135     // LPDDR_SDRAM
136     // LPDDR2_SDRAM
137     // LPDDR5_SDRAM
138     return "";
139 }
140 
141 inline void
142     dimmPropToHex(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
143                   const char* key,
144                   const dbus::utility::DBusPropertiesMap::value_type& 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 dbus::utility::DBusPropertiesMap::value_type& 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 (value->ends_with(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 (value->ends_with(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 (value->ends_with(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 (value->ends_with(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 (value->ends_with("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 void getDimmData(std::shared_ptr<bmcweb::AsyncResp> aResp,
820                         const std::string& dimmId)
821 {
822     BMCWEB_LOG_DEBUG << "Get available system dimm resources.";
823     crow::connections::systemBus->async_method_call(
824         [dimmId, aResp{std::move(aResp)}](
825             const boost::system::error_code ec,
826             const dbus::utility::MapperGetSubTreeResponse& subtree) {
827         if (ec)
828         {
829             BMCWEB_LOG_DEBUG << "DBUS response error";
830             messages::internalError(aResp->res);
831 
832             return;
833         }
834         bool found = false;
835         for (const auto& [rawPath, object] : subtree)
836         {
837             sdbusplus::message::object_path path(rawPath);
838             for (const auto& [service, interfaces] : object)
839             {
840                 for (const auto& interface : interfaces)
841                 {
842                     if (interface ==
843                             "xyz.openbmc_project.Inventory.Item.Dimm" &&
844                         path.filename() == dimmId)
845                     {
846                         getDimmDataByService(aResp, dimmId, service, rawPath);
847                         found = true;
848                     }
849 
850                     // partitions are separate as there can be multiple
851                     // per
852                     // device, i.e.
853                     // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition1
854                     // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition2
855                     if (interface ==
856                             "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition" &&
857                         path.parent_path().filename() == dimmId)
858                     {
859                         getDimmPartitionData(aResp, service, rawPath);
860                     }
861                 }
862             }
863         }
864         // Object not found
865         if (!found)
866         {
867             messages::resourceNotFound(aResp->res, "Memory", dimmId);
868             return;
869         }
870         // Set @odata only if object is found
871         aResp->res.jsonValue["@odata.type"] = "#Memory.v1_11_0.Memory";
872         aResp->res.jsonValue["@odata.id"] =
873             "/redfish/v1/Systems/system/Memory/" + dimmId;
874         return;
875         },
876         "xyz.openbmc_project.ObjectMapper",
877         "/xyz/openbmc_project/object_mapper",
878         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
879         "/xyz/openbmc_project/inventory", 0,
880         std::array<const char*, 2>{
881             "xyz.openbmc_project.Inventory.Item.Dimm",
882             "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition"});
883 }
884 
885 inline void requestRoutesMemoryCollection(App& app)
886 {
887     /**
888      * Functions triggers appropriate requests on DBus
889      */
890     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Memory/")
891         .privileges(redfish::privileges::getMemoryCollection)
892         .methods(boost::beast::http::verb::get)(
893             [&app](const crow::Request& req,
894                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
895         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
896         {
897             return;
898         }
899         asyncResp->res.jsonValue["@odata.type"] =
900             "#MemoryCollection.MemoryCollection";
901         asyncResp->res.jsonValue["Name"] = "Memory Module Collection";
902         asyncResp->res.jsonValue["@odata.id"] =
903             "/redfish/v1/Systems/system/Memory";
904 
905         collection_util::getCollectionMembers(
906             asyncResp, "/redfish/v1/Systems/system/Memory",
907             {"xyz.openbmc_project.Inventory.Item.Dimm"});
908         });
909 }
910 
911 inline void requestRoutesMemory(App& app)
912 {
913     /**
914      * Functions triggers appropriate requests on DBus
915      */
916     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Memory/<str>/")
917         .privileges(redfish::privileges::getMemory)
918         .methods(boost::beast::http::verb::get)(
919             [&app](const crow::Request& req,
920                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
921                    const std::string& dimmId) {
922         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
923         {
924             return;
925         }
926         getDimmData(asyncResp, dimmId);
927         });
928 }
929 
930 } // namespace redfish
931