xref: /openbmc/bmcweb/redfish-core/lib/memory.hpp (revision ed76121b)
1 /*
2 // Copyright (c) 2018 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 #pragma once
17 
18 #include "health.hpp"
19 
20 #include <app.hpp>
21 #include <dbus_utility.hpp>
22 #include <nlohmann/json.hpp>
23 #include <query.hpp>
24 #include <registries/privilege_registry.hpp>
25 #include <sdbusplus/asio/property.hpp>
26 #include <sdbusplus/unpack_properties.hpp>
27 #include <utils/collection.hpp>
28 #include <utils/hex_utils.hpp>
29 #include <utils/json_utils.hpp>
30 
31 namespace redfish
32 {
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     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.HBM3")
123     {
124         return "HBM3";
125     }
126     // This is values like Other or Unknown
127     // Also D-Bus values:
128     // DRAM
129     // EDRAM
130     // VRAM
131     // SRAM
132     // RAM
133     // FLASH
134     // EEPROM
135     // FEPROM
136     // EPROM
137     // CDRAM
138     // ThreeDRAM
139     // RDRAM
140     // FBD2
141     // LPDDR_SDRAM
142     // LPDDR2_SDRAM
143     // LPDDR5_SDRAM
144     return "";
145 }
146 
147 inline void dimmPropToHex(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
148                           const char* key, const uint16_t* value,
149                           const nlohmann::json::json_pointer& jsonPtr)
150 {
151     if (value == nullptr)
152     {
153         return;
154     }
155     aResp->res.jsonValue[jsonPtr][key] = "0x" + intToHexString(*value, 4);
156 }
157 
158 inline void getPersistentMemoryProperties(
159     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
160     const dbus::utility::DBusPropertiesMap& properties,
161     const nlohmann::json::json_pointer& jsonPtr)
162 {
163     const uint16_t* moduleManufacturerID = nullptr;
164     const uint16_t* moduleProductID = nullptr;
165     const uint16_t* subsystemVendorID = nullptr;
166     const uint16_t* subsystemDeviceID = nullptr;
167     const uint64_t* volatileRegionSizeLimitInKiB = nullptr;
168     const uint64_t* pmRegionSizeLimitInKiB = nullptr;
169     const uint64_t* volatileSizeInKiB = nullptr;
170     const uint64_t* pmSizeInKiB = nullptr;
171     const uint64_t* cacheSizeInKB = nullptr;
172     const uint64_t* voltaileRegionMaxSizeInKib = nullptr;
173     const uint64_t* pmRegionMaxSizeInKiB = nullptr;
174     const uint64_t* allocationIncrementInKiB = nullptr;
175     const uint64_t* allocationAlignmentInKiB = nullptr;
176     const uint64_t* volatileRegionNumberLimit = nullptr;
177     const uint64_t* pmRegionNumberLimit = nullptr;
178     const uint64_t* spareDeviceCount = nullptr;
179     const bool* isSpareDeviceInUse = nullptr;
180     const bool* isRankSpareEnabled = nullptr;
181     const std::vector<uint32_t>* maxAveragePowerLimitmW = nullptr;
182     const bool* configurationLocked = nullptr;
183     const std::string* allowedMemoryModes = nullptr;
184     const std::string* memoryMedia = nullptr;
185     const bool* configurationLockCapable = nullptr;
186     const bool* dataLockCapable = nullptr;
187     const bool* passphraseCapable = nullptr;
188     const uint64_t* maxPassphraseCount = nullptr;
189     const uint64_t* passphraseLockLimit = nullptr;
190 
191     const bool success = sdbusplus::unpackPropertiesNoThrow(
192         dbus_utils::UnpackErrorPrinter(), properties, "ModuleManufacturerID",
193         moduleManufacturerID, "ModuleProductID", moduleProductID,
194         "SubsystemVendorID", subsystemVendorID, "SubsystemDeviceID",
195         subsystemDeviceID, "VolatileRegionSizeLimitInKiB",
196         volatileRegionSizeLimitInKiB, "PmRegionSizeLimitInKiB",
197         pmRegionSizeLimitInKiB, "VolatileSizeInKiB", volatileSizeInKiB,
198         "PmSizeInKiB", pmSizeInKiB, "CacheSizeInKB", cacheSizeInKB,
199         "VoltaileRegionMaxSizeInKib", voltaileRegionMaxSizeInKib,
200         "PmRegionMaxSizeInKiB", pmRegionMaxSizeInKiB,
201         "AllocationIncrementInKiB", allocationIncrementInKiB,
202         "AllocationAlignmentInKiB", allocationAlignmentInKiB,
203         "VolatileRegionNumberLimit", volatileRegionNumberLimit,
204         "PmRegionNumberLimit", pmRegionNumberLimit, "SpareDeviceCount",
205         spareDeviceCount, "IsSpareDeviceInUse", isSpareDeviceInUse,
206         "IsRankSpareEnabled", isRankSpareEnabled, "MaxAveragePowerLimitmW",
207         maxAveragePowerLimitmW, "ConfigurationLocked", configurationLocked,
208         "AllowedMemoryModes", allowedMemoryModes, "MemoryMedia", memoryMedia,
209         "ConfigurationLockCapable", configurationLockCapable, "DataLockCapable",
210         dataLockCapable, "PassphraseCapable", passphraseCapable,
211         "MaxPassphraseCount", maxPassphraseCount, "PassphraseLockLimit",
212         passphraseLockLimit);
213 
214     if (!success)
215     {
216         messages::internalError(aResp->res);
217         return;
218     }
219 
220     dimmPropToHex(aResp, "ModuleManufacturerID", moduleManufacturerID, jsonPtr);
221     dimmPropToHex(aResp, "ModuleProductID", moduleProductID, jsonPtr);
222     dimmPropToHex(aResp, "MemorySubsystemControllerManufacturerID",
223                   subsystemVendorID, jsonPtr);
224     dimmPropToHex(aResp, "MemorySubsystemControllerProductID",
225                   subsystemDeviceID, jsonPtr);
226 
227     if (volatileRegionSizeLimitInKiB != nullptr)
228     {
229         aResp->res.jsonValue[jsonPtr]["VolatileRegionSizeLimitMiB"] =
230             (*volatileRegionSizeLimitInKiB) >> 10;
231     }
232 
233     if (pmRegionSizeLimitInKiB != nullptr)
234     {
235         aResp->res.jsonValue[jsonPtr]["PersistentRegionSizeLimitMiB"] =
236             (*pmRegionSizeLimitInKiB) >> 10;
237     }
238 
239     if (volatileSizeInKiB != nullptr)
240     {
241 
242         aResp->res.jsonValue[jsonPtr]["VolatileSizeMiB"] =
243             (*volatileSizeInKiB) >> 10;
244     }
245 
246     if (pmSizeInKiB != nullptr)
247     {
248         aResp->res.jsonValue[jsonPtr]["NonVolatileSizeMiB"] =
249             (*pmSizeInKiB) >> 10;
250     }
251 
252     if (cacheSizeInKB != nullptr)
253     {
254         aResp->res.jsonValue[jsonPtr]["CacheSizeMiB"] = (*cacheSizeInKB >> 10);
255     }
256 
257     if (voltaileRegionMaxSizeInKib != nullptr)
258     {
259         aResp->res.jsonValue[jsonPtr]["VolatileRegionSizeMaxMiB"] =
260             (*voltaileRegionMaxSizeInKib) >> 10;
261     }
262 
263     if (pmRegionMaxSizeInKiB != nullptr)
264     {
265         aResp->res.jsonValue[jsonPtr]["PersistentRegionSizeMaxMiB"] =
266             (*pmRegionMaxSizeInKiB) >> 10;
267     }
268 
269     if (allocationIncrementInKiB != nullptr)
270     {
271         aResp->res.jsonValue[jsonPtr]["AllocationIncrementMiB"] =
272             (*allocationIncrementInKiB) >> 10;
273     }
274 
275     if (allocationAlignmentInKiB != nullptr)
276     {
277         aResp->res.jsonValue[jsonPtr]["AllocationAlignmentMiB"] =
278             (*allocationAlignmentInKiB) >> 10;
279     }
280 
281     if (volatileRegionNumberLimit != nullptr)
282     {
283         aResp->res.jsonValue[jsonPtr]["VolatileRegionNumberLimit"] =
284             *volatileRegionNumberLimit;
285     }
286 
287     if (pmRegionNumberLimit != nullptr)
288     {
289         aResp->res.jsonValue[jsonPtr]["PersistentRegionNumberLimit"] =
290             *pmRegionNumberLimit;
291     }
292 
293     if (spareDeviceCount != nullptr)
294     {
295         aResp->res.jsonValue[jsonPtr]["SpareDeviceCount"] = *spareDeviceCount;
296     }
297 
298     if (isSpareDeviceInUse != nullptr)
299     {
300         aResp->res.jsonValue[jsonPtr]["IsSpareDeviceEnabled"] =
301             *isSpareDeviceInUse;
302     }
303 
304     if (isRankSpareEnabled != nullptr)
305     {
306         aResp->res.jsonValue[jsonPtr]["IsRankSpareEnabled"] =
307             *isRankSpareEnabled;
308     }
309 
310     if (maxAveragePowerLimitmW != nullptr)
311     {
312         aResp->res.jsonValue[jsonPtr]["MaxTDPMilliWatts"] =
313             *maxAveragePowerLimitmW;
314     }
315 
316     if (configurationLocked != nullptr)
317     {
318         aResp->res.jsonValue[jsonPtr]["ConfigurationLocked"] =
319             *configurationLocked;
320     }
321 
322     if (allowedMemoryModes != nullptr)
323     {
324         constexpr const std::array<const char*, 3> values{"Volatile", "PMEM",
325                                                           "Block"};
326 
327         for (const char* v : values)
328         {
329             if (allowedMemoryModes->ends_with(v))
330             {
331                 aResp->res.jsonValue[jsonPtr]["OperatingMemoryModes"].push_back(
332                     v);
333                 break;
334             }
335         }
336     }
337 
338     if (memoryMedia != nullptr)
339     {
340         constexpr const std::array<const char*, 3> values{"DRAM", "NAND",
341                                                           "Intel3DXPoint"};
342 
343         for (const char* v : values)
344         {
345             if (memoryMedia->ends_with(v))
346             {
347                 aResp->res.jsonValue[jsonPtr]["MemoryMedia"].push_back(v);
348                 break;
349             }
350         }
351     }
352 
353     if (configurationLockCapable != nullptr)
354     {
355         aResp->res.jsonValue[jsonPtr]["SecurityCapabilities"]
356                             ["ConfigurationLockCapable"] =
357             *configurationLockCapable;
358     }
359 
360     if (dataLockCapable != nullptr)
361     {
362         aResp->res
363             .jsonValue[jsonPtr]["SecurityCapabilities"]["DataLockCapable"] =
364             *dataLockCapable;
365     }
366 
367     if (passphraseCapable != nullptr)
368     {
369         aResp->res
370             .jsonValue[jsonPtr]["SecurityCapabilities"]["PassphraseCapable"] =
371             *passphraseCapable;
372     }
373 
374     if (maxPassphraseCount != nullptr)
375     {
376         aResp->res
377             .jsonValue[jsonPtr]["SecurityCapabilities"]["MaxPassphraseCount"] =
378             *maxPassphraseCount;
379     }
380 
381     if (passphraseLockLimit != nullptr)
382     {
383         aResp->res
384             .jsonValue[jsonPtr]["SecurityCapabilities"]["PassphraseLockLimit"] =
385             *passphraseLockLimit;
386     }
387 }
388 
389 inline void
390     assembleDimmProperties(std::string_view dimmId,
391                            const std::shared_ptr<bmcweb::AsyncResp>& aResp,
392                            const dbus::utility::DBusPropertiesMap& properties,
393                            const nlohmann::json::json_pointer& jsonPtr)
394 {
395     aResp->res.jsonValue[jsonPtr]["Id"] = dimmId;
396     aResp->res.jsonValue[jsonPtr]["Name"] = "DIMM Slot";
397     aResp->res.jsonValue[jsonPtr]["Status"]["State"] = "Enabled";
398     aResp->res.jsonValue[jsonPtr]["Status"]["Health"] = "OK";
399 
400     const uint16_t* memoryDataWidth = nullptr;
401     const size_t* memorySizeInKB = nullptr;
402     const std::string* partNumber = nullptr;
403     const std::string* serialNumber = nullptr;
404     const std::string* manufacturer = nullptr;
405     const uint16_t* revisionCode = nullptr;
406     const bool* present = nullptr;
407     const uint16_t* memoryTotalWidth = nullptr;
408     const std::string* ecc = nullptr;
409     const std::string* formFactor = nullptr;
410     const std::vector<uint16_t>* allowedSpeedsMT = nullptr;
411     const uint8_t* memoryAttributes = nullptr;
412     const uint16_t* memoryConfiguredSpeedInMhz = nullptr;
413     const std::string* memoryType = nullptr;
414     const std::string* channel = nullptr;
415     const std::string* memoryController = nullptr;
416     const std::string* slot = nullptr;
417     const std::string* socket = nullptr;
418     const std::string* sparePartNumber = nullptr;
419     const std::string* model = nullptr;
420     const std::string* locationCode = nullptr;
421 
422     const bool success = sdbusplus::unpackPropertiesNoThrow(
423         dbus_utils::UnpackErrorPrinter(), properties, "MemoryDataWidth",
424         memoryDataWidth, "MemorySizeInKB", memorySizeInKB, "PartNumber",
425         partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer,
426         "RevisionCode", revisionCode, "Present", present, "MemoryTotalWidth",
427         memoryTotalWidth, "ECC", ecc, "FormFactor", formFactor,
428         "AllowedSpeedsMT", allowedSpeedsMT, "MemoryAttributes",
429         memoryAttributes, "MemoryConfiguredSpeedInMhz",
430         memoryConfiguredSpeedInMhz, "MemoryType", memoryType, "Channel",
431         channel, "MemoryController", memoryController, "Slot", slot, "Socket",
432         socket, "SparePartNumber", sparePartNumber, "Model", model,
433         "LocationCode", locationCode);
434 
435     if (!success)
436     {
437         messages::internalError(aResp->res);
438         return;
439     }
440 
441     if (memoryDataWidth != nullptr)
442     {
443         aResp->res.jsonValue[jsonPtr]["DataWidthBits"] = *memoryDataWidth;
444     }
445 
446     if (memorySizeInKB != nullptr)
447     {
448         aResp->res.jsonValue[jsonPtr]["CapacityMiB"] = (*memorySizeInKB >> 10);
449     }
450 
451     if (partNumber != nullptr)
452     {
453         aResp->res.jsonValue[jsonPtr]["PartNumber"] = *partNumber;
454     }
455 
456     if (serialNumber != nullptr)
457     {
458         aResp->res.jsonValue[jsonPtr]["SerialNumber"] = *serialNumber;
459     }
460 
461     if (manufacturer != nullptr)
462     {
463         aResp->res.jsonValue[jsonPtr]["Manufacturer"] = *manufacturer;
464     }
465 
466     if (revisionCode != nullptr)
467     {
468         aResp->res.jsonValue[jsonPtr]["FirmwareRevision"] =
469             std::to_string(*revisionCode);
470     }
471 
472     if (present != nullptr && !*present)
473     {
474         aResp->res.jsonValue[jsonPtr]["Status"]["State"] = "Absent";
475     }
476 
477     if (memoryTotalWidth != nullptr)
478     {
479         aResp->res.jsonValue[jsonPtr]["BusWidthBits"] = *memoryTotalWidth;
480     }
481 
482     if (ecc != nullptr)
483     {
484         constexpr const std::array<const char*, 4> values{
485             "NoECC", "SingleBitECC", "MultiBitECC", "AddressParity"};
486 
487         for (const char* v : values)
488         {
489             if (ecc->ends_with(v))
490             {
491                 aResp->res.jsonValue[jsonPtr]["ErrorCorrection"] = v;
492                 break;
493             }
494         }
495     }
496 
497     if (formFactor != nullptr)
498     {
499         constexpr const std::array<const char*, 11> values{
500             "RDIMM",       "UDIMM",       "SO_DIMM",      "LRDIMM",
501             "Mini_RDIMM",  "Mini_UDIMM",  "SO_RDIMM_72b", "SO_UDIMM_72b",
502             "SO_DIMM_16b", "SO_DIMM_32b", "Die"};
503 
504         for (const char* v : values)
505         {
506             if (formFactor->ends_with(v))
507             {
508                 aResp->res.jsonValue[jsonPtr]["BaseModuleType"] = v;
509                 break;
510             }
511         }
512     }
513 
514     if (allowedSpeedsMT != nullptr)
515     {
516         nlohmann::json& jValue =
517             aResp->res.jsonValue[jsonPtr]["AllowedSpeedsMHz"];
518         jValue = nlohmann::json::array();
519         for (uint16_t subVal : *allowedSpeedsMT)
520         {
521             jValue.push_back(subVal);
522         }
523     }
524 
525     if (memoryAttributes != nullptr)
526     {
527         aResp->res.jsonValue[jsonPtr]["RankCount"] =
528             static_cast<uint64_t>(*memoryAttributes);
529     }
530 
531     if (memoryConfiguredSpeedInMhz != nullptr)
532     {
533         aResp->res.jsonValue[jsonPtr]["OperatingSpeedMhz"] =
534             *memoryConfiguredSpeedInMhz;
535     }
536 
537     if (memoryType != nullptr)
538     {
539         std::string memoryDeviceType =
540             translateMemoryTypeToRedfish(*memoryType);
541         // Values like "Unknown" or "Other" will return empty
542         // so just leave off
543         if (!memoryDeviceType.empty())
544         {
545             aResp->res.jsonValue[jsonPtr]["MemoryDeviceType"] =
546                 memoryDeviceType;
547         }
548         if (memoryType->find("DDR") != std::string::npos)
549         {
550             aResp->res.jsonValue[jsonPtr]["MemoryType"] = "DRAM";
551         }
552         else if (memoryType->ends_with("Logical"))
553         {
554             aResp->res.jsonValue[jsonPtr]["MemoryType"] = "IntelOptane";
555         }
556     }
557 
558     if (channel != nullptr)
559     {
560         aResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Channel"] = *channel;
561     }
562 
563     if (memoryController != nullptr)
564     {
565         aResp->res.jsonValue[jsonPtr]["MemoryLocation"]["MemoryController"] =
566             *memoryController;
567     }
568 
569     if (slot != nullptr)
570     {
571         aResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Slot"] = *slot;
572     }
573 
574     if (socket != nullptr)
575     {
576         aResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Socket"] = *socket;
577     }
578 
579     if (sparePartNumber != nullptr)
580     {
581         aResp->res.jsonValue[jsonPtr]["SparePartNumber"] = *sparePartNumber;
582     }
583 
584     if (model != nullptr)
585     {
586         aResp->res.jsonValue[jsonPtr]["Model"] = *model;
587     }
588 
589     if (locationCode != nullptr)
590     {
591         aResp->res
592             .jsonValue[jsonPtr]["Location"]["PartLocation"]["ServiceLabel"] =
593             *locationCode;
594     }
595 
596     getPersistentMemoryProperties(aResp, properties, jsonPtr);
597 }
598 
599 inline void getDimmDataByService(std::shared_ptr<bmcweb::AsyncResp> aResp,
600                                  const std::string& dimmId,
601                                  const std::string& service,
602                                  const std::string& objPath)
603 {
604     auto health = std::make_shared<HealthPopulate>(aResp);
605     health->selfPath = objPath;
606     health->populate();
607 
608     BMCWEB_LOG_DEBUG << "Get available system components.";
609     sdbusplus::asio::getAllProperties(
610         *crow::connections::systemBus, service, objPath, "",
611         [dimmId, aResp{std::move(aResp)}](
612             const boost::system::error_code ec,
613             const dbus::utility::DBusPropertiesMap& properties) {
614         if (ec)
615         {
616             BMCWEB_LOG_DEBUG << "DBUS response error";
617             messages::internalError(aResp->res);
618             return;
619         }
620         assembleDimmProperties(dimmId, aResp, properties, ""_json_pointer);
621         });
622 }
623 
624 inline void assembleDimmPartitionData(
625     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
626     const dbus::utility::DBusPropertiesMap& properties,
627     const nlohmann::json::json_pointer& regionPtr)
628 {
629     const std::string* memoryClassification = nullptr;
630     const uint64_t* offsetInKiB = nullptr;
631     const std::string* partitionId = nullptr;
632     const bool* passphraseState = nullptr;
633     const uint64_t* sizeInKiB = nullptr;
634 
635     const bool success = sdbusplus::unpackPropertiesNoThrow(
636         dbus_utils::UnpackErrorPrinter(), properties, "MemoryClassification",
637         memoryClassification, "OffsetInKiB", offsetInKiB, "PartitionId",
638         partitionId, "PassphraseState", passphraseState, "SizeInKiB",
639         sizeInKiB);
640 
641     if (!success)
642     {
643         messages::internalError(aResp->res);
644         return;
645     }
646 
647     nlohmann::json::object_t partition;
648 
649     if (memoryClassification != nullptr)
650     {
651         partition["MemoryClassification"] = *memoryClassification;
652     }
653 
654     if (offsetInKiB != nullptr)
655     {
656         partition["OffsetMiB"] = (*offsetInKiB >> 10);
657     }
658 
659     if (partitionId != nullptr)
660     {
661         partition["RegionId"] = *partitionId;
662     }
663 
664     if (passphraseState != nullptr)
665     {
666         partition["PassphraseEnabled"] = *passphraseState;
667     }
668 
669     if (sizeInKiB != nullptr)
670     {
671         partition["SizeMiB"] = (*sizeInKiB >> 10);
672     }
673 
674     aResp->res.jsonValue[regionPtr].emplace_back(std::move(partition));
675 }
676 
677 inline void getDimmPartitionData(std::shared_ptr<bmcweb::AsyncResp> aResp,
678                                  const std::string& service,
679                                  const std::string& path)
680 {
681     sdbusplus::asio::getAllProperties(
682         *crow::connections::systemBus, service, path,
683         "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition",
684         [aResp{std::move(aResp)}](
685             const boost::system::error_code ec,
686             const dbus::utility::DBusPropertiesMap& properties) {
687         if (ec)
688         {
689             BMCWEB_LOG_DEBUG << "DBUS response error";
690             messages::internalError(aResp->res);
691 
692             return;
693         }
694         nlohmann::json::json_pointer regionPtr = "/Regions"_json_pointer;
695         assembleDimmPartitionData(aResp, properties, regionPtr);
696         }
697 
698     );
699 }
700 
701 inline void getDimmData(std::shared_ptr<bmcweb::AsyncResp> aResp,
702                         const std::string& dimmId)
703 {
704     BMCWEB_LOG_DEBUG << "Get available system dimm resources.";
705     crow::connections::systemBus->async_method_call(
706         [dimmId, aResp{std::move(aResp)}](
707             const boost::system::error_code ec,
708             const dbus::utility::MapperGetSubTreeResponse& subtree) {
709         if (ec)
710         {
711             BMCWEB_LOG_DEBUG << "DBUS response error";
712             messages::internalError(aResp->res);
713 
714             return;
715         }
716         bool found = false;
717         for (const auto& [rawPath, object] : subtree)
718         {
719             sdbusplus::message::object_path path(rawPath);
720             for (const auto& [service, interfaces] : object)
721             {
722                 for (const auto& interface : interfaces)
723                 {
724                     if (interface ==
725                             "xyz.openbmc_project.Inventory.Item.Dimm" &&
726                         path.filename() == dimmId)
727                     {
728                         getDimmDataByService(aResp, dimmId, service, rawPath);
729                         found = true;
730                     }
731 
732                     // partitions are separate as there can be multiple
733                     // per
734                     // device, i.e.
735                     // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition1
736                     // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition2
737                     if (interface ==
738                             "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition" &&
739                         path.parent_path().filename() == dimmId)
740                     {
741                         getDimmPartitionData(aResp, service, rawPath);
742                     }
743                 }
744             }
745         }
746         // Object not found
747         if (!found)
748         {
749             messages::resourceNotFound(aResp->res, "Memory", dimmId);
750             return;
751         }
752         // Set @odata only if object is found
753         aResp->res.jsonValue["@odata.type"] = "#Memory.v1_11_0.Memory";
754         aResp->res.jsonValue["@odata.id"] =
755             "/redfish/v1/Systems/system/Memory/" + dimmId;
756         return;
757         },
758         "xyz.openbmc_project.ObjectMapper",
759         "/xyz/openbmc_project/object_mapper",
760         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
761         "/xyz/openbmc_project/inventory", 0,
762         std::array<const char*, 2>{
763             "xyz.openbmc_project.Inventory.Item.Dimm",
764             "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition"});
765 }
766 
767 inline void requestRoutesMemoryCollection(App& app)
768 {
769     /**
770      * Functions triggers appropriate requests on DBus
771      */
772     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Memory/")
773         .privileges(redfish::privileges::getMemoryCollection)
774         .methods(boost::beast::http::verb::get)(
775             [&app](const crow::Request& req,
776                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
777         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
778         {
779             return;
780         }
781         asyncResp->res.jsonValue["@odata.type"] =
782             "#MemoryCollection.MemoryCollection";
783         asyncResp->res.jsonValue["Name"] = "Memory Module Collection";
784         asyncResp->res.jsonValue["@odata.id"] =
785             "/redfish/v1/Systems/system/Memory";
786 
787         collection_util::getCollectionMembers(
788             asyncResp, "/redfish/v1/Systems/system/Memory",
789             {"xyz.openbmc_project.Inventory.Item.Dimm"});
790         });
791 }
792 
793 inline void requestRoutesMemory(App& app)
794 {
795     /**
796      * Functions triggers appropriate requests on DBus
797      */
798     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Memory/<str>/")
799         .privileges(redfish::privileges::getMemory)
800         .methods(boost::beast::http::verb::get)(
801             [&app](const crow::Request& req,
802                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
803                    const std::string& dimmId) {
804         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
805         {
806             return;
807         }
808         getDimmData(asyncResp, dimmId);
809         });
810 }
811 
812 } // namespace redfish
813