xref: /openbmc/bmcweb/features/redfish/lib/memory.hpp (revision ce34d514150c0e4aa8f127dad8ede8b428c56930)
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, "Present", present,
426         "MemoryTotalWidth", memoryTotalWidth, "ECC", ecc, "FormFactor",
427         formFactor, "AllowedSpeedsMT", allowedSpeedsMT, "MemoryAttributes",
428         memoryAttributes, "MemoryConfiguredSpeedInMhz",
429         memoryConfiguredSpeedInMhz, "MemoryType", memoryType, "Channel",
430         channel, "MemoryController", memoryController, "Slot", slot, "Socket",
431         socket, "SparePartNumber", sparePartNumber, "Model", model,
432         "LocationCode", locationCode);
433 
434     if (!success)
435     {
436         messages::internalError(aResp->res);
437         return;
438     }
439 
440     if (memoryDataWidth != nullptr)
441     {
442         aResp->res.jsonValue[jsonPtr]["DataWidthBits"] = *memoryDataWidth;
443     }
444 
445     if (memorySizeInKB != nullptr)
446     {
447         aResp->res.jsonValue[jsonPtr]["CapacityMiB"] = (*memorySizeInKB >> 10);
448     }
449 
450     if (partNumber != nullptr)
451     {
452         aResp->res.jsonValue[jsonPtr]["PartNumber"] = *partNumber;
453     }
454 
455     if (serialNumber != nullptr)
456     {
457         aResp->res.jsonValue[jsonPtr]["SerialNumber"] = *serialNumber;
458     }
459 
460     if (manufacturer != nullptr)
461     {
462         aResp->res.jsonValue[jsonPtr]["Manufacturer"] = *manufacturer;
463     }
464 
465     if (revisionCode != nullptr)
466     {
467         aResp->res.jsonValue[jsonPtr]["FirmwareRevision"] =
468             std::to_string(*revisionCode);
469     }
470 
471     if (present != nullptr && !*present)
472     {
473         aResp->res.jsonValue[jsonPtr]["Status"]["State"] = "Absent";
474     }
475 
476     if (memoryTotalWidth != nullptr)
477     {
478         aResp->res.jsonValue[jsonPtr]["BusWidthBits"] = *memoryTotalWidth;
479     }
480 
481     if (ecc != nullptr)
482     {
483         constexpr const std::array<const char*, 4> values{
484             "NoECC", "SingleBitECC", "MultiBitECC", "AddressParity"};
485 
486         for (const char* v : values)
487         {
488             if (ecc->ends_with(v))
489             {
490                 aResp->res.jsonValue[jsonPtr]["ErrorCorrection"] = v;
491                 break;
492             }
493         }
494     }
495 
496     if (formFactor != nullptr)
497     {
498         constexpr const std::array<const char*, 11> values{
499             "RDIMM",       "UDIMM",       "SO_DIMM",      "LRDIMM",
500             "Mini_RDIMM",  "Mini_UDIMM",  "SO_RDIMM_72b", "SO_UDIMM_72b",
501             "SO_DIMM_16b", "SO_DIMM_32b", "Die"};
502 
503         for (const char* v : values)
504         {
505             if (formFactor->ends_with(v))
506             {
507                 aResp->res.jsonValue[jsonPtr]["BaseModuleType"] = v;
508                 break;
509             }
510         }
511     }
512 
513     if (allowedSpeedsMT != nullptr)
514     {
515         nlohmann::json& jValue =
516             aResp->res.jsonValue[jsonPtr]["AllowedSpeedsMHz"];
517         jValue = nlohmann::json::array();
518         for (uint16_t subVal : *allowedSpeedsMT)
519         {
520             jValue.push_back(subVal);
521         }
522     }
523 
524     if (memoryAttributes != nullptr)
525     {
526         aResp->res.jsonValue[jsonPtr]["RankCount"] =
527             static_cast<uint64_t>(*memoryAttributes);
528     }
529 
530     if (memoryConfiguredSpeedInMhz != nullptr)
531     {
532         aResp->res.jsonValue[jsonPtr]["OperatingSpeedMhz"] =
533             *memoryConfiguredSpeedInMhz;
534     }
535 
536     if (memoryType != nullptr)
537     {
538         std::string memoryDeviceType =
539             translateMemoryTypeToRedfish(*memoryType);
540         // Values like "Unknown" or "Other" will return empty
541         // so just leave off
542         if (!memoryDeviceType.empty())
543         {
544             aResp->res.jsonValue[jsonPtr]["MemoryDeviceType"] =
545                 memoryDeviceType;
546         }
547         if (memoryType->find("DDR") != std::string::npos)
548         {
549             aResp->res.jsonValue[jsonPtr]["MemoryType"] = "DRAM";
550         }
551         else if (memoryType->ends_with("Logical"))
552         {
553             aResp->res.jsonValue[jsonPtr]["MemoryType"] = "IntelOptane";
554         }
555     }
556 
557     if (channel != nullptr)
558     {
559         aResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Channel"] = *channel;
560     }
561 
562     if (memoryController != nullptr)
563     {
564         aResp->res.jsonValue[jsonPtr]["MemoryLocation"]["MemoryController"] =
565             *memoryController;
566     }
567 
568     if (slot != nullptr)
569     {
570         aResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Slot"] = *slot;
571     }
572 
573     if (socket != nullptr)
574     {
575         aResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Socket"] = *socket;
576     }
577 
578     if (sparePartNumber != nullptr)
579     {
580         aResp->res.jsonValue[jsonPtr]["SparePartNumber"] = *sparePartNumber;
581     }
582 
583     if (model != nullptr)
584     {
585         aResp->res.jsonValue[jsonPtr]["Model"] = *model;
586     }
587 
588     if (locationCode != nullptr)
589     {
590         aResp->res
591             .jsonValue[jsonPtr]["Location"]["PartLocation"]["ServiceLabel"] =
592             *locationCode;
593     }
594 
595     getPersistentMemoryProperties(aResp, properties, jsonPtr);
596 }
597 
598 inline void getDimmDataByService(std::shared_ptr<bmcweb::AsyncResp> aResp,
599                                  const std::string& dimmId,
600                                  const std::string& service,
601                                  const std::string& objPath)
602 {
603     auto health = std::make_shared<HealthPopulate>(aResp);
604     health->selfPath = objPath;
605     health->populate();
606 
607     BMCWEB_LOG_DEBUG << "Get available system components.";
608     sdbusplus::asio::getAllProperties(
609         *crow::connections::systemBus, service, objPath, "",
610         [dimmId, aResp{std::move(aResp)}](
611             const boost::system::error_code ec,
612             const dbus::utility::DBusPropertiesMap& properties) {
613         if (ec)
614         {
615             BMCWEB_LOG_DEBUG << "DBUS response error";
616             messages::internalError(aResp->res);
617             return;
618         }
619         assembleDimmProperties(dimmId, aResp, properties, ""_json_pointer);
620         });
621 }
622 
623 inline void assembleDimmPartitionData(
624     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
625     const dbus::utility::DBusPropertiesMap& properties,
626     const nlohmann::json::json_pointer& regionPtr)
627 {
628     const std::string* memoryClassification = nullptr;
629     const uint64_t* offsetInKiB = nullptr;
630     const std::string* partitionId = nullptr;
631     const bool* passphraseState = nullptr;
632     const uint64_t* sizeInKiB = nullptr;
633 
634     const bool success = sdbusplus::unpackPropertiesNoThrow(
635         dbus_utils::UnpackErrorPrinter(), properties, "MemoryClassification",
636         memoryClassification, "OffsetInKiB", offsetInKiB, "PartitionId",
637         partitionId, "PassphraseState", passphraseState, "SizeInKiB",
638         sizeInKiB);
639 
640     if (!success)
641     {
642         messages::internalError(aResp->res);
643         return;
644     }
645 
646     nlohmann::json::object_t partition;
647 
648     if (memoryClassification != nullptr)
649     {
650         partition["MemoryClassification"] = *memoryClassification;
651     }
652 
653     if (offsetInKiB != nullptr)
654     {
655         partition["OffsetMiB"] = (*offsetInKiB >> 10);
656     }
657 
658     if (partitionId != nullptr)
659     {
660         partition["RegionId"] = *partitionId;
661     }
662 
663     if (passphraseState != nullptr)
664     {
665         partition["PassphraseEnabled"] = *passphraseState;
666     }
667 
668     if (sizeInKiB != nullptr)
669     {
670         partition["SizeMiB"] = (*sizeInKiB >> 10);
671     }
672 
673     aResp->res.jsonValue[regionPtr].emplace_back(std::move(partition));
674 }
675 
676 inline void getDimmPartitionData(std::shared_ptr<bmcweb::AsyncResp> aResp,
677                                  const std::string& service,
678                                  const std::string& path)
679 {
680     sdbusplus::asio::getAllProperties(
681         *crow::connections::systemBus, service, path,
682         "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition",
683         [aResp{std::move(aResp)}](
684             const boost::system::error_code ec,
685             const dbus::utility::DBusPropertiesMap& properties) {
686         if (ec)
687         {
688             BMCWEB_LOG_DEBUG << "DBUS response error";
689             messages::internalError(aResp->res);
690 
691             return;
692         }
693         nlohmann::json::json_pointer regionPtr = "/Regions"_json_pointer;
694         assembleDimmPartitionData(aResp, properties, regionPtr);
695         }
696 
697     );
698 }
699 
700 inline void getDimmData(std::shared_ptr<bmcweb::AsyncResp> aResp,
701                         const std::string& dimmId)
702 {
703     BMCWEB_LOG_DEBUG << "Get available system dimm resources.";
704     crow::connections::systemBus->async_method_call(
705         [dimmId, aResp{std::move(aResp)}](
706             const boost::system::error_code ec,
707             const dbus::utility::MapperGetSubTreeResponse& subtree) {
708         if (ec)
709         {
710             BMCWEB_LOG_DEBUG << "DBUS response error";
711             messages::internalError(aResp->res);
712 
713             return;
714         }
715         bool found = false;
716         for (const auto& [rawPath, object] : subtree)
717         {
718             sdbusplus::message::object_path path(rawPath);
719             for (const auto& [service, interfaces] : object)
720             {
721                 for (const auto& interface : interfaces)
722                 {
723                     if (interface ==
724                             "xyz.openbmc_project.Inventory.Item.Dimm" &&
725                         path.filename() == dimmId)
726                     {
727                         getDimmDataByService(aResp, dimmId, service, rawPath);
728                         found = true;
729                     }
730 
731                     // partitions are separate as there can be multiple
732                     // per
733                     // device, i.e.
734                     // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition1
735                     // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition2
736                     if (interface ==
737                             "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition" &&
738                         path.parent_path().filename() == dimmId)
739                     {
740                         getDimmPartitionData(aResp, service, rawPath);
741                     }
742                 }
743             }
744         }
745         // Object not found
746         if (!found)
747         {
748             messages::resourceNotFound(aResp->res, "Memory", dimmId);
749             return;
750         }
751         // Set @odata only if object is found
752         aResp->res.jsonValue["@odata.type"] = "#Memory.v1_11_0.Memory";
753         aResp->res.jsonValue["@odata.id"] =
754             "/redfish/v1/Systems/system/Memory/" + dimmId;
755         return;
756         },
757         "xyz.openbmc_project.ObjectMapper",
758         "/xyz/openbmc_project/object_mapper",
759         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
760         "/xyz/openbmc_project/inventory", 0,
761         std::array<const char*, 2>{
762             "xyz.openbmc_project.Inventory.Item.Dimm",
763             "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition"});
764 }
765 
766 inline void requestRoutesMemoryCollection(App& app)
767 {
768     /**
769      * Functions triggers appropriate requests on DBus
770      */
771     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Memory/")
772         .privileges(redfish::privileges::getMemoryCollection)
773         .methods(boost::beast::http::verb::get)(
774             [&app](const crow::Request& req,
775                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
776         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
777         {
778             return;
779         }
780         asyncResp->res.jsonValue["@odata.type"] =
781             "#MemoryCollection.MemoryCollection";
782         asyncResp->res.jsonValue["Name"] = "Memory Module Collection";
783         asyncResp->res.jsonValue["@odata.id"] =
784             "/redfish/v1/Systems/system/Memory";
785 
786         collection_util::getCollectionMembers(
787             asyncResp, "/redfish/v1/Systems/system/Memory",
788             {"xyz.openbmc_project.Inventory.Item.Dimm"});
789         });
790 }
791 
792 inline void requestRoutesMemory(App& app)
793 {
794     /**
795      * Functions triggers appropriate requests on DBus
796      */
797     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Memory/<str>/")
798         .privileges(redfish::privileges::getMemory)
799         .methods(boost::beast::http::verb::get)(
800             [&app](const crow::Request& req,
801                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
802                    const std::string& dimmId) {
803         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
804         {
805             return;
806         }
807         getDimmData(asyncResp, dimmId);
808         });
809 }
810 
811 } // namespace redfish
812