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> 10*947b5346SGeorge Liu #include <phosphor-logging/lg2.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 { 50*947b5346SGeorge Liu lg2::error("Failed to create timerfd: {ERRNO}", "ERRNO", errno); 517b218796SLei YU elog<InternalFailure>(); 527b218796SLei YU } 537b218796SLei YU 54ab4cc6a5SGunnar Mills auto r = timerfd_settime( 55ab4cc6a5SGunnar Mills timeFd, TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &maxTime, nullptr); 567b218796SLei YU if (r != 0) 577b218796SLei YU { 58*947b5346SGeorge Liu lg2::error("Failed to set timerfd: {ERRNO}", "ERRNO", errno); 597b218796SLei YU elog<InternalFailure>(); 607b218796SLei YU } 617b218796SLei YU 627b218796SLei YU sd_event_source* es; 63ab4cc6a5SGunnar Mills r = sd_event_add_io(bus.get_event(), &es, timeFd, EPOLLIN, onTimeChange, 64ab4cc6a5SGunnar Mills this); 657b218796SLei YU if (r < 0) 667b218796SLei YU { 67*947b5346SGeorge Liu lg2::error("Failed to add event: {ERRNO}", "ERRNO", errno); 687b218796SLei YU elog<InternalFailure>(); 697b218796SLei YU } 707b218796SLei YU timeChangeEventSource.reset(es); 717b218796SLei YU } 727b218796SLei YU 737b218796SLei YU BmcEpoch::~BmcEpoch() 747b218796SLei YU { 757b218796SLei YU close(timeFd); 7696232827SLei YU } 7796232827SLei YU 7896232827SLei YU uint64_t BmcEpoch::elapsed() const 7996232827SLei YU { 8096232827SLei YU return getTime().count(); 8196232827SLei YU } 8296232827SLei YU 8396232827SLei YU uint64_t BmcEpoch::elapsed(uint64_t value) 8496232827SLei YU { 857b218796SLei YU /* 863c2f4496SGeorge Liu Mode | Set BMC Time 873c2f4496SGeorge Liu ----- | ------------- 883c2f4496SGeorge Liu NTP | Fail to set 893c2f4496SGeorge Liu MANUAL| OK 907b218796SLei YU */ 917b218796SLei YU auto time = microseconds(value); 923c2f4496SGeorge Liu setTime(time); 937b218796SLei YU 9496232827SLei YU server::EpochTime::elapsed(value); 9596232827SLei YU return value; 9696232827SLei YU } 9796232827SLei YU 981e1dc447SRatan Gupta int BmcEpoch::onTimeChange(sd_event_source* /* es */, int fd, 991e1dc447SRatan Gupta uint32_t /* revents */, void* /* userdata */) 1007b218796SLei YU { 1017b218796SLei YU std::array<char, 64> time{}; 1027b218796SLei YU 1037b218796SLei YU // We are not interested in the data here. 1047b218796SLei YU // So read until there is no new data here in the FD 105ab4cc6a5SGunnar Mills while (read(fd, time.data(), time.max_size()) > 0) 106ab4cc6a5SGunnar Mills ; 1077b218796SLei YU 1087b218796SLei YU return 0; 1097b218796SLei YU } 1107b218796SLei YU 111af5abc57SLei YU } // namespace time 112af5abc57SLei YU } // namespace phosphor 113