xref: /openbmc/witherspoon-pfault-analysis/power-sequencer/ucd90160.cpp (revision b7ed5773faba29c897871edfce4c9f8a237f499a)
1b54357f6SMatt Spinler /**
2b54357f6SMatt Spinler  * Copyright © 2017 IBM Corporation
3b54357f6SMatt Spinler  *
4b54357f6SMatt Spinler  * Licensed under the Apache License, Version 2.0 (the "License");
5b54357f6SMatt Spinler  * you may not use this file except in compliance with the License.
6b54357f6SMatt Spinler  * You may obtain a copy of the License at
7b54357f6SMatt Spinler  *
8b54357f6SMatt Spinler  *     http://www.apache.org/licenses/LICENSE-2.0
9b54357f6SMatt Spinler  *
10b54357f6SMatt Spinler  * Unless required by applicable law or agreed to in writing, software
11b54357f6SMatt Spinler  * distributed under the License is distributed on an "AS IS" BASIS,
12b54357f6SMatt Spinler  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b54357f6SMatt Spinler  * See the License for the specific language governing permissions and
14b54357f6SMatt Spinler  * limitations under the License.
15b54357f6SMatt Spinler  */
16f0f02b9aSMatt Spinler #include "ucd90160.hpp"
17f0f02b9aSMatt Spinler 
18f0f02b9aSMatt Spinler #include "names_values.hpp"
19f0f02b9aSMatt Spinler #include "utility.hpp"
20f0f02b9aSMatt Spinler 
21f0f02b9aSMatt Spinler #include <elog-errors.hpp>
22f0f02b9aSMatt Spinler #include <org/open_power/Witherspoon/Fault/error.hpp>
23b54357f6SMatt Spinler #include <phosphor-logging/elog.hpp>
24b54357f6SMatt Spinler #include <phosphor-logging/log.hpp>
25ceacf941SMatt Spinler #include <xyz/openbmc_project/Common/Device/error.hpp>
26b54357f6SMatt Spinler 
272c4fbc4cSPatrick Williams #include <map>
282c4fbc4cSPatrick Williams #include <memory>
292c4fbc4cSPatrick Williams 
30b54357f6SMatt Spinler namespace witherspoon
31b54357f6SMatt Spinler {
32b54357f6SMatt Spinler namespace power
33b54357f6SMatt Spinler {
34b54357f6SMatt Spinler 
35b54357f6SMatt Spinler using namespace std::string_literals;
36b54357f6SMatt Spinler 
37e7e432b4SMatt Spinler const auto MFR_STATUS = "mfr_status"s;
381e365698SMatt Spinler 
39b54357f6SMatt Spinler const auto DEVICE_NAME = "UCD90160"s;
40b54357f6SMatt Spinler const auto DRIVER_NAME = "ucd9000"s;
41e7e432b4SMatt Spinler constexpr auto NUM_PAGES = 16;
42b54357f6SMatt Spinler 
430e45ced1SMatt Spinler constexpr auto INVENTORY_OBJ_PATH = "/xyz/openbmc_project/inventory";
440e45ced1SMatt Spinler 
459c7897ceSBrandon Wyman namespace fs = std::filesystem;
46d998b736SMatt Spinler using namespace gpio;
47b54357f6SMatt Spinler using namespace pmbus;
48b54357f6SMatt Spinler using namespace phosphor::logging;
49ceacf941SMatt Spinler 
50f0f02b9aSMatt Spinler namespace device_error = sdbusplus::xyz::openbmc_project::Common::Device::Error;
51f0f02b9aSMatt Spinler namespace power_error = sdbusplus::org::open_power::Witherspoon::Fault::Error;
52b54357f6SMatt Spinler 
UCD90160(size_t instance,sdbusplus::bus_t & bus)53*1426a10bSPatrick Williams UCD90160::UCD90160(size_t instance, sdbusplus::bus_t& bus) :
54b54357f6SMatt Spinler     Device(DEVICE_NAME, instance),
55f0f02b9aSMatt Spinler     interface(std::get<ucd90160::pathField>(deviceMap.find(instance)->second),
56f0f02b9aSMatt Spinler               DRIVER_NAME, instance),
57f0f02b9aSMatt Spinler     gpioDevice(findGPIODevice(interface.path())), bus(bus)
582c4fbc4cSPatrick Williams {}
59b54357f6SMatt Spinler 
onFailure()60b54357f6SMatt Spinler void UCD90160::onFailure()
61b54357f6SMatt Spinler {
62b54357f6SMatt Spinler     try
63b54357f6SMatt Spinler     {
64b54357f6SMatt Spinler         auto voutError = checkVOUTFaults();
65b54357f6SMatt Spinler 
66b54357f6SMatt Spinler         auto pgoodError = checkPGOODFaults(false);
67b54357f6SMatt Spinler 
68b54357f6SMatt Spinler         // Not a voltage or PGOOD fault, but we know something
69b54357f6SMatt Spinler         // failed so still create an error log.
70b54357f6SMatt Spinler         if (!voutError && !pgoodError)
71b54357f6SMatt Spinler         {
72b54357f6SMatt Spinler             createPowerFaultLog();
73b54357f6SMatt Spinler         }
74b54357f6SMatt Spinler     }
75ceacf941SMatt Spinler     catch (device_error::ReadFailure& e)
76b54357f6SMatt Spinler     {
77b54357f6SMatt Spinler         if (!accessError)
78b54357f6SMatt Spinler         {
79ceacf941SMatt Spinler             commit<device_error::ReadFailure>();
80b54357f6SMatt Spinler             accessError = true;
81b54357f6SMatt Spinler         }
82b54357f6SMatt Spinler     }
83b54357f6SMatt Spinler }
84b54357f6SMatt Spinler 
analyze()85b54357f6SMatt Spinler void UCD90160::analyze()
86b54357f6SMatt Spinler {
87b54357f6SMatt Spinler     try
88b54357f6SMatt Spinler     {
89b54357f6SMatt Spinler         // Note: Voltage faults are always fatal, so they just
90b54357f6SMatt Spinler         // need to be analyzed in onFailure().
91b54357f6SMatt Spinler 
92b54357f6SMatt Spinler         checkPGOODFaults(true);
93b54357f6SMatt Spinler     }
94ceacf941SMatt Spinler     catch (device_error::ReadFailure& e)
95b54357f6SMatt Spinler     {
96b54357f6SMatt Spinler         if (!accessError)
97b54357f6SMatt Spinler         {
98ceacf941SMatt Spinler             commit<device_error::ReadFailure>();
99b54357f6SMatt Spinler             accessError = true;
100b54357f6SMatt Spinler         }
101b54357f6SMatt Spinler     }
102b54357f6SMatt Spinler }
103b54357f6SMatt Spinler 
readStatusWord()104e7e432b4SMatt Spinler uint16_t UCD90160::readStatusWord()
105e7e432b4SMatt Spinler {
106e7e432b4SMatt Spinler     return interface.read(STATUS_WORD, Type::Debug);
107e7e432b4SMatt Spinler }
108e7e432b4SMatt Spinler 
readMFRStatus()109e7e432b4SMatt Spinler uint32_t UCD90160::readMFRStatus()
110e7e432b4SMatt Spinler {
111233a252eSMatt Spinler     return interface.read(MFR_STATUS, Type::HwmonDeviceDebug);
112e7e432b4SMatt Spinler }
113e7e432b4SMatt Spinler 
checkVOUTFaults()114b54357f6SMatt Spinler bool UCD90160::checkVOUTFaults()
115b54357f6SMatt Spinler {
116e7e432b4SMatt Spinler     bool errorCreated = false;
117e7e432b4SMatt Spinler     auto statusWord = readStatusWord();
118e7e432b4SMatt Spinler 
119e7e432b4SMatt Spinler     // The status_word register has a summary bit to tell us
120e7e432b4SMatt Spinler     // if each page even needs to be checked
121e7e432b4SMatt Spinler     if (!(statusWord & status_word::VOUT_FAULT))
122e7e432b4SMatt Spinler     {
123e7e432b4SMatt Spinler         return errorCreated;
124e7e432b4SMatt Spinler     }
125e7e432b4SMatt Spinler 
126e7e432b4SMatt Spinler     for (size_t page = 0; page < NUM_PAGES; page++)
127e7e432b4SMatt Spinler     {
128e7e432b4SMatt Spinler         if (isVoutFaultLogged(page))
129e7e432b4SMatt Spinler         {
130e7e432b4SMatt Spinler             continue;
131e7e432b4SMatt Spinler         }
132e7e432b4SMatt Spinler 
133e7e432b4SMatt Spinler         auto statusVout = interface.insertPageNum(STATUS_VOUT, page);
134e7e432b4SMatt Spinler         uint8_t vout = interface.read(statusVout, Type::Debug);
135e7e432b4SMatt Spinler 
136de16d053SMatt Spinler         // If any bits are on log them, though some are just
137de16d053SMatt Spinler         // warnings so they won't cause errors
138e7e432b4SMatt Spinler         if (vout)
139e7e432b4SMatt Spinler         {
140de16d053SMatt Spinler             log<level::INFO>("A voltage rail has bits on in STATUS_VOUT",
141de16d053SMatt Spinler                              entry("STATUS_VOUT=0x%X", vout),
142de16d053SMatt Spinler                              entry("PAGE=%d", page));
143de16d053SMatt Spinler         }
144de16d053SMatt Spinler 
145de16d053SMatt Spinler         // Log errors if any non-warning bits on
146de16d053SMatt Spinler         if (vout & ~status_vout::WARNING_MASK)
147de16d053SMatt Spinler         {
148e7e432b4SMatt Spinler             auto& railNames = std::get<ucd90160::railNamesField>(
149e7e432b4SMatt Spinler                 deviceMap.find(getInstance())->second);
150e7e432b4SMatt Spinler             auto railName = railNames.at(page);
151e7e432b4SMatt Spinler 
152e7e432b4SMatt Spinler             util::NamesValues nv;
1536def9098SMatt Spinler             try
1546def9098SMatt Spinler             {
155e7e432b4SMatt Spinler                 nv.add("STATUS_WORD", statusWord);
156e7e432b4SMatt Spinler                 nv.add("STATUS_VOUT", vout);
157e7e432b4SMatt Spinler                 nv.add("MFR_STATUS", readMFRStatus());
1586def9098SMatt Spinler             }
1596def9098SMatt Spinler             catch (device_error::ReadFailure& e)
1606def9098SMatt Spinler             {
1616def9098SMatt Spinler                 log<level::ERR>("ReadFailure when collecting metadata");
1626def9098SMatt Spinler                 commit<device_error::ReadFailure>();
1636def9098SMatt Spinler             }
164e7e432b4SMatt Spinler 
165f0f02b9aSMatt Spinler             using metadata =
166f0f02b9aSMatt Spinler                 org::open_power::Witherspoon::Fault::PowerSequencerVoltageFault;
167e7e432b4SMatt Spinler 
168ceacf941SMatt Spinler             report<power_error::PowerSequencerVoltageFault>(
169f0f02b9aSMatt Spinler                 metadata::RAIL(page), metadata::RAIL_NAME(railName.c_str()),
170e7e432b4SMatt Spinler                 metadata::RAW_STATUS(nv.get().c_str()));
171e7e432b4SMatt Spinler 
172e7e432b4SMatt Spinler             setVoutFaultLogged(page);
173e7e432b4SMatt Spinler             errorCreated = true;
174e7e432b4SMatt Spinler         }
175e7e432b4SMatt Spinler     }
176e7e432b4SMatt Spinler 
177e7e432b4SMatt Spinler     return errorCreated;
178b54357f6SMatt Spinler }
179b54357f6SMatt Spinler 
checkPGOODFaults(bool polling)180b54357f6SMatt Spinler bool UCD90160::checkPGOODFaults(bool polling)
181b54357f6SMatt Spinler {
182d998b736SMatt Spinler     bool errorCreated = false;
183d998b736SMatt Spinler 
184d998b736SMatt Spinler     // While PGOOD faults could show up in MFR_STATUS (and we could then
185d998b736SMatt Spinler     // check the summary bit in STATUS_WORD first), they are edge triggered,
186d998b736SMatt Spinler     // and as the device driver sends a clear faults command every time we
187d998b736SMatt Spinler     // do a read, we will never see them.  So, we'll have to just read the
188d998b736SMatt Spinler     // real time GPI status GPIO.
189d998b736SMatt Spinler 
190d998b736SMatt Spinler     // Check only the GPIs configured on this system.
191d998b736SMatt Spinler     auto& gpiConfigs = std::get<ucd90160::gpiConfigField>(
192d998b736SMatt Spinler         deviceMap.find(getInstance())->second);
193d998b736SMatt Spinler 
194d998b736SMatt Spinler     for (const auto& gpiConfig : gpiConfigs)
195d998b736SMatt Spinler     {
196d998b736SMatt Spinler         auto gpiNum = std::get<ucd90160::gpiNumField>(gpiConfig);
197d998b736SMatt Spinler         auto doPoll = std::get<ucd90160::pollField>(gpiConfig);
198d998b736SMatt Spinler 
199d998b736SMatt Spinler         // Can skip this one if there is already an error on this input,
200d998b736SMatt Spinler         // or we are polling and these inputs don't need to be polled
201d998b736SMatt Spinler         //(because errors on them are fatal).
202d998b736SMatt Spinler         if (isPGOODFaultLogged(gpiNum) || (polling && !doPoll))
203d998b736SMatt Spinler         {
204d998b736SMatt Spinler             continue;
205d998b736SMatt Spinler         }
206d998b736SMatt Spinler 
207d998b736SMatt Spinler         // The real time status is read via the pin ID
208d998b736SMatt Spinler         auto pinID = std::get<ucd90160::pinIDField>(gpiConfig);
209d998b736SMatt Spinler         auto gpio = gpios.find(pinID);
210d998b736SMatt Spinler         Value gpiStatus;
211d998b736SMatt Spinler 
212d998b736SMatt Spinler         try
213d998b736SMatt Spinler         {
214d998b736SMatt Spinler             // The first time through, create the GPIO objects
215d998b736SMatt Spinler             if (gpio == gpios.end())
216d998b736SMatt Spinler             {
217f0f02b9aSMatt Spinler                 gpios.emplace(pinID, std::make_unique<GPIO>(gpioDevice, pinID,
218f0f02b9aSMatt Spinler                                                             Direction::input));
219d998b736SMatt Spinler                 gpio = gpios.find(pinID);
220d998b736SMatt Spinler             }
221d998b736SMatt Spinler 
222d998b736SMatt Spinler             gpiStatus = gpio->second->read();
223d998b736SMatt Spinler         }
224d998b736SMatt Spinler         catch (std::exception& e)
225d998b736SMatt Spinler         {
226d998b736SMatt Spinler             if (!accessError)
227d998b736SMatt Spinler             {
228d998b736SMatt Spinler                 log<level::ERR>(e.what());
229d998b736SMatt Spinler                 accessError = true;
230d998b736SMatt Spinler             }
231d998b736SMatt Spinler             continue;
232d998b736SMatt Spinler         }
233d998b736SMatt Spinler 
234d998b736SMatt Spinler         if (gpiStatus == Value::low)
235d998b736SMatt Spinler         {
2368bc1283fSMatt Spinler             // There may be some extra analysis we can do to narrow the
2378bc1283fSMatt Spinler             // error down further.  Note that finding an error here won't
2388bc1283fSMatt Spinler             // prevent us from checking this GPI again.
2398bc1283fSMatt Spinler             errorCreated = doExtraAnalysis(gpiConfig);
2408bc1283fSMatt Spinler 
2418bc1283fSMatt Spinler             if (errorCreated)
2428bc1283fSMatt Spinler             {
2438bc1283fSMatt Spinler                 continue;
2448bc1283fSMatt Spinler             }
2458bc1283fSMatt Spinler 
246d998b736SMatt Spinler             auto& gpiName = std::get<ucd90160::gpiNameField>(gpiConfig);
247d998b736SMatt Spinler             auto status = (gpiStatus == Value::low) ? 0 : 1;
248d998b736SMatt Spinler 
249d998b736SMatt Spinler             util::NamesValues nv;
2506def9098SMatt Spinler 
2516def9098SMatt Spinler             try
2526def9098SMatt Spinler             {
253d998b736SMatt Spinler                 nv.add("STATUS_WORD", readStatusWord());
254d998b736SMatt Spinler                 nv.add("MFR_STATUS", readMFRStatus());
255d998b736SMatt Spinler                 nv.add("INPUT_STATUS", status);
2566def9098SMatt Spinler             }
2576def9098SMatt Spinler             catch (device_error::ReadFailure& e)
2586def9098SMatt Spinler             {
2596def9098SMatt Spinler                 log<level::ERR>("ReadFailure when collecting metadata");
2606def9098SMatt Spinler                 commit<device_error::ReadFailure>();
2616def9098SMatt Spinler             }
262d998b736SMatt Spinler 
263f0f02b9aSMatt Spinler             using metadata =
264f0f02b9aSMatt Spinler                 org::open_power::Witherspoon::Fault::PowerSequencerPGOODFault;
265d998b736SMatt Spinler 
266ceacf941SMatt Spinler             report<power_error::PowerSequencerPGOODFault>(
267d998b736SMatt Spinler                 metadata::INPUT_NUM(gpiNum),
268d998b736SMatt Spinler                 metadata::INPUT_NAME(gpiName.c_str()),
269d998b736SMatt Spinler                 metadata::RAW_STATUS(nv.get().c_str()));
270d998b736SMatt Spinler 
271d998b736SMatt Spinler             setPGOODFaultLogged(gpiNum);
272d998b736SMatt Spinler             errorCreated = true;
273d998b736SMatt Spinler         }
274d998b736SMatt Spinler     }
275d998b736SMatt Spinler 
276d998b736SMatt Spinler     return errorCreated;
277b54357f6SMatt Spinler }
278b54357f6SMatt Spinler 
createPowerFaultLog()279b54357f6SMatt Spinler void UCD90160::createPowerFaultLog()
280b54357f6SMatt Spinler {
2819efb308fSMatt Spinler     util::NamesValues nv;
2826def9098SMatt Spinler 
2836def9098SMatt Spinler     try
2846def9098SMatt Spinler     {
2859efb308fSMatt Spinler         nv.add("STATUS_WORD", readStatusWord());
2869efb308fSMatt Spinler         nv.add("MFR_STATUS", readMFRStatus());
2876def9098SMatt Spinler     }
2886def9098SMatt Spinler     catch (device_error::ReadFailure& e)
2896def9098SMatt Spinler     {
2906def9098SMatt Spinler         log<level::ERR>("ReadFailure when collecting metadata");
2916def9098SMatt Spinler         commit<device_error::ReadFailure>();
2926def9098SMatt Spinler     }
293b54357f6SMatt Spinler 
294f0f02b9aSMatt Spinler     using metadata = org::open_power::Witherspoon::Fault::PowerSequencerFault;
2959efb308fSMatt Spinler 
296ceacf941SMatt Spinler     report<power_error::PowerSequencerFault>(
2979efb308fSMatt Spinler         metadata::RAW_STATUS(nv.get().c_str()));
298b54357f6SMatt Spinler }
299b54357f6SMatt Spinler 
findGPIODevice(const fs::path & path)300fcd4a719SMatt Spinler fs::path UCD90160::findGPIODevice(const fs::path& path)
301110b2841SMatt Spinler {
302fcd4a719SMatt Spinler     fs::path gpioDevicePath;
303110b2841SMatt Spinler 
304110b2841SMatt Spinler     // In the driver directory, look for a subdirectory
305110b2841SMatt Spinler     // named gpiochipX, where X is some number.  Then
306110b2841SMatt Spinler     // we'll access the GPIO at /dev/gpiochipX.
307110b2841SMatt Spinler     if (fs::is_directory(path))
308110b2841SMatt Spinler     {
309110b2841SMatt Spinler         for (auto& f : fs::directory_iterator(path))
310110b2841SMatt Spinler         {
311110b2841SMatt Spinler             if (f.path().filename().string().find("gpiochip") !=
312110b2841SMatt Spinler                 std::string::npos)
313110b2841SMatt Spinler             {
314fcd4a719SMatt Spinler                 gpioDevicePath = "/dev" / f.path().filename();
315110b2841SMatt Spinler                 break;
316110b2841SMatt Spinler             }
317110b2841SMatt Spinler         }
318110b2841SMatt Spinler     }
319110b2841SMatt Spinler 
320fcd4a719SMatt Spinler     if (gpioDevicePath.empty())
321110b2841SMatt Spinler     {
322fcd4a719SMatt Spinler         log<level::ERR>("Could not find GPIO device path",
323110b2841SMatt Spinler                         entry("BASE_PATH=%s", path.c_str()));
324110b2841SMatt Spinler     }
325fcd4a719SMatt Spinler 
326fcd4a719SMatt Spinler     return gpioDevicePath;
327110b2841SMatt Spinler }
328110b2841SMatt Spinler 
doExtraAnalysis(const ucd90160::GPIConfig & config)3298bc1283fSMatt Spinler bool UCD90160::doExtraAnalysis(const ucd90160::GPIConfig& config)
3308bc1283fSMatt Spinler {
3318bc1283fSMatt Spinler     auto type = std::get<ucd90160::extraAnalysisField>(config);
3328bc1283fSMatt Spinler     if (type == ucd90160::extraAnalysisType::none)
3338bc1283fSMatt Spinler     {
3348bc1283fSMatt Spinler         return false;
3358bc1283fSMatt Spinler     }
3368bc1283fSMatt Spinler 
3378bc1283fSMatt Spinler     // Currently the only extra analysis to do is to check other GPIOs.
3388bc1283fSMatt Spinler     return doGPIOAnalysis(type);
3398bc1283fSMatt Spinler }
3408bc1283fSMatt Spinler 
doGPIOAnalysis(ucd90160::extraAnalysisType type)3418bc1283fSMatt Spinler bool UCD90160::doGPIOAnalysis(ucd90160::extraAnalysisType type)
3428bc1283fSMatt Spinler {
3438bc1283fSMatt Spinler     bool errorFound = false;
344a8269652SMatt Spinler     bool shutdown = false;
3458bc1283fSMatt Spinler 
3468bc1283fSMatt Spinler     const auto& analysisConfig = std::get<ucd90160::gpioAnalysisField>(
3478bc1283fSMatt Spinler         deviceMap.find(getInstance())->second);
3488bc1283fSMatt Spinler 
3498bc1283fSMatt Spinler     auto gpioConfig = analysisConfig.find(type);
3508bc1283fSMatt Spinler     if (gpioConfig == analysisConfig.end())
3518bc1283fSMatt Spinler     {
3528bc1283fSMatt Spinler         return errorFound;
3538bc1283fSMatt Spinler     }
3548bc1283fSMatt Spinler 
355f0f02b9aSMatt Spinler     auto path = std::get<ucd90160::gpioDevicePathField>(gpioConfig->second);
3568bc1283fSMatt Spinler 
3578bc1283fSMatt Spinler     // The /dev/gpiochipX device
3588bc1283fSMatt Spinler     auto device = findGPIODevice(path);
3598bc1283fSMatt Spinler 
3605c0ce175SMatt Spinler     if (device.empty())
3615c0ce175SMatt Spinler     {
3625c0ce175SMatt Spinler         log<level::ERR>(
3635c0ce175SMatt Spinler             "Missing GPIO device - cannot do GPIO analysis of fault",
3645c0ce175SMatt Spinler             entry("ANALYSIS_TYPE=%d\n", type));
3655c0ce175SMatt Spinler         return errorFound;
3665c0ce175SMatt Spinler     }
3675c0ce175SMatt Spinler 
3688bc1283fSMatt Spinler     // The GPIO value of the fault condition
369f0f02b9aSMatt Spinler     auto polarity = std::get<ucd90160::gpioPolarityField>(gpioConfig->second);
3708bc1283fSMatt Spinler 
3718bc1283fSMatt Spinler     // The GPIOs to check
372f0f02b9aSMatt Spinler     auto& gpios = std::get<ucd90160::gpioDefinitionField>(gpioConfig->second);
3738bc1283fSMatt Spinler 
3748bc1283fSMatt Spinler     for (const auto& gpio : gpios)
3758bc1283fSMatt Spinler     {
3768bc1283fSMatt Spinler         gpio::Value value;
3778bc1283fSMatt Spinler 
3788bc1283fSMatt Spinler         try
3798bc1283fSMatt Spinler         {
380f0f02b9aSMatt Spinler             GPIO g{device, std::get<ucd90160::gpioNumField>(gpio),
3818bc1283fSMatt Spinler                    Direction::input};
3828bc1283fSMatt Spinler 
3838bc1283fSMatt Spinler             value = g.read();
3848bc1283fSMatt Spinler         }
3858bc1283fSMatt Spinler         catch (std::exception& e)
3868bc1283fSMatt Spinler         {
3878bc1283fSMatt Spinler             if (!gpioAccessError)
3888bc1283fSMatt Spinler             {
3898bc1283fSMatt Spinler                 // GPIO only throws InternalErrors - not worth committing.
3908bc1283fSMatt Spinler                 log<level::ERR>(
3918bc1283fSMatt Spinler                     "GPIO read failed while analyzing a power fault",
3928bc1283fSMatt Spinler                     entry("CHIP_PATH=%s", path.c_str()));
3938bc1283fSMatt Spinler 
3948bc1283fSMatt Spinler                 gpioAccessError = true;
3958bc1283fSMatt Spinler             }
3968bc1283fSMatt Spinler             continue;
3978bc1283fSMatt Spinler         }
3988bc1283fSMatt Spinler 
3998bc1283fSMatt Spinler         if (value == polarity)
4008bc1283fSMatt Spinler         {
4018bc1283fSMatt Spinler             errorFound = true;
4028bc1283fSMatt Spinler 
4030e45ced1SMatt Spinler             std::string part{INVENTORY_OBJ_PATH};
4040e45ced1SMatt Spinler             part = part + std::get<ucd90160::gpioCalloutField>(gpio);
4058bc1283fSMatt Spinler             PartCallout callout{type, part};
4068bc1283fSMatt Spinler 
4078bc1283fSMatt Spinler             if (isPartCalledOut(callout))
4088bc1283fSMatt Spinler             {
4098bc1283fSMatt Spinler                 continue;
4108bc1283fSMatt Spinler             }
4118bc1283fSMatt Spinler 
4128bc1283fSMatt Spinler             // Look up and call the error creation function
413f0f02b9aSMatt Spinler             auto logError =
414f0f02b9aSMatt Spinler                 std::get<ucd90160::errorFunctionField>(gpioConfig->second);
4158bc1283fSMatt Spinler 
4168bc1283fSMatt Spinler             logError(*this, part);
4178bc1283fSMatt Spinler 
4188bc1283fSMatt Spinler             // Save the part callout so we don't call it out again
4198bc1283fSMatt Spinler             setPartCallout(callout);
420a8269652SMatt Spinler 
421a8269652SMatt Spinler             // Some errors (like overtemps) require a shutdown
422a8269652SMatt Spinler             auto actions = static_cast<uint32_t>(
423a8269652SMatt Spinler                 std::get<ucd90160::optionFlagsField>(gpioConfig->second));
424a8269652SMatt Spinler 
425a8269652SMatt Spinler             if (actions & static_cast<decltype(actions)>(
426a8269652SMatt Spinler                               ucd90160::optionFlags::shutdownOnFault))
427a8269652SMatt Spinler             {
428a8269652SMatt Spinler                 shutdown = true;
4298bc1283fSMatt Spinler             }
4308bc1283fSMatt Spinler         }
431a8269652SMatt Spinler     }
432a8269652SMatt Spinler 
433a8269652SMatt Spinler     if (shutdown)
434a8269652SMatt Spinler     {
435882ce956SMatt Spinler         // Will be replaced with a GPU specific error in a future commit
436882ce956SMatt Spinler         util::powerOff<power_error::Shutdown>(bus);
437a8269652SMatt Spinler     }
4388bc1283fSMatt Spinler 
4398bc1283fSMatt Spinler     return errorFound;
4408bc1283fSMatt Spinler }
4418bc1283fSMatt Spinler 
gpuPGOODError(const std::string & callout)4427b14db24SMatt Spinler void UCD90160::gpuPGOODError(const std::string& callout)
4437b14db24SMatt Spinler {
4447b14db24SMatt Spinler     util::NamesValues nv;
4456def9098SMatt Spinler 
4466def9098SMatt Spinler     try
4476def9098SMatt Spinler     {
4487b14db24SMatt Spinler         nv.add("STATUS_WORD", readStatusWord());
4497b14db24SMatt Spinler         nv.add("MFR_STATUS", readMFRStatus());
4506def9098SMatt Spinler     }
4516def9098SMatt Spinler     catch (device_error::ReadFailure& e)
4526def9098SMatt Spinler     {
4536def9098SMatt Spinler         log<level::ERR>("ReadFailure when collecting metadata");
4546def9098SMatt Spinler         commit<device_error::ReadFailure>();
4556def9098SMatt Spinler     }
4567b14db24SMatt Spinler 
457e0eb45ccSBrandon Wyman     using metadata = org::open_power::Witherspoon::Fault::GPUPowerFault;
4587b14db24SMatt Spinler 
459ceacf941SMatt Spinler     report<power_error::GPUPowerFault>(
4607b14db24SMatt Spinler         metadata::RAW_STATUS(nv.get().c_str()),
4610e45ced1SMatt Spinler         metadata::CALLOUT_INVENTORY_PATH(callout.c_str()));
4627b14db24SMatt Spinler }
4637b14db24SMatt Spinler 
gpuOverTempError(const std::string & callout)4647b14db24SMatt Spinler void UCD90160::gpuOverTempError(const std::string& callout)
4657b14db24SMatt Spinler {
4667b14db24SMatt Spinler     util::NamesValues nv;
4676def9098SMatt Spinler 
4686def9098SMatt Spinler     try
4696def9098SMatt Spinler     {
4707b14db24SMatt Spinler         nv.add("STATUS_WORD", readStatusWord());
4717b14db24SMatt Spinler         nv.add("MFR_STATUS", readMFRStatus());
4726def9098SMatt Spinler     }
4736def9098SMatt Spinler     catch (device_error::ReadFailure& e)
4746def9098SMatt Spinler     {
4756def9098SMatt Spinler         log<level::ERR>("ReadFailure when collecting metadata");
4766def9098SMatt Spinler         commit<device_error::ReadFailure>();
4776def9098SMatt Spinler     }
4787b14db24SMatt Spinler 
479e0eb45ccSBrandon Wyman     using metadata = org::open_power::Witherspoon::Fault::GPUOverTemp;
4807b14db24SMatt Spinler 
481ceacf941SMatt Spinler     report<power_error::GPUOverTemp>(
4827b14db24SMatt Spinler         metadata::RAW_STATUS(nv.get().c_str()),
4830e45ced1SMatt Spinler         metadata::CALLOUT_INVENTORY_PATH(callout.c_str()));
4847b14db24SMatt Spinler }
4857b14db24SMatt Spinler 
memGoodError(const std::string & callout)48603c19db6SBrandon Wyman void UCD90160::memGoodError(const std::string& callout)
48703c19db6SBrandon Wyman {
48803c19db6SBrandon Wyman     util::NamesValues nv;
48903c19db6SBrandon Wyman 
49003c19db6SBrandon Wyman     try
49103c19db6SBrandon Wyman     {
49203c19db6SBrandon Wyman         nv.add("STATUS_WORD", readStatusWord());
49303c19db6SBrandon Wyman         nv.add("MFR_STATUS", readMFRStatus());
49403c19db6SBrandon Wyman     }
49503c19db6SBrandon Wyman     catch (device_error::ReadFailure& e)
49603c19db6SBrandon Wyman     {
49703c19db6SBrandon Wyman         log<level::ERR>("ReadFailure when collecting metadata");
49803c19db6SBrandon Wyman         commit<device_error::ReadFailure>();
49903c19db6SBrandon Wyman     }
50003c19db6SBrandon Wyman 
50103c19db6SBrandon Wyman     using metadata = org::open_power::Witherspoon::Fault::MemoryPowerFault;
50203c19db6SBrandon Wyman 
50303c19db6SBrandon Wyman     report<power_error::MemoryPowerFault>(
50403c19db6SBrandon Wyman         metadata::RAW_STATUS(nv.get().c_str()),
50503c19db6SBrandon Wyman         metadata::CALLOUT_INVENTORY_PATH(callout.c_str()));
50603c19db6SBrandon Wyman }
50703c19db6SBrandon Wyman 
508f0f02b9aSMatt Spinler } // namespace power
509f0f02b9aSMatt Spinler } // namespace witherspoon
510