xref: /openbmc/phosphor-power/phosphor-power-sequencer/test/ucd90x_device_tests.cpp (revision f54021972b91be5058b50e9046bb0dd5a3b22a80)
171d7fe43SShawn McCarney /**
271d7fe43SShawn McCarney  * Copyright © 2024 IBM Corporation
371d7fe43SShawn McCarney  *
471d7fe43SShawn McCarney  * Licensed under the Apache License, Version 2.0 (the "License");
571d7fe43SShawn McCarney  * you may not use this file except in compliance with the License.
671d7fe43SShawn McCarney  * You may obtain a copy of the License at
771d7fe43SShawn McCarney  *
871d7fe43SShawn McCarney  *     http://www.apache.org/licenses/LICENSE-2.0
971d7fe43SShawn McCarney  *
1071d7fe43SShawn McCarney  * Unless required by applicable law or agreed to in writing, software
1171d7fe43SShawn McCarney  * distributed under the License is distributed on an "AS IS" BASIS,
1271d7fe43SShawn McCarney  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1371d7fe43SShawn McCarney  * See the License for the specific language governing permissions and
1471d7fe43SShawn McCarney  * limitations under the License.
1571d7fe43SShawn McCarney  */
1671d7fe43SShawn McCarney 
1771d7fe43SShawn McCarney #include "mock_pmbus.hpp"
1871d7fe43SShawn McCarney #include "mock_services.hpp"
1971d7fe43SShawn McCarney #include "pmbus.hpp"
2071d7fe43SShawn McCarney #include "rail.hpp"
2171d7fe43SShawn McCarney #include "services.hpp"
2271d7fe43SShawn McCarney #include "ucd90x_device.hpp"
2371d7fe43SShawn McCarney 
2471d7fe43SShawn McCarney #include <cstdint>
2571d7fe43SShawn McCarney #include <exception>
2671d7fe43SShawn McCarney #include <map>
2771d7fe43SShawn McCarney #include <memory>
2871d7fe43SShawn McCarney #include <optional>
2971d7fe43SShawn McCarney #include <string>
3071d7fe43SShawn McCarney #include <utility>
3171d7fe43SShawn McCarney #include <vector>
3271d7fe43SShawn McCarney 
3371d7fe43SShawn McCarney #include <gmock/gmock.h>
3471d7fe43SShawn McCarney #include <gtest/gtest.h>
3571d7fe43SShawn McCarney 
3671d7fe43SShawn McCarney using namespace phosphor::power::sequencer;
3771d7fe43SShawn McCarney using namespace phosphor::pmbus;
3871d7fe43SShawn McCarney 
3971d7fe43SShawn McCarney using ::testing::Return;
4071d7fe43SShawn McCarney using ::testing::Throw;
4171d7fe43SShawn McCarney 
4271d7fe43SShawn McCarney /**
4371d7fe43SShawn McCarney  * Creates a Rail object that checks for a pgood fault using a GPIO.
4471d7fe43SShawn McCarney  *
4571d7fe43SShawn McCarney  * @param name Unique name for the rail
4671d7fe43SShawn McCarney  * @param gpio GPIO line to read to determine the pgood status of the rail
4771d7fe43SShawn McCarney  * @return Rail object
4871d7fe43SShawn McCarney  */
createRail(const std::string & name,unsigned int gpioLine)49fec38334SShawn McCarney static std::unique_ptr<Rail> createRail(const std::string& name,
50fec38334SShawn McCarney                                         unsigned int gpioLine)
5171d7fe43SShawn McCarney {
5271d7fe43SShawn McCarney     std::optional<std::string> presence{};
5371d7fe43SShawn McCarney     std::optional<uint8_t> page{};
5471d7fe43SShawn McCarney     bool isPowerSupplyRail{false};
5571d7fe43SShawn McCarney     bool checkStatusVout{false};
5671d7fe43SShawn McCarney     bool compareVoltageToLimit{false};
5771d7fe43SShawn McCarney     bool activeLow{false};
5871d7fe43SShawn McCarney     std::optional<GPIO> gpio{GPIO{gpioLine, activeLow}};
5971d7fe43SShawn McCarney     return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail,
6071d7fe43SShawn McCarney                                   checkStatusVout, compareVoltageToLimit, gpio);
6171d7fe43SShawn McCarney }
6271d7fe43SShawn McCarney 
TEST(UCD90xDeviceTests,Constructor)6371d7fe43SShawn McCarney TEST(UCD90xDeviceTests, Constructor)
6471d7fe43SShawn McCarney {
6571d7fe43SShawn McCarney     MockServices services;
6671d7fe43SShawn McCarney 
6771d7fe43SShawn McCarney     std::string name{"ucd90320"};
6871d7fe43SShawn McCarney     std::vector<std::unique_ptr<Rail>> rails;
6971d7fe43SShawn McCarney     rails.emplace_back(createRail("VDD", 5));
7071d7fe43SShawn McCarney     rails.emplace_back(createRail("VIO", 7));
7171d7fe43SShawn McCarney     uint8_t bus{3};
7271d7fe43SShawn McCarney     uint16_t address{0x72};
7371d7fe43SShawn McCarney     UCD90xDevice device{name, std::move(rails), services, bus, address};
7471d7fe43SShawn McCarney 
7571d7fe43SShawn McCarney     EXPECT_EQ(device.getName(), name);
7671d7fe43SShawn McCarney     EXPECT_EQ(device.getRails().size(), 2);
7771d7fe43SShawn McCarney     EXPECT_EQ(device.getRails()[0]->getName(), "VDD");
7871d7fe43SShawn McCarney     EXPECT_EQ(device.getRails()[1]->getName(), "VIO");
7971d7fe43SShawn McCarney     EXPECT_EQ(device.getBus(), bus);
8071d7fe43SShawn McCarney     EXPECT_EQ(device.getAddress(), address);
8171d7fe43SShawn McCarney     EXPECT_EQ(device.getDriverName(), "ucd9000");
8271d7fe43SShawn McCarney     EXPECT_EQ(device.getInstance(), 0);
8371d7fe43SShawn McCarney     EXPECT_NE(&(device.getPMBusInterface()), nullptr);
8471d7fe43SShawn McCarney }
8571d7fe43SShawn McCarney 
TEST(UCD90xDeviceTests,GetMfrStatus)8671d7fe43SShawn McCarney TEST(UCD90xDeviceTests, GetMfrStatus)
8771d7fe43SShawn McCarney {
8871d7fe43SShawn McCarney     // Test where works
8971d7fe43SShawn McCarney     {
9071d7fe43SShawn McCarney         MockServices services;
9171d7fe43SShawn McCarney 
9271d7fe43SShawn McCarney         std::string name{"ucd90320"};
9371d7fe43SShawn McCarney         std::vector<std::unique_ptr<Rail>> rails;
9471d7fe43SShawn McCarney         uint8_t bus{3};
9571d7fe43SShawn McCarney         uint16_t address{0x72};
9671d7fe43SShawn McCarney         UCD90xDevice device{name, std::move(rails), services, bus, address};
9771d7fe43SShawn McCarney 
9871d7fe43SShawn McCarney         MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
9971d7fe43SShawn McCarney         uint64_t mfrStatus{0x123456789abcull};
10071d7fe43SShawn McCarney         EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true))
10171d7fe43SShawn McCarney             .Times(1)
10271d7fe43SShawn McCarney             .WillOnce(Return(mfrStatus));
10371d7fe43SShawn McCarney 
10471d7fe43SShawn McCarney         EXPECT_EQ(device.getMfrStatus(), mfrStatus);
10571d7fe43SShawn McCarney     }
10671d7fe43SShawn McCarney 
10771d7fe43SShawn McCarney     // Test where fails with exception
10871d7fe43SShawn McCarney     {
10971d7fe43SShawn McCarney         MockServices services;
11071d7fe43SShawn McCarney 
11171d7fe43SShawn McCarney         std::string name{"ucd90320"};
11271d7fe43SShawn McCarney         std::vector<std::unique_ptr<Rail>> rails;
11371d7fe43SShawn McCarney         uint8_t bus{3};
11471d7fe43SShawn McCarney         uint16_t address{0x72};
11571d7fe43SShawn McCarney         UCD90xDevice device{name, std::move(rails), services, bus, address};
11671d7fe43SShawn McCarney 
11771d7fe43SShawn McCarney         MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
11871d7fe43SShawn McCarney         EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true))
11971d7fe43SShawn McCarney             .Times(1)
12071d7fe43SShawn McCarney             .WillOnce(Throw(std::runtime_error{"File does not exist"}));
12171d7fe43SShawn McCarney 
12271d7fe43SShawn McCarney         try
12371d7fe43SShawn McCarney         {
12471d7fe43SShawn McCarney             device.getMfrStatus();
12571d7fe43SShawn McCarney             ADD_FAILURE() << "Should not have reached this line.";
12671d7fe43SShawn McCarney         }
12771d7fe43SShawn McCarney         catch (const std::exception& e)
12871d7fe43SShawn McCarney         {
12971d7fe43SShawn McCarney             EXPECT_STREQ(e.what(),
13071d7fe43SShawn McCarney                          "Unable to read MFR_STATUS for device ucd90320: "
13171d7fe43SShawn McCarney                          "File does not exist");
13271d7fe43SShawn McCarney         }
13371d7fe43SShawn McCarney     }
13471d7fe43SShawn McCarney }
13571d7fe43SShawn McCarney 
TEST(UCD90xDeviceTests,StorePgoodFaultDebugData)13671d7fe43SShawn McCarney TEST(UCD90xDeviceTests, StorePgoodFaultDebugData)
13771d7fe43SShawn McCarney {
13871d7fe43SShawn McCarney     // This is a protected method and cannot be called directly from a gtest.
13971d7fe43SShawn McCarney     // Call findPgoodFault() which calls storePgoodFaultDebugData().
14071d7fe43SShawn McCarney 
14171d7fe43SShawn McCarney     // Test where works
14271d7fe43SShawn McCarney     {
14371d7fe43SShawn McCarney         MockServices services;
14471d7fe43SShawn McCarney         std::vector<int> gpioValues{1, 1, 0};
14571d7fe43SShawn McCarney         EXPECT_CALL(services, getGPIOValues("ucd90320"))
14671d7fe43SShawn McCarney             .Times(1)
14771d7fe43SShawn McCarney             .WillOnce(Return(gpioValues));
14871d7fe43SShawn McCarney         EXPECT_CALL(services,
14971d7fe43SShawn McCarney                     logInfoMsg("Device ucd90320 GPIO values: [1, 1, 0]"))
15071d7fe43SShawn McCarney             .Times(1);
15171d7fe43SShawn McCarney         EXPECT_CALL(services,
15271d7fe43SShawn McCarney                     logInfoMsg("Device ucd90320 MFR_STATUS: 0x123456789abc"))
15371d7fe43SShawn McCarney             .Times(1);
15471d7fe43SShawn McCarney         EXPECT_CALL(
15571d7fe43SShawn McCarney             services,
15671d7fe43SShawn McCarney             logErrorMsg(
15771d7fe43SShawn McCarney                 "Pgood fault found in rail monitored by device ucd90320"))
15871d7fe43SShawn McCarney             .Times(1);
15971d7fe43SShawn McCarney         EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD"))
16071d7fe43SShawn McCarney             .Times(1);
16171d7fe43SShawn McCarney         EXPECT_CALL(
16271d7fe43SShawn McCarney             services,
16371d7fe43SShawn McCarney             logErrorMsg(
16471d7fe43SShawn McCarney                 "Rail VDD pgood GPIO line offset 2 has inactive value 0"))
16571d7fe43SShawn McCarney             .Times(1);
16671d7fe43SShawn McCarney 
16771d7fe43SShawn McCarney         std::string name{"ucd90320"};
16871d7fe43SShawn McCarney         std::vector<std::unique_ptr<Rail>> rails;
16971d7fe43SShawn McCarney         rails.emplace_back(createRail("VDD", 2));
17071d7fe43SShawn McCarney         uint8_t bus{3};
17171d7fe43SShawn McCarney         uint16_t address{0x72};
17271d7fe43SShawn McCarney         UCD90xDevice device{name, std::move(rails), services, bus, address};
17371d7fe43SShawn McCarney 
17471d7fe43SShawn McCarney         MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
17571d7fe43SShawn McCarney         EXPECT_CALL(pmbus, getPath(Type::Hwmon))
17671d7fe43SShawn McCarney             .Times(1)
17771d7fe43SShawn McCarney             .WillOnce(Return("/tmp"));
17871d7fe43SShawn McCarney         EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true))
17971d7fe43SShawn McCarney             .Times(1)
18071d7fe43SShawn McCarney             .WillOnce(Return(0x123456789abcull));
18171d7fe43SShawn McCarney 
18271d7fe43SShawn McCarney         // Call findPgoodFault() which calls storePgoodFaultDebugData()
18371d7fe43SShawn McCarney         std::string powerSupplyError{};
18471d7fe43SShawn McCarney         std::map<std::string, std::string> additionalData{};
185*f5402197SPatrick Williams         std::string error =
186*f5402197SPatrick Williams             device.findPgoodFault(services, powerSupplyError, additionalData);
18771d7fe43SShawn McCarney         EXPECT_EQ(error,
18871d7fe43SShawn McCarney                   "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
18971d7fe43SShawn McCarney         EXPECT_EQ(additionalData.size(), 6);
19071d7fe43SShawn McCarney         EXPECT_EQ(additionalData["MFR_STATUS"], "0x123456789abc");
19171d7fe43SShawn McCarney         EXPECT_EQ(additionalData["DEVICE_NAME"], "ucd90320");
19271d7fe43SShawn McCarney         EXPECT_EQ(additionalData["GPIO_VALUES"], "[1, 1, 0]");
19371d7fe43SShawn McCarney         EXPECT_EQ(additionalData["RAIL_NAME"], "VDD");
19471d7fe43SShawn McCarney         EXPECT_EQ(additionalData["GPIO_LINE"], "2");
19571d7fe43SShawn McCarney         EXPECT_EQ(additionalData["GPIO_VALUE"], "0");
19671d7fe43SShawn McCarney     }
19771d7fe43SShawn McCarney 
19871d7fe43SShawn McCarney     // Test where exception thrown trying to get MFR_STATUS
19971d7fe43SShawn McCarney     {
20071d7fe43SShawn McCarney         MockServices services;
20171d7fe43SShawn McCarney         std::vector<int> gpioValues{1, 1, 0};
20271d7fe43SShawn McCarney         EXPECT_CALL(services, getGPIOValues("ucd90320"))
20371d7fe43SShawn McCarney             .Times(1)
20471d7fe43SShawn McCarney             .WillOnce(Return(gpioValues));
20571d7fe43SShawn McCarney         EXPECT_CALL(services,
20671d7fe43SShawn McCarney                     logInfoMsg("Device ucd90320 GPIO values: [1, 1, 0]"))
20771d7fe43SShawn McCarney             .Times(1);
20871d7fe43SShawn McCarney         EXPECT_CALL(
20971d7fe43SShawn McCarney             services,
21071d7fe43SShawn McCarney             logErrorMsg(
21171d7fe43SShawn McCarney                 "Pgood fault found in rail monitored by device ucd90320"))
21271d7fe43SShawn McCarney             .Times(1);
21371d7fe43SShawn McCarney         EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD"))
21471d7fe43SShawn McCarney             .Times(1);
21571d7fe43SShawn McCarney         EXPECT_CALL(
21671d7fe43SShawn McCarney             services,
21771d7fe43SShawn McCarney             logErrorMsg(
21871d7fe43SShawn McCarney                 "Rail VDD pgood GPIO line offset 2 has inactive value 0"))
21971d7fe43SShawn McCarney             .Times(1);
22071d7fe43SShawn McCarney 
22171d7fe43SShawn McCarney         std::string name{"ucd90320"};
22271d7fe43SShawn McCarney         std::vector<std::unique_ptr<Rail>> rails;
22371d7fe43SShawn McCarney         rails.emplace_back(createRail("VDD", 2));
22471d7fe43SShawn McCarney         uint8_t bus{3};
22571d7fe43SShawn McCarney         uint16_t address{0x72};
22671d7fe43SShawn McCarney         UCD90xDevice device{name, std::move(rails), services, bus, address};
22771d7fe43SShawn McCarney 
22871d7fe43SShawn McCarney         MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
22971d7fe43SShawn McCarney         EXPECT_CALL(pmbus, getPath(Type::Hwmon))
23071d7fe43SShawn McCarney             .Times(1)
23171d7fe43SShawn McCarney             .WillOnce(Return("/tmp"));
23271d7fe43SShawn McCarney         EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true))
23371d7fe43SShawn McCarney             .Times(1)
23471d7fe43SShawn McCarney             .WillOnce(Throw(std::runtime_error{"File does not exist"}));
23571d7fe43SShawn McCarney 
23671d7fe43SShawn McCarney         // Call findPgoodFault() which calls storePgoodFaultDebugData()
23771d7fe43SShawn McCarney         std::string powerSupplyError{};
23871d7fe43SShawn McCarney         std::map<std::string, std::string> additionalData{};
239*f5402197SPatrick Williams         std::string error =
240*f5402197SPatrick Williams             device.findPgoodFault(services, powerSupplyError, additionalData);
24171d7fe43SShawn McCarney         EXPECT_EQ(error,
24271d7fe43SShawn McCarney                   "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
24371d7fe43SShawn McCarney         EXPECT_EQ(additionalData.size(), 5);
24471d7fe43SShawn McCarney         EXPECT_EQ(additionalData["DEVICE_NAME"], "ucd90320");
24571d7fe43SShawn McCarney         EXPECT_EQ(additionalData["GPIO_VALUES"], "[1, 1, 0]");
24671d7fe43SShawn McCarney         EXPECT_EQ(additionalData["RAIL_NAME"], "VDD");
24771d7fe43SShawn McCarney         EXPECT_EQ(additionalData["GPIO_LINE"], "2");
24871d7fe43SShawn McCarney         EXPECT_EQ(additionalData["GPIO_VALUE"], "0");
24971d7fe43SShawn McCarney     }
25071d7fe43SShawn McCarney }
251