xref: /openbmc/phosphor-power/power-sequencer/pgood_monitor.cpp (revision 8b38b177315d40f1f9bc1e4d0784d45ea17cbd5c)
1 /**
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 "config.h"
17 
18 #include "pgood_monitor.hpp"
19 
20 #include "elog-errors.hpp"
21 #include "utility.hpp"
22 
23 #include <org/open_power/Witherspoon/Fault/error.hpp>
24 #include <phosphor-logging/lg2.hpp>
25 
26 namespace phosphor
27 {
28 namespace power
29 {
30 
31 constexpr auto POWER_OBJ_PATH = "/org/openbmc/control/power0";
32 constexpr auto POWER_INTERFACE = "org.openbmc.control.Power";
33 
34 using namespace sdbusplus::org::open_power::Witherspoon::Fault::Error;
35 
36 bool PGOODMonitor::pgoodPending()
37 {
38     bool pending = false;
39     int32_t state = 0;
40     int32_t pgood = 0;
41 
42     auto service = util::getService(POWER_OBJ_PATH, POWER_INTERFACE, bus);
43 
44     util::getProperty<int32_t>(POWER_INTERFACE, "pgood", POWER_OBJ_PATH,
45                                service, bus, pgood);
46 
47     // When state = 1, system was switched on
48     util::getProperty<int32_t>(POWER_INTERFACE, "state", POWER_OBJ_PATH,
49                                service, bus, state);
50 
51     // On but no PGOOD
52     if (state && !pgood)
53     {
54         pending = true;
55     }
56 
57     return pending;
58 }
59 
60 void PGOODMonitor::analyze()
61 {
62     // Timer callback.
63     // The timer expired before it was stopped.
64     // If PGOOD is still pending (it should be),
65     // then there is a real failure.
66 
67     if (pgoodPending())
68     {
69 #ifdef DEVICE_ACCESS
70         device->onFailure();
71 #endif
72         phosphor::logging::report<PowerOnFailure>();
73     }
74 
75     // The pgood-wait service (with a longer timeout)
76     // will handle powering off the system.
77     timer.get_event().exit(EXIT_SUCCESS);
78 }
79 
80 void PGOODMonitor::propertyChanged()
81 {
82     // Multiple properties could have changed here.
83     // Keep things simple and just recheck the important ones.
84     if (!pgoodPending())
85     {
86         // PGOOD is on, or system is off, so we are done.
87         timer.get_event().exit(EXIT_SUCCESS);
88     }
89 }
90 
91 void PGOODMonitor::startListening()
92 {
93     match = std::make_unique<sdbusplus::bus::match_t>(
94         bus,
95         sdbusplus::bus::match::rules::propertiesChanged(POWER_OBJ_PATH,
96                                                         POWER_INTERFACE),
97         [this](auto&) { this->propertyChanged(); });
98 }
99 
100 int PGOODMonitor::run()
101 {
102     try
103     {
104         startListening();
105 
106         // If PGOOD came up before we got here, we're done.
107         // Otherwise if PGOOD doesn't get asserted before
108         // the timer expires, it's a failure.
109         if (!pgoodPending())
110         {
111             return EXIT_SUCCESS;
112         }
113 
114         return timer.get_event().loop();
115     }
116     catch (const std::exception& e)
117     {
118         lg2::error("Unexpected failure prevented PGOOD checking: {ERROR}",
119                    "ERROR", e);
120     }
121 
122     // Letting the service fail won't help anything, so don't do it.
123     return EXIT_SUCCESS;
124 }
125 
126 } // namespace power
127 } // namespace phosphor
128