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 device->onFailure(); 88 report<PowerOnFailure>(); 89 } 90 91 //The pgood-wait service (with a longer timeout) 92 //will handle powering off the system. 93 94 exitEventLoop(); 95 } 96 97 void PGOODMonitor::propertyChanged() 98 { 99 //Multiple properties could have changed here. 100 //Keep things simple and just recheck the important ones. 101 if (!pgoodPending()) 102 { 103 //PGOOD is on, or system is off, so we are done. 104 timer.stop(); 105 exitEventLoop(); 106 } 107 } 108 109 void PGOODMonitor::startListening() 110 { 111 match = std::make_unique<sdbusplus::bus::match_t>( 112 bus, 113 sdbusplus::bus::match::rules::propertiesChanged( 114 POWER_OBJ_PATH, 115 POWER_INTERFACE), 116 [this](auto& msg){this->propertyChanged();}); 117 } 118 119 int PGOODMonitor::run() 120 { 121 try 122 { 123 startListening(); 124 125 //If PGOOD came up before we got here, we're done. 126 //Otherwise if PGOOD doesn't get asserted before 127 //the timer expires, it's a failure. 128 if (!pgoodPending()) 129 { 130 return EXIT_SUCCESS; 131 } 132 133 timer.start(interval); 134 135 auto r = sd_event_loop(event.get()); 136 if (r < 0) 137 { 138 log<level::ERR>("sd_event_loop() failed", 139 entry("ERROR=%d", r)); 140 } 141 } 142 catch (std::exception& e) 143 { 144 log<level::ERR>(e.what()); 145 log<level::ERR>("Unexpected failure prevented PGOOD checking"); 146 } 147 148 //Letting the service fail won't help anything, so don't do it. 149 return EXIT_SUCCESS; 150 } 151 152 153 } 154 } 155