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<PgoodGPIO> gpio{PgoodGPIO{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 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 UCD90320Device device{bus, 73 address, 74 powerControlGPIOName, 75 powerGoodGPIOName, 76 std::move(rails), 77 services}; 78 79 EXPECT_EQ(device.getName(), "UCD90320"); 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(UCD90320DeviceTests, 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, 1, 1, 0, 0, 1, 0, 0, 1, // MAR01-12 101 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, // MAR13-24 102 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, // EN1-12 103 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, // EN13-24 104 1, 1, 0, 0, 1, 1, 1, 0, // EN25-32 105 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, // LGP01-12 106 1, 1, 0, 0, // LGP13-16 107 1, 0, 0, 1, 1, 1, 0, 0, // DMON1-8 108 1, 0, 0, 1 // GPIO1-4 109 }; 110 111 MockServices services; 112 EXPECT_CALL(services, getGPIOValues("ucd90320")) 113 .Times(1) 114 .WillOnce(Return(gpioValues)); 115 EXPECT_CALL(services, logInfoMsg("Device UCD90320 GPIO values:")) 116 .Times(1); 117 EXPECT_CALL(services, logInfoMsg("MAR01-24: [" 118 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 119 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0]")) 120 .Times(1); 121 EXPECT_CALL(services, logInfoMsg("EN1-32: [" 122 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 123 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, " 124 "1, 1, 0, 0, 1, 1, 1, 0]")) 125 .Times(1); 126 EXPECT_CALL(services, logInfoMsg("LGP01-16: [" 127 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 128 "1, 1, 0, 0]")) 129 .Times(1); 130 EXPECT_CALL(services, logInfoMsg("DMON1-8: [" 131 "1, 0, 0, 1, 1, 1, 0, 0]")) 132 .Times(1); 133 EXPECT_CALL(services, logInfoMsg("GPIO1-4: [" 134 "1, 0, 0, 1]")) 135 .Times(1); 136 EXPECT_CALL(services, 137 logInfoMsg("Device UCD90320 MFR_STATUS: 0x123456789abc")) 138 .Times(1); 139 EXPECT_CALL( 140 services, 141 logErrorMsg( 142 "Pgood fault found in rail monitored by device UCD90320")) 143 .Times(1); 144 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD")) 145 .Times(1); 146 EXPECT_CALL( 147 services, 148 logErrorMsg( 149 "Rail VDD pgood GPIO line offset 2 has inactive value 0")) 150 .Times(1); 151 152 uint8_t bus{3}; 153 uint16_t address{0x72}; 154 std::string powerControlGPIOName{"power-chassis-control"}; 155 std::string powerGoodGPIOName{"power-chassis-good"}; 156 std::vector<std::unique_ptr<Rail>> rails; 157 rails.emplace_back(createRail("VDD", 2)); 158 UCD90320Device device{bus, 159 address, 160 powerControlGPIOName, 161 powerGoodGPIOName, 162 std::move(rails), 163 services}; 164 165 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 166 EXPECT_CALL(pmbus, getPath(Type::Hwmon)) 167 .Times(1) 168 .WillOnce(Return("/tmp")); 169 EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true)) 170 .Times(1) 171 .WillOnce(Return(0x123456789abcull)); 172 173 // Call findPgoodFault() which calls storeGPIOValues() 174 std::string powerSupplyError{}; 175 std::map<std::string, std::string> additionalData{}; 176 std::string error = 177 device.findPgoodFault(services, powerSupplyError, additionalData); 178 EXPECT_EQ(error, 179 "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault"); 180 EXPECT_EQ(additionalData.size(), 10); 181 EXPECT_EQ(additionalData["MFR_STATUS"], "0x123456789abc"); 182 EXPECT_EQ(additionalData["DEVICE_NAME"], "UCD90320"); 183 EXPECT_EQ(additionalData["MAR01_24_GPIO_VALUES"], 184 "[1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 185 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0]"); 186 EXPECT_EQ(additionalData["EN1_32_GPIO_VALUES"], 187 "[1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 188 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, " 189 "1, 1, 0, 0, 1, 1, 1, 0]"); 190 EXPECT_EQ(additionalData["LGP01_16_GPIO_VALUES"], 191 "[1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 192 "1, 1, 0, 0]"); 193 EXPECT_EQ(additionalData["DMON1_8_GPIO_VALUES"], 194 "[1, 0, 0, 1, 1, 1, 0, 0]"); 195 EXPECT_EQ(additionalData["GPIO1_4_GPIO_VALUES"], "[1, 0, 0, 1]"); 196 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD"); 197 EXPECT_EQ(additionalData["GPIO_LINE"], "2"); 198 EXPECT_EQ(additionalData["GPIO_VALUE"], "0"); 199 } 200 201 // Test where there are the wrong number of GPIOs (83 instead of 84) 202 { 203 std::vector<int> gpioValues{ 204 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, // MAR01-12 205 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, // MAR13-24 206 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, // EN1-12 207 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, // EN13-24 208 1, 1, 0, 0, 1, 1, 1, 0, // EN25-32 209 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, // LGP01-12 210 1, 1, 0, 0, // LGP13-16 211 1, 0, 0, 1, 1, 1, 0, 0, // DMON1-8 212 1, 0, 0 // GPIO1-4 (1 missing) 213 }; 214 215 MockServices services; 216 EXPECT_CALL(services, getGPIOValues("ucd90320")) 217 .Times(1) 218 .WillOnce(Return(gpioValues)); 219 EXPECT_CALL(services, 220 logInfoMsg("Device UCD90320 GPIO values: [" 221 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 222 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, " 223 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 224 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, " 225 "1, 1, 0, 0, 1, 1, 1, 0, " 226 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 227 "1, 1, 0, 0, " 228 "1, 0, 0, 1, 1, 1, 0, 0, " 229 "1, 0, 0]")) 230 .Times(1); 231 EXPECT_CALL(services, 232 logInfoMsg("Device UCD90320 MFR_STATUS: 0x123456789abc")) 233 .Times(1); 234 EXPECT_CALL( 235 services, 236 logErrorMsg( 237 "Pgood fault found in rail monitored by device UCD90320")) 238 .Times(1); 239 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD")) 240 .Times(1); 241 EXPECT_CALL( 242 services, 243 logErrorMsg( 244 "Rail VDD pgood GPIO line offset 2 has inactive value 0")) 245 .Times(1); 246 247 uint8_t bus{3}; 248 uint16_t address{0x72}; 249 std::string powerControlGPIOName{"power-chassis-control"}; 250 std::string powerGoodGPIOName{"power-chassis-good"}; 251 std::vector<std::unique_ptr<Rail>> rails; 252 rails.emplace_back(createRail("VDD", 2)); 253 UCD90320Device device{bus, 254 address, 255 powerControlGPIOName, 256 powerGoodGPIOName, 257 std::move(rails), 258 services}; 259 260 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 261 EXPECT_CALL(pmbus, getPath(Type::Hwmon)) 262 .Times(1) 263 .WillOnce(Return("/tmp")); 264 EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true)) 265 .Times(1) 266 .WillOnce(Return(0x123456789abcull)); 267 268 // Call findPgoodFault() which calls storeGPIOValues() 269 std::string powerSupplyError{}; 270 std::map<std::string, std::string> additionalData{}; 271 std::string error = 272 device.findPgoodFault(services, powerSupplyError, additionalData); 273 EXPECT_EQ(error, 274 "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault"); 275 EXPECT_EQ(additionalData.size(), 6); 276 EXPECT_EQ(additionalData["MFR_STATUS"], "0x123456789abc"); 277 EXPECT_EQ(additionalData["DEVICE_NAME"], "UCD90320"); 278 EXPECT_EQ(additionalData["GPIO_VALUES"], 279 "[1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 280 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, " 281 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 282 "1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, " 283 "1, 1, 0, 0, 1, 1, 1, 0, " 284 "1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, " 285 "1, 1, 0, 0, " 286 "1, 0, 0, 1, 1, 1, 0, 0, " 287 "1, 0, 0]"); 288 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD"); 289 EXPECT_EQ(additionalData["GPIO_LINE"], "2"); 290 EXPECT_EQ(additionalData["GPIO_VALUE"], "0"); 291 } 292 } 293