1*f02daec1SMatt Spinler /**
2*f02daec1SMatt Spinler  * Copyright © 2017 IBM Corporation
3*f02daec1SMatt Spinler  *
4*f02daec1SMatt Spinler  * Licensed under the Apache License, Version 2.0 (the "License");
5*f02daec1SMatt Spinler  * you may not use this file except in compliance with the License.
6*f02daec1SMatt Spinler  * You may obtain a copy of the License at
7*f02daec1SMatt Spinler  *
8*f02daec1SMatt Spinler  *     http://www.apache.org/licenses/LICENSE-2.0
9*f02daec1SMatt Spinler  *
10*f02daec1SMatt Spinler  * Unless required by applicable law or agreed to in writing, software
11*f02daec1SMatt Spinler  * distributed under the License is distributed on an "AS IS" BASIS,
12*f02daec1SMatt Spinler  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*f02daec1SMatt Spinler  * See the License for the specific language governing permissions and
14*f02daec1SMatt Spinler  * limitations under the License.
15*f02daec1SMatt Spinler  */
16*f02daec1SMatt Spinler #include <phosphor-logging/log.hpp>
17*f02daec1SMatt Spinler #include <xyz/openbmc_project/Power/Fault/error.hpp>
18*f02daec1SMatt Spinler #include "elog-errors.hpp"
19*f02daec1SMatt Spinler #include "pgood_monitor.hpp"
20*f02daec1SMatt Spinler #include "utility.hpp"
21*f02daec1SMatt Spinler 
22*f02daec1SMatt Spinler namespace witherspoon
23*f02daec1SMatt Spinler {
24*f02daec1SMatt Spinler namespace power
25*f02daec1SMatt Spinler {
26*f02daec1SMatt Spinler 
27*f02daec1SMatt Spinler constexpr auto POWER_OBJ_PATH = "/org/openbmc/control/power0";
28*f02daec1SMatt Spinler constexpr auto POWER_INTERFACE = "org.openbmc.control.Power";
29*f02daec1SMatt Spinler 
30*f02daec1SMatt Spinler using namespace phosphor::logging;
31*f02daec1SMatt Spinler using namespace sdbusplus::xyz::openbmc_project::Power::Fault::Error;
32*f02daec1SMatt Spinler 
33*f02daec1SMatt Spinler bool PGOODMonitor::pgoodPending()
34*f02daec1SMatt Spinler {
35*f02daec1SMatt Spinler     bool pending = false;
36*f02daec1SMatt Spinler     int32_t state = 0;
37*f02daec1SMatt Spinler     int32_t pgood = 0;
38*f02daec1SMatt Spinler 
39*f02daec1SMatt Spinler     auto service = util::getService(POWER_OBJ_PATH,
40*f02daec1SMatt Spinler             POWER_INTERFACE,
41*f02daec1SMatt Spinler             bus);
42*f02daec1SMatt Spinler 
43*f02daec1SMatt Spinler     util::getProperty<int32_t>(POWER_INTERFACE,
44*f02daec1SMatt Spinler             "pgood",
45*f02daec1SMatt Spinler             POWER_OBJ_PATH,
46*f02daec1SMatt Spinler             service,
47*f02daec1SMatt Spinler             bus,
48*f02daec1SMatt Spinler             pgood);
49*f02daec1SMatt Spinler 
50*f02daec1SMatt Spinler     //When state = 1, system was switched on
51*f02daec1SMatt Spinler     util::getProperty<int32_t>(POWER_INTERFACE,
52*f02daec1SMatt Spinler             "state",
53*f02daec1SMatt Spinler             POWER_OBJ_PATH,
54*f02daec1SMatt Spinler             service,
55*f02daec1SMatt Spinler             bus,
56*f02daec1SMatt Spinler             state);
57*f02daec1SMatt Spinler 
58*f02daec1SMatt Spinler     //On but no PGOOD
59*f02daec1SMatt Spinler     if (state && !pgood)
60*f02daec1SMatt Spinler     {
61*f02daec1SMatt Spinler         pending = true;
62*f02daec1SMatt Spinler     }
63*f02daec1SMatt Spinler 
64*f02daec1SMatt Spinler     return pending;
65*f02daec1SMatt Spinler }
66*f02daec1SMatt Spinler 
67*f02daec1SMatt Spinler 
68*f02daec1SMatt Spinler void PGOODMonitor::exitEventLoop()
69*f02daec1SMatt Spinler {
70*f02daec1SMatt Spinler     auto r = sd_event_exit(event.get(), EXIT_SUCCESS);
71*f02daec1SMatt Spinler     if (r < 0)
72*f02daec1SMatt Spinler     {
73*f02daec1SMatt Spinler         log<level::ERR>("sd_event_exit failed",
74*f02daec1SMatt Spinler                 entry("RC = %d", r));
75*f02daec1SMatt Spinler     }
76*f02daec1SMatt Spinler }
77*f02daec1SMatt Spinler 
78*f02daec1SMatt Spinler void PGOODMonitor::analyze()
79*f02daec1SMatt Spinler {
80*f02daec1SMatt Spinler     //Timer callback.
81*f02daec1SMatt Spinler     //The timer expired before it was stopped.
82*f02daec1SMatt Spinler     //If PGOOD is still pending (it should be),
83*f02daec1SMatt Spinler     //then there is a real failure.
84*f02daec1SMatt Spinler 
85*f02daec1SMatt Spinler     if (pgoodPending())
86*f02daec1SMatt Spinler     {
87*f02daec1SMatt Spinler         report<PowerOnFailure>();
88*f02daec1SMatt Spinler     }
89*f02daec1SMatt Spinler 
90*f02daec1SMatt Spinler     //The pgood-wait service (with a longer timeout)
91*f02daec1SMatt Spinler     //will handle powering off the system.
92*f02daec1SMatt Spinler 
93*f02daec1SMatt Spinler     exitEventLoop();
94*f02daec1SMatt Spinler }
95*f02daec1SMatt Spinler 
96*f02daec1SMatt Spinler void PGOODMonitor::propertyChanged()
97*f02daec1SMatt Spinler {
98*f02daec1SMatt Spinler     //Multiple properties could have changed here.
99*f02daec1SMatt Spinler     //Keep things simple and just recheck the important ones.
100*f02daec1SMatt Spinler     if (!pgoodPending())
101*f02daec1SMatt Spinler     {
102*f02daec1SMatt Spinler         //PGOOD is on, or system is off, so we are done.
103*f02daec1SMatt Spinler         timer.stop();
104*f02daec1SMatt Spinler         exitEventLoop();
105*f02daec1SMatt Spinler     }
106*f02daec1SMatt Spinler }
107*f02daec1SMatt Spinler 
108*f02daec1SMatt Spinler void PGOODMonitor::startListening()
109*f02daec1SMatt Spinler {
110*f02daec1SMatt Spinler     match = std::make_unique<sdbusplus::bus::match_t>(
111*f02daec1SMatt Spinler             bus,
112*f02daec1SMatt Spinler             sdbusplus::bus::match::rules::propertiesChanged(
113*f02daec1SMatt Spinler                 POWER_OBJ_PATH,
114*f02daec1SMatt Spinler                 POWER_INTERFACE),
115*f02daec1SMatt Spinler             [this](auto& msg){this->propertyChanged();});
116*f02daec1SMatt Spinler }
117*f02daec1SMatt Spinler 
118*f02daec1SMatt Spinler int PGOODMonitor::run()
119*f02daec1SMatt Spinler {
120*f02daec1SMatt Spinler     try
121*f02daec1SMatt Spinler     {
122*f02daec1SMatt Spinler         startListening();
123*f02daec1SMatt Spinler 
124*f02daec1SMatt Spinler         //If PGOOD came up before we got here, we're done.
125*f02daec1SMatt Spinler         //Otherwise if PGOOD doesn't get asserted before
126*f02daec1SMatt Spinler         //the timer expires, it's a failure.
127*f02daec1SMatt Spinler         if (!pgoodPending())
128*f02daec1SMatt Spinler         {
129*f02daec1SMatt Spinler             return EXIT_SUCCESS;
130*f02daec1SMatt Spinler         }
131*f02daec1SMatt Spinler 
132*f02daec1SMatt Spinler         timer.start(interval);
133*f02daec1SMatt Spinler 
134*f02daec1SMatt Spinler         auto r = sd_event_loop(event.get());
135*f02daec1SMatt Spinler         if (r < 0)
136*f02daec1SMatt Spinler         {
137*f02daec1SMatt Spinler             log<level::ERR>("sd_event_loop() failed",
138*f02daec1SMatt Spinler                     entry("ERROR=%d", r));
139*f02daec1SMatt Spinler         }
140*f02daec1SMatt Spinler     }
141*f02daec1SMatt Spinler     catch (std::exception& e)
142*f02daec1SMatt Spinler     {
143*f02daec1SMatt Spinler         log<level::ERR>(e.what());
144*f02daec1SMatt Spinler         log<level::ERR>("Unexpected failure prevented PGOOD checking");
145*f02daec1SMatt Spinler     }
146*f02daec1SMatt Spinler 
147*f02daec1SMatt Spinler     //Letting the service fail won't help anything, so don't do it.
148*f02daec1SMatt Spinler     return EXIT_SUCCESS;
149*f02daec1SMatt Spinler }
150*f02daec1SMatt Spinler 
151*f02daec1SMatt Spinler 
152*f02daec1SMatt Spinler }
153*f02daec1SMatt Spinler }
154