1 /** 2 * Copyright © 2024 IBM 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 17 #include "mock_pmbus.hpp" 18 #include "mock_services.hpp" 19 #include "pmbus.hpp" 20 #include "rail.hpp" 21 #include "services.hpp" 22 #include "ucd90320_device.hpp" 23 24 #include <cstdint> 25 #include <map> 26 #include <memory> 27 #include <optional> 28 #include <string> 29 #include <utility> 30 #include <vector> 31 32 #include <gmock/gmock.h> 33 #include <gtest/gtest.h> 34 35 using namespace phosphor::power::sequencer; 36 using namespace phosphor::pmbus; 37 38 using ::testing::Return; 39 40 /** 41 * Creates a Rail object that checks for a pgood fault using a GPIO. 42 * 43 * @param name Unique name for the rail 44 * @param gpio GPIO line to read to determine the pgood status of the rail 45 * @return Rail object 46 */ 47 static std::unique_ptr<Rail> createRail(const std::string& name, 48 unsigned int gpioLine) 49 { 50 std::optional<std::string> presence{}; 51 std::optional<uint8_t> page{}; 52 bool isPowerSupplyRail{false}; 53 bool checkStatusVout{false}; 54 bool compareVoltageToLimit{false}; 55 bool activeLow{false}; 56 std::optional<GPIO> gpio{GPIO{gpioLine, activeLow}}; 57 return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail, 58 checkStatusVout, compareVoltageToLimit, gpio); 59 } 60 61 TEST(UCD90320DeviceTests, Constructor) 62 { 63 MockServices services; 64 65 std::vector<std::unique_ptr<Rail>> rails; 66 rails.emplace_back(createRail("VDD", 5)); 67 rails.emplace_back(createRail("VIO", 7)); 68 uint8_t bus{3}; 69 uint16_t address{0x72}; 70 UCD90320Device device{std::move(rails), services, bus, address}; 71 72 EXPECT_EQ(device.getName(), "UCD90320"); 73 EXPECT_EQ(device.getRails().size(), 2); 74 EXPECT_EQ(device.getRails()[0]->getName(), "VDD"); 75 EXPECT_EQ(device.getRails()[1]->getName(), "VIO"); 76 EXPECT_EQ(device.getBus(), bus); 77 EXPECT_EQ(device.getAddress(), address); 78 EXPECT_EQ(device.getDriverName(), "ucd9000"); 79 EXPECT_EQ(device.getInstance(), 0); 80 EXPECT_NE(&(device.getPMBusInterface()), nullptr); 81 } 82 83 TEST(UCD90320DeviceTests, StoreGPIOValues) 84 { 85 // This is a protected method and cannot be called directly from a gtest. 86 // Call findPgoodFault() which calls storeGPIOValues(). 87 88 // Test where works 89 { 90 std::vector<int> gpioValues{ 91 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, // MAR01-12 92 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, // MAR13-24 93 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, // EN1-12 94 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, // EN13-24 95 1, 1, 0, 0, 1, 1, 1, 0, // EN25-32 96 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, // LGP01-12 97 1, 1, 0, 0, // LGP13-16 98 1, 0, 0, 1, 1, 1, 0, 0, // DMON1-8 99 1, 0, 0, 1 // GPIO1-4 100 }; 101 102 MockServices services; 103 EXPECT_CALL(services, getGPIOValues("ucd90320")) 104 .Times(1) 105 .WillOnce(Return(gpioValues)); 106 EXPECT_CALL(services, logInfoMsg("Device UCD90320 GPIO values:")) 107 .Times(1); 108 EXPECT_CALL(services, logInfoMsg("MAR01-24: [" 109 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 110 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0]")) 111 .Times(1); 112 EXPECT_CALL(services, logInfoMsg("EN1-32: [" 113 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 114 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, " 115 "1, 1, 0, 0, 1, 1, 1, 0]")) 116 .Times(1); 117 EXPECT_CALL(services, logInfoMsg("LGP01-16: [" 118 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 119 "1, 1, 0, 0]")) 120 .Times(1); 121 EXPECT_CALL(services, logInfoMsg("DMON1-8: [" 122 "1, 0, 0, 1, 1, 1, 0, 0]")) 123 .Times(1); 124 EXPECT_CALL(services, logInfoMsg("GPIO1-4: [" 125 "1, 0, 0, 1]")) 126 .Times(1); 127 EXPECT_CALL(services, 128 logInfoMsg("Device UCD90320 MFR_STATUS: 0x123456789abc")) 129 .Times(1); 130 EXPECT_CALL( 131 services, 132 logErrorMsg( 133 "Pgood fault found in rail monitored by device UCD90320")) 134 .Times(1); 135 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD")) 136 .Times(1); 137 EXPECT_CALL( 138 services, 139 logErrorMsg( 140 "Rail VDD pgood GPIO line offset 2 has inactive value 0")) 141 .Times(1); 142 143 std::vector<std::unique_ptr<Rail>> rails; 144 rails.emplace_back(createRail("VDD", 2)); 145 uint8_t bus{3}; 146 uint16_t address{0x72}; 147 UCD90320Device device{std::move(rails), services, bus, address}; 148 149 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 150 EXPECT_CALL(pmbus, getPath(Type::Hwmon)) 151 .Times(1) 152 .WillOnce(Return("/tmp")); 153 EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true)) 154 .Times(1) 155 .WillOnce(Return(0x123456789abcull)); 156 157 // Call findPgoodFault() which calls storeGPIOValues() 158 std::string powerSupplyError{}; 159 std::map<std::string, std::string> additionalData{}; 160 std::string error = device.findPgoodFault(services, powerSupplyError, 161 additionalData); 162 EXPECT_EQ(error, 163 "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault"); 164 EXPECT_EQ(additionalData.size(), 10); 165 EXPECT_EQ(additionalData["MFR_STATUS"], "0x123456789abc"); 166 EXPECT_EQ(additionalData["DEVICE_NAME"], "UCD90320"); 167 EXPECT_EQ(additionalData["MAR01_24_GPIO_VALUES"], 168 "[1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 169 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0]"); 170 EXPECT_EQ(additionalData["EN1_32_GPIO_VALUES"], 171 "[1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 172 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, " 173 "1, 1, 0, 0, 1, 1, 1, 0]"); 174 EXPECT_EQ(additionalData["LGP01_16_GPIO_VALUES"], 175 "[1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 176 "1, 1, 0, 0]"); 177 EXPECT_EQ(additionalData["DMON1_8_GPIO_VALUES"], 178 "[1, 0, 0, 1, 1, 1, 0, 0]"); 179 EXPECT_EQ(additionalData["GPIO1_4_GPIO_VALUES"], "[1, 0, 0, 1]"); 180 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD"); 181 EXPECT_EQ(additionalData["GPIO_LINE"], "2"); 182 EXPECT_EQ(additionalData["GPIO_VALUE"], "0"); 183 } 184 185 // Test where there are the wrong number of GPIOs (83 instead of 84) 186 { 187 std::vector<int> gpioValues{ 188 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, // MAR01-12 189 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, // MAR13-24 190 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, // EN1-12 191 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, // EN13-24 192 1, 1, 0, 0, 1, 1, 1, 0, // EN25-32 193 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, // LGP01-12 194 1, 1, 0, 0, // LGP13-16 195 1, 0, 0, 1, 1, 1, 0, 0, // DMON1-8 196 1, 0, 0 // GPIO1-4 (1 missing) 197 }; 198 199 MockServices services; 200 EXPECT_CALL(services, getGPIOValues("ucd90320")) 201 .Times(1) 202 .WillOnce(Return(gpioValues)); 203 EXPECT_CALL(services, logInfoMsg("Device UCD90320 GPIO values: [" 204 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 205 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, " 206 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 207 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, " 208 "1, 1, 0, 0, 1, 1, 1, 0, " 209 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 210 "1, 1, 0, 0, " 211 "1, 0, 0, 1, 1, 1, 0, 0, " 212 "1, 0, 0]")) 213 .Times(1); 214 EXPECT_CALL(services, 215 logInfoMsg("Device UCD90320 MFR_STATUS: 0x123456789abc")) 216 .Times(1); 217 EXPECT_CALL( 218 services, 219 logErrorMsg( 220 "Pgood fault found in rail monitored by device UCD90320")) 221 .Times(1); 222 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD")) 223 .Times(1); 224 EXPECT_CALL( 225 services, 226 logErrorMsg( 227 "Rail VDD pgood GPIO line offset 2 has inactive value 0")) 228 .Times(1); 229 230 std::vector<std::unique_ptr<Rail>> rails; 231 rails.emplace_back(createRail("VDD", 2)); 232 uint8_t bus{3}; 233 uint16_t address{0x72}; 234 UCD90320Device device{std::move(rails), services, bus, address}; 235 236 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 237 EXPECT_CALL(pmbus, getPath(Type::Hwmon)) 238 .Times(1) 239 .WillOnce(Return("/tmp")); 240 EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true)) 241 .Times(1) 242 .WillOnce(Return(0x123456789abcull)); 243 244 // Call findPgoodFault() which calls storeGPIOValues() 245 std::string powerSupplyError{}; 246 std::map<std::string, std::string> additionalData{}; 247 std::string error = device.findPgoodFault(services, powerSupplyError, 248 additionalData); 249 EXPECT_EQ(error, 250 "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault"); 251 EXPECT_EQ(additionalData.size(), 6); 252 EXPECT_EQ(additionalData["MFR_STATUS"], "0x123456789abc"); 253 EXPECT_EQ(additionalData["DEVICE_NAME"], "UCD90320"); 254 EXPECT_EQ(additionalData["GPIO_VALUES"], 255 "[1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 256 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, " 257 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 258 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, " 259 "1, 1, 0, 0, 1, 1, 1, 0, " 260 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 261 "1, 1, 0, 0, " 262 "1, 0, 0, 1, 1, 1, 0, 0, " 263 "1, 0, 0]"); 264 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD"); 265 EXPECT_EQ(additionalData["GPIO_LINE"], "2"); 266 EXPECT_EQ(additionalData["GPIO_VALUE"], "0"); 267 } 268 } 269