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 <org/open_power/Witherspoon/Fault/error.hpp> 18 #include "config.h" 19 #include "elog-errors.hpp" 20 #include "pgood_monitor.hpp" 21 #include "utility.hpp" 22 23 namespace witherspoon 24 { 25 namespace power 26 { 27 28 constexpr auto POWER_OBJ_PATH = "/org/openbmc/control/power0"; 29 constexpr auto POWER_INTERFACE = "org.openbmc.control.Power"; 30 31 using namespace phosphor::logging; 32 using namespace sdbusplus::org::open_power::Witherspoon::Fault::Error; 33 34 bool PGOODMonitor::pgoodPending() 35 { 36 bool pending = false; 37 int32_t state = 0; 38 int32_t pgood = 0; 39 40 auto service = util::getService(POWER_OBJ_PATH, 41 POWER_INTERFACE, 42 bus); 43 44 util::getProperty<int32_t>(POWER_INTERFACE, 45 "pgood", 46 POWER_OBJ_PATH, 47 service, 48 bus, 49 pgood); 50 51 //When state = 1, system was switched on 52 util::getProperty<int32_t>(POWER_INTERFACE, 53 "state", 54 POWER_OBJ_PATH, 55 service, 56 bus, 57 state); 58 59 //On but no PGOOD 60 if (state && !pgood) 61 { 62 pending = true; 63 } 64 65 return pending; 66 } 67 68 69 void PGOODMonitor::exitEventLoop() 70 { 71 auto r = sd_event_exit(event.get(), EXIT_SUCCESS); 72 if (r < 0) 73 { 74 log<level::ERR>("sd_event_exit failed", 75 entry("RC = %d", r)); 76 } 77 } 78 79 void PGOODMonitor::analyze() 80 { 81 //Timer callback. 82 //The timer expired before it was stopped. 83 //If PGOOD is still pending (it should be), 84 //then there is a real failure. 85 86 if (pgoodPending()) 87 { 88 #ifdef UCD90160_DEVICE_ACCESS 89 device->onFailure(); 90 #endif 91 report<PowerOnFailure>(); 92 } 93 94 //The pgood-wait service (with a longer timeout) 95 //will handle powering off the system. 96 97 exitEventLoop(); 98 } 99 100 void PGOODMonitor::propertyChanged() 101 { 102 //Multiple properties could have changed here. 103 //Keep things simple and just recheck the important ones. 104 if (!pgoodPending()) 105 { 106 //PGOOD is on, or system is off, so we are done. 107 timer.stop(); 108 exitEventLoop(); 109 } 110 } 111 112 void PGOODMonitor::startListening() 113 { 114 match = std::make_unique<sdbusplus::bus::match_t>( 115 bus, 116 sdbusplus::bus::match::rules::propertiesChanged( 117 POWER_OBJ_PATH, 118 POWER_INTERFACE), 119 [this](auto& msg){this->propertyChanged();}); 120 } 121 122 int PGOODMonitor::run() 123 { 124 try 125 { 126 startListening(); 127 128 //If PGOOD came up before we got here, we're done. 129 //Otherwise if PGOOD doesn't get asserted before 130 //the timer expires, it's a failure. 131 if (!pgoodPending()) 132 { 133 return EXIT_SUCCESS; 134 } 135 136 timer.start(interval); 137 138 auto r = sd_event_loop(event.get()); 139 if (r < 0) 140 { 141 log<level::ERR>("sd_event_loop() failed", 142 entry("ERROR=%d", r)); 143 } 144 } 145 catch (std::exception& e) 146 { 147 log<level::ERR>(e.what()); 148 log<level::ERR>("Unexpected failure prevented PGOOD checking"); 149 } 150 151 //Letting the service fail won't help anything, so don't do it. 152 return EXIT_SUCCESS; 153 } 154 155 156 } 157 } 158