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