Powercap: add p8 support

P8 uses i2c-occ and powercap is not created.
Add P8 support by creating powercap object with i2c device name.

Fixes openbmc/openbmc#2688

Change-Id: Ia63070d63f4392cc4b084ab628cdbdcf4206c883
Signed-off-by: Lei YU <mine260309@gmail.com>
diff --git a/i2c_occ.cpp b/i2c_occ.cpp
index c364967..00e4187 100644
--- a/i2c_occ.cpp
+++ b/i2c_occ.cpp
@@ -12,6 +12,8 @@
 
 namespace fs = std::experimental::filesystem;
 
+// The occ_master sysfs file
+constexpr auto OCC_MASTER_FILE = "occ_master";
 // The device name's length, e.g. "p8-occ-hwmon"
 constexpr auto DEVICE_NAME_LENGTH = 12;
 // The occ name's length, e.g. "occ"
@@ -21,6 +23,13 @@
 static_assert(sizeof(I2C_OCC_DEVICE_NAME) -1 == DEVICE_NAME_LENGTH);
 static_assert(sizeof(OCC_NAME) -1 == OCC_NAME_LENGTH);
 
+static bool isMasterOcc(const fs::directory_entry& p)
+{
+    auto f = p / OCC_MASTER_FILE;
+    auto str = getFileContent(f);
+    return (!str.empty()) && (str[0] == '1');
+}
+
 std::string getFileContent(const fs::path& f)
 {
     std::string ret(DEVICE_NAME_LENGTH, 0);
@@ -46,10 +55,22 @@
             auto str = getFileContent(f);
             if (str == I2C_OCC_DEVICE_NAME)
             {
-                result.emplace_back(p.path().filename());
+                if (isMasterOcc(p))
+                {
+                    // Insert master occ at the beginning
+                    result.emplace(result.begin(), p.path().filename());
+                }
+                else
+                {
+                    result.emplace_back(p.path().filename());
+                }
             }
         }
-        std::sort(result.begin(), result.end());
+    }
+    if (!result.empty())
+    {
+        // Sort the occ devices except for master
+        std::sort(result.begin() + 1, result.end());
     }
     return result;
 }
diff --git a/i2c_occ.hpp b/i2c_occ.hpp
index 31b6721..66dc12c 100644
--- a/i2c_occ.hpp
+++ b/i2c_occ.hpp
@@ -31,6 +31,7 @@
  * @param[in] path - The path to search
  *
  * @return A vector of strings containing the occ hwmon device path
+           where the first device is master occ
  */
 std::vector<std::string> getOccHwmonDevices(const char* path);
 
diff --git a/occ_manager.cpp b/occ_manager.cpp
index 42b6390..67e96a6 100644
--- a/occ_manager.cpp
+++ b/occ_manager.cpp
@@ -108,6 +108,7 @@
     static_assert(sizeof(DEV_PATH) != 0);
 
     auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH);
+    auto occMasterName = deviceNames.front();
     for (auto& name : deviceNames)
     {
         i2c_occ::i2cToDbus(name);
@@ -120,6 +121,11 @@
                 path.c_str(),
                 *this));
     }
+    // The first device is master occ
+    pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
+               bus,
+               *statusObjects.front(),
+               occMasterName);
 }
 #endif
 
diff --git a/powercap.cpp b/powercap.cpp
index 0aca3e4..f2ae331 100644
--- a/powercap.cpp
+++ b/powercap.cpp
@@ -118,7 +118,7 @@
     // Create path out to master occ hwmon entry
     std::unique_ptr<fs::path> fileName =
             std::make_unique<fs::path>(OCC_HWMON_PATH);
-    *fileName /= OCC_MASTER_NAME;
+    *fileName /= occMasterName;
     *fileName /= "/hwmon/";
 
     // Need to get the hwmonXX directory name, there better only be 1 dir
diff --git a/powercap.hpp b/powercap.hpp
index ddf2a74..6a77c9d 100644
--- a/powercap.hpp
+++ b/powercap.hpp
@@ -35,8 +35,10 @@
      * @param[in] occStatus - The occ status object
      */
     PowerCap(sdbusplus::bus::bus &bus,
-             Status &occStatus) :
+             Status &occStatus,
+             const std::string& occMasterName = OCC_MASTER_NAME) :
         bus(bus),
+        occMasterName(occMasterName),
         occStatus(occStatus),
         pcapMatch(
                 bus,
@@ -100,6 +102,9 @@
     /** @brief Reference to sdbus **/
     sdbusplus::bus::bus& bus;
 
+    /** @brief The master occ name */
+    std::string occMasterName;
+
     /* @brief OCC Status object */
     Status &occStatus;
 
diff --git a/test/TestI2cOcc.cpp b/test/TestI2cOcc.cpp
index c92da5b..bf976d7 100644
--- a/test/TestI2cOcc.cpp
+++ b/test/TestI2cOcc.cpp
@@ -28,6 +28,7 @@
 const auto I2C_6_0056 = BASE + STR_6_0056;
 const auto I2C_7_0057 = BASE + STR_7_0057;
 const auto NAME = "/name";
+const auto OCC_MASTER_NAME = "/occ_master";
 const auto P8_OCC_HWMON = "p8-occ-hwmon";
 
 const auto OTHER_STRING = "SomeOtherString123"s;
@@ -69,14 +70,26 @@
         ofs << "p8-occ-hwmon\n"; // 4-0050/name is p8-occ-hwmon
         ofs.close();
 
+        ofs.open(I2C_4_0050 + OCC_MASTER_NAME);
+        ofs << "0\n"; // Make 4-0050 the slave occ
+        ofs.close();
+
         ofs.open(I2C_5_0051 + NAME);
         ofs << "p8-occ-hwmon\n"; // 5-0051/name is p8-occ-hwmon
         ofs.close();
 
+        ofs.open(I2C_5_0051 + OCC_MASTER_NAME);
+        ofs << "0\n"; // Make 5-0051 the slave occ
+        ofs.close();
+
         ofs.open(I2C_6_0056 + NAME);
         ofs << "p8-occ-hwmon\n"; // 6-0056/name is p8-occ-hwmon
         ofs.close();
 
+        ofs.open(I2C_6_0056 + OCC_MASTER_NAME);
+        ofs << "1\n"; // Make 6-0056 the master occ
+        ofs.close();
+
         ofs.open(I2C_7_0057 + NAME);
         ofs << "p8-occ-hwmon\n"; // 7-0057/name is p8-occ-hwmon
         ofs.close();
@@ -94,9 +107,11 @@
     // With test env, it shall find all the 4 p8-occ-hwmon devices
     auto ret = getOccHwmonDevices(BASE.c_str());
     EXPECT_EQ(4u, ret.size());
-    EXPECT_EQ(STR_4_0050, ret[0]);
-    EXPECT_EQ(STR_5_0051, ret[1]);
-    EXPECT_EQ(STR_6_0056, ret[2]);
+    // The first one shall be master occ
+    EXPECT_EQ(STR_6_0056, ret[0]);
+    // The left is sorted
+    EXPECT_EQ(STR_4_0050, ret[1]);
+    EXPECT_EQ(STR_5_0051, ret[2]);
     EXPECT_EQ(STR_7_0057, ret[3]);
 }