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