mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Satyam Gupta <sgsatyam@google.com>
To: Benson Leung <bleung@chromium.org>, Tzung-Bi Shih <tzungbi@kernel.org>
Cc: Guenter Roeck <groeck@chromium.org>,
	Gwendal Grignou <gwendal@chromium.org>,
	 Scott Collyer <scollyer@google.com>,
	chrome-platform@lists.linux.dev,  linux-kernel@vger.kernel.org,
	Satyam Gupta <sgsatyam@google.com>
Subject: [PATCH v5 1/6] platform/chrome: cros_ec_sensorhub: Fix AP/EC TS wrap
Date: Wed, 14 Oct 2026 07:43:01 +0000	[thread overview]
Message-ID: <20261014074306.2500909-2-sgsatyam@google.com> (raw)
In-Reply-To: <20261014074306.2500909-1-sgsatyam@google.com>

When the AP goes into deep sleep, the EC physically continues executing
and silently wraps its 32-bit timestamp counter one or more times.
Because Linux natively advances ktime_get_boottime() across suspend,
the AP clock leaps forward but the incoming 32-bit EC timestamp
appears historically delayed.

Calculate how many 71.5 minute epochs were swallowed during sleep by
dividing the AP's recorded sleep duration against the overflow period.
By injecting these missed wraps directly into the running EC offset
tracker, the EC timeline snaps forward instantly and achieves parity
with AP boottime, avoiding fatal negative delta time-skew calculations.

Any massive suspend gaps (>500ms) inherently trigger the
TS_HISTORY_BORED_US fallback during the first post-resume sensor event,
scrubbing the poisoned clock drift data. Because the clocks are
explicitly resynchronized by the math above, newly arriving samples
remain valid and are delivered without being warped by stale filter
history.

Signed-off-by: Satyam Gupta <sgsatyam@google.com>
---
 drivers/platform/chrome/cros_ec_sensorhub.c   | 37 ++++++++++++++++++-
 .../platform/chrome/cros_ec_sensorhub_ring.c  | 30 ++++++++++++---
 .../linux/platform_data/cros_ec_sensorhub.h   |  2 +
 3 files changed, 62 insertions(+), 7 deletions(-)

diff --git a/drivers/platform/chrome/cros_ec_sensorhub.c b/drivers/platform/chrome/cros_ec_sensorhub.c
index 31fb8bdaad5a..5644ff4f8a90 100644
--- a/drivers/platform/chrome/cros_ec_sensorhub.c
+++ b/drivers/platform/chrome/cros_ec_sensorhub.c
@@ -227,6 +227,8 @@ static int cros_ec_sensorhub_suspend(struct device *dev)
 	struct cros_ec_sensorhub *sensorhub = dev_get_drvdata(dev);
 	struct cros_ec_dev *ec = sensorhub->ec;
 
+	sensorhub->suspend_time = ktime_get_boottime();
+
 	if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO))
 		return cros_ec_sensorhub_ring_fifo_enable(sensorhub, false);
 	return 0;
@@ -237,8 +239,41 @@ static int cros_ec_sensorhub_resume(struct device *dev)
 	struct cros_ec_sensorhub *sensorhub = dev_get_drvdata(dev);
 	struct cros_ec_dev *ec = sensorhub->ec;
 
-	if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO))
+	if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) {
+		/*
+		 * The EC's 32-bit hardware timestamp natively rolls over every
+		 * 71.5 minutes. When the AP goes into deep sleep, the EC
+		 * physically continues executing and silently wraps its 32-bit
+		 * timestamp counter one or more times.
+		 *
+		 * Because Linux natively advances ktime_get_boottime() across
+		 * suspend, the AP clock leaps forward, but the incoming 32-bit
+		 * EC timestamp appears massively historically delayed due to
+		 * the lost silent overflows.
+		 *
+		 * Calculate how many 71.5 minute epochs were swallowed during
+		 * sleep by dividing the AP's recorded sleep duration against
+		 * the overflow period. By injecting these missed wraps directly
+		 * into the running EC offset tracker, the EC timeline snaps
+		 * forward instantly and achieves active parity with the AP
+		 * boottime, avoiding fatal negative delta time-skew
+		 * calculations.
+		 *
+		 * Lastly, massive suspend gaps (>500ms) inherently trigger the
+		 * TS_HISTORY_BORED_US fallback during the first post-resume
+		 * sensor event, scrubbing the poisoned clock drift data.
+		 */
+		u64 sleep_duration = ktime_to_us(ktime_sub(
+					ktime_get_boottime(),
+					sensorhub->suspend_time));
+		u64 missed_overflows = div64_u64(sleep_duration, 1ULL << 32);
+
+		sensorhub->overflow_a.offset += missed_overflows * (1ULL << 32);
+		sensorhub->overflow_b.offset += missed_overflows * (1ULL << 32);
+
 		return cros_ec_sensorhub_ring_fifo_enable(sensorhub, true);
+	}
+
 	return 0;
 }
 #endif
diff --git a/drivers/platform/chrome/cros_ec_sensorhub_ring.c b/drivers/platform/chrome/cros_ec_sensorhub_ring.c
index 1205219515d6..cc038af59218 100644
--- a/drivers/platform/chrome/cros_ec_sensorhub_ring.c
+++ b/drivers/platform/chrome/cros_ec_sensorhub_ring.c
@@ -369,13 +369,31 @@ cros_ec_sensor_ring_fix_overflow(s64 *ts,
 				 struct cros_ec_sensors_ec_overflow_state
 				 *state)
 {
-	s64 adjust;
-
 	*ts += state->offset;
-	if (abs(state->last - *ts) > (overflow_period / 2)) {
-		adjust = state->last > *ts ? overflow_period : -overflow_period;
-		state->offset += adjust;
-		*ts += adjust;
+
+	/*
+	 * We must strictly detect exclusively forward overflows. A naive `abs()`
+	 * check paired with a dual-direction adjustment (`+/- overflow_period`)
+	 * is fundamentally flawed during deep suspend. If a device sleeps for
+	 * longer than half the overflow period (e.g. 45 minutes), the massive
+	 * legitimate forward leap in time is mathematically aliased as a backward
+	 * jump.
+	 *
+	 * This would historically cause the logic to forcibly inject a negative
+	 * `overflow_period` adjustment, irrevocably corrupting the sensor's
+	 * timestamps backwards by ~71 minutes upon resume and failing CTS.
+	 *
+	 * By eliminating the negative adjustment path and exclusively evaluating
+	 * `state->last - *ts > (overflow_period / 2)` via signed arithmetic, we
+	 * ensure that multi-minute sleep leaps bypass the threshold safely as
+	 * large negative relative differentials, naturally carrying time forward
+	 * without bogus timestamp rollbacks. Furthermore, the massive timestamp
+	 * differential will naturally trigger the TS_HISTORY_BORED_US threshold
+	 * downstream, safely resetting the historical median filter array.
+	 */
+	if (state->last - *ts > (overflow_period / 2)) {
+		state->offset += overflow_period;
+		*ts += overflow_period;
 	}
 	state->last = *ts;
 }
diff --git a/include/linux/platform_data/cros_ec_sensorhub.h b/include/linux/platform_data/cros_ec_sensorhub.h
index 0ecce6aa69d5..498a7d827b19 100644
--- a/include/linux/platform_data/cros_ec_sensorhub.h
+++ b/include/linux/platform_data/cros_ec_sensorhub.h
@@ -175,6 +175,8 @@ struct cros_ec_sensorhub {
 	s64 future_timestamp_total_ns;
 
 	struct cros_ec_sensorhub_sensor_push_data *push_data;
+
+	ktime_t suspend_time;
 };
 
 int cros_ec_sensorhub_register_push_data(struct cros_ec_sensorhub *sensorhub,
-- 
2.56.0.385.gd3acb90ef8-goog


  reply	other threads:[~2026-10-14  7:43 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-14  7:43 [PATCH v5 0/6] platform/chrome: cros_ec_sensorhub: Timestamp wrap and drift filter fixes Satyam Gupta
2026-10-14  7:43 ` Satyam Gupta [this message]
2026-10-14  7:43 ` [PATCH v5 2/6] platform/chrome: cros_ec_sensorhub: Fix TS filter history shift index Satyam Gupta
2026-10-14  7:43 ` [PATCH v5 3/6] platform/chrome: cros_ec_sensorhub: Clamp clock drift slope to MAX_DRIFT_PPM Satyam Gupta
2026-10-14  7:43 ` [PATCH v5 4/6] platform/chrome: cros_ec_sensorhub: Reset TS filter on ODR or mode changes Satyam Gupta
2026-10-14  7:43 ` [PATCH v5 5/6] platform/chrome: cros_ec_sensorhub: Increase TS_HISTORY_BORED_US to 2s Satyam Gupta
2026-10-14  7:43 ` [PATCH v5 6/6] platform/chrome: cros_ec_sensorhub: Drop sensor samples with past timestamps Satyam Gupta

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261014074306.2500909-2-sgsatyam@google.com \
    --to=sgsatyam@google.com \
    --cc=bleung@chromium.org \
    --cc=chrome-platform@lists.linux.dev \
    --cc=groeck@chromium.org \
    --cc=gwendal@chromium.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=scollyer@google.com \
    --cc=tzungbi@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®