From: sashiko-bot@kernel.org
To: "Fenglin Wu" <fenglin.wu@oss.qualcomm.com>
Cc: linux-input@vger.kernel.org, robh@kernel.org,
devicetree@vger.kernel.org, conor+dt@kernel.org,
dmitry.torokhov@gmail.com
Subject: Re: [PATCH v5 3/3] input: misc: Add Qualcomm SPMI PMIC haptics driver
Date: Wed, 05 Aug 2026 06:28:57 +0000 [thread overview]
Message-ID: <20260805062858.67D3B1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260804-qcom-spmi-haptics-v5-3-77128ebbdd2d@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Multiplexing play_work for both playback requests and duration timers causes race conditions where active effect duration timers are overwritten, leading to indefinite playback.
- [High] The driver permanently disables the playback workqueue in `qcom_haptics_close()` but lacks an `open` callback to re-enable it, rendering the device inoperable after the first close.
- [High] Manually disabling the hardware module in `close()` desynchronizes the runtime PM state, causing subsequent playbacks to silently fail if started quickly.
--
--- Patch [3]: [PATCH v5 3/3] input: misc: Add Qualcomm SPMI PMIC haptics driver ---
commit 64b23ca2ca86ee295bdc5ad669c51fb6d603b0fc
Author: Fenglin Wu <fenglin.wu@oss.qualcomm.com>
input: misc: Add Qualcomm SPMI PMIC haptics driver
Add an initial driver for the Qualcomm PMIH0108 PMIC haptics module,
named as HAP530_HV. This module supports several play modes, including
DIRECT_PLAY, FIFO, PAT_MEM, and SWR, each with distinct data sourcing
and hardware data handling logic. Currently, the driver provides support
for two play modes using the input force-feedback framework: FF_CONSTANT
effect for DIRECT_PLAY mode and FF_PERIODIC effect with FF_CUSTOM
waveform for FIFO mode.
diff --git a/drivers/input/misc/qcom-spmi-haptics.c b/drivers/input/misc/qcom-spmi-haptics.c
--- /dev/null
+++ b/drivers/input/misc/qcom-spmi-haptics.c
[ ... ]
> +static void haptics_play_work(struct work_struct *work)
> +{
> + struct qcom_haptics *h = container_of(to_delayed_work(work),
> + struct qcom_haptics, play_work);
> + struct haptics_play_req *req = haptics_dequeue_play_req(h);
> + bool rearmed = false;
> + u32 length_us;
> + int ret;
> +
> + guard(mutex)(&h->play_lock);
> +
> + if (!req) {
> + /*
> + * Not a new request: the play-duration re-arm timer fired
> + * so stop the play
> + */
> + if (h->active_effect_id != -1)
> + haptics_stop(h, false);
> + } else if (req->play) {
> + ret = haptics_start(h, req->effect_id);
> + if (ret) {
> + dev_err(h->dev, "play haptics failed, ret=%d\n", ret);
> + } else {
> + /*
> + * Re-arm the work to stop the play or advance
> + * to next play after the play duration
> + */
> + length_us = h->effects[req->effect_id].length_us;
> + if (length_us) {
> + schedule_delayed_work(&h->play_work,
> + usecs_to_jiffies(length_us));
> + rearmed = true;
> + }
> + }
> + } else {
> + if (req->effect_id == h->active_effect_id)
> + haptics_stop(h, false);
> + }
> +
> + kfree(req);
> +
> + /* Wait for the re-arm to stop the play */
> + if (rearmed)
> + return;
> +
> + /* Handle the remaining requests if the queue is not empty */
> + guard(spinlock_irqsave)(&h->play_queue_lock);
> + if (!list_empty(&h->play_queue))
> + schedule_delayed_work(&h->play_work, 0);
> +}
[Severity: High]
Does this code handle the active effect's stop timer correctly when a STOP
request for a different effect arrives?
If an effect is currently playing with a scheduled stop timer, and userspace
sends a STOP request for a different inactive effect, the worker sees that the
STOP request is for an inactive effect and drops it.
However, it appears it fails to re-arm the duration timer for the active
effect, which could result in the active effect vibrating indefinitely.
[ ... ]
> +static int haptics_playback(struct input_dev *dev, int effect_id, int val)
> +{
> + struct qcom_haptics *h = input_get_drvdata(dev);
> + int ret;
> +
> + ret = haptics_enqueue_play_req(h, effect_id, val > 0);
> + if (ret)
> + return ret;
> +
> + if (val > 0)
> + /*
> + * Queue the play. If a duration re-arm is already pending this
> + * is a no-op, so the new play waits for the current effect to
> + * finish before the worker dequeues it.
> + */
> + schedule_delayed_work(&h->play_work, 0);
> + else
> + /*
> + * Run the worker now, cancelling any pending duration re-arm,
> + * so an explicit stop takes effect immediately.
> + */
> + mod_delayed_work(system_percpu_wq, &h->play_work, 0);
> +
> + return 0;
> +}
[Severity: High]
Can calling mod_delayed_work() here overwrite an active duration timer?
If userspace sends a STOP request for a different inactive effect,
mod_delayed_work() is called unconditionally, cancelling the active effect's
duration timer before the worker gets a chance to process the inactive STOP
request.
[ ... ]
> +static void qcom_haptics_close(struct input_dev *input)
> +{
> + struct qcom_haptics *h = input_get_drvdata(input);
> +
> + cancel_work_sync(&h->gain_work);
> + haptics_enable_play_work(h, false);
> + scoped_guard(mutex, &h->play_lock) {
> + haptics_queue_flush(h);
> + haptics_stop(h, false);
> + }
> +
> + haptics_enable_module(h, false);
> +}
[Severity: High]
Does disabling play_work here permanently render the device inoperable?
When the input device is closed, haptics_enable_play_work() uses
disable_delayed_work_sync() which sets the WORK_STRUCT_DISABLE bit on the
play_work item.
Because there is no corresponding open() callback registered to re-enable it,
subsequent playback requests will fail to schedule the work after the device
is opened again.
[Severity: High]
Can manually disabling the hardware module here desynchronize the runtime PM
state?
Calling haptics_enable_module() directly bypasses the PM runtime framework.
Earlier in the close sequence, haptics_stop() calls
pm_runtime_put_autosuspend() which leaves the PM state as RPM_ACTIVE for the
1000ms autosuspend delay.
If userspace reopens the device and requests playback within this window,
haptics_start() will see the device as already active and skip calling
qcom_haptics_runtime_resume(). The hardware module will remain disabled,
causing subsequent register writes to be silently ignored.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260804-qcom-spmi-haptics-v5-0-77128ebbdd2d@oss.qualcomm.com?part=3
prev parent reply other threads:[~2026-08-05 6:28 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-05 6:18 [PATCH v5 0/3] input: misc: Add an initial driver for haptics inside Qcom PMIH010x PMIC Fenglin Wu
2026-08-05 6:18 ` [PATCH v5 1/3] dt-bindings: input: Add Qualcomm SPMI PMIC haptics Fenglin Wu
2026-08-05 6:18 ` [PATCH v5 2/3] dt-bindings: mfd: qcom,spmi-pmic: Document haptics device Fenglin Wu
2026-08-06 13:22 ` (subset) " Lee Jones
2026-08-05 6:18 ` [PATCH v5 3/3] input: misc: Add Qualcomm SPMI PMIC haptics driver Fenglin Wu
2026-08-05 6:28 ` sashiko-bot [this message]
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=20260805062858.67D3B1F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=dmitry.torokhov@gmail.com \
--cc=fenglin.wu@oss.qualcomm.com \
--cc=linux-input@vger.kernel.org \
--cc=robh@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/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