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