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