blob: 9fc30973f25ab43d871b5f47468c1db5c6229ed7 [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
George Liucb421092022-08-16 17:02:31 +080029BmcEpoch::BmcEpoch(sdbusplus::bus_t& bus, const char* objPath,
30 Manager& manager) :
31 EpochBase(bus, objPath, manager)
Lei YU96232822017-01-20 14:05:46 +080032{
Lei YU7b218792017-02-09 12:10:13 +080033 initialize();
34}
35
36void BmcEpoch::initialize()
37{
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050038 using InternalFailure =
39 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Lei YU7b218792017-02-09 12:10:13 +080040
41 // Subscribe time change event
42 // Choose the MAX time that is possible to avoid mis fires.
43 constexpr itimerspec maxTime = {
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050044 {0, 0}, // it_interval
45 {TIME_T_MAX, 0}, // it_value
Lei YU7b218792017-02-09 12:10:13 +080046 };
47
48 timeFd = timerfd_create(CLOCK_REALTIME, 0);
49 if (timeFd == -1)
50 {
George Liu947b5342022-07-01 16:12:18 +080051 lg2::error("Failed to create timerfd: {ERRNO}", "ERRNO", errno);
Lei YU7b218792017-02-09 12:10:13 +080052 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 {
George Liu947b5342022-07-01 16:12:18 +080059 lg2::error("Failed to set timerfd: {ERRNO}", "ERRNO", errno);
Lei YU7b218792017-02-09 12:10:13 +080060 elog<InternalFailure>();
61 }
62
63 sd_event_source* es;
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050064 r = sd_event_add_io(bus.get_event(), &es, timeFd, EPOLLIN, onTimeChange,
65 this);
Lei YU7b218792017-02-09 12:10:13 +080066 if (r < 0)
67 {
George Liu947b5342022-07-01 16:12:18 +080068 lg2::error("Failed to add event: {ERRNO}", "ERRNO", errno);
Lei YU7b218792017-02-09 12:10:13 +080069 elog<InternalFailure>();
70 }
71 timeChangeEventSource.reset(es);
72}
73
74BmcEpoch::~BmcEpoch()
75{
76 close(timeFd);
Lei YU96232822017-01-20 14:05:46 +080077}
78
79uint64_t BmcEpoch::elapsed() const
80{
Lei YU96232822017-01-20 14:05:46 +080081 return getTime().count();
82}
83
84uint64_t BmcEpoch::elapsed(uint64_t value)
85{
Lei YU7b218792017-02-09 12:10:13 +080086 /*
George Liu3c2f4492020-04-12 11:35:57 +080087 Mode | Set BMC Time
88 ----- | -------------
89 NTP | Fail to set
90 MANUAL| OK
Lei YU7b218792017-02-09 12:10:13 +080091 */
Lei YU7b218792017-02-09 12:10:13 +080092 auto time = microseconds(value);
George Liu3c2f4492020-04-12 11:35:57 +080093 setTime(time);
Lei YU7b218792017-02-09 12:10:13 +080094
Lei YU96232822017-01-20 14:05:46 +080095 server::EpochTime::elapsed(value);
96 return value;
97}
98
Ratan Gupta1e1dc442021-02-02 05:51:08 -060099int BmcEpoch::onTimeChange(sd_event_source* /* es */, int fd,
100 uint32_t /* revents */, void* /* userdata */)
Lei YU7b218792017-02-09 12:10:13 +0800101{
Gunnar Millsab4cc6a2018-09-14 14:42:39 -0500102 std::array<char, 64> time{};
Lei YU7b218792017-02-09 12:10:13 +0800103
104 // We are not interested in the data here.
105 // So read until there is no new data here in the FD
Gunnar Millsab4cc6a2018-09-14 14:42:39 -0500106 while (read(fd, time.data(), time.max_size()) > 0)
107 ;
Lei YU7b218792017-02-09 12:10:13 +0800108
Lei YU7b218792017-02-09 12:10:13 +0800109 return 0;
110}
111
Lei YUaf5abc52017-03-07 17:49:17 +0800112} // namespace time
113} // namespace phosphor