Implement HostEpoch set time logic
1. When setting host epoch, follow below logic:
Mode | Owner | Set Host Time
----- | ----- | -------------
NTP | BMC | Not allowed
NTP | HOST | Not allowed
NTP | SPLIT | OK, and just save offset
NTP | BOTH | Not allowed
MANUAL| BMC | Not allowed
MANUAL| HOST | OK, and set time to BMC
MANUAL| SPLIT | OK, and just save offset
MANUAL| BOTH | OK, and set time to BMC
2. If owner is SPLIT and BMC time is changed, update the offset accordinly;
3. Use timerfd to get notified on BMC time change, and update host time
diff accordingly;
4. Add unit test cases.
Change-Id: I2d60a821f7da9b689c579ae7ab672cc37967322c
Signed-off-by: Lei YU <mine260309@gmail.com>
diff --git a/host_epoch.cpp b/host_epoch.cpp
index 3b4c00e..129d224 100644
--- a/host_epoch.cpp
+++ b/host_epoch.cpp
@@ -9,43 +9,107 @@
{
using namespace sdbusplus::xyz::openbmc_project::Time;
using namespace phosphor::logging;
+using namespace std::chrono;
HostEpoch::HostEpoch(sdbusplus::bus::bus& bus,
const char* objPath)
: EpochBase(bus, objPath),
offset(utils::readData<decltype(offset)::rep>(offsetFile))
{
- // Empty
+ // Initialize the diffToSteadyClock
+ auto steadyTime = duration_cast<microseconds>(
+ steady_clock::now().time_since_epoch());
+ diffToSteadyClock = getTime() + offset - steadyTime;
}
uint64_t HostEpoch::elapsed() const
{
- // It does not needs to check owner when getting time
- return (getTime() + offset).count();
+ auto ret = getTime();
+ if (timeOwner == Owner::SPLIT)
+ {
+ ret += offset;
+ }
+ return ret.count();
}
uint64_t HostEpoch::elapsed(uint64_t value)
{
- if (timeOwner == Owner::BMC)
+ /*
+ Mode | Owner | Set Host Time
+ ----- | ----- | -------------
+ NTP | BMC | Not allowed
+ NTP | HOST | Not allowed
+ NTP | SPLIT | OK, and just save offset
+ NTP | BOTH | Not allowed
+ MANUAL| BMC | Not allowed
+ MANUAL| HOST | OK, and set time to BMC
+ MANUAL| SPLIT | OK, and just save offset
+ MANUAL| BOTH | OK, and set time to BMC
+ */
+ if (timeOwner == Owner::BMC ||
+ (timeMode == Mode::NTP
+ && (timeOwner == Owner::HOST || timeOwner == Owner::BOTH)))
{
- log<level::ERR>("Setting HostTime in BMC owner is not allowed");
+ log<level::ERR>("Setting HostTime is not allowed");
// TODO: throw NotAllowed exception
return 0;
}
- // TODO: implement the logic of setting host time
- // based on timeOwner and timeMode
+ auto time = microseconds(value);
+ if (timeOwner == Owner::SPLIT)
+ {
+ // Calculate the offset between host and bmc time
+ offset = time - getTime();
+ saveOffset();
- auto time = std::chrono::microseconds(value);
- offset = time - getTime();
-
- // Store the offset to file
- utils::writeData(offsetFile, offset.count());
+ // Calculate the diff between host and steady time
+ auto steadyTime = duration_cast<microseconds>(
+ steady_clock::now().time_since_epoch());
+ diffToSteadyClock = time - steadyTime;
+ }
+ else
+ {
+ // Set time to BMC
+ setTime(time);
+ }
server::EpochTime::elapsed(value);
return value;
}
+void HostEpoch::onOwnerChanged(Owner owner)
+{
+ // If timeOwner is changed to SPLIT, the offset shall be preserved
+ // Otherwise it shall be cleared;
+ timeOwner = owner;
+ if (timeOwner != Owner::SPLIT)
+ {
+ offset = microseconds(0);
+ saveOffset();
+ }
+}
+
+void HostEpoch::saveOffset()
+{
+ // Store the offset to file
+ utils::writeData(offsetFile, offset.count());
+}
+
+void HostEpoch::onBmcTimeChanged(const microseconds& bmcTime)
+{
+ // If owner is split and BMC time is changed,
+ // the offset shall be adjusted
+ if (timeOwner == Owner::SPLIT)
+ {
+ auto steadyTime = duration_cast<microseconds>(
+ steady_clock::now().time_since_epoch());
+ auto hostTime = steadyTime + diffToSteadyClock;
+ offset = hostTime - bmcTime;
+
+ saveOffset();
+ }
+}
+
} // namespace time
} // namespace phosphor