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