Add proc IO Ring and core/IO ring DVFS sensors

Add support for the processor IO ring temperature sensor which the OCC
uses fru type 9 for.  There is one per OCC.

Add support for reading the processor core and IO ring DVFS (Dynamic
Voltage and Frequency Slewing) temperature values out of the tempN_max
files and putting them on D-Bus.  These values are the temperatures at
which the OCC starts using DVFS to cool the chip and are being put on
D-Bus so that fan control can read them and increase fan speeds before
then so the OCC doesn't have to do the DVFS.

Even though there is a value in the tempN_max file for every core, there
only needs to be one value on D-Bus per OCC.  These are put in the
sensors namespace using the xyz.openbmc_project.Sensor.Value interface.
They do not need associations to the chassis, and they don't need to be
set to NaN when the OCCs aren't active, since the values can never
change.

There are values in the tempN_max files for most, if not all, other
temperature types as well, but the IO ring and core DVFS temps are the
only ones that aren't known ahead of time because they come from the
processor EEPROM.

Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I3e3f7a2a5db4053ea055e7baa16f0b0bf6eddbca
diff --git a/occ_manager.cpp b/occ_manager.cpp
index ed69274..eadbca1 100644
--- a/occ_manager.cpp
+++ b/occ_manager.cpp
@@ -24,6 +24,7 @@
 constexpr auto fruTypeSuffix = "fru_type";
 constexpr auto faultSuffix = "fault";
 constexpr auto inputSuffix = "input";
+constexpr auto maxSuffix = "max";
 
 using namespace phosphor::logging;
 
@@ -492,10 +493,18 @@
         std::string sensorPath =
             OCC_SENSORS_ROOT + std::string("/temperature/");
 
+        std::string dvfsTempPath;
+
         if (fruTypeValue == VRMVdd)
         {
             sensorPath.append("vrm_vdd" + std::to_string(id) + "_temp");
         }
+        else if (fruTypeValue == processorIoRing)
+        {
+            sensorPath.append("proc" + std::to_string(id) + "_ioring_temp");
+            dvfsTempPath = std::string{OCC_SENSORS_ROOT} + "/temperature/proc" +
+                           std::to_string(id) + "_ioring_dvfs_temp";
+        }
         else
         {
             uint16_t type = (labelValue & 0xFF000000) >> 24;
@@ -525,20 +534,25 @@
             }
             else if (type == OCC_CPU_TEMP_SENSOR_TYPE)
             {
-                if (fruTypeValue != processorCore)
+                if (fruTypeValue == processorCore)
                 {
-                    // TODO: support IO ring temp
+                    // The OCC reports small core temps, of which there are
+                    // two per big core.  All current P10 systems are in big
+                    // core mode, so use a big core name.
+                    uint16_t coreNum = instanceID / 2;
+                    uint16_t tempNum = instanceID % 2;
+                    sensorPath.append("proc" + std::to_string(id) + "_core" +
+                                      std::to_string(coreNum) + "_" +
+                                      std::to_string(tempNum) + "_temp");
+
+                    dvfsTempPath = std::string{OCC_SENSORS_ROOT} +
+                                   "/temperature/proc" + std::to_string(id) +
+                                   "_core_dvfs_temp";
+                }
+                else
+                {
                     continue;
                 }
-
-                // The OCC reports small core temps, of which there are
-                // two per big core.  All current P10 systems are in big
-                // core mode, so use a big core name.
-                uint16_t coreNum = instanceID / 2;
-                uint16_t tempNum = instanceID % 2;
-                sensorPath.append("proc" + std::to_string(id) + "_core" +
-                                  std::to_string(coreNum) + "_" +
-                                  std::to_string(tempNum) + "_temp");
             }
             else
             {
@@ -546,6 +560,27 @@
             }
         }
 
+        // The dvfs temp file only needs to be read once per chip per type.
+        if (!dvfsTempPath.empty() &&
+            !dbus::OccDBusSensors::getOccDBus().hasDvfsTemp(dvfsTempPath))
+        {
+            try
+            {
+                auto dvfsValue = readFile<double>(filePathString + maxSuffix);
+
+                dbus::OccDBusSensors::getOccDBus().setDvfsTemp(
+                    dvfsTempPath, dvfsValue * std::pow(10, -3));
+            }
+            catch (const std::system_error& e)
+            {
+                log<level::DEBUG>(
+                    fmt::format(
+                        "readTempSensors: Failed reading {}, errno = {}",
+                        filePathString + maxSuffix, e.code().value())
+                        .c_str());
+            }
+        }
+
         uint32_t faultValue{0};
         try
         {