blob: d86acefd3decfc602b6755bec75fac7c1aa77208 [file] [log] [blame]
/**
* Copyright © 2017 IBM Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "config.h"
#include "pgood_monitor.hpp"
#include "elog-errors.hpp"
#include "utility.hpp"
#include <org/open_power/Witherspoon/Fault/error.hpp>
#include <phosphor-logging/log.hpp>
namespace phosphor
{
namespace power
{
constexpr auto POWER_OBJ_PATH = "/org/openbmc/control/power0";
constexpr auto POWER_INTERFACE = "org.openbmc.control.Power";
using namespace phosphor::logging;
using namespace sdbusplus::org::open_power::Witherspoon::Fault::Error;
bool PGOODMonitor::pgoodPending()
{
bool pending = false;
int32_t state = 0;
int32_t pgood = 0;
auto service = util::getService(POWER_OBJ_PATH, POWER_INTERFACE, bus);
util::getProperty<int32_t>(POWER_INTERFACE, "pgood", POWER_OBJ_PATH,
service, bus, pgood);
// When state = 1, system was switched on
util::getProperty<int32_t>(POWER_INTERFACE, "state", POWER_OBJ_PATH,
service, bus, state);
// On but no PGOOD
if (state && !pgood)
{
pending = true;
}
return pending;
}
void PGOODMonitor::analyze()
{
// Timer callback.
// The timer expired before it was stopped.
// If PGOOD is still pending (it should be),
// then there is a real failure.
if (pgoodPending())
{
#ifdef DEVICE_ACCESS
device->onFailure();
#endif
report<PowerOnFailure>();
}
// The pgood-wait service (with a longer timeout)
// will handle powering off the system.
timer.get_event().exit(EXIT_SUCCESS);
}
void PGOODMonitor::propertyChanged()
{
// Multiple properties could have changed here.
// Keep things simple and just recheck the important ones.
if (!pgoodPending())
{
// PGOOD is on, or system is off, so we are done.
timer.get_event().exit(EXIT_SUCCESS);
}
}
void PGOODMonitor::startListening()
{
match = std::make_unique<sdbusplus::bus::match_t>(
bus,
sdbusplus::bus::match::rules::propertiesChanged(POWER_OBJ_PATH,
POWER_INTERFACE),
[this](auto&) { this->propertyChanged(); });
}
int PGOODMonitor::run()
{
try
{
startListening();
// If PGOOD came up before we got here, we're done.
// Otherwise if PGOOD doesn't get asserted before
// the timer expires, it's a failure.
if (!pgoodPending())
{
return EXIT_SUCCESS;
}
return timer.get_event().loop();
}
catch (const std::exception& e)
{
log<level::ERR>(e.what());
log<level::ERR>("Unexpected failure prevented PGOOD checking");
}
// Letting the service fail won't help anything, so don't do it.
return EXIT_SUCCESS;
}
} // namespace power
} // namespace phosphor