iichid: keep a fixed sampling cadence in polled mode

Touchpads using sampling mode have a sampling task which is run at
a certain polling rate. When the system is under load this task may
not complete quickly which might stretch the time taken beyond what
the polling rate should be, leading to dropped touchpad motion.
On my laptop this causes the touchpad to be barely useable when
the system is under heavy load, and it is really difficult to move
the cursor since so many events are dropped.

This change adjusts the sampling loop to schedule the next polling
event to take place at a specific time in the future, based on the
polling period. If servicing the poll takes longer due to load then
the next sample will still be scheduled at its original time.

Approved by:	wulf, khng (mentor)
Differential Revision:	https://reviews.freebsd.org/D0914
This commit is contained in:
Austin Shafer committed 2026-11-03 11:40:29 -05:00
1 parent 9ed1713e28
commit e58325fb98
1 file changed
+17 -1
+17 -1
View File
@@ -180,6 +180,7 @@ struct iichid_softc {
int sampling_rate_slow; /* iicbus lock */
int sampling_rate_fast;
int sampling_hysteresis;
sbintime_t next_sample; /* iicbus lock */
int missing_samples; /* iicbus lock */
int dup_samples; /* iicbus lock */
iichid_size_t dup_size; /* iicbus lock */
@@ -527,6 +528,7 @@ iichid_sampling_task(void *context, int pending)
{
struct iichid_softc *sc;
device_t parent;
sbintime_t now, period;
iichid_size_t actual;
bool bus_requested;
int error, rate;
@@ -569,8 +571,21 @@ rearm:
rate = sc->sampling_rate_slow;
else
rate = sc->sampling_rate_fast;
period = SBT_1S / MAX(rate, 1);
/*
* Schedule against an absolute deadline advanced by one
* period per sample, so that neither the time spent in the
* I2C transaction and handler dispatch nor the taskqueue
* wakeup latency stretches the sampling period. If the
* deadline has already passed then only advance the sample
* by one period rather than bursting polls to catch up.
*/
now = sbinuptime();
sc->next_sample += period;
if (sc->next_sample <= now)
sc->next_sample = now + period;
taskqueue_enqueue_timeout_sbt(sc->taskqueue, &sc->sampling_task,
SBT_1S / MAX(rate, 1), 0, C_PREL(2));
sc->next_sample, 0, C_ABSOLUTE);
}
out:
if (bus_requested)
@@ -746,6 +761,7 @@ iichid_reset_callout(struct iichid_softc *sc)
sc->missing_samples = sc->sampling_hysteresis;
sc->dup_samples = 0;
sc->dup_size = 0;
sc->next_sample = sbinuptime();
taskqueue_enqueue_timeout(sc->taskqueue, &sc->sampling_task, 0);
return (0);