Populate unique PrettyName for IO-SCM systems

IO-SCM is a DCM with one of the chips being just IO-Good, that is one of
the chips does not have any good computing cores. But those chips can be
useful for other purposes like connecting PCIE devices. So we still use
those cpu chips without trashing.

So to uniquely identify an IO-Good chip, this commit populates a unique
PrettyName for such cpus so that the redfish client can easily
distinguish between chips with good computing cores and an IO-Good chip.

Test:
Tested on io-SCM system.

Case 1: CPU which is not an IO.

=====> root@rain71bmc:/tmp# ./ibm-read-vpd --file /sys/bus/spi/drivers/at25/spi12.0/eeprom

=====> root@rain71bmc:/tmp# busctl introspect xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/dcm0/cpu0
NAME                                                  TYPE      SIGNATURE RESULT/VALUE                             FLAGS
com.ibm.ipzvpd.CP00                                   interface -         -                                        -
.AW                                                   property  ay        4 0 0 0 0                                emits-change writable
.D4                                                   property  ay        4 0 0 0 0                                emits-change writable
.D5                                                   property  ay        4 0 0 0 0                                emits-change writable
.MK                                                   property  ay        7 1 0 0 0 0 0 0                          emits-change writable
.PD_G                                                 property  ay        7168 23 82 83 5 9 0 20 0 0 1 3 73 2 255… emits-change writable
......

xyz.openbmc_project.Inventory.Item                    interface -         -                                        -
.Present                                              property  b         true                                     emits-change writable
.PrettyName                                           property  s         "PROCESSOR MODULE"                       emits-change writable
xyz.openbmc_project.Inventory.Item.Cpu                interface -         -                                        -
.Characteristics                                      property  as        0                                        emits-change writable
.CoreCount                                            property  q         10                                       emits-change writable

....

=====> curl -k -H "X-Auth-Token: $bmc_token" -X GET https://${bmc}/redfish/v1/Systems/system/Processors/dcm0-cpu0
{
  "@odata.id": "/redfish/v1/Systems/system/Processors/dcm0-cpu0",
  "@odata.type": "#Processor.v1_12_0.Processor",
  "Id": "dcm0-cpu0",
  "Location": {
    "PartLocation": {
      "ServiceLabel": "U78DA.ND0.WZS0042-P0-C15"
    }
  },
  "LocationIndicatorActive": false,
  "Manufacturer": "",
  "MaxSpeedMHz": 0,
  "Model": "5C74",
  "Name": "PROCESSOR MODULE",
  "PartNumber": "03JM528",
  "ProcessorId": {
    "EffectiveFamily": ""
  },
  "ProcessorType": "CPU",
  "SerialNumber": "YA3936127705",
  "Socket": "",
  "SparePartNumber": "F210110",
  "Status": {
    "Health": "OK",
    "State": "Enabled"
  },
  "SubProcessors": {
    "@odata.id": "/redfish/v1/Systems/system/Processors/dcm0-cpu0/SubProcessors"
  },
  "TotalCores": 10,
  "TotalThreads": 0
}

Case 2: CPU which is an IO only chip.

=====> root@rain71bmc:/tmp# ./ibm-read-vpd --file /sys/bus/spi/drivers/at25/spi22.0/eeprom

=====> root@rain71bmc:/tmp# busctl introspect xyz.openbmc_project.Inventory.Manager /xyz/openbmc_project/inventory/system/chassis/motherboard/dcm0/cpu1
NAME                                                  TYPE      SIGNATURE RESULT/VALUE                             FLAGS
com.ibm.ipzvpd.CP00                                   interface -         -                                        -
.AW                                                   property  ay        4 0 0 0 0                                emits-change writable
.D4                                                   property  ay        4 0 0 0 0                                emits-change writable
.D5                                                   property  ay        4 0 0 0 0                                emits-change writable
.MK                                                   property  ay        7 1 0 0 0 0 0 0                          emits-change writable
.PD_G                                                 property  ay        7168 23

.......

xyz.openbmc_project.Inventory.Item                    interface -         -                                        -
.Present                                              property  b         true                                     emits-change writable
.PrettyName                                           property  s         "IO"                                     emits-change writable
xyz.openbmc_project.Inventory.Item.Cpu                interface -         -                                        -
.Characteristics                                      property  as        0

...

=====> curl -k -H "X-Auth-Token: $bmc_token" -X GET https://${bmc}/redfish/v1/Systems/system/Processors/dcm0-cpu1
{
  "@odata.id": "/redfish/v1/Systems/system/Processors/dcm0-cpu1",
  "@odata.type": "#Processor.v1_12_0.Processor",
  "Id": "dcm0-cpu1",
  "Location": {
    "PartLocation": {
      "ServiceLabel": "U78DA.ND0.WZS0042-P0-C15"
    }
  },
  "LocationIndicatorActive": false,
  "Manufacturer": "",
  "MaxSpeedMHz": 0,
  "Model": "5C74",
  "Name": "IO",
  "PartNumber": "03JM528",
  "ProcessorId": {
    "EffectiveFamily": ""
  },
  "ProcessorType": "CPU",
  "SerialNumber": "YA3936127705",
  "Socket": "",
  "SparePartNumber": "F210110",
  "Status": {
    "Health": "OK",
    "State": "Enabled"
  },
  "SubProcessors": {
    "@odata.id": "/redfish/v1/Systems/system/Processors/dcm0-cpu1/SubProcessors"
  },
  "TotalCores": 0,
  "TotalThreads": 0
}
==========

Signed-off-by: Priyanga Ramasamy <priyanga24@in.ibm.com>
Change-Id: I39917557b50074650fe381f161e101640f7d870c
diff --git a/ibm_vpd_app.cpp b/ibm_vpd_app.cpp
index edc95c9..2b8bfcd 100644
--- a/ibm_vpd_app.cpp
+++ b/ibm_vpd_app.cpp
@@ -992,6 +992,34 @@
 }
 
 /**
+ * @brief Check if the given CPU is an IO only chip.
+ * The CPU is termed as IO, whose all of the cores are bad and can never be
+ * used. Those CPU chips can be used for IO purpose like connecting PCIe devices
+ * etc., The CPU whose every cores are bad, can be identified from the CP00
+ * record's PG keyword, only if all of the 8 EQs' value equals 0xE7F9FF. (1EQ
+ * has 4 cores grouped together by sharing its cache memory.)
+ * @param [in] pgKeyword - PG Keyword of CPU.
+ * @return true if the given cpu is an IO, false otherwise.
+ */
+static bool isCPUIOGoodOnly(const string& pgKeyword)
+{
+    const unsigned char io[] = {0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9,
+                                0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7,
+                                0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF};
+    // EQ0 index (in PG keyword) starts at 97 (with offset starting from 0).
+    // Each EQ carries 3 bytes of data. Totally there are 8 EQs. If all EQs'
+    // value equals 0xE7F9FF, then the cpu has no good cores and its treated as
+    // IO.
+    if (memcmp(io, pgKeyword.data() + 97, 24) == 0)
+    {
+        return true;
+    }
+
+    // The CPU is not an IO
+    return false;
+}
+
+/**
  * @brief Populate Dbus.
  * This method invokes all the populateInterface functions
  * and notifies PIM about dbus object.
@@ -1167,6 +1195,18 @@
         {
             populateInterfaces(item["extraInterfaces"], interfaces, vpdMap,
                                isSystemVpd);
+            if constexpr (is_same<T, Parsed>::value)
+            {
+                if (item["extraInterfaces"].find(
+                        "xyz.openbmc_project.Inventory.Item.Cpu") !=
+                    item["extraInterfaces"].end())
+                {
+                    if (isCPUIOGoodOnly(getKwVal(vpdMap, "CP00", "PG")))
+                    {
+                        interfaces[invItemIntf]["PrettyName"] = "IO";
+                    }
+                }
+            }
         }
         inventory::PropertyMap presProp;
         presProp.emplace("Present", true);