From: sashiko-bot@kernel.org
To: "Wadim Mueller" <wafgo01@gmail.com>
Cc: robh@kernel.org, conor+dt@kernel.org, devicetree@vger.kernel.org
Subject: Re: [PATCH v6 2/3] counter: add GPIO-based counter driver
Date: Sun, 28 Jun 2026 21:13:29 +0000 [thread overview]
Message-ID: <20260628211330.0F3A31F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260628210241.119825-3-wafgo01@gmail.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Missing direction state update on enable for PULSE_DIRECTION mode.
- [High] Reading GPIO pin states outside the spinlock in the ISRs allows out-of-order state evaluation, leading to spurious counter steps.
- [Medium] Enabling a count overwrites shared quadrature state, corrupting the active state machine of the other running count.
--
commit 002c8f1bc700b17784c2bbc34b75aada303eee61
Author: Wadim Mueller <wafgo01@gmail.com>
counter: add GPIO-based counter driver
This adds a platform driver to decode plain GPIOs into a counter device,
supporting quadrature, pulse-direction, and increase/decrease modes.
> diff --git a/drivers/counter/gpio-counter.c b/drivers/counter/gpio-counter.c
> new file mode 100644
> index 0000000000000..8d9fa0b616d5c
> --- /dev/null
> +++ b/drivers/counter/gpio-counter.c
[ ... ]
> +static irqreturn_t gpio_counter_a_isr(int irq, void *dev_id)
> +{
> + struct counter_device *counter = dev_id;
> + struct gpio_counter_priv *priv = counter_priv(counter);
> + struct gpio_counter_count_priv *cp =
> + &priv->count_priv[GPIO_COUNTER_COUNT_1];
> + unsigned long flags;
> + bool enabled;
> + int a, b;
> +
> + /* !! drops negative gpiod_get_value() errors. */
> + a = !!gpiod_get_value(priv->gpio_a);
> + b = !!gpiod_get_value(priv->gpio_b);
> +
> + spin_lock_irqsave(&priv->lock, flags);
[Severity: High]
Does reading the GPIO pin states outside the spinlock here and in
gpio_counter_b_isr() create a data race that allows out-of-order state
evaluation?
If high-frequency edges on A and B pins trigger interrupts that are serviced
concurrently on different CPUs, CPU 0 could read the states locklessly, get
preempted, and then apply a stale state after CPU 1 has already acquired the
lock and updated it. This could rewind the Gray-code state machine and
generate spurious backward steps or drop valid transitions.
Would moving the gpiod_get_value() reads inside the lock ensure late-arriving
ISRs read the most current state and safely drop redundant edges?
[ ... ]
> +static irqreturn_t gpio_counter_b_isr(int irq, void *dev_id)
> +{
> + struct counter_device *counter = dev_id;
> + struct gpio_counter_priv *priv = counter_priv(counter);
> + struct gpio_counter_count_priv *c1 =
> + &priv->count_priv[GPIO_COUNTER_COUNT_1];
> + struct gpio_counter_count_priv *c2 =
> + &priv->count_priv[GPIO_COUNTER_COUNT_2];
> + bool c1_enabled, c2_enabled;
> + unsigned long flags;
> + int a, b;
> +
> + a = !!gpiod_get_value(priv->gpio_a);
> + b = !!gpiod_get_value(priv->gpio_b);
> +
> + spin_lock_irqsave(&priv->lock, flags);
> +
> + c1_enabled = c1->enabled;
> + c2_enabled = c2->enabled;
> +
> + /* Count 1: A+B decoding on this B edge */
> + if (c1_enabled) {
> + switch (c1->function) {
> + case COUNTER_FUNCTION_QUADRATURE_X4:
> + case COUNTER_FUNCTION_QUADRATURE_X2_B:
> + case COUNTER_FUNCTION_QUADRATURE_X1_B:
> + if (!GPIO_COUNTER_STATE_CHANGED(priv->prev_a,
> + priv->prev_b, a, b))
> + break;
> + c1->direction =
> + GPIO_COUNTER_GET_DIRECTION(priv->prev_b, a);
> + if (c1->function == COUNTER_FUNCTION_QUADRATURE_X1_B)
> + gpio_counter_quadrature_x1_step(c1, b);
> + else
> + gpio_counter_value_step(c1);
> + break;
> +
> + case COUNTER_FUNCTION_PULSE_DIRECTION:
> + /* B is the direction line */
> + c1->direction = b ? COUNTER_COUNT_DIRECTION_BACKWARD
> + : COUNTER_COUNT_DIRECTION_FORWARD;
> + break;
[Severity: High]
Is a direction state update missing on enable for PULSE_DIRECTION mode?
Since the direction is only updated here when the count is enabled, any B pin
toggles that happen while the counter is disabled are not tracked. When the
counter is subsequently enabled, gpio_counter_enable_write() does not
synchronize cp->direction with the current B pin level.
Could this cause the counter to step in the wrong direction until the B pin
toggles again?
[ ... ]
> +static int gpio_counter_enable_write(struct counter_device *counter,
> + struct counter_count *count, u8 enable)
> +{
> + struct gpio_counter_priv *priv = counter_priv(counter);
> + struct gpio_counter_count_priv *cp = &priv->count_priv[count->id];
> + unsigned long flags;
> + bool current_state;
> +
> + guard(mutex)(&priv->enable_lock);
> +
> + spin_lock_irqsave(&priv->lock, flags);
> + current_state = cp->enabled;
> + spin_unlock_irqrestore(&priv->lock, flags);
> +
> + if (current_state == enable)
> + return 0;
> +
> + /* disable_irq() may sleep, so it can not run under the spinlock. */
> + if (enable) {
> + spin_lock_irqsave(&priv->lock, flags);
> + priv->prev_a = !!gpiod_get_value(priv->gpio_a);
> + priv->prev_b = !!gpiod_get_value(priv->gpio_b);
[Severity: Medium]
Does enabling a count unconditionally overwrite the shared quadrature state,
corrupting the active state machine of the other running count?
Because priv->prev_a and priv->prev_b are updated here whenever any count is
enabled, enabling Count 2 while Count 1 is actively running will overwrite
Count 1's state tracker.
If an edge interrupt was pending for Count 1, its ISR might observe no state
change and incorrectly drop the step.
> + cp->enabled = true;
> + spin_unlock_irqrestore(&priv->lock, flags);
> + gpio_counter_enable_irqs(priv, count->id);
> + } else {
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260628210241.119825-1-wafgo01@gmail.com?part=2
next prev parent reply other threads:[~2026-06-28 21:13 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-28 21:02 [PATCH v6 0/3] counter: add GPIO-based counter driver Wadim Mueller
2026-06-28 21:02 ` [PATCH v6 1/3] dt-bindings: counter: add gpio-counter binding Wadim Mueller
2026-06-28 21:02 ` [PATCH v6 2/3] counter: add GPIO-based counter driver Wadim Mueller
2026-06-28 21:13 ` sashiko-bot [this message]
2026-06-28 21:02 ` [PATCH v6 3/3] MAINTAINERS: add entry for GPIO " Wadim Mueller
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=20260628211330.0F3A31F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=robh@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=wafgo01@gmail.com \
/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