blob: 9e8abba9355da6404766f825f62191ce7d5b2e1d [file] [log] [blame]
Matt Spinlerf02daec2017-08-14 14:00:46 -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 <phosphor-logging/log.hpp>
17#include <xyz/openbmc_project/Power/Fault/error.hpp>
Matt Spinler45a054a2017-08-22 15:07:07 -050018#include "config.h"
Matt Spinlerf02daec2017-08-14 14:00:46 -050019#include "elog-errors.hpp"
20#include "pgood_monitor.hpp"
21#include "utility.hpp"
22
23namespace witherspoon
24{
25namespace power
26{
27
28constexpr auto POWER_OBJ_PATH = "/org/openbmc/control/power0";
29constexpr auto POWER_INTERFACE = "org.openbmc.control.Power";
30
31using namespace phosphor::logging;
32using namespace sdbusplus::xyz::openbmc_project::Power::Fault::Error;
33
34bool PGOODMonitor::pgoodPending()
35{
36 bool pending = false;
37 int32_t state = 0;
38 int32_t pgood = 0;
39
40 auto service = util::getService(POWER_OBJ_PATH,
41 POWER_INTERFACE,
42 bus);
43
44 util::getProperty<int32_t>(POWER_INTERFACE,
45 "pgood",
46 POWER_OBJ_PATH,
47 service,
48 bus,
49 pgood);
50
51 //When state = 1, system was switched on
52 util::getProperty<int32_t>(POWER_INTERFACE,
53 "state",
54 POWER_OBJ_PATH,
55 service,
56 bus,
57 state);
58
59 //On but no PGOOD
60 if (state && !pgood)
61 {
62 pending = true;
63 }
64
65 return pending;
66}
67
68
69void PGOODMonitor::exitEventLoop()
70{
71 auto r = sd_event_exit(event.get(), EXIT_SUCCESS);
72 if (r < 0)
73 {
74 log<level::ERR>("sd_event_exit failed",
75 entry("RC = %d", r));
76 }
77}
78
79void PGOODMonitor::analyze()
80{
81 //Timer callback.
82 //The timer expired before it was stopped.
83 //If PGOOD is still pending (it should be),
84 //then there is a real failure.
85
86 if (pgoodPending())
87 {
Matt Spinler45a054a2017-08-22 15:07:07 -050088#ifdef UCD90160_DEVICE_ACCESS
Matt Spinlerb2d72512017-08-22 09:07:01 -050089 device->onFailure();
Matt Spinler45a054a2017-08-22 15:07:07 -050090#endif
Matt Spinlerf02daec2017-08-14 14:00:46 -050091 report<PowerOnFailure>();
92 }
93
94 //The pgood-wait service (with a longer timeout)
95 //will handle powering off the system.
96
97 exitEventLoop();
98}
99
100void PGOODMonitor::propertyChanged()
101{
102 //Multiple properties could have changed here.
103 //Keep things simple and just recheck the important ones.
104 if (!pgoodPending())
105 {
106 //PGOOD is on, or system is off, so we are done.
107 timer.stop();
108 exitEventLoop();
109 }
110}
111
112void PGOODMonitor::startListening()
113{
114 match = std::make_unique<sdbusplus::bus::match_t>(
115 bus,
116 sdbusplus::bus::match::rules::propertiesChanged(
117 POWER_OBJ_PATH,
118 POWER_INTERFACE),
119 [this](auto& msg){this->propertyChanged();});
120}
121
122int PGOODMonitor::run()
123{
124 try
125 {
126 startListening();
127
128 //If PGOOD came up before we got here, we're done.
129 //Otherwise if PGOOD doesn't get asserted before
130 //the timer expires, it's a failure.
131 if (!pgoodPending())
132 {
133 return EXIT_SUCCESS;
134 }
135
136 timer.start(interval);
137
138 auto r = sd_event_loop(event.get());
139 if (r < 0)
140 {
141 log<level::ERR>("sd_event_loop() failed",
142 entry("ERROR=%d", r));
143 }
144 }
145 catch (std::exception& e)
146 {
147 log<level::ERR>(e.what());
148 log<level::ERR>("Unexpected failure prevented PGOOD checking");
149 }
150
151 //Letting the service fail won't help anything, so don't do it.
152 return EXIT_SUCCESS;
153}
154
155
156}
157}