blob: 704c4e0268d96ed149d8cf8aa745495c33b74d1d [file] [log] [blame]
Matt Spinlerb54357f2017-08-21 14:38:54 -05001/**
2 * Copyright © 2017 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#include <map>
17#include <memory>
18#include <phosphor-logging/elog.hpp>
19#include <phosphor-logging/log.hpp>
20#include <elog-errors.hpp>
21#include <xyz/openbmc_project/Sensor/Device/error.hpp>
22#include <xyz/openbmc_project/Control/Device/error.hpp>
23#include <xyz/openbmc_project/Power/Fault/error.hpp>
Matt Spinlere7e432b2017-08-21 15:01:40 -050024#include "names_values.hpp"
Matt Spinlerb54357f2017-08-21 14:38:54 -050025#include "ucd90160.hpp"
26
27namespace witherspoon
28{
29namespace power
30{
31
32using namespace std::string_literals;
33
Matt Spinler1e365692017-08-21 14:43:55 -050034const auto CLEAR_LOGGED_FAULTS = "clear_logged_faults"s;
Matt Spinlere7e432b2017-08-21 15:01:40 -050035const auto MFR_STATUS = "mfr_status"s;
Matt Spinler1e365692017-08-21 14:43:55 -050036
Matt Spinlerb54357f2017-08-21 14:38:54 -050037const auto DEVICE_NAME = "UCD90160"s;
38const auto DRIVER_NAME = "ucd9000"s;
Matt Spinlere7e432b2017-08-21 15:01:40 -050039constexpr auto NUM_PAGES = 16;
Matt Spinlerb54357f2017-08-21 14:38:54 -050040
41using namespace pmbus;
42using namespace phosphor::logging;
43using namespace sdbusplus::xyz::openbmc_project::Control::Device::Error;
44using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::Error;
45using namespace sdbusplus::xyz::openbmc_project::Power::Fault::Error;
46
47UCD90160::UCD90160(size_t instance) :
48 Device(DEVICE_NAME, instance),
49 interface(std::get<ucd90160::pathField>(
50 deviceMap.find(instance)->second),
51 DRIVER_NAME,
52 instance)
53{
54}
55
56void UCD90160::onFailure()
57{
58 try
59 {
60 auto voutError = checkVOUTFaults();
61
62 auto pgoodError = checkPGOODFaults(false);
63
64 //Not a voltage or PGOOD fault, but we know something
65 //failed so still create an error log.
66 if (!voutError && !pgoodError)
67 {
68 createPowerFaultLog();
69 }
70 }
71 catch (ReadFailure& e)
72 {
73 if (!accessError)
74 {
75 commit<ReadFailure>();
76 accessError = true;
77 }
78 }
79}
80
81void UCD90160::analyze()
82{
83 try
84 {
85 //Note: Voltage faults are always fatal, so they just
86 //need to be analyzed in onFailure().
87
88 checkPGOODFaults(true);
89 }
90 catch (ReadFailure& e)
91 {
92 if (!accessError)
93 {
94 commit<ReadFailure>();
95 accessError = true;
96 }
97 }
98}
99
Matt Spinlere7e432b2017-08-21 15:01:40 -0500100uint16_t UCD90160::readStatusWord()
101{
102 return interface.read(STATUS_WORD, Type::Debug);
103}
104
105uint32_t UCD90160::readMFRStatus()
106{
107 return interface.read(MFR_STATUS, Type::DeviceDebug);
108}
109
Matt Spinlerb54357f2017-08-21 14:38:54 -0500110void UCD90160::clearFaults()
111{
Matt Spinler1e365692017-08-21 14:43:55 -0500112 try
113 {
114 interface.write(CLEAR_LOGGED_FAULTS, 1, Type::Base);
115 }
116 catch (WriteFailure& e)
117 {
118 if (!accessError)
119 {
120 log<level::ERR>("UCD90160 clear logged faults command failed");
121 commit<WriteFailure>();
122 accessError = true;
123 }
124 }
Matt Spinlerb54357f2017-08-21 14:38:54 -0500125}
126
127bool UCD90160::checkVOUTFaults()
128{
Matt Spinlere7e432b2017-08-21 15:01:40 -0500129 bool errorCreated = false;
130 auto statusWord = readStatusWord();
131
132 //The status_word register has a summary bit to tell us
133 //if each page even needs to be checked
134 if (!(statusWord & status_word::VOUT_FAULT))
135 {
136 return errorCreated;
137 }
138
139 for (size_t page = 0; page < NUM_PAGES; page++)
140 {
141 if (isVoutFaultLogged(page))
142 {
143 continue;
144 }
145
146 auto statusVout = interface.insertPageNum(STATUS_VOUT, page);
147 uint8_t vout = interface.read(statusVout, Type::Debug);
148
149 //Any bit on is an error
150 if (vout)
151 {
152 auto& railNames = std::get<ucd90160::railNamesField>(
153 deviceMap.find(getInstance())->second);
154 auto railName = railNames.at(page);
155
156 util::NamesValues nv;
157 nv.add("STATUS_WORD", statusWord);
158 nv.add("STATUS_VOUT", vout);
159 nv.add("MFR_STATUS", readMFRStatus());
160
161 using metadata = xyz::openbmc_project::Power::Fault::
162 PowerSequencerVoltageFault;
163
164 report<PowerSequencerVoltageFault>(
165 metadata::RAIL(page),
166 metadata::RAIL_NAME(railName.c_str()),
167 metadata::RAW_STATUS(nv.get().c_str()));
168
169 setVoutFaultLogged(page);
170 errorCreated = true;
171 }
172 }
173
174 return errorCreated;
Matt Spinlerb54357f2017-08-21 14:38:54 -0500175}
176
177bool UCD90160::checkPGOODFaults(bool polling)
178{
179 return false;
180}
181
182void UCD90160::createPowerFaultLog()
183{
184
185}
186
187}
188}