From: Marc Zyngier <maz@kernel.org>
To: Linus Walleij <linus.walleij@linaro.org>
Cc: "Pali Rohár" <pali@kernel.org>,
"Lorenzo Pieralisi" <lorenzo.pieralisi@arm.com>,
"Rob Herring" <robh@kernel.org>,
linux-pci <linux-pci@vger.kernel.org>,
linux-kernel <linux-kernel@vger.kernel.org>
Subject: Re: pci-ftpci100: race condition in masking/unmasking interrupts
Date: Tue, 07 Sep 2021 17:53:54 +0100 [thread overview]
Message-ID: <87czpkconx.wl-maz@kernel.org> (raw)
In-Reply-To: <CACRpkdYe-Y-1YstovrJd7b8iNCDeX312mB4gLGcG1y6dE6di=A@mail.gmail.com>
Hi Linus,
On Tue, 07 Sep 2021 12:22:37 +0100,
Linus Walleij <linus.walleij@linaro.org> wrote:
>
> On Wed, Aug 18, 2021 at 1:47 PM Pali Rohár <pali@kernel.org> wrote:
>
> > I do not see any entry in MAINTAINERS file for pci-ftpci100.c driver, so
> > I'm not sure to whom should I address this issue...
>
> It's me.
>
> > During pci-aardvark review, Marc pointed one issue which is currently
> > available also in pci-ftpci100.c driver.
> >
> > When masking or unmasking interrupts there is read-modify-write sequence
> > for FARADAY_PCI_CTRL2 register without any locking and is not atomic:
> >
> > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/pci/controller/pci-ftpci100.c?h=v5.13#n270
> >
> > So there is race condition when masking/unmasking more interrupts at the
> > same time.
>
> I thought those operations were called in atomic context.
> How did you fix it?
They are.
But that doesn't mean that you cannot have two CPUs dealing with two
different interrupts at the same time (using disable_irq(), for
example). When that happens, your interrupt masking becomes a bit
soup. irq_ack() also gets in the way, as it does a RMW of the same
register. If the underlying HW is strictly UP, you're safe. But even
in this case, you could have some locking that gets elided at compile
time.
I also don't understand why you always clear the interrupt status
every time you mask/unmask an interrupt.
I came up with the following patchlet, which is completely untested
(not even compile-tested).
Thanks,
M.
diff --git a/drivers/pci/controller/pci-ftpci100.c b/drivers/pci/controller/pci-ftpci100.c
index 88980a44461d..dd1697e61206 100644
--- a/drivers/pci/controller/pci-ftpci100.c
+++ b/drivers/pci/controller/pci-ftpci100.c
@@ -120,6 +120,7 @@ struct faraday_pci_variant {
};
struct faraday_pci {
+ raw_spinlock_t lock
struct device *dev;
void __iomem *base;
struct irq_domain *irqdomain;
@@ -270,34 +271,41 @@ static struct pci_ops faraday_pci_ops = {
static void faraday_pci_ack_irq(struct irq_data *d)
{
struct faraday_pci *p = irq_data_get_irq_chip_data(d);
+ unsigned long flags;
unsigned int reg;
+ raw_spin_lock_irqsave(&p->lock, flags);
faraday_raw_pci_read_config(p, 0, 0, FARADAY_PCI_CTRL2, 4, ®);
reg &= ~(0xF << PCI_CTRL2_INTSTS_SHIFT);
reg |= BIT(irqd_to_hwirq(d) + PCI_CTRL2_INTSTS_SHIFT);
faraday_raw_pci_write_config(p, 0, 0, FARADAY_PCI_CTRL2, 4, reg);
+ raw_spin_unlock_irqrestore(&p->lock, flags);
}
static void faraday_pci_mask_irq(struct irq_data *d)
{
struct faraday_pci *p = irq_data_get_irq_chip_data(d);
+ unsigned long flags;
unsigned int reg;
+ raw_spin_lock_irqsave(&p->lock, flags);
faraday_raw_pci_read_config(p, 0, 0, FARADAY_PCI_CTRL2, 4, ®);
- reg &= ~((0xF << PCI_CTRL2_INTSTS_SHIFT)
- | BIT(irqd_to_hwirq(d) + PCI_CTRL2_INTMASK_SHIFT));
+ reg &= ~BIT(irqd_to_hwirq(d) + PCI_CTRL2_INTMASK_SHIFT);
faraday_raw_pci_write_config(p, 0, 0, FARADAY_PCI_CTRL2, 4, reg);
+ raw_spin_unlock_irqrestore(&p->lock, flags);
}
static void faraday_pci_unmask_irq(struct irq_data *d)
{
struct faraday_pci *p = irq_data_get_irq_chip_data(d);
+ unsigned long flags;
unsigned int reg;
+ raw_spin_lock_irqsave(&p->lock, flags);
faraday_raw_pci_read_config(p, 0, 0, FARADAY_PCI_CTRL2, 4, ®);
- reg &= ~(0xF << PCI_CTRL2_INTSTS_SHIFT);
reg |= BIT(irqd_to_hwirq(d) + PCI_CTRL2_INTMASK_SHIFT);
faraday_raw_pci_write_config(p, 0, 0, FARADAY_PCI_CTRL2, 4, reg);
+ raw_spin_unlock_irqrestore(&p->lock, flags);
}
static void faraday_pci_irq_handler(struct irq_desc *desc)
@@ -441,6 +449,8 @@ static int faraday_pci_probe(struct platform_device *pdev)
host->sysdata = p;
p->dev = dev;
+ raw_spin_lock_init(&p->lock);
+
/* Retrieve and enable optional clocks */
clk = devm_clk_get(dev, "PCLK");
if (IS_ERR(clk))
--
Without deviation from the norm, progress is not possible.
prev parent reply other threads:[~2021-09-07 16:53 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-08-18 11:47 pci-ftpci100: race condition in masking/unmasking interrupts Pali Rohár
2021-09-07 11:22 ` Linus Walleij
2021-09-07 12:20 ` Pali Rohár
2021-09-07 16:53 ` Marc Zyngier [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=87czpkconx.wl-maz@kernel.org \
--to=maz@kernel.org \
--cc=linus.walleij@linaro.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=lorenzo.pieralisi@arm.com \
--cc=pali@kernel.org \
--cc=robh@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 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.