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 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 UCD90160Device device{std::move(rails), services, bus, address}; 71 72 EXPECT_EQ(device.getName(), "UCD90160"); 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(UCD90160DeviceTests, 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, // group 1 in journal 92 1, 1, 0, 0, // group 2 in journal 93 1, 0, 1, 1, // group 3 in journal 94 0, 0, 1, 1, // group 4 in journal 95 1, 0, 0, 0, // group 5 in journal 96 1, 0, 0, 1, // group 6 in journal 97 1, 1 // group 7 in journal 98 }; 99 100 MockServices services; 101 EXPECT_CALL(services, getGPIOValues("ucd90160")) 102 .Times(1) 103 .WillOnce(Return(gpioValues)); 104 EXPECT_CALL(services, logInfoMsg("Device UCD90160 GPIO values:")) 105 .Times(1); 106 EXPECT_CALL( 107 services, 108 logInfoMsg("[FPWM1_GPIO5, FPWM2_GPIO6, FPWM3_GPIO7, FPWM4_GPIO8]: " 109 "[1, 0, 0, 1]")) 110 .Times(1); 111 EXPECT_CALL( 112 services, 113 logInfoMsg( 114 "[FPWM5_GPIO9, FPWM6_GPIO10, FPWM7_GPIO11, FPWM8_GPIO12]: " 115 "[1, 1, 0, 0]")) 116 .Times(1); 117 EXPECT_CALL(services, 118 logInfoMsg("[GPI1_PWM1, GPI2_PWM2, GPI3_PWM3, GPI4_PWM4]: " 119 "[1, 0, 1, 1]")) 120 .Times(1); 121 EXPECT_CALL(services, 122 logInfoMsg("[GPIO14, GPIO15, TDO_GPIO20, TCK_GPIO19]: " 123 "[0, 0, 1, 1]")) 124 .Times(1); 125 EXPECT_CALL(services, 126 logInfoMsg("[TMS_GPIO22, TDI_GPIO21, GPIO1, GPIO2]: " 127 "[1, 0, 0, 0]")) 128 .Times(1); 129 EXPECT_CALL(services, logInfoMsg("[GPIO3, GPIO4, GPIO13, GPIO16]: " 130 "[1, 0, 0, 1]")) 131 .Times(1); 132 EXPECT_CALL(services, logInfoMsg("[GPIO17, GPIO18]: " 133 "[1, 1]")) 134 .Times(1); 135 EXPECT_CALL(services, 136 logInfoMsg("Device UCD90160 MFR_STATUS: 0x123456789abc")) 137 .Times(1); 138 EXPECT_CALL( 139 services, 140 logErrorMsg( 141 "Pgood fault found in rail monitored by device UCD90160")) 142 .Times(1); 143 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD")) 144 .Times(1); 145 EXPECT_CALL( 146 services, 147 logErrorMsg( 148 "Rail VDD pgood GPIO line offset 2 has inactive value 0")) 149 .Times(1); 150 151 std::vector<std::unique_ptr<Rail>> rails; 152 rails.emplace_back(createRail("VDD", 2)); 153 uint8_t bus{3}; 154 uint16_t address{0x72}; 155 UCD90160Device device{std::move(rails), services, bus, address}; 156 157 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 158 EXPECT_CALL(pmbus, getPath(Type::Hwmon)) 159 .Times(1) 160 .WillOnce(Return("/tmp")); 161 EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true)) 162 .Times(1) 163 .WillOnce(Return(0x123456789abcull)); 164 165 // Call findPgoodFault() which calls storeGPIOValues() 166 std::string powerSupplyError{}; 167 std::map<std::string, std::string> additionalData{}; 168 std::string error = device.findPgoodFault(services, powerSupplyError, 169 additionalData); 170 EXPECT_EQ(error, 171 "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault"); 172 EXPECT_EQ(additionalData.size(), 31); 173 EXPECT_EQ(additionalData["MFR_STATUS"], "0x123456789abc"); 174 EXPECT_EQ(additionalData["DEVICE_NAME"], "UCD90160"); 175 EXPECT_EQ(additionalData["FPWM1_GPIO5"], "1"); 176 EXPECT_EQ(additionalData["FPWM2_GPIO6"], "0"); 177 EXPECT_EQ(additionalData["FPWM3_GPIO7"], "0"); 178 EXPECT_EQ(additionalData["FPWM4_GPIO8"], "1"); 179 EXPECT_EQ(additionalData["FPWM5_GPIO9"], "1"); 180 EXPECT_EQ(additionalData["FPWM6_GPIO10"], "1"); 181 EXPECT_EQ(additionalData["FPWM7_GPIO11"], "0"); 182 EXPECT_EQ(additionalData["FPWM8_GPIO12"], "0"); 183 EXPECT_EQ(additionalData["GPI1_PWM1"], "1"); 184 EXPECT_EQ(additionalData["GPI2_PWM2"], "0"); 185 EXPECT_EQ(additionalData["GPI3_PWM3"], "1"); 186 EXPECT_EQ(additionalData["GPI4_PWM4"], "1"); 187 EXPECT_EQ(additionalData["GPIO14"], "0"); 188 EXPECT_EQ(additionalData["GPIO15"], "0"); 189 EXPECT_EQ(additionalData["TDO_GPIO20"], "1"); 190 EXPECT_EQ(additionalData["TCK_GPIO19"], "1"); 191 EXPECT_EQ(additionalData["TMS_GPIO22"], "1"); 192 EXPECT_EQ(additionalData["TDI_GPIO21"], "0"); 193 EXPECT_EQ(additionalData["GPIO1"], "0"); 194 EXPECT_EQ(additionalData["GPIO2"], "0"); 195 EXPECT_EQ(additionalData["GPIO3"], "1"); 196 EXPECT_EQ(additionalData["GPIO4"], "0"); 197 EXPECT_EQ(additionalData["GPIO13"], "0"); 198 EXPECT_EQ(additionalData["GPIO16"], "1"); 199 EXPECT_EQ(additionalData["GPIO17"], "1"); 200 EXPECT_EQ(additionalData["GPIO18"], "1"); 201 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD"); 202 EXPECT_EQ(additionalData["GPIO_LINE"], "2"); 203 EXPECT_EQ(additionalData["GPIO_VALUE"], "0"); 204 } 205 206 // Test where there are the wrong number of GPIOs (27 instead of 26) 207 { 208 std::vector<int> gpioValues{ 209 1, 0, 0, 1, // group 1 in journal 210 1, 1, 0, 0, // group 2 in journal 211 1, 0, 1, 1, // group 3 in journal 212 0, 0, 1, 1, // group 4 in journal 213 1, 0, 0, 0, // group 5 in journal 214 1, 0, 0, 1, // group 6 in journal 215 1, 1, 0 // group 7 in journal + extra value 216 }; 217 218 MockServices services; 219 EXPECT_CALL(services, getGPIOValues("ucd90160")) 220 .Times(1) 221 .WillOnce(Return(gpioValues)); 222 EXPECT_CALL(services, logInfoMsg("Device UCD90160 GPIO values: [" 223 "1, 0, 0, 1, " 224 "1, 1, 0, 0, " 225 "1, 0, 1, 1, " 226 "0, 0, 1, 1, " 227 "1, 0, 0, 0, " 228 "1, 0, 0, 1, " 229 "1, 1, 0]")) 230 .Times(1); 231 EXPECT_CALL(services, 232 logInfoMsg("Device UCD90160 MFR_STATUS: 0x123456789abc")) 233 .Times(1); 234 EXPECT_CALL( 235 services, 236 logErrorMsg( 237 "Pgood fault found in rail monitored by device UCD90160")) 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 std::vector<std::unique_ptr<Rail>> rails; 248 rails.emplace_back(createRail("VDD", 2)); 249 uint8_t bus{3}; 250 uint16_t address{0x72}; 251 UCD90160Device device{std::move(rails), services, bus, address}; 252 253 MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface()); 254 EXPECT_CALL(pmbus, getPath(Type::Hwmon)) 255 .Times(1) 256 .WillOnce(Return("/tmp")); 257 EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true)) 258 .Times(1) 259 .WillOnce(Return(0x123456789abcull)); 260 261 // Call findPgoodFault() which calls storeGPIOValues() 262 std::string powerSupplyError{}; 263 std::map<std::string, std::string> additionalData{}; 264 std::string error = device.findPgoodFault(services, powerSupplyError, 265 additionalData); 266 EXPECT_EQ(error, 267 "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault"); 268 EXPECT_EQ(additionalData.size(), 6); 269 EXPECT_EQ(additionalData["MFR_STATUS"], "0x123456789abc"); 270 EXPECT_EQ(additionalData["DEVICE_NAME"], "UCD90160"); 271 EXPECT_EQ(additionalData["GPIO_VALUES"], "[1, 0, 0, 1, " 272 "1, 1, 0, 0, " 273 "1, 0, 1, 1, " 274 "0, 0, 1, 1, " 275 "1, 0, 0, 0, " 276 "1, 0, 0, 1, " 277 "1, 1, 0]"); 278 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD"); 279 EXPECT_EQ(additionalData["GPIO_LINE"], "2"); 280 EXPECT_EQ(additionalData["GPIO_VALUE"], "0"); 281 } 282 } 283