From: Anup Patel <apatel@ventanamicro.com>
To: Thomas Gleixner <tglx@linutronix.de>
Cc: Marc Zyngier <maz@kernel.org>, Shawn Guo <shawnguo@kernel.org>,
Sascha Hauer <s.hauer@pengutronix.de>,
Pengutronix Kernel Team <kernel@pengutronix.de>,
Andrew Lunn <andrew@lunn.ch>,
Gregory Clement <gregory.clement@bootlin.com>,
Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>,
Palmer Dabbelt <palmer@dabbelt.com>,
Paul Walmsley <paul.walmsley@sifive.com>,
Atish Patra <atishp@atishpatra.org>,
Andrew Jones <ajones@ventanamicro.com>,
Sunil V L <sunilvl@ventanamicro.com>,
Anup Patel <anup@brainfault.org>,
linux-riscv@lists.infradead.org,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, imx@lists.linux.dev,
Anup Patel <apatel@ventanamicro.com>
Subject: [PATCH v3 01/10] irqchip/riscv-imsic: Handle non-atomic MSI updates for device
Date: Tue, 4 Feb 2025 13:23:56 +0530 [thread overview]
Message-ID: <20250204075405.824721-2-apatel@ventanamicro.com> (raw)
In-Reply-To: <20250204075405.824721-1-apatel@ventanamicro.com>
Device having non-atomic MSI update might see an intermediate
state when changing target IMSIC vector from one CPU to another.
To handle such intermediate device state, update MSI address
and MSI data through separate MSI writes to the device.
Fixes: 027e125acdba ("irqchip/riscv-imsic: Add device MSI domain support for platform devices")
Suggested-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
drivers/irqchip/irq-riscv-imsic-early.c | 8 +++-
drivers/irqchip/irq-riscv-imsic-platform.c | 27 ++++++++++++
drivers/irqchip/irq-riscv-imsic-state.c | 50 ++++++++++++++--------
drivers/irqchip/irq-riscv-imsic-state.h | 2 +-
4 files changed, 68 insertions(+), 19 deletions(-)
diff --git a/drivers/irqchip/irq-riscv-imsic-early.c b/drivers/irqchip/irq-riscv-imsic-early.c
index c5c2e6929a2f..73a93ce8668f 100644
--- a/drivers/irqchip/irq-riscv-imsic-early.c
+++ b/drivers/irqchip/irq-riscv-imsic-early.c
@@ -77,6 +77,12 @@ static void imsic_handle_irq(struct irq_desc *desc)
struct imsic_vector *vec;
unsigned long local_id;
+ /*
+ * First process pending IMSIC vector enable, disable and movement
+ * on the current CPU.
+ */
+ imsic_local_sync_all(false);
+
chained_irq_enter(chip, desc);
while ((local_id = csr_swap(CSR_TOPEI, 0))) {
@@ -120,7 +126,7 @@ static int imsic_starting_cpu(unsigned int cpu)
* Interrupts identities might have been enabled/disabled while
* this CPU was not running so sync-up local enable/disable state.
*/
- imsic_local_sync_all();
+ imsic_local_sync_all(true);
/* Enable local interrupt delivery */
imsic_local_delivery(true);
diff --git a/drivers/irqchip/irq-riscv-imsic-platform.c b/drivers/irqchip/irq-riscv-imsic-platform.c
index c708780e8760..b44eb0b3990b 100644
--- a/drivers/irqchip/irq-riscv-imsic-platform.c
+++ b/drivers/irqchip/irq-riscv-imsic-platform.c
@@ -97,6 +97,7 @@ static int imsic_irq_set_affinity(struct irq_data *d, const struct cpumask *mask
{
struct imsic_vector *old_vec, *new_vec;
struct irq_data *pd = d->parent_data;
+ struct imsic_vector tmp_vec;
old_vec = irq_data_get_irq_chip_data(pd);
if (WARN_ON(!old_vec))
@@ -115,6 +116,32 @@ static int imsic_irq_set_affinity(struct irq_data *d, const struct cpumask *mask
if (!new_vec)
return -ENOSPC;
+ /*
+ * Device having non-atomic MSI update might see an intermediate
+ * state when changing target IMSIC vector from one CPU to another.
+ *
+ * To avoid losing interrupt to some intermediate state, do the
+ * following (just like x86 APIC):
+ *
+ * 1) First write a temporary IMSIC vector to the device which
+ * has MSI address same as the old IMSIC vector but MSI data
+ * matches the new IMSIC vector.
+ *
+ * 2) Next write the new IMSIC vector to the device.
+ *
+ * Based on the above, the __imsic_local_sync() must check both
+ * old MSI data and new MSI data on the old CPU for pending
+ */
+
+ if (new_vec->local_id != old_vec->local_id) {
+ /* Setup temporary vector */
+ tmp_vec.cpu = old_vec->cpu;
+ tmp_vec.local_id = new_vec->local_id;
+
+ /* Point device to the temporary vector */
+ imsic_msi_update_msg(d, &tmp_vec);
+ }
+
/* Point device to the new vector */
imsic_msi_update_msg(d, new_vec);
diff --git a/drivers/irqchip/irq-riscv-imsic-state.c b/drivers/irqchip/irq-riscv-imsic-state.c
index b97e6cd89ed7..a8645084bd8f 100644
--- a/drivers/irqchip/irq-riscv-imsic-state.c
+++ b/drivers/irqchip/irq-riscv-imsic-state.c
@@ -126,21 +126,21 @@ void __imsic_eix_update(unsigned long base_id, unsigned long num_id, bool pend,
static void __imsic_local_sync(struct imsic_local_priv *lpriv)
{
- struct imsic_local_config *mlocal;
- struct imsic_vector *vec, *mvec;
+ struct imsic_local_config *tlocal, *mlocal;
+ struct imsic_vector *vec, *tvec, *mvec;
int i;
lockdep_assert_held(&lpriv->lock);
for_each_set_bit(i, lpriv->dirty_bitmap, imsic->global.nr_ids + 1) {
if (!i || i == IMSIC_IPI_ID)
- goto skip;
+ continue;
vec = &lpriv->vectors[i];
if (READ_ONCE(vec->enable))
- __imsic_id_set_enable(i);
+ __imsic_id_set_enable(vec->local_id);
else
- __imsic_id_clear_enable(i);
+ __imsic_id_clear_enable(vec->local_id);
/*
* If the ID was being moved to a new ID on some other CPU
@@ -151,26 +151,47 @@ static void __imsic_local_sync(struct imsic_local_priv *lpriv)
mvec = READ_ONCE(vec->move);
WRITE_ONCE(vec->move, NULL);
if (mvec && mvec != vec) {
- if (__imsic_id_read_clear_pending(i)) {
+ /*
+ * Device having non-atomic MSI update might see an
+ * intermediate state so check both old ID and new ID
+ * for pending interrupts.
+ *
+ * For details, refer imsic_irq_set_affinity().
+ */
+
+ tvec = vec->local_id == mvec->local_id ?
+ NULL : &lpriv->vectors[mvec->local_id];
+ if (tvec && __imsic_id_read_clear_pending(tvec->local_id)) {
+ /* Retrigger temporary vector if it was already in-use */
+ if (READ_ONCE(tvec->enable)) {
+ tlocal = per_cpu_ptr(imsic->global.local, tvec->cpu);
+ writel_relaxed(tvec->local_id, tlocal->msi_va);
+ }
+
mlocal = per_cpu_ptr(imsic->global.local, mvec->cpu);
writel_relaxed(mvec->local_id, mlocal->msi_va);
}
- imsic_vector_free(&lpriv->vectors[i]);
+ if (__imsic_id_read_clear_pending(vec->local_id)) {
+ mlocal = per_cpu_ptr(imsic->global.local, mvec->cpu);
+ writel_relaxed(mvec->local_id, mlocal->msi_va);
+ }
+
+ imsic_vector_free(vec);
}
-skip:
- bitmap_clear(lpriv->dirty_bitmap, i, 1);
+ bitmap_clear(lpriv->dirty_bitmap, vec->local_id, 1);
}
}
-void imsic_local_sync_all(void)
+void imsic_local_sync_all(bool force_all)
{
struct imsic_local_priv *lpriv = this_cpu_ptr(imsic->lpriv);
unsigned long flags;
raw_spin_lock_irqsave(&lpriv->lock, flags);
- bitmap_fill(lpriv->dirty_bitmap, imsic->global.nr_ids + 1);
+ if (force_all)
+ bitmap_fill(lpriv->dirty_bitmap, imsic->global.nr_ids + 1);
__imsic_local_sync(lpriv);
raw_spin_unlock_irqrestore(&lpriv->lock, flags);
}
@@ -190,12 +211,7 @@ void imsic_local_delivery(bool enable)
#ifdef CONFIG_SMP
static void imsic_local_timer_callback(struct timer_list *timer)
{
- struct imsic_local_priv *lpriv = this_cpu_ptr(imsic->lpriv);
- unsigned long flags;
-
- raw_spin_lock_irqsave(&lpriv->lock, flags);
- __imsic_local_sync(lpriv);
- raw_spin_unlock_irqrestore(&lpriv->lock, flags);
+ imsic_local_sync_all(false);
}
static void __imsic_remote_sync(struct imsic_local_priv *lpriv, unsigned int cpu)
diff --git a/drivers/irqchip/irq-riscv-imsic-state.h b/drivers/irqchip/irq-riscv-imsic-state.h
index 391e44280827..8fae6c99b019 100644
--- a/drivers/irqchip/irq-riscv-imsic-state.h
+++ b/drivers/irqchip/irq-riscv-imsic-state.h
@@ -74,7 +74,7 @@ static inline void __imsic_id_clear_enable(unsigned long id)
__imsic_eix_update(id, 1, false, false);
}
-void imsic_local_sync_all(void);
+void imsic_local_sync_all(bool force_all);
void imsic_local_delivery(bool enable);
void imsic_vector_mask(struct imsic_vector *vec);
--
2.43.0
next prev parent reply other threads:[~2025-02-04 7:57 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-04 7:53 [PATCH v3 00/10] RISC-V IMSIC driver improvements Anup Patel
2025-02-04 7:53 ` Anup Patel [this message]
2025-02-04 13:08 ` [PATCH v3 01/10] irqchip/riscv-imsic: Handle non-atomic MSI updates for device Thomas Gleixner
2025-02-04 14:51 ` Anup Patel
2025-02-04 7:53 ` [PATCH v3 02/10] irqchip/irq-msi-lib: Optionally set default irq_eoi/irq_ack Anup Patel
2025-02-04 7:53 ` [PATCH v3 03/10] irqchip/riscv-imsic: Set irq_set_affinity for IMSIC base Anup Patel
2025-02-04 7:53 ` [PATCH v3 04/10] irqchip/riscv-imsic: Move to common MSI lib Anup Patel
2025-02-04 7:54 ` [PATCH v3 05/10] genirq: Introduce common irq_force_complete_move() implementation Anup Patel
2025-02-04 7:54 ` [PATCH v3 06/10] RISC-V: Enable GENERIC_PENDING_IRQ and GENERIC_PENDING_IRQ_CHIPFLAGS Anup Patel
2025-02-04 7:54 ` [PATCH v3 07/10] irqchip/riscv-imsic: Separate next and previous pointers in IMSIC vector Anup Patel
2025-02-04 7:54 ` [PATCH v3 08/10] irqchip/riscv-imsic: Implement irq_force_complete_move() for IMSIC Anup Patel
2025-02-04 7:54 ` [PATCH v3 09/10] irqchip/riscv-imsic: Replace hwirq with irq in the IMSIC vector Anup Patel
2025-02-04 7:54 ` [PATCH v3 10/10] irqchip/riscv-imsic: Use IRQCHIP_MOVE_DEFERRED flag for PCI devices Anup Patel
2025-02-04 8:56 ` Thomas Gleixner
2025-02-04 14:49 ` Anup Patel
2025-02-04 15:20 ` Thomas Gleixner
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=20250204075405.824721-2-apatel@ventanamicro.com \
--to=apatel@ventanamicro.com \
--cc=ajones@ventanamicro.com \
--cc=andrew@lunn.ch \
--cc=anup@brainfault.org \
--cc=atishp@atishpatra.org \
--cc=gregory.clement@bootlin.com \
--cc=imx@lists.linux.dev \
--cc=kernel@pengutronix.de \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=maz@kernel.org \
--cc=palmer@dabbelt.com \
--cc=paul.walmsley@sifive.com \
--cc=s.hauer@pengutronix.de \
--cc=sebastian.hesselbarth@gmail.com \
--cc=shawnguo@kernel.org \
--cc=sunilvl@ventanamicro.com \
--cc=tglx@linutronix.de \
/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;
as well as URLs for NNTP newsgroup(s).