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