Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / Atom feed
From: Mohamed Mediouni <mohamed.mediouni@caramail.com>
To: linux-arm-kernel@lists.infradead.org
Cc: Mark Rutland <mark.rutland@arm.com>,
	Catalin Marinas <catalin.marinas@arm.com>,
	Hector Martin <marcan@marcan.st>,
	linux-kernel@vger.kernel.org, Marc Zyngier <maz@kernel.org>,
	Mohamed Mediouni <mohamed.mediouni@caramail.com>,
	Will Deacon <will@kernel.org>,
	Stan Skowronek <stan@corellium.com>
Subject: [RFC PATCH 7/7] irqchip/apple-aic: add SMP support to the Apple AIC driver.
Date: Wed, 20 Jan 2021 14:27:17 +0100
Message-ID: <20210120132717.395873-8-mohamed.mediouni@caramail.com> (raw)
In-Reply-To: <20210120132717.395873-1-mohamed.mediouni@caramail.com>

From: Stan Skowronek <stan@corellium.com>

This includes IPI support and a workaround for non-working WFI on
Apple processors.

Signed-off-by: Stan Skowronek <stan@corellium.com>
Signed-off-by: Mohamed Mediouni <mohamed.mediouni@caramail.com>
---
 drivers/irqchip/irq-apple-aic.c | 177 +++++++++++++++++++++++++++++---
 1 file changed, 165 insertions(+), 12 deletions(-)

diff --git a/drivers/irqchip/irq-apple-aic.c b/drivers/irqchip/irq-apple-aic.c
index c601bc4b501a..ce4e39d56fcf 100644
--- a/drivers/irqchip/irq-apple-aic.c
+++ b/drivers/irqchip/irq-apple-aic.c
@@ -17,6 +17,7 @@

 #include <asm/exception.h>
 #include <asm/irq.h>
+#include <asm/smp.h>

 #define REG_ID_REVISION 0x0000
 #define REG_ID_CONFIG 0x0004
@@ -53,12 +54,17 @@
 #define REG_PERCPU(r, c)                                                       \
 	((r) + REG_CPU_REGION - REG_CPU_LOCAL + ((c) << REG_CPU_SHIFT))

+#define NUM_IPI 8
+
 static struct aic_chip_data {
 	void __iomem *base;
 	struct irq_domain *domain;
 	unsigned int num_irqs;
+	bool fast_ipi;
 } aic;

+static DEFINE_PER_CPU(atomic_t, aic_ipi_mask);
+
 static void apple_aic_irq_mask(struct irq_data *d)
 {
 	writel(REG_IRQ_xABLE_MASK(d->hwirq),
@@ -78,18 +84,71 @@ static struct irq_chip apple_aic_irq_chip = {
 	.irq_unmask = apple_aic_irq_unmask,
 };

-static void apple_aic_fiq_mask(struct irq_data *d)
+static void apple_aic_fiq_ipi_mask(struct irq_data *d)
 {
 }

-static void apple_aic_fiq_unmask(struct irq_data *d)
+static void apple_aic_fiq_ipi_unmask(struct irq_data *d)
 {
 }

 static struct irq_chip apple_aic_irq_chip_fiq = {
 	.name = "apple_aic_fiq",
-	.irq_mask = apple_aic_fiq_mask,
-	.irq_unmask = apple_aic_fiq_unmask,
+	.irq_mask = apple_aic_fiq_ipi_mask,
+	.irq_unmask = apple_aic_fiq_ipi_unmask,
+};
+
+#define SR_APPLE_IPI_LOCAL s3_5_c15_c0_0
+#define SR_APPLE_IPI_REMOTE s3_5_c15_c0_1
+#define SR_APPLE_IPI_STAT s3_5_c15_c1_1
+
+#ifdef CONFIG_SMP
+static void apple_aic_ipi_send_mask(struct irq_data *d,
+				    const struct cpumask *mask)
+{
+	int cpu, lcpu;
+	int irqnr = d->hwirq - (aic.num_irqs + 2);
+
+	if (WARN_ON(irqnr < 0 || irqnr >= NUM_IPI))
+		return;
+
+	/*
+     * Ensure that stores to Normal memory are visible to the
+     * other CPUs before issuing the IPI.
+     */
+	wmb();
+
+	for_each_cpu (cpu, mask) {
+		smp_mb__before_atomic();
+		atomic_or(1u << irqnr, per_cpu_ptr(&aic_ipi_mask, cpu));
+		smp_mb__after_atomic();
+		lcpu = get_cpu();
+		if (aic.fast_ipi) {
+			if ((lcpu >> 2) == (cpu >> 2))
+				write_sysreg(cpu & 3, SR_APPLE_IPI_LOCAL);
+			else
+				write_sysreg((cpu & 3) | ((cpu >> 2) << 16),
+					     SR_APPLE_IPI_REMOTE);
+		} else
+			writel(lcpu == cpu ? REG_IPI_FLAG_SELF :
+						   (REG_IPI_FLAG_OTHER << cpu),
+			       aic.base + REG_IPI_SET);
+		put_cpu();
+	}
+
+	/* Force the above writes to be executed */
+	if (aic.fast_ipi)
+		isb();
+}
+#else
+#define apple_aic_ipi_send_mask NULL
+#endif
+
+static struct irq_chip apple_aic_irq_chip_ipi = {
+	.name = "apple_aic_ipi",
+	.irq_mask = apple_aic_fiq_ipi_mask,
+	.irq_unmask = apple_aic_fiq_ipi_unmask,
+	.ipi_send_mask = apple_aic_ipi_send_mask,
 };

 static int apple_aic_irq_domain_xlate(struct irq_domain *d,
@@ -98,16 +157,27 @@ static int apple_aic_irq_domain_xlate(struct irq_domain *d,
 				      unsigned long *out_hwirq,
 				      unsigned int *out_type)
 {
-	if (intspec[0]) { /* FIQ */
+	switch (intspec[0]) {
+	case 0: /* IRQ */
+		if (intspec[1] >= aic.num_irqs)
+			return -EINVAL;
+		if (out_hwirq)
+			*out_hwirq = intspec[1];
+		break;
+	case 1: /* FIQ */
 		if (intspec[1] >= 2)
 			return -EINVAL;
 		if (out_hwirq)
 			*out_hwirq = aic.num_irqs + intspec[1];
-	} else {
-		if (intspec[1] >= aic.num_irqs)
+		break;
+	case 2: /* IPI */
+		if (intspec[1] >= NUM_IPI)
 			return -EINVAL;
 		if (out_hwirq)
-			*out_hwirq = intspec[1];
+			*out_hwirq = aic.num_irqs + 2 + intspec[1];
+		break;
+	default:
+		return -EINVAL;
 	}

 	if (out_type)
@@ -118,7 +188,13 @@ static int apple_aic_irq_domain_xlate(struct irq_domain *d,
 static int apple_aic_irq_domain_map(struct irq_domain *d, unsigned int virq,
 				    irq_hw_number_t hw)
 {
-	if (hw >= aic.num_irqs) {
+	if (hw >= aic.num_irqs + 2) {
+		irq_set_percpu_devid(virq);
+		irq_domain_set_info(d, virq, hw, &apple_aic_irq_chip_ipi,
+				    d->host_data, handle_percpu_devid_irq, NULL,
+				    NULL);
+		irq_set_status_flags(virq, IRQ_NOAUTOEN);
+	} else if (hw >= aic.num_irqs) {
 		irq_set_percpu_devid(virq);
 		irq_domain_set_info(d, virq, hw, &apple_aic_irq_chip_fiq,
 				    d->host_data, handle_percpu_devid_irq, NULL,
@@ -141,8 +217,10 @@ static const struct irq_domain_ops apple_aic_irq_domain_ops = {

 static void __exception_irq_entry apple_aic_handle_irq(struct pt_regs *regs)
 {
+	atomic_t *maskptr;
 	uint32_t ack;
-	unsigned done = 0;
+	unsigned done = 0, irqnr;
+	unsigned long mask;

 	while (1) {
 		ack = readl(aic.base + REG_IRQ_ACK);
@@ -154,6 +232,36 @@ static void __exception_irq_entry apple_aic_handle_irq(struct pt_regs *regs)
 			handle_domain_irq(aic.domain,
 					  ack & REG_IRQ_ACK_NUM_MASK, regs);
 			break;
+		case REG_IRQ_ACK_TYPE_IPI:
+#ifdef CONFIG_SMP
+			if (ack == REG_IRQ_ACK_IPI_SELF)
+				writel(REG_IPI_FLAG_SELF,
+				       aic.base + REG_IPI_CLEAR);
+			else
+				writel(REG_IPI_FLAG_OTHER,
+				       aic.base + REG_IPI_CLEAR);
+			maskptr = get_cpu_ptr(&aic_ipi_mask);
+			smp_mb__before_atomic();
+			mask = atomic_xchg(maskptr, 0);
+			smp_mb__after_atomic();
+			put_cpu_ptr(&aic_ipi_mask);
+			for_each_set_bit (irqnr, &mask, NUM_IPI) {
+				handle_domain_irq(aic.domain,
+						  aic.num_irqs + 2 + irqnr,
+						  regs);
+			}
+			if (ack == REG_IRQ_ACK_IPI_SELF)
+				writel(REG_IPI_FLAG_SELF,
+				       aic.base +
+					       REG_PERCPU(REG_IPI_ENABLE,
+							  __smp_processor_id()));
+			else
+				writel(REG_IPI_FLAG_OTHER,
+				       aic.base +
+					       REG_PERCPU(REG_IPI_ENABLE,
+							  __smp_processor_id()));
+#endif
+			break;
 		}
 		if (done)
 			break;
@@ -162,6 +270,27 @@ static void __exception_irq_entry apple_aic_handle_irq(struct pt_regs *regs)

 static void __exception_irq_entry apple_aic_handle_fiq(struct pt_regs *regs)
 {
+#ifdef CONFIG_SMP
+	atomic_t *maskptr;
+	unsigned long mask;
+	unsigned irqnr;
+
+	if (aic.fast_ipi) {
+		if (read_sysreg(SR_APPLE_IPI_STAT)) {
+			write_sysreg(1, SR_APPLE_IPI_STAT);
+
+			maskptr = get_cpu_ptr(&aic_ipi_mask);
+			smp_mb__before_atomic();
+			mask = atomic_xchg(maskptr, 0);
+			smp_mb__after_atomic();
+			put_cpu_ptr(&aic_ipi_mask);
+			for_each_set_bit (irqnr, &mask, NUM_IPI)
+				handle_domain_irq(aic.domain,
+						  aic.num_irqs + 2 + irqnr,
+						  regs);
+		}
+	}
+#endif
 	handle_domain_irq(aic.domain, aic.num_irqs, regs);
 }

@@ -169,6 +298,13 @@ void apple_aic_cpu_prepare(unsigned int cpu)
 {
 	unsigned i;

+	if (aic.fast_ipi)
+		writel(REG_IPI_FLAG_SELF | REG_IPI_FLAG_OTHER,
+		       aic.base + REG_PERCPU(REG_IPI_DISABLE, cpu));
+	else
+		writel(REG_IPI_FLAG_SELF | REG_IPI_FLAG_OTHER,
+		       aic.base + REG_PERCPU(REG_IPI_ENABLE, cpu));
+
 	for (i = 0; i < aic.num_irqs; i++)
 		writel(readl(aic.base + REG_IRQ_AFFINITY(i)) | (1u << cpu),
 		       aic.base + REG_IRQ_AFFINITY(i));
@@ -178,6 +314,9 @@ static int __init apple_aic_init(struct device_node *node,
 				 struct device_node *interrupt_parent)
 {
 	unsigned i;
+#ifdef CONFIG_SMP
+	int base_ipi, ret;
+#endif

 	if (!node)
 		return -ENODEV;
@@ -186,8 +325,11 @@ static int __init apple_aic_init(struct device_node *node,
 	if (WARN(!aic.base, "unable to map aic registers\n"))
 		return -EINVAL;

+	aic.fast_ipi = of_property_read_bool(node, "fast-ipi");
+
 	aic.num_irqs = readl(aic.base + REG_ID_CONFIG) & 0xFFFF;
-	pr_info("Apple AIC: %d IRQs + 1 FIQ + 1 dummy\n", aic.num_irqs);
+	pr_info("Apple AIC: %d IRQs + 1 FIQ + 1 dummy + %d IPIs%s\n",
+		aic.num_irqs, NUM_IPI, aic.fast_ipi ? " (fast)" : "");

 	for (i = 0; i < aic.num_irqs; i++)
 		writel(1, aic.base + REG_IRQ_AFFINITY(i));
@@ -201,10 +343,21 @@ static int __init apple_aic_init(struct device_node *node,

 	apple_aic_cpu_prepare(0);

-	aic.domain = irq_domain_add_linear(node, aic.num_irqs + 2,
+	aic.domain = irq_domain_add_linear(node, aic.num_irqs + 2 + NUM_IPI,
 					   &apple_aic_irq_domain_ops,
 					   &apple_aic_irq_chip);
 	irq_set_default_host(aic.domain);
+
+#ifdef CONFIG_SMP
+	base_ipi = aic.num_irqs + 2;
+	ret = irq_create_strict_mappings(aic.domain, base_ipi, aic.num_irqs + 2,
+					 NUM_IPI);
+	if (ret < 0)
+		pr_err("%s: irq_create_strict_mappings failed with %d\n",
+		       __func__, ret);
+	set_smp_ipi_range(base_ipi, NUM_IPI);
+#endif
+
 	return 0;
 }

--
2.29.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  parent reply index

Thread overview: 55+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-20 13:27 [RFC PATCH 0/7] Linux on Apple Silicon Mohamed Mediouni
2021-01-20 13:27 ` [RFC PATCH 1/7] arm64: kernel: FIQ support Mohamed Mediouni
2021-01-20 13:27 ` [RFC PATCH 2/7] arm64: kernel: Add a WFI hook Mohamed Mediouni
2021-01-20 16:46   ` Alexander Graf
     [not found]     ` <94C20F55-D3B8-4349-B26F-9EA8AAEBF639@caramail.com>
2021-01-21 12:33       ` Hector Martin 'marcan'
2021-01-21 10:52   ` Arnd Bergmann
2021-01-21 11:01     ` Mohamed Mediouni
2021-01-21 11:36       ` Arnd Bergmann
2021-01-20 13:27 ` [RFC PATCH 3/7] arm64: mm: use nGnRnE instead of nGnRE on Apple processors Mohamed Mediouni
2021-01-20 16:47   ` Alexander Graf
2021-01-20 18:06     ` Mohamed Mediouni
2021-01-20 18:10       ` Alexander Graf
2021-01-21 11:27   ` Will Deacon
2021-01-21 11:38     ` Arnd Bergmann
2021-01-21 11:44     ` Marc Zyngier
2021-01-21 12:47       ` Will Deacon
2021-01-21 15:12         ` Mohamed Mediouni
2021-01-21 16:25           ` Marc Zyngier
2021-01-21 17:55             ` Will Deacon
2021-01-21 18:15               ` Marc Zyngier
2021-01-21 18:22                 ` Mohamed Mediouni
2021-01-21 18:22                 ` Will Deacon
2021-01-20 13:27 ` [RFC PATCH 4/7] irqchip/apple-aic: Add support for Apple AIC Mohamed Mediouni
2021-01-20 17:11   ` Alexander Graf
2021-01-20 18:04     ` Mohamed Mediouni
2021-01-20 20:16       ` Andrew Lunn
2021-01-20 21:18   ` Stan Skowronek
2021-01-21  9:48   ` Linus Walleij
2021-01-21 10:37     ` Arnd Bergmann
2021-01-21 15:29       ` Hector Martin 'marcan'
2021-01-21 17:09         ` Rob Herring
2021-01-21 17:45       ` Rob Herring
2021-01-21 16:44     ` Rob Herring
2021-01-21 16:53   ` Hector Martin 'marcan'
2021-01-20 13:27 ` [RFC PATCH 5/7] arm64/Kconfig: Add Apple Silicon SoC platform Mohamed Mediouni
2021-01-20 13:27 ` [RFC PATCH 6/7] arm64: kernel: Apple CPU start driver Mohamed Mediouni
2021-01-21 11:14   ` Arnd Bergmann
2021-01-20 13:27 ` Mohamed Mediouni [this message]
2021-01-21 12:44   ` [RFC PATCH 7/7] irqchip/apple-aic: add SMP support to the Apple AIC driver Arnd Bergmann
2021-01-21 12:50     ` Mohamed Mediouni
2021-01-21 13:00       ` Arnd Bergmann
2021-01-21 13:01         ` Hector Martin 'marcan'
2021-01-21 13:22       ` Marc Zyngier
2021-01-21 13:32         ` Mark Rutland
2021-01-21 14:05           ` Marc Zyngier
2021-01-21 13:34         ` Mohamed Mediouni
2021-01-21 14:10           ` Marc Zyngier
2021-01-21 15:09             ` Arnd Bergmann
2021-01-21 15:18               ` Mohamed Mediouni
2021-01-21 16:40       ` Rob Herring
2021-01-21 16:43         ` Mohamed Mediouni
2021-01-21 17:37           ` Rob Herring
2021-01-21 18:08             ` Mohamed Mediouni
2021-01-21 18:57               ` Rob Herring
2021-02-02 19:15   ` Linus Walleij

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=20210120132717.395873-8-mohamed.mediouni@caramail.com \
    --to=mohamed.mediouni@caramail.com \
    --cc=catalin.marinas@arm.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=marcan@marcan.st \
    --cc=mark.rutland@arm.com \
    --cc=maz@kernel.org \
    --cc=stan@corellium.com \
    --cc=will@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

Linux-ARM-Kernel Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-arm-kernel/0 linux-arm-kernel/git/0.git
	git clone --mirror https://lore.kernel.org/linux-arm-kernel/1 linux-arm-kernel/git/1.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-arm-kernel linux-arm-kernel/ https://lore.kernel.org/linux-arm-kernel \
		linux-arm-kernel@lists.infradead.org
	public-inbox-index linux-arm-kernel

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.infradead.lists.linux-arm-kernel


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git