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