blob: 7135768aeff3d7c9a6b2fbcaa5d432d43af842bb [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>
George Liu947b5342022-07-01 16:12:18 +080010#include <phosphor-logging/lg2.hpp>
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050011#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
Patrick Williams38679262022-07-22 19:26:55 -050029BmcEpoch::BmcEpoch(sdbusplus::bus_t& bus, const char* objPath) :
George Liu261525d2022-07-01 17:02:55 +080030 EpochBase(bus, objPath)
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 {
George Liu947b5342022-07-01 16:12:18 +080050 lg2::error("Failed to create timerfd: {ERRNO}", "ERRNO", errno);
Lei YU7b218792017-02-09 12:10:13 +080051 elog<InternalFailure>();
52 }
53
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050054 auto r = timerfd_settime(
55 timeFd, TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &maxTime, nullptr);
Lei YU7b218792017-02-09 12:10:13 +080056 if (r != 0)
57 {
George Liu947b5342022-07-01 16:12:18 +080058 lg2::error("Failed to set timerfd: {ERRNO}", "ERRNO", errno);
Lei YU7b218792017-02-09 12:10:13 +080059 elog<InternalFailure>();
60 }
61
62 sd_event_source* es;
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050063 r = sd_event_add_io(bus.get_event(), &es, timeFd, EPOLLIN, onTimeChange,
64 this);
Lei YU7b218792017-02-09 12:10:13 +080065 if (r < 0)
66 {
George Liu947b5342022-07-01 16:12:18 +080067 lg2::error("Failed to add event: {ERRNO}", "ERRNO", errno);
Lei YU7b218792017-02-09 12:10:13 +080068 elog<InternalFailure>();
69 }
70 timeChangeEventSource.reset(es);
71}
72
73BmcEpoch::~BmcEpoch()
74{
75 close(timeFd);
Lei YU96232822017-01-20 14:05:46 +080076}
77
78uint64_t BmcEpoch::elapsed() const
79{
Lei YU96232822017-01-20 14:05:46 +080080 return getTime().count();
81}
82
83uint64_t BmcEpoch::elapsed(uint64_t value)
84{
Lei YU7b218792017-02-09 12:10:13 +080085 /*
George Liu3c2f4492020-04-12 11:35:57 +080086 Mode | Set BMC Time
87 ----- | -------------
88 NTP | Fail to set
89 MANUAL| OK
Lei YU7b218792017-02-09 12:10:13 +080090 */
Lei YU7b218792017-02-09 12:10:13 +080091 auto time = microseconds(value);
George Liu3c2f4492020-04-12 11:35:57 +080092 setTime(time);
Lei YU7b218792017-02-09 12:10:13 +080093
Lei YU96232822017-01-20 14:05:46 +080094 server::EpochTime::elapsed(value);
95 return value;
96}
97
Ratan Gupta1e1dc442021-02-02 05:51:08 -060098int BmcEpoch::onTimeChange(sd_event_source* /* es */, int fd,
99 uint32_t /* revents */, void* /* userdata */)
Lei YU7b218792017-02-09 12:10:13 +0800100{
Gunnar Millsab4cc6a2018-09-14 14:42:39 -0500101 std::array<char, 64> time{};
Lei YU7b218792017-02-09 12:10:13 +0800102
103 // We are not interested in the data here.
104 // So read until there is no new data here in the FD
Gunnar Millsab4cc6a2018-09-14 14:42:39 -0500105 while (read(fd, time.data(), time.max_size()) > 0)
106 ;
Lei YU7b218792017-02-09 12:10:13 +0800107
Lei YU7b218792017-02-09 12:10:13 +0800108 return 0;
109}
110
Lei YUaf5abc52017-03-07 17:49:17 +0800111} // namespace time
112} // namespace phosphor