blob: 9c8affc4f284fb01771d9628331d09ab49b09c42 [file] [log] [blame]
Lei YU96232822017-01-20 14:05:46 +08001#include "bmc_epoch.hpp"
2
Gunnar Millsab4cc6a2018-09-14 14:42:39 -05003#include "utils.hpp"
Lei YU7b218792017-02-09 12:10:13 +08004
5#include <sys/timerfd.h>
6#include <unistd.h>
7
Gunnar Millsab4cc6a2018-09-14 14:42:39 -05008#include <phosphor-logging/elog-errors.hpp>
9#include <phosphor-logging/elog.hpp>
10#include <phosphor-logging/log.hpp>
11#include <xyz/openbmc_project/Common/error.hpp>
Lei YU7b218792017-02-09 12:10:13 +080012
Gunnar Mills75710b62018-04-08 14:50:11 -050013// Need to do this since its not exported outside of the kernel.
Lei YU7b218792017-02-09 12:10:13 +080014// Refer : https://gist.github.com/lethean/446cea944b7441228298
15#ifndef TFD_TIMER_CANCEL_ON_SET
16#define TFD_TIMER_CANCEL_ON_SET (1 << 1)
17#endif
18
19// Needed to make sure timerfd does not misfire even though we set CANCEL_ON_SET
20#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
Lei YU96232822017-01-20 14:05:46 +080021
22namespace phosphor
23{
24namespace time
25{
26namespace server = sdbusplus::xyz::openbmc_project::Time::server;
27using namespace phosphor::logging;
Lei YUf6fad822018-07-13 16:35:45 +080028
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050029BmcEpoch::BmcEpoch(sdbusplus::bus::bus& bus, const char* objPath) :
30 EpochBase(bus, objPath), bus(bus)
Lei YU96232822017-01-20 14:05:46 +080031{
Lei YU7b218792017-02-09 12:10:13 +080032 initialize();
33}
34
35void BmcEpoch::initialize()
36{
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050037 using InternalFailure =
38 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Lei YU7b218792017-02-09 12:10:13 +080039
40 // Subscribe time change event
41 // Choose the MAX time that is possible to avoid mis fires.
42 constexpr itimerspec maxTime = {
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050043 {0, 0}, // it_interval
44 {TIME_T_MAX, 0}, // it_value
Lei YU7b218792017-02-09 12:10:13 +080045 };
46
47 timeFd = timerfd_create(CLOCK_REALTIME, 0);
48 if (timeFd == -1)
49 {
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050050 log<level::ERR>("Failed to create timerfd", entry("ERRNO=%d", errno),
Lei YU7b218792017-02-09 12:10:13 +080051 entry("ERR=%s", strerror(errno)));
52 elog<InternalFailure>();
53 }
54
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050055 auto r = timerfd_settime(
56 timeFd, TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &maxTime, nullptr);
Lei YU7b218792017-02-09 12:10:13 +080057 if (r != 0)
58 {
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050059 log<level::ERR>("Failed to set timerfd", entry("ERRNO=%d", errno),
Lei YU7b218792017-02-09 12:10:13 +080060 entry("ERR=%s", strerror(errno)));
61 elog<InternalFailure>();
62 }
63
64 sd_event_source* es;
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050065 r = sd_event_add_io(bus.get_event(), &es, timeFd, EPOLLIN, onTimeChange,
66 this);
Lei YU7b218792017-02-09 12:10:13 +080067 if (r < 0)
68 {
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050069 log<level::ERR>("Failed to add event", entry("ERRNO=%d", -r),
Lei YU7b218792017-02-09 12:10:13 +080070 entry("ERR=%s", strerror(-r)));
71 elog<InternalFailure>();
72 }
73 timeChangeEventSource.reset(es);
74}
75
76BmcEpoch::~BmcEpoch()
77{
78 close(timeFd);
Lei YU96232822017-01-20 14:05:46 +080079}
80
81uint64_t BmcEpoch::elapsed() const
82{
Lei YU96232822017-01-20 14:05:46 +080083 return getTime().count();
84}
85
86uint64_t BmcEpoch::elapsed(uint64_t value)
87{
Lei YU7b218792017-02-09 12:10:13 +080088 /*
George Liu3c2f4492020-04-12 11:35:57 +080089 Mode | Set BMC Time
90 ----- | -------------
91 NTP | Fail to set
92 MANUAL| OK
Lei YU7b218792017-02-09 12:10:13 +080093 */
Lei YU7b218792017-02-09 12:10:13 +080094 auto time = microseconds(value);
George Liu3c2f4492020-04-12 11:35:57 +080095 setTime(time);
Lei YU7b218792017-02-09 12:10:13 +080096
Lei YU96232822017-01-20 14:05:46 +080097 server::EpochTime::elapsed(value);
98 return value;
99}
100
Gunnar Millsab4cc6a2018-09-14 14:42:39 -0500101int BmcEpoch::onTimeChange(sd_event_source* es, int fd, uint32_t /* revents */,
102 void* userdata)
Lei YU7b218792017-02-09 12:10:13 +0800103{
Gunnar Millsab4cc6a2018-09-14 14:42:39 -0500104 std::array<char, 64> time{};
Lei YU7b218792017-02-09 12:10:13 +0800105
106 // We are not interested in the data here.
107 // So read until there is no new data here in the FD
Gunnar Millsab4cc6a2018-09-14 14:42:39 -0500108 while (read(fd, time.data(), time.max_size()) > 0)
109 ;
Lei YU7b218792017-02-09 12:10:13 +0800110
Lei YU7b218792017-02-09 12:10:13 +0800111 return 0;
112}
113
Lei YUaf5abc52017-03-07 17:49:17 +0800114} // namespace time
115} // namespace phosphor