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