All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] irqchip/gic: Fix handling of Samsung's non-standard GIC
@ 2020-09-15 13:39 ` Marc Zyngier
  0 siblings, 0 replies; 12+ messages in thread
From: Marc Zyngier @ 2020-09-15 13:39 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel
  Cc: Thomas Gleixner, Jason Cooper, Marek Szyprowski, kernel-team

Marek pointed out that the new IPI code broke the two ancient A9
platforms that use the dreaded Franken-GIC (not the official name), as
it appears it is even more broken than we though 9 years ago.

The fix isn't nice, although it allows for some further cleanup.

Marek, could you please give these another spin on your boards? For
convenience, I've stashed them as part of [1].

Thanks,

	M.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git/log/?h=irq/ipi-as-irq

Marc Zyngier (2):
  irqchip/gic: Handle non-standard SGI deactivation on Samsung's
    Franken-GIC
  irqchip/gic: Cleanup Franken-GIC handling

 drivers/irqchip/irq-gic.c | 67 +++++++++++++++++++++++++--------------
 1 file changed, 43 insertions(+), 24 deletions(-)

-- 
2.28.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 0/2] irqchip/gic: Fix handling of Samsung's non-standard GIC
@ 2020-09-15 13:39 ` Marc Zyngier
  0 siblings, 0 replies; 12+ messages in thread
From: Marc Zyngier @ 2020-09-15 13:39 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel
  Cc: Thomas Gleixner, kernel-team, Jason Cooper, Marek Szyprowski

Marek pointed out that the new IPI code broke the two ancient A9
platforms that use the dreaded Franken-GIC (not the official name), as
it appears it is even more broken than we though 9 years ago.

The fix isn't nice, although it allows for some further cleanup.

Marek, could you please give these another spin on your boards? For
convenience, I've stashed them as part of [1].

Thanks,

	M.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git/log/?h=irq/ipi-as-irq

Marc Zyngier (2):
  irqchip/gic: Handle non-standard SGI deactivation on Samsung's
    Franken-GIC
  irqchip/gic: Cleanup Franken-GIC handling

 drivers/irqchip/irq-gic.c | 67 +++++++++++++++++++++++++--------------
 1 file changed, 43 insertions(+), 24 deletions(-)

-- 
2.28.0


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

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/2] irqchip/gic: Handle non-standard SGI deactivation on Samsung's Franken-GIC
  2020-09-15 13:39 ` Marc Zyngier
@ 2020-09-15 13:39   ` Marc Zyngier
  -1 siblings, 0 replies; 12+ messages in thread
From: Marc Zyngier @ 2020-09-15 13:39 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel
  Cc: Thomas Gleixner, Jason Cooper, Marek Szyprowski, kernel-team

The GIC available on some of Samsung's A9-based platform is
thankfully one of a kind. On top of not presenting a banked
programing model (each CPU has its own base addresses for both
distributor and CPU interface), it also encodes the source CPU
for SGIs in the INTID read from IAR, and requires this exact
value to be written back to EOI.

Without this, interrupts are never deactivated, and the kernel
grinds to a halt.

Work around it by stashing the INTID for in-flight SGIs, and
using that value on EOI. This only works because we don't nest
SGIs.

Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
Fixes: ac063232d4b0 ("irqchip/gic: Configure SGIs as standard interrupts")
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 drivers/irqchip/irq-gic.c | 49 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 47 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4be2b62f816f..84a2d2a1aab7 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -150,10 +150,37 @@ static inline void gic_set_base_accessor(struct gic_chip_data *data,
 {
 	data->get_base = f;
 }
+
+static DEFINE_STATIC_KEY_FALSE(frankengic_key);
+static DEFINE_PER_CPU(u32, sgi_intid);
+
+static void enable_frankengic(void)
+{
+	static_branch_enable(&frankengic_key);
+}
+
+static inline bool is_frankengic(void)
+{
+	return static_branch_unlikely(&frankengic_key);
+}
+
+static inline void set_sgi_intid(u32 intid)
+{
+	this_cpu_write(sgi_intid, intid);
+}
+
+static inline u32 get_sgi_intid(void)
+{
+	return this_cpu_read(sgi_intid);
+}
 #else
 #define gic_data_dist_base(d)	((d)->dist_base.common_base)
 #define gic_data_cpu_base(d)	((d)->cpu_base.common_base)
 #define gic_set_base_accessor(d, f)
+#define enable_frankengic()	do { } while(0)
+#define is_frankengic()		false
+#define set_sgi_intid(i)	do { } while(0)
+#define get_sgi_intid()		0
 #endif
 
 static inline void __iomem *gic_dist_base(struct irq_data *d)
@@ -226,7 +253,12 @@ static void gic_unmask_irq(struct irq_data *d)
 
 static void gic_eoi_irq(struct irq_data *d)
 {
-	writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
+	u32 hwirq = gic_irq(d);
+
+	if (is_frankengic() && hwirq < 16)
+		hwirq = get_sgi_intid();
+
+	writel_relaxed(hwirq, gic_cpu_base(d) + GIC_CPU_EOI);
 }
 
 static void gic_eoimode1_eoi_irq(struct irq_data *d)
@@ -348,8 +380,20 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 		 *
 		 * Pairs with the write barrier in gic_ipi_send_mask
 		 */
-		if (irqnr <= 15)
+		if (irqnr <= 15) {
 			smp_rmb();
+
+			/*
+			 * Samsung's funky GIC encodes the source CPU in
+			 * GICC_IAR, leading to the deactivation to fail if
+			 * not written back as is to GICC_EOI.  Stash the
+			 * INTID away for gic_eoi_irq() to write back.
+			 * This only works because we don't nest SGIs...
+			 */
+			if (is_frankengic())
+				set_sgi_intid(irqstat);
+		}
+
 		handle_domain_irq(gic->domain, irqnr, regs);
 	} while (1);
 }
@@ -1142,6 +1186,7 @@ static int gic_init_bases(struct gic_chip_data *gic,
 				gic->raw_cpu_base + offset;
 		}
 
+		enable_frankengic();
 		gic_set_base_accessor(gic, gic_get_percpu_base);
 	} else {
 		/* Normal, sane GIC... */
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 1/2] irqchip/gic: Handle non-standard SGI deactivation on Samsung's Franken-GIC
@ 2020-09-15 13:39   ` Marc Zyngier
  0 siblings, 0 replies; 12+ messages in thread
From: Marc Zyngier @ 2020-09-15 13:39 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel
  Cc: Thomas Gleixner, kernel-team, Jason Cooper, Marek Szyprowski

The GIC available on some of Samsung's A9-based platform is
thankfully one of a kind. On top of not presenting a banked
programing model (each CPU has its own base addresses for both
distributor and CPU interface), it also encodes the source CPU
for SGIs in the INTID read from IAR, and requires this exact
value to be written back to EOI.

Without this, interrupts are never deactivated, and the kernel
grinds to a halt.

Work around it by stashing the INTID for in-flight SGIs, and
using that value on EOI. This only works because we don't nest
SGIs.

Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
Fixes: ac063232d4b0 ("irqchip/gic: Configure SGIs as standard interrupts")
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 drivers/irqchip/irq-gic.c | 49 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 47 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4be2b62f816f..84a2d2a1aab7 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -150,10 +150,37 @@ static inline void gic_set_base_accessor(struct gic_chip_data *data,
 {
 	data->get_base = f;
 }
+
+static DEFINE_STATIC_KEY_FALSE(frankengic_key);
+static DEFINE_PER_CPU(u32, sgi_intid);
+
+static void enable_frankengic(void)
+{
+	static_branch_enable(&frankengic_key);
+}
+
+static inline bool is_frankengic(void)
+{
+	return static_branch_unlikely(&frankengic_key);
+}
+
+static inline void set_sgi_intid(u32 intid)
+{
+	this_cpu_write(sgi_intid, intid);
+}
+
+static inline u32 get_sgi_intid(void)
+{
+	return this_cpu_read(sgi_intid);
+}
 #else
 #define gic_data_dist_base(d)	((d)->dist_base.common_base)
 #define gic_data_cpu_base(d)	((d)->cpu_base.common_base)
 #define gic_set_base_accessor(d, f)
+#define enable_frankengic()	do { } while(0)
+#define is_frankengic()		false
+#define set_sgi_intid(i)	do { } while(0)
+#define get_sgi_intid()		0
 #endif
 
 static inline void __iomem *gic_dist_base(struct irq_data *d)
@@ -226,7 +253,12 @@ static void gic_unmask_irq(struct irq_data *d)
 
 static void gic_eoi_irq(struct irq_data *d)
 {
-	writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
+	u32 hwirq = gic_irq(d);
+
+	if (is_frankengic() && hwirq < 16)
+		hwirq = get_sgi_intid();
+
+	writel_relaxed(hwirq, gic_cpu_base(d) + GIC_CPU_EOI);
 }
 
 static void gic_eoimode1_eoi_irq(struct irq_data *d)
@@ -348,8 +380,20 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 		 *
 		 * Pairs with the write barrier in gic_ipi_send_mask
 		 */
-		if (irqnr <= 15)
+		if (irqnr <= 15) {
 			smp_rmb();
+
+			/*
+			 * Samsung's funky GIC encodes the source CPU in
+			 * GICC_IAR, leading to the deactivation to fail if
+			 * not written back as is to GICC_EOI.  Stash the
+			 * INTID away for gic_eoi_irq() to write back.
+			 * This only works because we don't nest SGIs...
+			 */
+			if (is_frankengic())
+				set_sgi_intid(irqstat);
+		}
+
 		handle_domain_irq(gic->domain, irqnr, regs);
 	} while (1);
 }
@@ -1142,6 +1186,7 @@ static int gic_init_bases(struct gic_chip_data *gic,
 				gic->raw_cpu_base + offset;
 		}
 
+		enable_frankengic();
 		gic_set_base_accessor(gic, gic_get_percpu_base);
 	} else {
 		/* Normal, sane GIC... */
-- 
2.28.0


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

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/2] irqchip/gic: Cleanup Franken-GIC handling
  2020-09-15 13:39 ` Marc Zyngier
@ 2020-09-15 13:39   ` Marc Zyngier
  -1 siblings, 0 replies; 12+ messages in thread
From: Marc Zyngier @ 2020-09-15 13:39 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel
  Cc: Thomas Gleixner, Jason Cooper, Marek Szyprowski, kernel-team

Now that we have a static key identifying Samsung's unique creation,
let's replace the indirect call to compute the base addresses by
a simple test on the static key.

Faster, cheaper, negative diffstat.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 drivers/irqchip/irq-gic.c | 48 +++++++++------------------------------
 1 file changed, 11 insertions(+), 37 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 84a2d2a1aab7..98743afdaea6 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -83,9 +83,6 @@ struct gic_chip_data {
 #endif
 	struct irq_domain *domain;
 	unsigned int gic_irqs;
-#ifdef CONFIG_GIC_NON_BANKED
-	void __iomem *(*get_base)(union gic_base *);
-#endif
 };
 
 #ifdef CONFIG_BL_SWITCHER
@@ -125,32 +122,6 @@ static struct gic_chip_data gic_data[CONFIG_ARM_GIC_MAX_NR] __read_mostly;
 static struct gic_kvm_info gic_v2_kvm_info;
 
 #ifdef CONFIG_GIC_NON_BANKED
-static void __iomem *gic_get_percpu_base(union gic_base *base)
-{
-	return raw_cpu_read(*base->percpu_base);
-}
-
-static void __iomem *gic_get_common_base(union gic_base *base)
-{
-	return base->common_base;
-}
-
-static inline void __iomem *gic_data_dist_base(struct gic_chip_data *data)
-{
-	return data->get_base(&data->dist_base);
-}
-
-static inline void __iomem *gic_data_cpu_base(struct gic_chip_data *data)
-{
-	return data->get_base(&data->cpu_base);
-}
-
-static inline void gic_set_base_accessor(struct gic_chip_data *data,
-					 void __iomem *(*f)(union gic_base *))
-{
-	data->get_base = f;
-}
-
 static DEFINE_STATIC_KEY_FALSE(frankengic_key);
 static DEFINE_PER_CPU(u32, sgi_intid);
 
@@ -173,10 +144,20 @@ static inline u32 get_sgi_intid(void)
 {
 	return this_cpu_read(sgi_intid);
 }
+
+static inline void __iomem *__get_base(union gic_base *base)
+{
+	if (is_frankengic())
+		return raw_cpu_read(*base->percpu_base);
+
+	return base->common_base;
+}
+
+#define gic_data_dist_base(d)	__get_base(&(d)->dist_base)
+#define gic_data_cpu_base(d)	__get_base(&(d)->cpu_base)
 #else
 #define gic_data_dist_base(d)	((d)->dist_base.common_base)
 #define gic_data_cpu_base(d)	((d)->cpu_base.common_base)
-#define gic_set_base_accessor(d, f)
 #define enable_frankengic()	do { } while(0)
 #define is_frankengic()		false
 #define set_sgi_intid(i)	do { } while(0)
@@ -741,11 +722,6 @@ static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
 	int i;
 
 	for (i = 0; i < CONFIG_ARM_GIC_MAX_NR; i++) {
-#ifdef CONFIG_GIC_NON_BANKED
-		/* Skip over unused GICs */
-		if (!gic_data[i].get_base)
-			continue;
-#endif
 		switch (cmd) {
 		case CPU_PM_ENTER:
 			gic_cpu_save(&gic_data[i]);
@@ -1187,7 +1163,6 @@ static int gic_init_bases(struct gic_chip_data *gic,
 		}
 
 		enable_frankengic();
-		gic_set_base_accessor(gic, gic_get_percpu_base);
 	} else {
 		/* Normal, sane GIC... */
 		WARN(gic->percpu_offset,
@@ -1195,7 +1170,6 @@ static int gic_init_bases(struct gic_chip_data *gic,
 		     gic->percpu_offset);
 		gic->dist_base.common_base = gic->raw_dist_base;
 		gic->cpu_base.common_base = gic->raw_cpu_base;
-		gic_set_base_accessor(gic, gic_get_common_base);
 	}
 
 	/*
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/2] irqchip/gic: Cleanup Franken-GIC handling
@ 2020-09-15 13:39   ` Marc Zyngier
  0 siblings, 0 replies; 12+ messages in thread
From: Marc Zyngier @ 2020-09-15 13:39 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel
  Cc: Thomas Gleixner, kernel-team, Jason Cooper, Marek Szyprowski

Now that we have a static key identifying Samsung's unique creation,
let's replace the indirect call to compute the base addresses by
a simple test on the static key.

Faster, cheaper, negative diffstat.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 drivers/irqchip/irq-gic.c | 48 +++++++++------------------------------
 1 file changed, 11 insertions(+), 37 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 84a2d2a1aab7..98743afdaea6 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -83,9 +83,6 @@ struct gic_chip_data {
 #endif
 	struct irq_domain *domain;
 	unsigned int gic_irqs;
-#ifdef CONFIG_GIC_NON_BANKED
-	void __iomem *(*get_base)(union gic_base *);
-#endif
 };
 
 #ifdef CONFIG_BL_SWITCHER
@@ -125,32 +122,6 @@ static struct gic_chip_data gic_data[CONFIG_ARM_GIC_MAX_NR] __read_mostly;
 static struct gic_kvm_info gic_v2_kvm_info;
 
 #ifdef CONFIG_GIC_NON_BANKED
-static void __iomem *gic_get_percpu_base(union gic_base *base)
-{
-	return raw_cpu_read(*base->percpu_base);
-}
-
-static void __iomem *gic_get_common_base(union gic_base *base)
-{
-	return base->common_base;
-}
-
-static inline void __iomem *gic_data_dist_base(struct gic_chip_data *data)
-{
-	return data->get_base(&data->dist_base);
-}
-
-static inline void __iomem *gic_data_cpu_base(struct gic_chip_data *data)
-{
-	return data->get_base(&data->cpu_base);
-}
-
-static inline void gic_set_base_accessor(struct gic_chip_data *data,
-					 void __iomem *(*f)(union gic_base *))
-{
-	data->get_base = f;
-}
-
 static DEFINE_STATIC_KEY_FALSE(frankengic_key);
 static DEFINE_PER_CPU(u32, sgi_intid);
 
@@ -173,10 +144,20 @@ static inline u32 get_sgi_intid(void)
 {
 	return this_cpu_read(sgi_intid);
 }
+
+static inline void __iomem *__get_base(union gic_base *base)
+{
+	if (is_frankengic())
+		return raw_cpu_read(*base->percpu_base);
+
+	return base->common_base;
+}
+
+#define gic_data_dist_base(d)	__get_base(&(d)->dist_base)
+#define gic_data_cpu_base(d)	__get_base(&(d)->cpu_base)
 #else
 #define gic_data_dist_base(d)	((d)->dist_base.common_base)
 #define gic_data_cpu_base(d)	((d)->cpu_base.common_base)
-#define gic_set_base_accessor(d, f)
 #define enable_frankengic()	do { } while(0)
 #define is_frankengic()		false
 #define set_sgi_intid(i)	do { } while(0)
@@ -741,11 +722,6 @@ static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
 	int i;
 
 	for (i = 0; i < CONFIG_ARM_GIC_MAX_NR; i++) {
-#ifdef CONFIG_GIC_NON_BANKED
-		/* Skip over unused GICs */
-		if (!gic_data[i].get_base)
-			continue;
-#endif
 		switch (cmd) {
 		case CPU_PM_ENTER:
 			gic_cpu_save(&gic_data[i]);
@@ -1187,7 +1163,6 @@ static int gic_init_bases(struct gic_chip_data *gic,
 		}
 
 		enable_frankengic();
-		gic_set_base_accessor(gic, gic_get_percpu_base);
 	} else {
 		/* Normal, sane GIC... */
 		WARN(gic->percpu_offset,
@@ -1195,7 +1170,6 @@ static int gic_init_bases(struct gic_chip_data *gic,
 		     gic->percpu_offset);
 		gic->dist_base.common_base = gic->raw_dist_base;
 		gic->cpu_base.common_base = gic->raw_cpu_base;
-		gic_set_base_accessor(gic, gic_get_common_base);
 	}
 
 	/*
-- 
2.28.0


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

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/2] irqchip/gic: Handle non-standard SGI deactivation on Samsung's Franken-GIC
  2020-09-15 13:39   ` Marc Zyngier
@ 2020-09-15 14:06     ` Marek Szyprowski
  -1 siblings, 0 replies; 12+ messages in thread
From: Marek Szyprowski @ 2020-09-15 14:06 UTC (permalink / raw)
  To: Marc Zyngier, linux-arm-kernel, linux-kernel
  Cc: Thomas Gleixner, Jason Cooper, kernel-team

On 15.09.2020 15:39, Marc Zyngier wrote:
> The GIC available on some of Samsung's A9-based platform is
> thankfully one of a kind. On top of not presenting a banked
> programing model (each CPU has its own base addresses for both
> distributor and CPU interface), it also encodes the source CPU
> for SGIs in the INTID read from IAR, and requires this exact
> value to be written back to EOI.
>
> Without this, interrupts are never deactivated, and the kernel
> grinds to a halt.
>
> Work around it by stashing the INTID for in-flight SGIs, and
> using that value on EOI. This only works because we don't nest
> SGIs.
>
> Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Fixes: ac063232d4b0 ("irqchip/gic: Configure SGIs as standard interrupts")
> Signed-off-by: Marc Zyngier <maz@kernel.org>

Works fine, thanks!

Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>

> ---
>   drivers/irqchip/irq-gic.c | 49 +++++++++++++++++++++++++++++++++++++--
>   1 file changed, 47 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index 4be2b62f816f..84a2d2a1aab7 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -150,10 +150,37 @@ static inline void gic_set_base_accessor(struct gic_chip_data *data,
>   {
>   	data->get_base = f;
>   }
> +
> +static DEFINE_STATIC_KEY_FALSE(frankengic_key);
> +static DEFINE_PER_CPU(u32, sgi_intid);
> +
> +static void enable_frankengic(void)
> +{
> +	static_branch_enable(&frankengic_key);
> +}
> +
> +static inline bool is_frankengic(void)
> +{
> +	return static_branch_unlikely(&frankengic_key);
> +}
> +
> +static inline void set_sgi_intid(u32 intid)
> +{
> +	this_cpu_write(sgi_intid, intid);
> +}
> +
> +static inline u32 get_sgi_intid(void)
> +{
> +	return this_cpu_read(sgi_intid);
> +}
>   #else
>   #define gic_data_dist_base(d)	((d)->dist_base.common_base)
>   #define gic_data_cpu_base(d)	((d)->cpu_base.common_base)
>   #define gic_set_base_accessor(d, f)
> +#define enable_frankengic()	do { } while(0)
> +#define is_frankengic()		false
> +#define set_sgi_intid(i)	do { } while(0)
> +#define get_sgi_intid()		0
>   #endif
>   
>   static inline void __iomem *gic_dist_base(struct irq_data *d)
> @@ -226,7 +253,12 @@ static void gic_unmask_irq(struct irq_data *d)
>   
>   static void gic_eoi_irq(struct irq_data *d)
>   {
> -	writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
> +	u32 hwirq = gic_irq(d);
> +
> +	if (is_frankengic() && hwirq < 16)
> +		hwirq = get_sgi_intid();
> +
> +	writel_relaxed(hwirq, gic_cpu_base(d) + GIC_CPU_EOI);
>   }
>   
>   static void gic_eoimode1_eoi_irq(struct irq_data *d)
> @@ -348,8 +380,20 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
>   		 *
>   		 * Pairs with the write barrier in gic_ipi_send_mask
>   		 */
> -		if (irqnr <= 15)
> +		if (irqnr <= 15) {
>   			smp_rmb();
> +
> +			/*
> +			 * Samsung's funky GIC encodes the source CPU in
> +			 * GICC_IAR, leading to the deactivation to fail if
> +			 * not written back as is to GICC_EOI.  Stash the
> +			 * INTID away for gic_eoi_irq() to write back.
> +			 * This only works because we don't nest SGIs...
> +			 */
> +			if (is_frankengic())
> +				set_sgi_intid(irqstat);
> +		}
> +
>   		handle_domain_irq(gic->domain, irqnr, regs);
>   	} while (1);
>   }
> @@ -1142,6 +1186,7 @@ static int gic_init_bases(struct gic_chip_data *gic,
>   				gic->raw_cpu_base + offset;
>   		}
>   
> +		enable_frankengic();
>   		gic_set_base_accessor(gic, gic_get_percpu_base);
>   	} else {
>   		/* Normal, sane GIC... */

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/2] irqchip/gic: Handle non-standard SGI deactivation on Samsung's Franken-GIC
@ 2020-09-15 14:06     ` Marek Szyprowski
  0 siblings, 0 replies; 12+ messages in thread
From: Marek Szyprowski @ 2020-09-15 14:06 UTC (permalink / raw)
  To: Marc Zyngier, linux-arm-kernel, linux-kernel
  Cc: Thomas Gleixner, kernel-team, Jason Cooper

On 15.09.2020 15:39, Marc Zyngier wrote:
> The GIC available on some of Samsung's A9-based platform is
> thankfully one of a kind. On top of not presenting a banked
> programing model (each CPU has its own base addresses for both
> distributor and CPU interface), it also encodes the source CPU
> for SGIs in the INTID read from IAR, and requires this exact
> value to be written back to EOI.
>
> Without this, interrupts are never deactivated, and the kernel
> grinds to a halt.
>
> Work around it by stashing the INTID for in-flight SGIs, and
> using that value on EOI. This only works because we don't nest
> SGIs.
>
> Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Fixes: ac063232d4b0 ("irqchip/gic: Configure SGIs as standard interrupts")
> Signed-off-by: Marc Zyngier <maz@kernel.org>

Works fine, thanks!

Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>

> ---
>   drivers/irqchip/irq-gic.c | 49 +++++++++++++++++++++++++++++++++++++--
>   1 file changed, 47 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index 4be2b62f816f..84a2d2a1aab7 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -150,10 +150,37 @@ static inline void gic_set_base_accessor(struct gic_chip_data *data,
>   {
>   	data->get_base = f;
>   }
> +
> +static DEFINE_STATIC_KEY_FALSE(frankengic_key);
> +static DEFINE_PER_CPU(u32, sgi_intid);
> +
> +static void enable_frankengic(void)
> +{
> +	static_branch_enable(&frankengic_key);
> +}
> +
> +static inline bool is_frankengic(void)
> +{
> +	return static_branch_unlikely(&frankengic_key);
> +}
> +
> +static inline void set_sgi_intid(u32 intid)
> +{
> +	this_cpu_write(sgi_intid, intid);
> +}
> +
> +static inline u32 get_sgi_intid(void)
> +{
> +	return this_cpu_read(sgi_intid);
> +}
>   #else
>   #define gic_data_dist_base(d)	((d)->dist_base.common_base)
>   #define gic_data_cpu_base(d)	((d)->cpu_base.common_base)
>   #define gic_set_base_accessor(d, f)
> +#define enable_frankengic()	do { } while(0)
> +#define is_frankengic()		false
> +#define set_sgi_intid(i)	do { } while(0)
> +#define get_sgi_intid()		0
>   #endif
>   
>   static inline void __iomem *gic_dist_base(struct irq_data *d)
> @@ -226,7 +253,12 @@ static void gic_unmask_irq(struct irq_data *d)
>   
>   static void gic_eoi_irq(struct irq_data *d)
>   {
> -	writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
> +	u32 hwirq = gic_irq(d);
> +
> +	if (is_frankengic() && hwirq < 16)
> +		hwirq = get_sgi_intid();
> +
> +	writel_relaxed(hwirq, gic_cpu_base(d) + GIC_CPU_EOI);
>   }
>   
>   static void gic_eoimode1_eoi_irq(struct irq_data *d)
> @@ -348,8 +380,20 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
>   		 *
>   		 * Pairs with the write barrier in gic_ipi_send_mask
>   		 */
> -		if (irqnr <= 15)
> +		if (irqnr <= 15) {
>   			smp_rmb();
> +
> +			/*
> +			 * Samsung's funky GIC encodes the source CPU in
> +			 * GICC_IAR, leading to the deactivation to fail if
> +			 * not written back as is to GICC_EOI.  Stash the
> +			 * INTID away for gic_eoi_irq() to write back.
> +			 * This only works because we don't nest SGIs...
> +			 */
> +			if (is_frankengic())
> +				set_sgi_intid(irqstat);
> +		}
> +
>   		handle_domain_irq(gic->domain, irqnr, regs);
>   	} while (1);
>   }
> @@ -1142,6 +1186,7 @@ static int gic_init_bases(struct gic_chip_data *gic,
>   				gic->raw_cpu_base + offset;
>   		}
>   
> +		enable_frankengic();
>   		gic_set_base_accessor(gic, gic_get_percpu_base);
>   	} else {
>   		/* Normal, sane GIC... */

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland


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

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/2] irqchip/gic: Cleanup Franken-GIC handling
  2020-09-15 13:39   ` Marc Zyngier
@ 2020-09-15 14:06     ` Marek Szyprowski
  -1 siblings, 0 replies; 12+ messages in thread
From: Marek Szyprowski @ 2020-09-15 14:06 UTC (permalink / raw)
  To: Marc Zyngier, linux-arm-kernel, linux-kernel
  Cc: Thomas Gleixner, Jason Cooper, kernel-team

On 15.09.2020 15:39, Marc Zyngier wrote:
> Now that we have a static key identifying Samsung's unique creation,
> let's replace the indirect call to compute the base addresses by
> a simple test on the static key.
>
> Faster, cheaper, negative diffstat.
>
> Signed-off-by: Marc Zyngier <maz@kernel.org>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
>   drivers/irqchip/irq-gic.c | 48 +++++++++------------------------------
>   1 file changed, 11 insertions(+), 37 deletions(-)
>
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index 84a2d2a1aab7..98743afdaea6 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -83,9 +83,6 @@ struct gic_chip_data {
>   #endif
>   	struct irq_domain *domain;
>   	unsigned int gic_irqs;
> -#ifdef CONFIG_GIC_NON_BANKED
> -	void __iomem *(*get_base)(union gic_base *);
> -#endif
>   };
>   
>   #ifdef CONFIG_BL_SWITCHER
> @@ -125,32 +122,6 @@ static struct gic_chip_data gic_data[CONFIG_ARM_GIC_MAX_NR] __read_mostly;
>   static struct gic_kvm_info gic_v2_kvm_info;
>   
>   #ifdef CONFIG_GIC_NON_BANKED
> -static void __iomem *gic_get_percpu_base(union gic_base *base)
> -{
> -	return raw_cpu_read(*base->percpu_base);
> -}
> -
> -static void __iomem *gic_get_common_base(union gic_base *base)
> -{
> -	return base->common_base;
> -}
> -
> -static inline void __iomem *gic_data_dist_base(struct gic_chip_data *data)
> -{
> -	return data->get_base(&data->dist_base);
> -}
> -
> -static inline void __iomem *gic_data_cpu_base(struct gic_chip_data *data)
> -{
> -	return data->get_base(&data->cpu_base);
> -}
> -
> -static inline void gic_set_base_accessor(struct gic_chip_data *data,
> -					 void __iomem *(*f)(union gic_base *))
> -{
> -	data->get_base = f;
> -}
> -
>   static DEFINE_STATIC_KEY_FALSE(frankengic_key);
>   static DEFINE_PER_CPU(u32, sgi_intid);
>   
> @@ -173,10 +144,20 @@ static inline u32 get_sgi_intid(void)
>   {
>   	return this_cpu_read(sgi_intid);
>   }
> +
> +static inline void __iomem *__get_base(union gic_base *base)
> +{
> +	if (is_frankengic())
> +		return raw_cpu_read(*base->percpu_base);
> +
> +	return base->common_base;
> +}
> +
> +#define gic_data_dist_base(d)	__get_base(&(d)->dist_base)
> +#define gic_data_cpu_base(d)	__get_base(&(d)->cpu_base)
>   #else
>   #define gic_data_dist_base(d)	((d)->dist_base.common_base)
>   #define gic_data_cpu_base(d)	((d)->cpu_base.common_base)
> -#define gic_set_base_accessor(d, f)
>   #define enable_frankengic()	do { } while(0)
>   #define is_frankengic()		false
>   #define set_sgi_intid(i)	do { } while(0)
> @@ -741,11 +722,6 @@ static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
>   	int i;
>   
>   	for (i = 0; i < CONFIG_ARM_GIC_MAX_NR; i++) {
> -#ifdef CONFIG_GIC_NON_BANKED
> -		/* Skip over unused GICs */
> -		if (!gic_data[i].get_base)
> -			continue;
> -#endif
>   		switch (cmd) {
>   		case CPU_PM_ENTER:
>   			gic_cpu_save(&gic_data[i]);
> @@ -1187,7 +1163,6 @@ static int gic_init_bases(struct gic_chip_data *gic,
>   		}
>   
>   		enable_frankengic();
> -		gic_set_base_accessor(gic, gic_get_percpu_base);
>   	} else {
>   		/* Normal, sane GIC... */
>   		WARN(gic->percpu_offset,
> @@ -1195,7 +1170,6 @@ static int gic_init_bases(struct gic_chip_data *gic,
>   		     gic->percpu_offset);
>   		gic->dist_base.common_base = gic->raw_dist_base;
>   		gic->cpu_base.common_base = gic->raw_cpu_base;
> -		gic_set_base_accessor(gic, gic_get_common_base);
>   	}
>   
>   	/*

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/2] irqchip/gic: Cleanup Franken-GIC handling
@ 2020-09-15 14:06     ` Marek Szyprowski
  0 siblings, 0 replies; 12+ messages in thread
From: Marek Szyprowski @ 2020-09-15 14:06 UTC (permalink / raw)
  To: Marc Zyngier, linux-arm-kernel, linux-kernel
  Cc: Thomas Gleixner, kernel-team, Jason Cooper

On 15.09.2020 15:39, Marc Zyngier wrote:
> Now that we have a static key identifying Samsung's unique creation,
> let's replace the indirect call to compute the base addresses by
> a simple test on the static key.
>
> Faster, cheaper, negative diffstat.
>
> Signed-off-by: Marc Zyngier <maz@kernel.org>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
>   drivers/irqchip/irq-gic.c | 48 +++++++++------------------------------
>   1 file changed, 11 insertions(+), 37 deletions(-)
>
> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
> index 84a2d2a1aab7..98743afdaea6 100644
> --- a/drivers/irqchip/irq-gic.c
> +++ b/drivers/irqchip/irq-gic.c
> @@ -83,9 +83,6 @@ struct gic_chip_data {
>   #endif
>   	struct irq_domain *domain;
>   	unsigned int gic_irqs;
> -#ifdef CONFIG_GIC_NON_BANKED
> -	void __iomem *(*get_base)(union gic_base *);
> -#endif
>   };
>   
>   #ifdef CONFIG_BL_SWITCHER
> @@ -125,32 +122,6 @@ static struct gic_chip_data gic_data[CONFIG_ARM_GIC_MAX_NR] __read_mostly;
>   static struct gic_kvm_info gic_v2_kvm_info;
>   
>   #ifdef CONFIG_GIC_NON_BANKED
> -static void __iomem *gic_get_percpu_base(union gic_base *base)
> -{
> -	return raw_cpu_read(*base->percpu_base);
> -}
> -
> -static void __iomem *gic_get_common_base(union gic_base *base)
> -{
> -	return base->common_base;
> -}
> -
> -static inline void __iomem *gic_data_dist_base(struct gic_chip_data *data)
> -{
> -	return data->get_base(&data->dist_base);
> -}
> -
> -static inline void __iomem *gic_data_cpu_base(struct gic_chip_data *data)
> -{
> -	return data->get_base(&data->cpu_base);
> -}
> -
> -static inline void gic_set_base_accessor(struct gic_chip_data *data,
> -					 void __iomem *(*f)(union gic_base *))
> -{
> -	data->get_base = f;
> -}
> -
>   static DEFINE_STATIC_KEY_FALSE(frankengic_key);
>   static DEFINE_PER_CPU(u32, sgi_intid);
>   
> @@ -173,10 +144,20 @@ static inline u32 get_sgi_intid(void)
>   {
>   	return this_cpu_read(sgi_intid);
>   }
> +
> +static inline void __iomem *__get_base(union gic_base *base)
> +{
> +	if (is_frankengic())
> +		return raw_cpu_read(*base->percpu_base);
> +
> +	return base->common_base;
> +}
> +
> +#define gic_data_dist_base(d)	__get_base(&(d)->dist_base)
> +#define gic_data_cpu_base(d)	__get_base(&(d)->cpu_base)
>   #else
>   #define gic_data_dist_base(d)	((d)->dist_base.common_base)
>   #define gic_data_cpu_base(d)	((d)->cpu_base.common_base)
> -#define gic_set_base_accessor(d, f)
>   #define enable_frankengic()	do { } while(0)
>   #define is_frankengic()		false
>   #define set_sgi_intid(i)	do { } while(0)
> @@ -741,11 +722,6 @@ static int gic_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
>   	int i;
>   
>   	for (i = 0; i < CONFIG_ARM_GIC_MAX_NR; i++) {
> -#ifdef CONFIG_GIC_NON_BANKED
> -		/* Skip over unused GICs */
> -		if (!gic_data[i].get_base)
> -			continue;
> -#endif
>   		switch (cmd) {
>   		case CPU_PM_ENTER:
>   			gic_cpu_save(&gic_data[i]);
> @@ -1187,7 +1163,6 @@ static int gic_init_bases(struct gic_chip_data *gic,
>   		}
>   
>   		enable_frankengic();
> -		gic_set_base_accessor(gic, gic_get_percpu_base);
>   	} else {
>   		/* Normal, sane GIC... */
>   		WARN(gic->percpu_offset,
> @@ -1195,7 +1170,6 @@ static int gic_init_bases(struct gic_chip_data *gic,
>   		     gic->percpu_offset);
>   		gic->dist_base.common_base = gic->raw_dist_base;
>   		gic->cpu_base.common_base = gic->raw_cpu_base;
> -		gic_set_base_accessor(gic, gic_get_common_base);
>   	}
>   
>   	/*

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland


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

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/2] irqchip/gic: Handle non-standard SGI deactivation on Samsung's Franken-GIC
  2020-09-15 14:06     ` Marek Szyprowski
@ 2020-09-15 14:52       ` Marc Zyngier
  -1 siblings, 0 replies; 12+ messages in thread
From: Marc Zyngier @ 2020-09-15 14:52 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: linux-arm-kernel, linux-kernel, Thomas Gleixner, Jason Cooper,
	kernel-team

On 2020-09-15 15:06, Marek Szyprowski wrote:
> On 15.09.2020 15:39, Marc Zyngier wrote:
>> The GIC available on some of Samsung's A9-based platform is
>> thankfully one of a kind. On top of not presenting a banked
>> programing model (each CPU has its own base addresses for both
>> distributor and CPU interface), it also encodes the source CPU
>> for SGIs in the INTID read from IAR, and requires this exact
>> value to be written back to EOI.
>> 
>> Without this, interrupts are never deactivated, and the kernel
>> grinds to a halt.
>> 
>> Work around it by stashing the INTID for in-flight SGIs, and
>> using that value on EOI. This only works because we don't nest
>> SGIs.
>> 
>> Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> Fixes: ac063232d4b0 ("irqchip/gic: Configure SGIs as standard 
>> interrupts")
>> Signed-off-by: Marc Zyngier <maz@kernel.org>
> 
> Works fine, thanks!
> 
> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>

Thanks for having reported the failure, and your patience with testing
all kind of random things! ;-)

         M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/2] irqchip/gic: Handle non-standard SGI deactivation on Samsung's Franken-GIC
@ 2020-09-15 14:52       ` Marc Zyngier
  0 siblings, 0 replies; 12+ messages in thread
From: Marc Zyngier @ 2020-09-15 14:52 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: Thomas Gleixner, kernel-team, linux-kernel, linux-arm-kernel,
	Jason Cooper

On 2020-09-15 15:06, Marek Szyprowski wrote:
> On 15.09.2020 15:39, Marc Zyngier wrote:
>> The GIC available on some of Samsung's A9-based platform is
>> thankfully one of a kind. On top of not presenting a banked
>> programing model (each CPU has its own base addresses for both
>> distributor and CPU interface), it also encodes the source CPU
>> for SGIs in the INTID read from IAR, and requires this exact
>> value to be written back to EOI.
>> 
>> Without this, interrupts are never deactivated, and the kernel
>> grinds to a halt.
>> 
>> Work around it by stashing the INTID for in-flight SGIs, and
>> using that value on EOI. This only works because we don't nest
>> SGIs.
>> 
>> Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> Fixes: ac063232d4b0 ("irqchip/gic: Configure SGIs as standard 
>> interrupts")
>> Signed-off-by: Marc Zyngier <maz@kernel.org>
> 
> Works fine, thanks!
> 
> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>

Thanks for having reported the failure, and your patience with testing
all kind of random things! ;-)

         M.
-- 
Jazz is not dead. It just smells funny...

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

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2020-09-16  0:35 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-15 13:39 [PATCH 0/2] irqchip/gic: Fix handling of Samsung's non-standard GIC Marc Zyngier
2020-09-15 13:39 ` Marc Zyngier
2020-09-15 13:39 ` [PATCH 1/2] irqchip/gic: Handle non-standard SGI deactivation on Samsung's Franken-GIC Marc Zyngier
2020-09-15 13:39   ` Marc Zyngier
2020-09-15 14:06   ` Marek Szyprowski
2020-09-15 14:06     ` Marek Szyprowski
2020-09-15 14:52     ` Marc Zyngier
2020-09-15 14:52       ` Marc Zyngier
2020-09-15 13:39 ` [PATCH 2/2] irqchip/gic: Cleanup Franken-GIC handling Marc Zyngier
2020-09-15 13:39   ` Marc Zyngier
2020-09-15 14:06   ` Marek Szyprowski
2020-09-15 14:06     ` Marek Szyprowski

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.