xref: /openbmc/bmcweb/redfish-core/lib/memory.hpp (revision 10f270b4)
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 == "Present")
536                 {
537                     const bool* value = std::get_if<bool>(&property.second);
538                     if (value == nullptr)
539                     {
540                         messages::internalError(aResp->res);
541                         BMCWEB_LOG_DEBUG
542                             << "Invalid property type for Dimm Presence";
543                         return;
544                     }
545                     if (*value == false)
546                     {
547                         aResp->res.jsonValue["Status"]["State"] = "Absent";
548                     }
549                 }
550                 else if (property.first == "MemoryTotalWidth")
551                 {
552                     const uint16_t* value =
553                         std::get_if<uint16_t>(&property.second);
554                     if (value == nullptr)
555                     {
556                         continue;
557                     }
558                     aResp->res.jsonValue["BusWidthBits"] = *value;
559                 }
560                 else if (property.first == "ECC")
561                 {
562                     const std::string* value =
563                         std::get_if<std::string>(&property.second);
564                     if (value == nullptr)
565                     {
566                         messages::internalError(aResp->res);
567                         BMCWEB_LOG_DEBUG << "Invalid property type for ECC";
568                         return;
569                     }
570                     constexpr const std::array<const char*, 4> values{
571                         "NoECC", "SingleBitECC", "MultiBitECC",
572                         "AddressParity"};
573 
574                     for (const char* v : values)
575                     {
576                         if (boost::ends_with(*value, v))
577                         {
578                             aResp->res.jsonValue["ErrorCorrection"] = v;
579                             break;
580                         }
581                     }
582                 }
583                 else if (property.first == "FormFactor")
584                 {
585                     const std::string* value =
586                         std::get_if<std::string>(&property.second);
587                     if (value == nullptr)
588                     {
589                         messages::internalError(aResp->res);
590                         BMCWEB_LOG_DEBUG
591                             << "Invalid property type for FormFactor";
592                         return;
593                     }
594                     constexpr const std::array<const char*, 11> values{
595                         "RDIMM",        "UDIMM",        "SO_DIMM",
596                         "LRDIMM",       "Mini_RDIMM",   "Mini_UDIMM",
597                         "SO_RDIMM_72b", "SO_UDIMM_72b", "SO_DIMM_16b",
598                         "SO_DIMM_32b",  "Die"};
599 
600                     for (const char* v : values)
601                     {
602                         if (boost::ends_with(*value, v))
603                         {
604                             aResp->res.jsonValue["BaseModuleType"] = v;
605                             break;
606                         }
607                     }
608                 }
609                 else if (property.first == "AllowedSpeedsMT")
610                 {
611                     const std::vector<uint16_t>* value =
612                         std::get_if<std::vector<uint16_t>>(&property.second);
613                     if (value == nullptr)
614                     {
615                         continue;
616                     }
617                     nlohmann::json& jValue =
618                         aResp->res.jsonValue["AllowedSpeedsMHz"];
619                     jValue = nlohmann::json::array();
620                     for (uint16_t subVal : *value)
621                     {
622                         jValue.push_back(subVal);
623                     }
624                 }
625                 else if (property.first == "MemoryAttributes")
626                 {
627                     const uint8_t* value =
628                         std::get_if<uint8_t>(&property.second);
629 
630                     if (value == nullptr)
631                     {
632                         messages::internalError(aResp->res);
633                         BMCWEB_LOG_DEBUG
634                             << "Invalid property type for MemoryAttributes";
635                         return;
636                     }
637                     aResp->res.jsonValue["RankCount"] =
638                         static_cast<uint64_t>(*value);
639                 }
640                 else if (property.first == "MemoryConfiguredSpeedInMhz")
641                 {
642                     const uint16_t* value =
643                         std::get_if<uint16_t>(&property.second);
644                     if (value == nullptr)
645                     {
646                         continue;
647                     }
648                     aResp->res.jsonValue["OperatingSpeedMhz"] = *value;
649                 }
650                 else if (property.first == "MemoryType")
651                 {
652                     const auto* value =
653                         std::get_if<std::string>(&property.second);
654                     if (value != nullptr)
655                     {
656                         std::string memoryDeviceType =
657                             translateMemoryTypeToRedfish(*value);
658                         // Values like "Unknown" or "Other" will return empty
659                         // so just leave off
660                         if (!memoryDeviceType.empty())
661                         {
662                             aResp->res.jsonValue["MemoryDeviceType"] =
663                                 memoryDeviceType;
664                         }
665                         if (value->find("DDR") != std::string::npos)
666                         {
667                             aResp->res.jsonValue["MemoryType"] = "DRAM";
668                         }
669                         else if (boost::ends_with(*value, "Logical"))
670                         {
671                             aResp->res.jsonValue["MemoryType"] = "IntelOptane";
672                         }
673                     }
674                 }
675                 // memory location interface
676                 else if (property.first == "Channel" ||
677                          property.first == "MemoryController" ||
678                          property.first == "Slot" || property.first == "Socket")
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["MemoryLocation"][property.first] =
688                         *value;
689                 }
690                 else if (property.first == "SparePartNumber")
691                 {
692                     const std::string* value =
693                         std::get_if<std::string>(&property.second);
694                     if (value == nullptr)
695                     {
696                         messages::internalError(aResp->res);
697                         return;
698                     }
699                     aResp->res.jsonValue["SparePartNumber"] = *value;
700                 }
701                 else if (property.first == "Model")
702                 {
703                     const std::string* value =
704                         std::get_if<std::string>(&property.second);
705                     if (value == nullptr)
706                     {
707                         messages::internalError(aResp->res);
708                         return;
709                     }
710                     aResp->res.jsonValue["Model"] = *value;
711                 }
712                 else if (property.first == "LocationCode")
713                 {
714                     const std::string* value =
715                         std::get_if<std::string>(&property.second);
716                     if (value == nullptr)
717                     {
718                         messages::internalError(aResp->res);
719                         return;
720                     }
721                     aResp->res
722                         .jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
723                         *value;
724                 }
725                 else
726                 {
727                     getPersistentMemoryProperties(aResp, properties);
728                 }
729             }
730         },
731         service, objPath, "org.freedesktop.DBus.Properties", "GetAll", "");
732 }
733 
734 inline void getDimmPartitionData(std::shared_ptr<bmcweb::AsyncResp> aResp,
735                                  const std::string& service,
736                                  const std::string& path)
737 {
738     crow::connections::systemBus->async_method_call(
739         [aResp{std::move(aResp)}](
740             const boost::system::error_code ec,
741             const boost::container::flat_map<
742                 std::string, std::variant<std::string, uint64_t, uint32_t,
743                                           bool>>& properties) {
744             if (ec)
745             {
746                 BMCWEB_LOG_DEBUG << "DBUS response error";
747                 messages::internalError(aResp->res);
748 
749                 return;
750             }
751 
752             nlohmann::json& partition =
753                 aResp->res.jsonValue["Regions"].emplace_back(
754                     nlohmann::json::object());
755             for (const auto& [key, val] : properties)
756             {
757                 if (key == "MemoryClassification")
758                 {
759                     const std::string* value = std::get_if<std::string>(&val);
760                     if (value == nullptr)
761                     {
762                         messages::internalError(aResp->res);
763                         return;
764                     }
765                     partition[key] = *value;
766                 }
767                 else if (key == "OffsetInKiB")
768                 {
769                     const uint64_t* value = std::get_if<uint64_t>(&val);
770                     if (value == nullptr)
771                     {
772                         messages::internalError(aResp->res);
773                         return;
774                     }
775 
776                     partition["OffsetMiB"] = (*value >> 10);
777                 }
778                 else if (key == "PartitionId")
779                 {
780                     const std::string* value = std::get_if<std::string>(&val);
781                     if (value == nullptr)
782                     {
783                         messages::internalError(aResp->res);
784                         return;
785                     }
786                     partition["RegionId"] = *value;
787                 }
788 
789                 else if (key == "PassphraseState")
790                 {
791                     const bool* value = std::get_if<bool>(&val);
792                     if (value == nullptr)
793                     {
794                         messages::internalError(aResp->res);
795                         return;
796                     }
797                     partition["PassphraseEnabled"] = *value;
798                 }
799                 else if (key == "SizeInKiB")
800                 {
801                     const uint64_t* value = std::get_if<uint64_t>(&val);
802                     if (value == nullptr)
803                     {
804                         messages::internalError(aResp->res);
805                         BMCWEB_LOG_DEBUG
806                             << "Invalid property type for SizeInKiB";
807                         return;
808                     }
809                     partition["SizeMiB"] = (*value >> 10);
810                 }
811             }
812         },
813 
814         service, path, "org.freedesktop.DBus.Properties", "GetAll",
815         "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition");
816 }
817 
818 inline void getDimmData(std::shared_ptr<bmcweb::AsyncResp> aResp,
819                         const std::string& dimmId)
820 {
821     BMCWEB_LOG_DEBUG << "Get available system dimm resources.";
822     crow::connections::systemBus->async_method_call(
823         [dimmId, aResp{std::move(aResp)}](
824             const boost::system::error_code ec,
825             const boost::container::flat_map<
826                 std::string, boost::container::flat_map<
827                                  std::string, std::vector<std::string>>>&
828                 subtree) {
829             if (ec)
830             {
831                 BMCWEB_LOG_DEBUG << "DBUS response error";
832                 messages::internalError(aResp->res);
833 
834                 return;
835             }
836             bool found = false;
837             for (const auto& [path, object] : subtree)
838             {
839                 if (path.find(dimmId) != std::string::npos)
840                 {
841                     for (const auto& [service, interfaces] : object)
842                     {
843                         if (!found &&
844                             (std::find(
845                                  interfaces.begin(), interfaces.end(),
846                                  "xyz.openbmc_project.Inventory.Item.Dimm") !=
847                              interfaces.end()))
848                         {
849                             getDimmDataByService(aResp, dimmId, service, path);
850                             found = true;
851                         }
852 
853                         // partitions are separate as there can be multiple per
854                         // device, i.e.
855                         // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition1
856                         // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition2
857                         if (std::find(interfaces.begin(), interfaces.end(),
858                                       "xyz.openbmc_project.Inventory.Item."
859                                       "PersistentMemory.Partition") !=
860                             interfaces.end())
861                         {
862                             getDimmPartitionData(aResp, service, path);
863                         }
864                     }
865                 }
866             }
867             // Object not found
868             if (!found)
869             {
870                 messages::resourceNotFound(aResp->res, "Memory", dimmId);
871             }
872             return;
873         },
874         "xyz.openbmc_project.ObjectMapper",
875         "/xyz/openbmc_project/object_mapper",
876         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
877         "/xyz/openbmc_project/inventory", 0,
878         std::array<const char*, 2>{
879             "xyz.openbmc_project.Inventory.Item.Dimm",
880             "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition"});
881 }
882 
883 class MemoryCollection : public Node
884 {
885   public:
886     /*
887      * Default Constructor
888      */
889     MemoryCollection(App& app) : Node(app, "/redfish/v1/Systems/system/Memory/")
890     {
891         entityPrivileges = {
892             {boost::beast::http::verb::get, {{"Login"}}},
893             {boost::beast::http::verb::head, {{"Login"}}},
894             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
895             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
896             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
897             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
898     }
899 
900   private:
901     /**
902      * Functions triggers appropriate requests on DBus
903      */
904     void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
905                const crow::Request&, const std::vector<std::string>&) override
906     {
907         asyncResp->res.jsonValue["@odata.type"] =
908             "#MemoryCollection.MemoryCollection";
909         asyncResp->res.jsonValue["Name"] = "Memory Module Collection";
910         asyncResp->res.jsonValue["@odata.id"] =
911             "/redfish/v1/Systems/system/Memory";
912 
913         collection_util::getCollectionMembers(
914             asyncResp, "/redfish/v1/Systems/system/Memory",
915             {"xyz.openbmc_project.Inventory.Item.Dimm"});
916     }
917 };
918 
919 class Memory : public Node
920 {
921   public:
922     /*
923      * Default Constructor
924      */
925     Memory(App& app) :
926         Node(app, "/redfish/v1/Systems/system/Memory/<str>/", std::string())
927     {
928         entityPrivileges = {
929             {boost::beast::http::verb::get, {{"Login"}}},
930             {boost::beast::http::verb::head, {{"Login"}}},
931             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
932             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
933             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
934             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
935     }
936 
937   private:
938     /**
939      * Functions triggers appropriate requests on DBus
940      */
941     void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
942                const crow::Request&,
943                const std::vector<std::string>& params) override
944     {
945         // Check if there is required param, truly entering this shall be
946         // impossible
947         if (params.size() != 1)
948         {
949             messages::internalError(asyncResp->res);
950             return;
951         }
952         const std::string& dimmId = params[0];
953 
954         asyncResp->res.jsonValue["@odata.type"] = "#Memory.v1_11_0.Memory";
955         asyncResp->res.jsonValue["@odata.id"] =
956             "/redfish/v1/Systems/system/Memory/" + dimmId;
957 
958         getDimmData(asyncResp, dimmId);
959     }
960 };
961 
962 } // namespace redfish
963