196232827SLei YU #include "bmc_epoch.hpp" 296232827SLei YU 3ab4cc6a5SGunnar Mills #include "utils.hpp" 47b218796SLei YU 57b218796SLei YU #include <sys/timerfd.h> 67b218796SLei YU #include <unistd.h> 77b218796SLei YU 8ab4cc6a5SGunnar Mills #include <phosphor-logging/elog-errors.hpp> 9ab4cc6a5SGunnar Mills #include <phosphor-logging/elog.hpp> 10ab4cc6a5SGunnar Mills #include <phosphor-logging/log.hpp> 11ab4cc6a5SGunnar Mills #include <xyz/openbmc_project/Common/error.hpp> 127b218796SLei YU 1375710b6aSGunnar Mills // Need to do this since its not exported outside of the kernel. 147b218796SLei YU // Refer : https://gist.github.com/lethean/446cea944b7441228298 157b218796SLei YU #ifndef TFD_TIMER_CANCEL_ON_SET 167b218796SLei YU #define TFD_TIMER_CANCEL_ON_SET (1 << 1) 177b218796SLei YU #endif 187b218796SLei YU 197b218796SLei YU // Needed to make sure timerfd does not misfire even though we set CANCEL_ON_SET 207b218796SLei YU #define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1) 2196232827SLei YU 2296232827SLei YU namespace phosphor 2396232827SLei YU { 2496232827SLei YU namespace time 2596232827SLei YU { 2696232827SLei YU namespace server = sdbusplus::xyz::openbmc_project::Time::server; 2796232827SLei YU using namespace phosphor::logging; 28f6fad820SLei YU 29ab4cc6a5SGunnar Mills BmcEpoch::BmcEpoch(sdbusplus::bus::bus& bus, const char* objPath) : 30ab4cc6a5SGunnar Mills EpochBase(bus, objPath), bus(bus) 3196232827SLei YU { 327b218796SLei YU initialize(); 337b218796SLei YU } 347b218796SLei YU 357b218796SLei YU void BmcEpoch::initialize() 367b218796SLei YU { 37ab4cc6a5SGunnar Mills using InternalFailure = 38ab4cc6a5SGunnar Mills sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 397b218796SLei YU 407b218796SLei YU // Subscribe time change event 417b218796SLei YU // Choose the MAX time that is possible to avoid mis fires. 427b218796SLei YU constexpr itimerspec maxTime = { 437b218796SLei YU {0, 0}, // it_interval 447b218796SLei YU {TIME_T_MAX, 0}, // it_value 457b218796SLei YU }; 467b218796SLei YU 477b218796SLei YU timeFd = timerfd_create(CLOCK_REALTIME, 0); 487b218796SLei YU if (timeFd == -1) 497b218796SLei YU { 50ab4cc6a5SGunnar Mills log<level::ERR>("Failed to create timerfd", entry("ERRNO=%d", errno), 517b218796SLei YU entry("ERR=%s", strerror(errno))); 527b218796SLei YU elog<InternalFailure>(); 537b218796SLei YU } 547b218796SLei YU 55ab4cc6a5SGunnar Mills auto r = timerfd_settime( 56ab4cc6a5SGunnar Mills timeFd, TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &maxTime, nullptr); 577b218796SLei YU if (r != 0) 587b218796SLei YU { 59ab4cc6a5SGunnar Mills log<level::ERR>("Failed to set timerfd", entry("ERRNO=%d", errno), 607b218796SLei YU entry("ERR=%s", strerror(errno))); 617b218796SLei YU elog<InternalFailure>(); 627b218796SLei YU } 637b218796SLei YU 647b218796SLei YU sd_event_source* es; 65ab4cc6a5SGunnar Mills r = sd_event_add_io(bus.get_event(), &es, timeFd, EPOLLIN, onTimeChange, 66ab4cc6a5SGunnar Mills this); 677b218796SLei YU if (r < 0) 687b218796SLei YU { 69ab4cc6a5SGunnar Mills log<level::ERR>("Failed to add event", entry("ERRNO=%d", -r), 707b218796SLei YU entry("ERR=%s", strerror(-r))); 717b218796SLei YU elog<InternalFailure>(); 727b218796SLei YU } 737b218796SLei YU timeChangeEventSource.reset(es); 747b218796SLei YU } 757b218796SLei YU 767b218796SLei YU BmcEpoch::~BmcEpoch() 777b218796SLei YU { 787b218796SLei YU close(timeFd); 7996232827SLei YU } 8096232827SLei YU 8196232827SLei YU uint64_t BmcEpoch::elapsed() const 8296232827SLei YU { 8396232827SLei YU return getTime().count(); 8496232827SLei YU } 8596232827SLei YU 8696232827SLei YU uint64_t BmcEpoch::elapsed(uint64_t value) 8796232827SLei YU { 887b218796SLei YU /* 893c2f4496SGeorge Liu Mode | Set BMC Time 903c2f4496SGeorge Liu ----- | ------------- 913c2f4496SGeorge Liu NTP | Fail to set 923c2f4496SGeorge Liu MANUAL| OK 937b218796SLei YU */ 947b218796SLei YU auto time = microseconds(value); 953c2f4496SGeorge Liu setTime(time); 967b218796SLei YU 9796232827SLei YU server::EpochTime::elapsed(value); 9896232827SLei YU return value; 9996232827SLei YU } 10096232827SLei YU 101*1e1dc447SRatan Gupta int BmcEpoch::onTimeChange(sd_event_source* /* es */, int fd, 102*1e1dc447SRatan Gupta uint32_t /* revents */, void* /* userdata */) 1037b218796SLei YU { 1047b218796SLei YU std::array<char, 64> time{}; 1057b218796SLei YU 1067b218796SLei YU // We are not interested in the data here. 1077b218796SLei YU // So read until there is no new data here in the FD 108ab4cc6a5SGunnar Mills while (read(fd, time.data(), time.max_size()) > 0) 109ab4cc6a5SGunnar Mills ; 1107b218796SLei YU 1117b218796SLei YU return 0; 1127b218796SLei YU } 1137b218796SLei YU 114af5abc57SLei YU } // namespace time 115af5abc57SLei YU } // namespace phosphor 116