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