/** * 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 #include 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(POWER_INTERFACE, "pgood", POWER_OBJ_PATH, service, bus, pgood); // When state = 1, system was switched on util::getProperty(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(); } // 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( 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(e.what()); log("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