All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Runyu Xiao" <runyu.xiao@seu.edu.cn>
Cc: linux-rt-devel@lists.linux.dev, linux-kernel@vger.kernel.org
Subject: Re: [PATCH 2/2] gpio: eic-sprd: use raw_spinlock_t in the irq startup path
Date: Wed, 17 Jun 2026 20:32:48 +0000	[thread overview]
Message-ID: <20260617203248.6EB581F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260617154035.1199948-3-runyu.xiao@seu.edu.cn>

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:

Pre-existing issues:
- [Critical] Potential NULL pointer dereference in `sprd_eic_toggle_trigger` for unmapped or spurious hardware interrupts.
- [High] `sprd_eic_toggle_trigger` fails to properly toggle polarity for `SPRD_EIC_LATCH` because `sprd_eic_get` returns `-ENOTSUPP`.
- [High] Potential hardirq livelock and console spam due to `dev_warn` inside a retry loop in `sprd_eic_toggle_trigger`.
- [High] Unbinding one EIC instance breaks all other EIC instances because they share the same parent IRQ chained handler.
- [High] sprd_eic_toggle_trigger modifies interrupt masks unconditionally without holding desc->lock, creating a race condition with disable_irq().
--

commit 69e3dda6e9ba1a662342eec6f6b0ec04beeadc64
Author: Runyu Xiao <runyu.xiao@seu.edu.cn>

gpio: eic-sprd: use raw_spinlock_t in the irq startup path

sprd_eic_irq_unmask() enables the GPIO IRQ and then updates controller
state through sprd_eic_update(), which takes sprd_eic->lock with
spin_lock_irqsave(). The callback can be reached from irq_startup()
while setting up a requested IRQ, which is not sleepable on PREEMPT_RT.
This patch converts the lock to raw_spinlock_t to avoid sleeping.

> diff --git a/drivers/gpio/gpio-eic-sprd.c b/drivers/gpio/gpio-eic-sprd.c
> index 50fafeda8d7e2..3b7ebcf12fe7f 100644
> --- a/drivers/gpio/gpio-eic-sprd.c
> +++ b/drivers/gpio/gpio-eic-sprd.c
[ ... ]
> @@ -149,7 +149,7 @@ static void sprd_eic_update(struct gpio_chip *chip, unsigned int offset,
>  	unsigned long flags;
>  	u32 tmp;
>  
> -	spin_lock_irqsave(&sprd_eic->lock, flags);
> +	raw_spin_lock_irqsave(&sprd_eic->lock, flags);
>  	tmp = readl_relaxed(base + reg);
>  
>  	if (val)
> @@ -158,7 +158,7 @@ static void sprd_eic_update(struct gpio_chip *chip, unsigned int offset,
>  		tmp &= ~BIT(SPRD_EIC_BIT(offset));
>  
>  	writel_relaxed(tmp, base + reg);
> -	spin_unlock_irqrestore(&sprd_eic->lock, flags);
> +	raw_spin_unlock_irqrestore(&sprd_eic->lock, flags);
>  }

[Severity: Critical]
This is a pre-existing issue, but can sprd_eic_handle_one_type() cause a
NULL pointer dereference for unmapped or spurious hardware interrupts?

If an interrupt is unmapped, irq_find_mapping() returns 0:

drivers/gpio/gpio-eic-sprd.c:sprd_eic_handle_one_type() {
    ...
    girq = irq_find_mapping(chip->irq.domain, offset);
    generic_handle_irq(girq);
    sprd_eic_toggle_trigger(chip, girq, offset);
}

The girq value 0 is then passed into sprd_eic_toggle_trigger():

drivers/gpio/gpio-eic-sprd.c:sprd_eic_toggle_trigger() {
    ...
    struct irq_data *data = irq_get_irq_data(irq);
    u32 trigger = irqd_get_trigger_type(data);
    ...
}

Calling irq_get_irq_data(0) returns NULL, which causes irqd_get_trigger_type()
to dereference NULL. Can this path be triggered by the bootloader leaving an
interrupt unmasked?

[Severity: High]
This is a pre-existing issue, but does sprd_eic_toggle_trigger() race with
disable_irq() since it alters the hardware mask without holding the
descriptor lock?

Looking at sprd_eic_toggle_trigger(), it unconditionally calls
sprd_eic_irq_unmask() after returning from an interrupt handler:

drivers/gpio/gpio-eic-sprd.c:sprd_eic_toggle_trigger() {
    ...
    sprd_eic_irq_mask(data);
    ...
    sprd_eic_irq_unmask(data);
}

If a concurrent thread calls disable_irq(), which holds desc->lock and masks
the hardware, sprd_eic_toggle_trigger() could execute immediately afterward and
unmask it again without checking irqd_irq_disabled(data). Can this leave the
system vulnerable to unhandled interrupt storms?

[Severity: High]
This is a pre-existing issue, but does sprd_eic_toggle_trigger() have a
potential hardirq livelock and console spam issue?

If the line state changes, the code logs a warning and retries endlessly:

drivers/gpio/gpio-eic-sprd.c:sprd_eic_toggle_trigger() {
    ...
retry:
    ...
    post_state = sprd_eic_get(chip, offset);
    if (state != post_state) {
        dev_warn(chip->parent, "EIC level was changed.\n");
        state = post_state;
        goto retry;
    }
}

Since this runs in the context of a cascaded interrupt handler, if the input
line oscillates rapidly, will the dev_warn() overhead inside a tight loop
cause lockups and watchdog panics without any retry bounds?

[Severity: High]
This is a pre-existing issue, but does SPRD_EIC_LATCH fail to toggle polarity?

In sprd_eic_toggle_trigger(), the state is used to set the latch polarity:

drivers/gpio/gpio-eic-sprd.c:sprd_eic_toggle_trigger() {
    ...
    state = sprd_eic_get(chip, offset);
    ...
    case SPRD_EIC_LATCH:
        if (state)
            sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 0);
        else
            sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 1);
        break;
}

However, sprd_eic_get() doesn't implement reading for SPRD_EIC_LATCH
and returns -ENOTSUPP. This negative value evaluates as true, meaning the
code will always execute the true branch and never toggle to 1. Will this
cause LATCH EICs to become permanently stuck?

[ ... ]
> @@ -628,7 +628,7 @@ static int sprd_eic_probe(struct platform_device *pdev)
>  	if (!sprd_eic)
>  		return -ENOMEM;
>  
> -	spin_lock_init(&sprd_eic->lock);
> +	raw_spin_lock_init(&sprd_eic->lock);
>  	sprd_eic->type = pdata->type;
>  
>  	sprd_eic->irq = platform_get_irq(pdev, 0);

[Severity: High]
This is a pre-existing issue, but will unbinding one EIC instance break all
other EIC instances?

During probe, each instance sets its parent handler to sprd_eic_irq_handler
on the shared parent IRQ:

drivers/gpio/gpio-eic-sprd.c:sprd_eic_probe() {
    ...
    irq->parent_handler = sprd_eic_irq_handler;
    irq->parent_handler_data = sprd_eic;
    irq->num_parents = 1;
    irq->parents = &sprd_eic->irq;
    ...
}

If any single EIC instance is unbound, gpiolib's cleanup routine calls
irq_set_chained_handler_and_data(parent, NULL, NULL), clearing the shared
parent handler entirely. Will this leave the remaining EIC instances
completely non-functional?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260617154035.1199948-1-runyu.xiao@seu.edu.cn?part=2

      reply	other threads:[~2026-06-17 20:32 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-17 15:40 [PATCH 0/2] gpio: use raw spinlocks in irq startup paths Runyu Xiao
2026-06-17 15:40 ` [PATCH 1/2] gpio: sch: use raw_spinlock_t in the irq startup path Runyu Xiao
2026-06-17 15:57   ` Andy Shevchenko
2026-06-17 20:21   ` sashiko-bot
2026-06-17 15:40 ` [PATCH 2/2] gpio: eic-sprd: " Runyu Xiao
2026-06-17 20:32   ` 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=20260617203248.6EB581F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rt-devel@lists.linux.dev \
    --cc=runyu.xiao@seu.edu.cn \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.