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
next prev 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