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 "ucd90160_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(UCD90160DeviceTests, Constructor) 62 { 63 MockServices services; 64 65 uint8_t bus{3}; 66 uint16_t address{0x72}; 67 std::string powerControlGPIOName{"power-chassis-control"}; 68 std::string powerGoodGPIOName{"power-chassis-good"}; 69 std::vector<std::unique_ptr<Rail>> rails; 70 rails.emplace_back(createRail("VDD", 5)); 71 rails.emplace_back(createRail("VIO", 7)); 72 UCD90160Device device{bus, 73 address, 74 powerControlGPIOName, 75 powerGoodGPIOName, 76 std::move(rails), 77 services}; 78 79 EXPECT_EQ(device.getName(), "UCD90160"); 80 EXPECT_EQ(device.getBus(), bus); 81 EXPECT_EQ(device.getAddress(), address); 82 EXPECT_EQ(device.getPowerControlGPIOName(), powerControlGPIOName); 83 EXPECT_EQ(device.getPowerGoodGPIOName(), powerGoodGPIOName); 84 EXPECT_EQ(device.getRails().size(), 2); 85 EXPECT_EQ(device.getRails()[0]->getName(), "VDD"); 86 EXPECT_EQ(device.getRails()[1]->getName(), "VIO"); 87 EXPECT_EQ(device.getDriverName(), "ucd9000"); 88 EXPECT_EQ(device.getInstance(), 0); 89 EXPECT_NE(&(device.getPMBusInterface()), nullptr); 90 } 91 92 TEST(UCD90160DeviceTests, StoreGPIOValues) 93 { 94 // This is a protected method and cannot be called directly from a gtest. 95 // Call findPgoodFault() which calls storeGPIOValues(). 96 97 // Test where works 98 { 99 std::vector<int> gpioValues{ 100 1, 0, 0, 1, // group 1 in journal 101 1, 1, 0, 0, // group 2 in journal 102 1, 0, 1, 1, // group 3 in journal 103 0, 0, 1, 1, // group 4 in journal 104 1, 0, 0, 0, // group 5 in journal 105 1, 0, 0, 1, // group 6 in journal 106 1, 1 // group 7 in journal 107 }; 108 109 MockServices services; 110 EXPECT_CALL(services, getGPIOValues("ucd90160")) 111 .Times(1) 112 .WillOnce(Return(gpioValues)); 113 EXPECT_CALL(services, logInfoMsg("Device UCD90160 GPIO values:")) 114 .Times(1); 115 EXPECT_CALL(services, 116 logInfoMsg( 117 "[FPWM1_GPIO5, FPWM2_GPIO6, FPWM3_GPIO7, FPWM4_GPIO8]: " 118 "[1, 0, 0, 1]")) 119 .Times(1); 120 EXPECT_CALL( 121 services, 122 logInfoMsg( 123 "[FPWM5_GPIO9, FPWM6_GPIO10, FPWM7_GPIO11, FPWM8_GPIO12]: " 124 "[1, 1, 0, 0]")) 125 .Times(1); 126 EXPECT_CALL(services, 127 logInfoMsg("[GPI1_PWM1, GPI2_PWM2, GPI3_PWM3, GPI4_PWM4]: " 128 "[1, 0, 1, 1]")) 129 .Times(1); 130 EXPECT_CALL(services, 131 logInfoMsg("[GPIO14, GPIO15, TDO_GPIO20, TCK_GPIO19]: " 132 "[0, 0, 1, 1]")) 133 .Times(1); 134 EXPECT_CALL(services, 135 logInfoMsg("[TMS_GPIO22, TDI_GPIO21, GPIO1, GPIO2]: " 136 "[1, 0, 0, 0]")) 137 .Times(1); 138 EXPECT_CALL(services, logInfoMsg("[GPIO3, GPIO4, GPIO13, GPIO16]: " 139 "[1, 0, 0, 1]")) 140 .Times(1); 141 EXPECT_CALL(services, logInfoMsg("[GPIO17, GPIO18]: " 142 "[1, 1]")) 143 .Times(1); 144 EXPECT_CALL(services, 145 logInfoMsg("Device UCD90160 MFR_STATUS: 0x123456789abc")) 146 .Times(1); 147 EXPECT_CALL( 148 services, 149 logErrorMsg( 150 "Pgood fault found in rail monitored by device UCD90160")) 151 .Times(1); 152 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD")) 153 .Times(1); 154 EXPECT_CALL( 155 services, 156 logErrorMsg( 157 "Rail VDD pgood GPIO line offset 2 has inactive value 0")) 158 .Times(1); 159 160 uint8_t bus{3}; 161 uint16_t address{0x72}; 162 std::string powerControlGPIOName{"power-chassis-control"}; 163 std::string powerGoodGPIOName{"power-chassis-good"}; 164 std::vector<std::unique_ptr<Rail>> rails; 165 rails.emplace_back(createRail("VDD", 2)); 166 UCD90160Device device{bus, 167 address, 168 powerControlGPIOName, 169 powerGoodGPIOName, 170 std::move(rails), 171 services}; 172 173 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 174 EXPECT_CALL(pmbus, getPath(Type::Hwmon)) 175 .Times(1) 176 .WillOnce(Return("/tmp")); 177 EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true)) 178 .Times(1) 179 .WillOnce(Return(0x123456789abcull)); 180 181 // Call findPgoodFault() which calls storeGPIOValues() 182 std::string powerSupplyError{}; 183 std::map<std::string, std::string> additionalData{}; 184 std::string error = 185 device.findPgoodFault(services, powerSupplyError, additionalData); 186 EXPECT_EQ(error, 187 "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault"); 188 EXPECT_EQ(additionalData.size(), 31); 189 EXPECT_EQ(additionalData["MFR_STATUS"], "0x123456789abc"); 190 EXPECT_EQ(additionalData["DEVICE_NAME"], "UCD90160"); 191 EXPECT_EQ(additionalData["FPWM1_GPIO5"], "1"); 192 EXPECT_EQ(additionalData["FPWM2_GPIO6"], "0"); 193 EXPECT_EQ(additionalData["FPWM3_GPIO7"], "0"); 194 EXPECT_EQ(additionalData["FPWM4_GPIO8"], "1"); 195 EXPECT_EQ(additionalData["FPWM5_GPIO9"], "1"); 196 EXPECT_EQ(additionalData["FPWM6_GPIO10"], "1"); 197 EXPECT_EQ(additionalData["FPWM7_GPIO11"], "0"); 198 EXPECT_EQ(additionalData["FPWM8_GPIO12"], "0"); 199 EXPECT_EQ(additionalData["GPI1_PWM1"], "1"); 200 EXPECT_EQ(additionalData["GPI2_PWM2"], "0"); 201 EXPECT_EQ(additionalData["GPI3_PWM3"], "1"); 202 EXPECT_EQ(additionalData["GPI4_PWM4"], "1"); 203 EXPECT_EQ(additionalData["GPIO14"], "0"); 204 EXPECT_EQ(additionalData["GPIO15"], "0"); 205 EXPECT_EQ(additionalData["TDO_GPIO20"], "1"); 206 EXPECT_EQ(additionalData["TCK_GPIO19"], "1"); 207 EXPECT_EQ(additionalData["TMS_GPIO22"], "1"); 208 EXPECT_EQ(additionalData["TDI_GPIO21"], "0"); 209 EXPECT_EQ(additionalData["GPIO1"], "0"); 210 EXPECT_EQ(additionalData["GPIO2"], "0"); 211 EXPECT_EQ(additionalData["GPIO3"], "1"); 212 EXPECT_EQ(additionalData["GPIO4"], "0"); 213 EXPECT_EQ(additionalData["GPIO13"], "0"); 214 EXPECT_EQ(additionalData["GPIO16"], "1"); 215 EXPECT_EQ(additionalData["GPIO17"], "1"); 216 EXPECT_EQ(additionalData["GPIO18"], "1"); 217 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD"); 218 EXPECT_EQ(additionalData["GPIO_LINE"], "2"); 219 EXPECT_EQ(additionalData["GPIO_VALUE"], "0"); 220 } 221 222 // Test where there are the wrong number of GPIOs (27 instead of 26) 223 { 224 std::vector<int> gpioValues{ 225 1, 0, 0, 1, // group 1 in journal 226 1, 1, 0, 0, // group 2 in journal 227 1, 0, 1, 1, // group 3 in journal 228 0, 0, 1, 1, // group 4 in journal 229 1, 0, 0, 0, // group 5 in journal 230 1, 0, 0, 1, // group 6 in journal 231 1, 1, 0 // group 7 in journal + extra value 232 }; 233 234 MockServices services; 235 EXPECT_CALL(services, getGPIOValues("ucd90160")) 236 .Times(1) 237 .WillOnce(Return(gpioValues)); 238 EXPECT_CALL(services, 239 logInfoMsg("Device UCD90160 GPIO values: [" 240 "1, 0, 0, 1, " 241 "1, 1, 0, 0, " 242 "1, 0, 1, 1, " 243 "0, 0, 1, 1, " 244 "1, 0, 0, 0, " 245 "1, 0, 0, 1, " 246 "1, 1, 0]")) 247 .Times(1); 248 EXPECT_CALL(services, 249 logInfoMsg("Device UCD90160 MFR_STATUS: 0x123456789abc")) 250 .Times(1); 251 EXPECT_CALL( 252 services, 253 logErrorMsg( 254 "Pgood fault found in rail monitored by device UCD90160")) 255 .Times(1); 256 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD")) 257 .Times(1); 258 EXPECT_CALL( 259 services, 260 logErrorMsg( 261 "Rail VDD pgood GPIO line offset 2 has inactive value 0")) 262 .Times(1); 263 264 uint8_t bus{3}; 265 uint16_t address{0x72}; 266 std::string powerControlGPIOName{"power-chassis-control"}; 267 std::string powerGoodGPIOName{"power-chassis-good"}; 268 std::vector<std::unique_ptr<Rail>> rails; 269 rails.emplace_back(createRail("VDD", 2)); 270 UCD90160Device device{bus, 271 address, 272 powerControlGPIOName, 273 powerGoodGPIOName, 274 std::move(rails), 275 services}; 276 277 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 278 EXPECT_CALL(pmbus, getPath(Type::Hwmon)) 279 .Times(1) 280 .WillOnce(Return("/tmp")); 281 EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true)) 282 .Times(1) 283 .WillOnce(Return(0x123456789abcull)); 284 285 // Call findPgoodFault() which calls storeGPIOValues() 286 std::string powerSupplyError{}; 287 std::map<std::string, std::string> additionalData{}; 288 std::string error = 289 device.findPgoodFault(services, powerSupplyError, additionalData); 290 EXPECT_EQ(error, 291 "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault"); 292 EXPECT_EQ(additionalData.size(), 6); 293 EXPECT_EQ(additionalData["MFR_STATUS"], "0x123456789abc"); 294 EXPECT_EQ(additionalData["DEVICE_NAME"], "UCD90160"); 295 EXPECT_EQ(additionalData["GPIO_VALUES"], 296 "[1, 0, 0, 1, " 297 "1, 1, 0, 0, " 298 "1, 0, 1, 1, " 299 "0, 0, 1, 1, " 300 "1, 0, 0, 0, " 301 "1, 0, 0, 1, " 302 "1, 1, 0]"); 303 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD"); 304 EXPECT_EQ(additionalData["GPIO_LINE"], "2"); 305 EXPECT_EQ(additionalData["GPIO_VALUE"], "0"); 306 } 307 } 308