| /** |
| * Copyright © 2017 IBM Corporation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include "config.h" |
| |
| #include "pgood_monitor.hpp" |
| |
| #include "elog-errors.hpp" |
| #include "utility.hpp" |
| |
| #include <org/open_power/Witherspoon/Fault/error.hpp> |
| #include <phosphor-logging/log.hpp> |
| |
| namespace phosphor |
| { |
| namespace power |
| { |
| |
| constexpr auto POWER_OBJ_PATH = "/org/openbmc/control/power0"; |
| constexpr auto POWER_INTERFACE = "org.openbmc.control.Power"; |
| |
| using namespace phosphor::logging; |
| using namespace sdbusplus::org::open_power::Witherspoon::Fault::Error; |
| |
| bool PGOODMonitor::pgoodPending() |
| { |
| bool pending = false; |
| int32_t state = 0; |
| int32_t pgood = 0; |
| |
| auto service = util::getService(POWER_OBJ_PATH, POWER_INTERFACE, bus); |
| |
| util::getProperty<int32_t>(POWER_INTERFACE, "pgood", POWER_OBJ_PATH, |
| service, bus, pgood); |
| |
| // When state = 1, system was switched on |
| util::getProperty<int32_t>(POWER_INTERFACE, "state", POWER_OBJ_PATH, |
| service, bus, state); |
| |
| // On but no PGOOD |
| if (state && !pgood) |
| { |
| pending = true; |
| } |
| |
| return pending; |
| } |
| |
| void PGOODMonitor::analyze() |
| { |
| // Timer callback. |
| // The timer expired before it was stopped. |
| // If PGOOD is still pending (it should be), |
| // then there is a real failure. |
| |
| if (pgoodPending()) |
| { |
| #ifdef DEVICE_ACCESS |
| device->onFailure(); |
| #endif |
| report<PowerOnFailure>(); |
| } |
| |
| // The pgood-wait service (with a longer timeout) |
| // will handle powering off the system. |
| timer.get_event().exit(EXIT_SUCCESS); |
| } |
| |
| void PGOODMonitor::propertyChanged() |
| { |
| // Multiple properties could have changed here. |
| // Keep things simple and just recheck the important ones. |
| if (!pgoodPending()) |
| { |
| // PGOOD is on, or system is off, so we are done. |
| timer.get_event().exit(EXIT_SUCCESS); |
| } |
| } |
| |
| void PGOODMonitor::startListening() |
| { |
| match = std::make_unique<sdbusplus::bus::match_t>( |
| bus, |
| sdbusplus::bus::match::rules::propertiesChanged(POWER_OBJ_PATH, |
| POWER_INTERFACE), |
| [this](auto&) { this->propertyChanged(); }); |
| } |
| |
| int PGOODMonitor::run() |
| { |
| try |
| { |
| startListening(); |
| |
| // If PGOOD came up before we got here, we're done. |
| // Otherwise if PGOOD doesn't get asserted before |
| // the timer expires, it's a failure. |
| if (!pgoodPending()) |
| { |
| return EXIT_SUCCESS; |
| } |
| |
| return timer.get_event().loop(); |
| } |
| catch (const std::exception& e) |
| { |
| log<level::ERR>(e.what()); |
| log<level::ERR>("Unexpected failure prevented PGOOD checking"); |
| } |
| |
| // Letting the service fail won't help anything, so don't do it. |
| return EXIT_SUCCESS; |
| } |
| |
| } // namespace power |
| } // namespace phosphor |