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