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