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