mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: "tip-bot2 for Anup Patel" <tip-bot2@linutronix.de>
To: linux-tip-commits@vger.kernel.org
Cc: Anup Patel <apatel@ventanamicro.com>,
	Thomas Gleixner <tglx@linutronix.de>,
	x86@kernel.org, linux-kernel@vger.kernel.org
Subject: [tip: irq/drivers] irqchip/riscv-imsic: Special handling for non-atomic device MSI update
Date: Tue, 18 Feb 2025 09:03:43 -0000	[thread overview]
Message-ID: <173986942354.10177.15967997754963748971.tip-bot2@tip-bot2> (raw)
In-Reply-To: <20250217085657.789309-11-apatel@ventanamicro.com>

The following commit has been merged into the irq/drivers branch of tip:

Commit-ID:     46b9ba2ac09003d0a09f2f730b64cae03af29041
Gitweb:        https://git.kernel.org/tip/46b9ba2ac09003d0a09f2f730b64cae03af29041
Author:        Anup Patel <apatel@ventanamicro.com>
AuthorDate:    Mon, 17 Feb 2025 14:26:56 +05:30
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Tue, 18 Feb 2025 09:51:02 +01:00

irqchip/riscv-imsic: Special handling for non-atomic device MSI update

Devices, which have a non-atomic MSI update, might see an intermediate
state when changing the target IMSIC vector from one CPU to another.

To avoid losing interrupts due to this intermediate state, do the following
just like x86 APIC:

 1) First write a temporary IMSIC vector to the device which has the same
    MSI address as the old IMSIC vector and MSI data pointing to the new
    IMSIC vector.

 2) Next write the new IMSIC vector to the device.

Based on the above, the __imsic_local_sync() must check pending status of
both old MSI data and new MSI data on the old CPU. In addition, the
movement of IMSIC vector for non-atomic device MSI update must be done in
interrupt context using IRQCHIP_MOVE_DEFERRED.

Implememnt the logic and enforce the chip flag for PCI/MSI[X].

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/all/20250217085657.789309-11-apatel@ventanamicro.com
---
 drivers/irqchip/irq-riscv-imsic-platform.c | 87 ++++++++++++++++++---
 drivers/irqchip/irq-riscv-imsic-state.c    | 30 ++++++-
 2 files changed, 102 insertions(+), 15 deletions(-)

diff --git a/drivers/irqchip/irq-riscv-imsic-platform.c b/drivers/irqchip/irq-riscv-imsic-platform.c
index 6bf5d63..b8ae67c 100644
--- a/drivers/irqchip/irq-riscv-imsic-platform.c
+++ b/drivers/irqchip/irq-riscv-imsic-platform.c
@@ -64,6 +64,11 @@ static int imsic_irq_retrigger(struct irq_data *d)
 	return 0;
 }
 
+static void imsic_irq_ack(struct irq_data *d)
+{
+	irq_move_irq(d);
+}
+
 static void imsic_irq_compose_vector_msg(struct imsic_vector *vec, struct msi_msg *msg)
 {
 	phys_addr_t msi_addr;
@@ -97,6 +102,21 @@ static int imsic_irq_set_affinity(struct irq_data *d, const struct cpumask *mask
 				  bool force)
 {
 	struct imsic_vector *old_vec, *new_vec;
+	struct imsic_vector tmp_vec;
+
+	/*
+	 * Requirements for the downstream irqdomains (or devices):
+	 *
+	 * 1) Downstream irqdomains (or devices) with atomic MSI update can
+	 *    happily do imsic_irq_set_affinity() in the process-context on
+	 *    any CPU so the irqchip of such irqdomains must not set the
+	 *    IRQCHIP_MOVE_DEFERRED flag.
+	 *
+	 * 2) Downstream irqdomains (or devices) with non-atomic MSI update
+	 *    must use imsic_irq_set_affinity() in nterrupt-context upon
+	 *    the next device interrupt so the irqchip of such irqdomains
+	 *    must set the IRQCHIP_MOVE_DEFERRED flag.
+	 */
 
 	old_vec = irq_data_get_irq_chip_data(d);
 	if (WARN_ON(!old_vec))
@@ -115,6 +135,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 such 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, __imsic_local_sync() must check pending
+	 * status of both old MSI data and new MSI data on the old CPU.
+	 */
+	if (!irq_can_move_in_process_context(d) &&
+	    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(irq_get_irq_data(d->irq), &tmp_vec);
+	}
+
 	/* Point device to the new vector */
 	imsic_msi_update_msg(irq_get_irq_data(d->irq), new_vec);
 
@@ -163,17 +209,17 @@ static void imsic_irq_force_complete_move(struct irq_data *d)
 #endif
 
 static struct irq_chip imsic_irq_base_chip = {
-	.name			= "IMSIC",
-	.irq_mask		= imsic_irq_mask,
-	.irq_unmask		= imsic_irq_unmask,
+	.name				= "IMSIC",
+	.irq_mask			= imsic_irq_mask,
+	.irq_unmask			= imsic_irq_unmask,
 #ifdef CONFIG_SMP
-	.irq_set_affinity	= imsic_irq_set_affinity,
-	.irq_force_complete_move = imsic_irq_force_complete_move,
+	.irq_set_affinity		= imsic_irq_set_affinity,
+	.irq_force_complete_move	= imsic_irq_force_complete_move,
 #endif
-	.irq_retrigger		= imsic_irq_retrigger,
-	.irq_compose_msi_msg	= imsic_irq_compose_msg,
-	.flags			= IRQCHIP_SKIP_SET_WAKE |
-				  IRQCHIP_MASK_ON_SUSPEND,
+	.irq_retrigger			= imsic_irq_retrigger,
+	.irq_ack			= imsic_irq_ack,
+	.irq_compose_msi_msg		= imsic_irq_compose_msg,
+	.flags				= IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND,
 };
 
 static int imsic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
@@ -190,7 +236,7 @@ static int imsic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
 		return -ENOSPC;
 
 	irq_domain_set_info(domain, virq, virq, &imsic_irq_base_chip, vec,
-			    handle_simple_irq, NULL, NULL);
+			    handle_edge_irq, NULL, NULL);
 	irq_set_noprobe(virq);
 	irq_set_affinity(virq, cpu_online_mask);
 	irq_data_update_effective_affinity(irq_get_irq_data(virq), cpumask_of(vec->cpu));
@@ -229,15 +275,34 @@ static const struct irq_domain_ops imsic_base_domain_ops = {
 #endif
 };
 
+static bool imsic_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
+				    struct irq_domain *real_parent, struct msi_domain_info *info)
+{
+	if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info))
+		return false;
+
+	switch (info->bus_token) {
+	case DOMAIN_BUS_PCI_DEVICE_MSI:
+	case DOMAIN_BUS_PCI_DEVICE_MSIX:
+		info->chip->flags |= IRQCHIP_MOVE_DEFERRED;
+		break;
+	default:
+		break;
+	}
+
+	return true;
+}
+
 static const struct msi_parent_ops imsic_msi_parent_ops = {
 	.supported_flags	= MSI_GENERIC_FLAGS_MASK |
 				  MSI_FLAG_PCI_MSIX,
 	.required_flags		= MSI_FLAG_USE_DEF_DOM_OPS |
 				  MSI_FLAG_USE_DEF_CHIP_OPS |
 				  MSI_FLAG_PCI_MSI_MASK_PARENT,
+	.chip_flags		= MSI_CHIP_FLAG_SET_ACK,
 	.bus_select_token	= DOMAIN_BUS_NEXUS,
 	.bus_select_mask	= MATCH_PCI_MSI | MATCH_PLATFORM_MSI,
-	.init_dev_msi_info	= msi_lib_init_dev_msi_info,
+	.init_dev_msi_info	= imsic_init_dev_msi_info,
 };
 
 int imsic_irqdomain_init(void)
diff --git a/drivers/irqchip/irq-riscv-imsic-state.c b/drivers/irqchip/irq-riscv-imsic-state.c
index b0849af..bdf5cd2 100644
--- a/drivers/irqchip/irq-riscv-imsic-state.c
+++ b/drivers/irqchip/irq-riscv-imsic-state.c
@@ -126,8 +126,8 @@ void __imsic_eix_update(unsigned long base_id, unsigned long num_id, bool pend, 
 
 static bool __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;
 	bool ret = true;
 	int i;
 
@@ -169,13 +169,35 @@ static bool __imsic_local_sync(struct imsic_local_priv *lpriv)
 		 */
 		mvec = READ_ONCE(vec->move_next);
 		if (mvec) {
-			if (__imsic_id_read_clear_pending(i)) {
+			/*
+			 * Devices having non-atomic MSI update might see
+			 * an intermediate state so check both old ID and
+			 * new ID for pending interrupts.
+			 *
+			 * For details, see imsic_irq_set_affinity().
+			 */
+			tvec = vec->local_id == mvec->local_id ?
+				NULL : &lpriv->vectors[mvec->local_id];
+
+			if (tvec && !irq_can_move_in_process_context(irq_get_irq_data(vec->irq)) &&
+			    __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);
+			}
+
+			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);
 			}
 
 			WRITE_ONCE(vec->move_next, NULL);
-			imsic_vector_free(&lpriv->vectors[i]);
+			imsic_vector_free(vec);
 		}
 
 skip:

  reply	other threads:[~2025-02-18  9:03 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-02-17  8:56 [PATCH v6 00/10] RISC-V IMSIC driver improvements Anup Patel
2025-02-17  8:56 ` [PATCH v6 01/10] irqchip/riscv-imsic: Set irq_set_affinity for IMSIC base Anup Patel
2025-02-18  9:03   ` [tip: irq/drivers] irqchip/riscv-imsic: Set irq_set_affinity() " tip-bot2 for Andrew Jones
2025-02-17  8:56 ` [PATCH v6 02/10] irqchip/irq-msi-lib: Optionally set default irq_eoi/irq_ack Anup Patel
2025-02-18  9:03   ` [tip: irq/drivers] irqchip/irq-msi-lib: Optionally set default irq_eoi()/irq_ack() tip-bot2 for Thomas Gleixner
2025-02-19 14:41   ` [PATCH v6 02/10] irqchip/irq-msi-lib: Optionally set default irq_eoi/irq_ack Mark Brown
2025-02-20 13:54     ` Thomas Gleixner
2025-02-20 14:21       ` Thomas Gleixner
2025-02-20 14:26   ` [tip: irq/drivers] irqchip/irq-msi-lib: Optionally set default irq_eoi()/irq_ack() tip-bot2 for Thomas Gleixner
2025-02-17  8:56 ` [PATCH v6 03/10] irqchip/riscv-imsic: Move to common MSI lib Anup Patel
2025-02-18  9:03   ` [tip: irq/drivers] irqchip/riscv-imsic: Move to common MSI library tip-bot2 for Thomas Gleixner
2025-02-20 14:26   ` tip-bot2 for Thomas Gleixner
2025-02-17  8:56 ` [PATCH v6 04/10] genirq: Introduce common irq_force_complete_move() implementation Anup Patel
2025-02-18  9:03   ` [tip: irq/drivers] " tip-bot2 for Thomas Gleixner
2025-02-20 14:26   ` tip-bot2 for Thomas Gleixner
2025-04-03 13:13   ` [PATCH v6 04/10] " Frank Scheiner
2025-04-03 15:03     ` Thomas Gleixner
2025-04-03 17:46       ` Frank Scheiner
2025-04-04 14:51         ` [PATCH] genirq/migration: Use irqd_get_parent_data() in irq_force_complete_move() Thomas Gleixner
2025-04-04 15:14           ` [tip: irq/urgent] " tip-bot2 for Thomas Gleixner
2025-02-17  8:56 ` [PATCH v6 05/10] genirq: Introduce irq_can_move_in_process_context() Anup Patel
2025-02-18  9:03   ` [tip: irq/drivers] " tip-bot2 for Anup Patel
2025-02-20 14:26   ` tip-bot2 for Anup Patel
2025-02-17  8:56 ` [PATCH v6 06/10] RISC-V: Select GENERIC_PENDING_IRQ Anup Patel
2025-02-18  9:03   ` [tip: irq/drivers] RISC-V: Select CONFIG_GENERIC_PENDING_IRQ tip-bot2 for Anup Patel
2025-02-20 14:26   ` tip-bot2 for Anup Patel
2025-02-17  8:56 ` [PATCH v6 07/10] irqchip/riscv-imsic: Separate next and previous pointers in IMSIC vector Anup Patel
2025-02-18  9:03   ` [tip: irq/drivers] " tip-bot2 for Anup Patel
2025-02-20 14:26   ` tip-bot2 for Anup Patel
2025-02-17  8:56 ` [PATCH v6 08/10] irqchip/riscv-imsic: Implement irq_force_complete_move() for IMSIC Anup Patel
2025-02-18  9:03   ` [tip: irq/drivers] " tip-bot2 for Anup Patel
2025-02-20 14:26   ` tip-bot2 for Anup Patel
2025-02-17  8:56 ` [PATCH v6 09/10] irqchip/riscv-imsic: Replace hwirq with irq in the IMSIC vector Anup Patel
2025-02-18  9:03   ` [tip: irq/drivers] irqchip/riscv-imsic: Avoid interrupt translation in interrupt handler tip-bot2 for Anup Patel
2025-02-20 14:26   ` tip-bot2 for Anup Patel
2025-02-17  8:56 ` [PATCH v6 10/10] irqchip/riscv-imsic: Special handling for non-atomic device MSI update Anup Patel
2025-02-18  9:03   ` tip-bot2 for Anup Patel [this message]
2025-02-20 14:26   ` [tip: irq/drivers] " tip-bot2 for Anup Patel

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=173986942354.10177.15967997754963748971.tip-bot2@tip-bot2 \
    --to=tip-bot2@linutronix.de \
    --cc=apatel@ventanamicro.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-tip-commits@vger.kernel.org \
    --cc=tglx@linutronix.de \
    --cc=x86@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®