diff mbox series

[v11,1/6] irqchip/gic-v3: Enable support for SGIs to act as NMIs

Message ID 20230824083012.v11.1.I1223c11c88937bd0cbd9b086d4ef216985797302@changeid (mailing list archive)
State New, archived
Headers show
Series arm64: Add IPI for backtraces / kgdb; try to use NMI for some IPIs | expand

Commit Message

Doug Anderson Aug. 24, 2023, 3:30 p.m. UTC
As of commit 6abbd6988971 ("irqchip/gic, gic-v3: Make SGIs use
handle_percpu_devid_irq()") SGIs are treated the same as PPIs/EPPIs
and use handle_percpu_devid_irq() by default. Unfortunately,
handle_percpu_devid_irq() isn't NMI safe, and so to run in an NMI
context those should use handle_percpu_devid_fasteoi_nmi().

In order to accomplish this, we just have to make room for SGIs in the
array of refcounts that keeps track of which interrupts are set as
NMI. We also rename the array and create a new indexing scheme that
accounts for SGIs.

Also, enable NMI support prior to gic_smp_init() as allocation of SGIs
as IRQs/NMIs happen as part of this routine.

Co-developed-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Douglas Anderson <dianders@chromium.org>
---
In v10 I removed the previous Reviewed-by and Tested-by tags since the
patch contents changed pretty drastically.

I'll also note that this change is a little more black magic to me
than others in this series. I don't have a massive amounts of
familiarity with all the moving parts of gic-v3, so I mostly just
followed Mark Rutland's advice [1]. Please pay extra attention to make
sure I didn't do anything too terrible.

Mark's advice wasn't a full patch and I ended up doing a bit of work
to translate it to reality, so I did not add him as "Co-developed-by"
here. Mark: if you would like this tag then please provide it and your
Signed-off-by. I certainly won't object.

[1] https://lore.kernel.org/r/ZNC-YRQopO0PaIIo@FVFF77S0Q05N.cambridge.arm.com

(no changes since v10)

Changes in v10:
- Rewrite as needed for 5.11+ as per Mark Rutland and Sumit.

 drivers/irqchip/irq-gic-v3.c | 54 ++++++++++++++++++++++++------------
 1 file changed, 36 insertions(+), 18 deletions(-)

Comments

Marc Zyngier Aug. 26, 2023, 10:36 a.m. UTC | #1
On Thu, 24 Aug 2023 16:30:27 +0100,
Douglas Anderson <dianders@chromium.org> wrote:
> 
> As of commit 6abbd6988971 ("irqchip/gic, gic-v3: Make SGIs use
> handle_percpu_devid_irq()") SGIs are treated the same as PPIs/EPPIs
> and use handle_percpu_devid_irq() by default. Unfortunately,
> handle_percpu_devid_irq() isn't NMI safe, and so to run in an NMI
> context those should use handle_percpu_devid_fasteoi_nmi().
> 
> In order to accomplish this, we just have to make room for SGIs in the
> array of refcounts that keeps track of which interrupts are set as
> NMI. We also rename the array and create a new indexing scheme that
> accounts for SGIs.
> 
> Also, enable NMI support prior to gic_smp_init() as allocation of SGIs
> as IRQs/NMIs happen as part of this routine.
> 
> Co-developed-by: Sumit Garg <sumit.garg@linaro.org>
> Signed-off-by: Sumit Garg <sumit.garg@linaro.org>
> Signed-off-by: Douglas Anderson <dianders@chromium.org>
> ---
> In v10 I removed the previous Reviewed-by and Tested-by tags since the
> patch contents changed pretty drastically.
> 
> I'll also note that this change is a little more black magic to me
> than others in this series. I don't have a massive amounts of
> familiarity with all the moving parts of gic-v3, so I mostly just
> followed Mark Rutland's advice [1]. Please pay extra attention to make
> sure I didn't do anything too terrible.
> 
> Mark's advice wasn't a full patch and I ended up doing a bit of work
> to translate it to reality, so I did not add him as "Co-developed-by"
> here. Mark: if you would like this tag then please provide it and your
> Signed-off-by. I certainly won't object.
> 
> [1] https://lore.kernel.org/r/ZNC-YRQopO0PaIIo@FVFF77S0Q05N.cambridge.arm.com
> 
> (no changes since v10)
> 
> Changes in v10:
> - Rewrite as needed for 5.11+ as per Mark Rutland and Sumit.
> 
>  drivers/irqchip/irq-gic-v3.c | 54 ++++++++++++++++++++++++------------
>  1 file changed, 36 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
> index eedfa8e9f077..49d18cf3f636 100644
> --- a/drivers/irqchip/irq-gic-v3.c
> +++ b/drivers/irqchip/irq-gic-v3.c
> @@ -78,6 +78,8 @@ static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
>  #define GIC_LINE_NR	min(GICD_TYPER_SPIS(gic_data.rdists.gicd_typer), 1020U)
>  #define GIC_ESPI_NR	GICD_TYPER_ESPIS(gic_data.rdists.gicd_typer)
>  
> +#define SGI_NR		16

Why 16? We only allocate 8, as the other 8 are potentially stolen by
the secure side. We do try and initialise them all so that they have a
known state if they were actually configured as Group-1NS, but we
don't use them.

I understand that this simplifies the indexing in the rdist_nmi_refs
array and I'm not going to cry over 32 wasted bytes, but this
definitely deserves a comment.

	M.
Doug Anderson Aug. 28, 2023, 3:35 p.m. UTC | #2
Hi,

On Sat, Aug 26, 2023 at 3:37 AM Marc Zyngier <maz@kernel.org> wrote:
>
> On Thu, 24 Aug 2023 16:30:27 +0100,
> Douglas Anderson <dianders@chromium.org> wrote:
> >
> > As of commit 6abbd6988971 ("irqchip/gic, gic-v3: Make SGIs use
> > handle_percpu_devid_irq()") SGIs are treated the same as PPIs/EPPIs
> > and use handle_percpu_devid_irq() by default. Unfortunately,
> > handle_percpu_devid_irq() isn't NMI safe, and so to run in an NMI
> > context those should use handle_percpu_devid_fasteoi_nmi().
> >
> > In order to accomplish this, we just have to make room for SGIs in the
> > array of refcounts that keeps track of which interrupts are set as
> > NMI. We also rename the array and create a new indexing scheme that
> > accounts for SGIs.
> >
> > Also, enable NMI support prior to gic_smp_init() as allocation of SGIs
> > as IRQs/NMIs happen as part of this routine.
> >
> > Co-developed-by: Sumit Garg <sumit.garg@linaro.org>
> > Signed-off-by: Sumit Garg <sumit.garg@linaro.org>
> > Signed-off-by: Douglas Anderson <dianders@chromium.org>
> > ---
> > In v10 I removed the previous Reviewed-by and Tested-by tags since the
> > patch contents changed pretty drastically.
> >
> > I'll also note that this change is a little more black magic to me
> > than others in this series. I don't have a massive amounts of
> > familiarity with all the moving parts of gic-v3, so I mostly just
> > followed Mark Rutland's advice [1]. Please pay extra attention to make
> > sure I didn't do anything too terrible.
> >
> > Mark's advice wasn't a full patch and I ended up doing a bit of work
> > to translate it to reality, so I did not add him as "Co-developed-by"
> > here. Mark: if you would like this tag then please provide it and your
> > Signed-off-by. I certainly won't object.
> >
> > [1] https://lore.kernel.org/r/ZNC-YRQopO0PaIIo@FVFF77S0Q05N.cambridge.arm.com
> >
> > (no changes since v10)
> >
> > Changes in v10:
> > - Rewrite as needed for 5.11+ as per Mark Rutland and Sumit.
> >
> >  drivers/irqchip/irq-gic-v3.c | 54 ++++++++++++++++++++++++------------
> >  1 file changed, 36 insertions(+), 18 deletions(-)
> >
> > diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
> > index eedfa8e9f077..49d18cf3f636 100644
> > --- a/drivers/irqchip/irq-gic-v3.c
> > +++ b/drivers/irqchip/irq-gic-v3.c
> > @@ -78,6 +78,8 @@ static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
> >  #define GIC_LINE_NR  min(GICD_TYPER_SPIS(gic_data.rdists.gicd_typer), 1020U)
> >  #define GIC_ESPI_NR  GICD_TYPER_ESPIS(gic_data.rdists.gicd_typer)
> >
> > +#define SGI_NR               16
>
> Why 16? We only allocate 8, as the other 8 are potentially stolen by
> the secure side. We do try and initialise them all so that they have a
> known state if they were actually configured as Group-1NS, but we
> don't use them.
>
> I understand that this simplifies the indexing in the rdist_nmi_refs
> array and I'm not going to cry over 32 wasted bytes, but this
> definitely deserves a comment.

Good point. I'll plan to wait another day or two to see if any other
feedback shows up and then send a v12 with this plus Stephen's nit
fixes on one of the other patches.

-Doug
Sumit Garg Aug. 29, 2023, 10:36 a.m. UTC | #3
On Thu, 24 Aug 2023 at 21:03, Douglas Anderson <dianders@chromium.org> wrote:
>
> As of commit 6abbd6988971 ("irqchip/gic, gic-v3: Make SGIs use
> handle_percpu_devid_irq()") SGIs are treated the same as PPIs/EPPIs
> and use handle_percpu_devid_irq() by default. Unfortunately,
> handle_percpu_devid_irq() isn't NMI safe, and so to run in an NMI
> context those should use handle_percpu_devid_fasteoi_nmi().
>
> In order to accomplish this, we just have to make room for SGIs in the
> array of refcounts that keeps track of which interrupts are set as
> NMI. We also rename the array and create a new indexing scheme that
> accounts for SGIs.
>
> Also, enable NMI support prior to gic_smp_init() as allocation of SGIs
> as IRQs/NMIs happen as part of this routine.
>
> Co-developed-by: Sumit Garg <sumit.garg@linaro.org>
> Signed-off-by: Sumit Garg <sumit.garg@linaro.org>
> Signed-off-by: Douglas Anderson <dianders@chromium.org>
> ---
> In v10 I removed the previous Reviewed-by and Tested-by tags since the
> patch contents changed pretty drastically.
>
> I'll also note that this change is a little more black magic to me
> than others in this series. I don't have a massive amounts of
> familiarity with all the moving parts of gic-v3, so I mostly just
> followed Mark Rutland's advice [1]. Please pay extra attention to make
> sure I didn't do anything too terrible.

The changes look good to me. I am not sure if my review tag will be
valuable here since I am a co-developer here.

-Sumit

>
> Mark's advice wasn't a full patch and I ended up doing a bit of work
> to translate it to reality, so I did not add him as "Co-developed-by"
> here. Mark: if you would like this tag then please provide it and your
> Signed-off-by. I certainly won't object.
>
> [1] https://lore.kernel.org/r/ZNC-YRQopO0PaIIo@FVFF77S0Q05N.cambridge.arm.com
>
> (no changes since v10)
>
> Changes in v10:
> - Rewrite as needed for 5.11+ as per Mark Rutland and Sumit.
>
>  drivers/irqchip/irq-gic-v3.c | 54 ++++++++++++++++++++++++------------
>  1 file changed, 36 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
> index eedfa8e9f077..49d18cf3f636 100644
> --- a/drivers/irqchip/irq-gic-v3.c
> +++ b/drivers/irqchip/irq-gic-v3.c
> @@ -78,6 +78,8 @@ static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
>  #define GIC_LINE_NR    min(GICD_TYPER_SPIS(gic_data.rdists.gicd_typer), 1020U)
>  #define GIC_ESPI_NR    GICD_TYPER_ESPIS(gic_data.rdists.gicd_typer)
>
> +#define SGI_NR         16
> +
>  /*
>   * The behaviours of RPR and PMR registers differ depending on the value of
>   * SCR_EL3.FIQ, and the behaviour of non-secure priority registers of the
> @@ -125,8 +127,8 @@ EXPORT_SYMBOL(gic_nonsecure_priorities);
>                 __priority;                                             \
>         })
>
> -/* ppi_nmi_refs[n] == number of cpus having ppi[n + 16] set as NMI */
> -static refcount_t *ppi_nmi_refs;
> +/* rdist_nmi_refs[n] == number of cpus having the rdist interrupt n set as NMI */
> +static refcount_t *rdist_nmi_refs;
>
>  static struct gic_kvm_info gic_v3_kvm_info __initdata;
>  static DEFINE_PER_CPU(bool, has_rss);
> @@ -519,9 +521,22 @@ static u32 __gic_get_ppi_index(irq_hw_number_t hwirq)
>         }
>  }
>
> -static u32 gic_get_ppi_index(struct irq_data *d)
> +static u32 __gic_get_rdist_idx(irq_hw_number_t hwirq)
> +{
> +       switch (__get_intid_range(hwirq)) {
> +       case SGI_RANGE:
> +       case PPI_RANGE:
> +               return hwirq;
> +       case EPPI_RANGE:
> +               return hwirq - EPPI_BASE_INTID + 32;
> +       default:
> +               unreachable();
> +       }
> +}
> +
> +static u32 gic_get_rdist_idx(struct irq_data *d)
>  {
> -       return __gic_get_ppi_index(d->hwirq);
> +       return __gic_get_rdist_idx(d->hwirq);
>  }
>
>  static int gic_irq_nmi_setup(struct irq_data *d)
> @@ -545,11 +560,14 @@ static int gic_irq_nmi_setup(struct irq_data *d)
>
>         /* desc lock should already be held */
>         if (gic_irq_in_rdist(d)) {
> -               u32 idx = gic_get_ppi_index(d);
> +               u32 idx = gic_get_rdist_idx(d);
>
> -               /* Setting up PPI as NMI, only switch handler for first NMI */
> -               if (!refcount_inc_not_zero(&ppi_nmi_refs[idx])) {
> -                       refcount_set(&ppi_nmi_refs[idx], 1);
> +               /*
> +                * Setting up a percpu interrupt as NMI, only switch handler
> +                * for first NMI
> +                */
> +               if (!refcount_inc_not_zero(&rdist_nmi_refs[idx])) {
> +                       refcount_set(&rdist_nmi_refs[idx], 1);
>                         desc->handle_irq = handle_percpu_devid_fasteoi_nmi;
>                 }
>         } else {
> @@ -582,10 +600,10 @@ static void gic_irq_nmi_teardown(struct irq_data *d)
>
>         /* desc lock should already be held */
>         if (gic_irq_in_rdist(d)) {
> -               u32 idx = gic_get_ppi_index(d);
> +               u32 idx = gic_get_rdist_idx(d);
>
>                 /* Tearing down NMI, only switch handler for last NMI */
> -               if (refcount_dec_and_test(&ppi_nmi_refs[idx]))
> +               if (refcount_dec_and_test(&rdist_nmi_refs[idx]))
>                         desc->handle_irq = handle_percpu_devid_irq;
>         } else {
>                 desc->handle_irq = handle_fasteoi_irq;
> @@ -1279,10 +1297,10 @@ static void gic_cpu_init(void)
>         rbase = gic_data_rdist_sgi_base();
>
>         /* Configure SGIs/PPIs as non-secure Group-1 */
> -       for (i = 0; i < gic_data.ppi_nr + 16; i += 32)
> +       for (i = 0; i < gic_data.ppi_nr + SGI_NR; i += 32)
>                 writel_relaxed(~0, rbase + GICR_IGROUPR0 + i / 8);
>
> -       gic_cpu_config(rbase, gic_data.ppi_nr + 16, gic_redist_wait_for_rwp);
> +       gic_cpu_config(rbase, gic_data.ppi_nr + SGI_NR, gic_redist_wait_for_rwp);
>
>         /* initialise system registers */
>         gic_cpu_sys_reg_init();
> @@ -1939,12 +1957,13 @@ static void gic_enable_nmi_support(void)
>                 return;
>         }
>
> -       ppi_nmi_refs = kcalloc(gic_data.ppi_nr, sizeof(*ppi_nmi_refs), GFP_KERNEL);
> -       if (!ppi_nmi_refs)
> +       rdist_nmi_refs = kcalloc(gic_data.ppi_nr + SGI_NR,
> +                                sizeof(*rdist_nmi_refs), GFP_KERNEL);
> +       if (!rdist_nmi_refs)
>                 return;
>
> -       for (i = 0; i < gic_data.ppi_nr; i++)
> -               refcount_set(&ppi_nmi_refs[i], 0);
> +       for (i = 0; i < gic_data.ppi_nr + SGI_NR; i++)
> +               refcount_set(&rdist_nmi_refs[i], 0);
>
>         pr_info("Pseudo-NMIs enabled using %s ICC_PMR_EL1 synchronisation\n",
>                 gic_has_relaxed_pmr_sync() ? "relaxed" : "forced");
> @@ -2061,6 +2080,7 @@ static int __init gic_init_bases(phys_addr_t dist_phys_base,
>
>         gic_dist_init();
>         gic_cpu_init();
> +       gic_enable_nmi_support();
>         gic_smp_init();
>         gic_cpu_pm_init();
>
> @@ -2073,8 +2093,6 @@ static int __init gic_init_bases(phys_addr_t dist_phys_base,
>                         gicv2m_init(handle, gic_data.domain);
>         }
>
> -       gic_enable_nmi_support();
> -
>         return 0;
>
>  out_free:
> --
> 2.42.0.rc1.204.g551eb34607-goog
>
diff mbox series

Patch

diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index eedfa8e9f077..49d18cf3f636 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -78,6 +78,8 @@  static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
 #define GIC_LINE_NR	min(GICD_TYPER_SPIS(gic_data.rdists.gicd_typer), 1020U)
 #define GIC_ESPI_NR	GICD_TYPER_ESPIS(gic_data.rdists.gicd_typer)
 
+#define SGI_NR		16
+
 /*
  * The behaviours of RPR and PMR registers differ depending on the value of
  * SCR_EL3.FIQ, and the behaviour of non-secure priority registers of the
@@ -125,8 +127,8 @@  EXPORT_SYMBOL(gic_nonsecure_priorities);
 		__priority;						\
 	})
 
-/* ppi_nmi_refs[n] == number of cpus having ppi[n + 16] set as NMI */
-static refcount_t *ppi_nmi_refs;
+/* rdist_nmi_refs[n] == number of cpus having the rdist interrupt n set as NMI */
+static refcount_t *rdist_nmi_refs;
 
 static struct gic_kvm_info gic_v3_kvm_info __initdata;
 static DEFINE_PER_CPU(bool, has_rss);
@@ -519,9 +521,22 @@  static u32 __gic_get_ppi_index(irq_hw_number_t hwirq)
 	}
 }
 
-static u32 gic_get_ppi_index(struct irq_data *d)
+static u32 __gic_get_rdist_idx(irq_hw_number_t hwirq)
+{
+	switch (__get_intid_range(hwirq)) {
+	case SGI_RANGE:
+	case PPI_RANGE:
+		return hwirq;
+	case EPPI_RANGE:
+		return hwirq - EPPI_BASE_INTID + 32;
+	default:
+		unreachable();
+	}
+}
+
+static u32 gic_get_rdist_idx(struct irq_data *d)
 {
-	return __gic_get_ppi_index(d->hwirq);
+	return __gic_get_rdist_idx(d->hwirq);
 }
 
 static int gic_irq_nmi_setup(struct irq_data *d)
@@ -545,11 +560,14 @@  static int gic_irq_nmi_setup(struct irq_data *d)
 
 	/* desc lock should already be held */
 	if (gic_irq_in_rdist(d)) {
-		u32 idx = gic_get_ppi_index(d);
+		u32 idx = gic_get_rdist_idx(d);
 
-		/* Setting up PPI as NMI, only switch handler for first NMI */
-		if (!refcount_inc_not_zero(&ppi_nmi_refs[idx])) {
-			refcount_set(&ppi_nmi_refs[idx], 1);
+		/*
+		 * Setting up a percpu interrupt as NMI, only switch handler
+		 * for first NMI
+		 */
+		if (!refcount_inc_not_zero(&rdist_nmi_refs[idx])) {
+			refcount_set(&rdist_nmi_refs[idx], 1);
 			desc->handle_irq = handle_percpu_devid_fasteoi_nmi;
 		}
 	} else {
@@ -582,10 +600,10 @@  static void gic_irq_nmi_teardown(struct irq_data *d)
 
 	/* desc lock should already be held */
 	if (gic_irq_in_rdist(d)) {
-		u32 idx = gic_get_ppi_index(d);
+		u32 idx = gic_get_rdist_idx(d);
 
 		/* Tearing down NMI, only switch handler for last NMI */
-		if (refcount_dec_and_test(&ppi_nmi_refs[idx]))
+		if (refcount_dec_and_test(&rdist_nmi_refs[idx]))
 			desc->handle_irq = handle_percpu_devid_irq;
 	} else {
 		desc->handle_irq = handle_fasteoi_irq;
@@ -1279,10 +1297,10 @@  static void gic_cpu_init(void)
 	rbase = gic_data_rdist_sgi_base();
 
 	/* Configure SGIs/PPIs as non-secure Group-1 */
-	for (i = 0; i < gic_data.ppi_nr + 16; i += 32)
+	for (i = 0; i < gic_data.ppi_nr + SGI_NR; i += 32)
 		writel_relaxed(~0, rbase + GICR_IGROUPR0 + i / 8);
 
-	gic_cpu_config(rbase, gic_data.ppi_nr + 16, gic_redist_wait_for_rwp);
+	gic_cpu_config(rbase, gic_data.ppi_nr + SGI_NR, gic_redist_wait_for_rwp);
 
 	/* initialise system registers */
 	gic_cpu_sys_reg_init();
@@ -1939,12 +1957,13 @@  static void gic_enable_nmi_support(void)
 		return;
 	}
 
-	ppi_nmi_refs = kcalloc(gic_data.ppi_nr, sizeof(*ppi_nmi_refs), GFP_KERNEL);
-	if (!ppi_nmi_refs)
+	rdist_nmi_refs = kcalloc(gic_data.ppi_nr + SGI_NR,
+				 sizeof(*rdist_nmi_refs), GFP_KERNEL);
+	if (!rdist_nmi_refs)
 		return;
 
-	for (i = 0; i < gic_data.ppi_nr; i++)
-		refcount_set(&ppi_nmi_refs[i], 0);
+	for (i = 0; i < gic_data.ppi_nr + SGI_NR; i++)
+		refcount_set(&rdist_nmi_refs[i], 0);
 
 	pr_info("Pseudo-NMIs enabled using %s ICC_PMR_EL1 synchronisation\n",
 		gic_has_relaxed_pmr_sync() ? "relaxed" : "forced");
@@ -2061,6 +2080,7 @@  static int __init gic_init_bases(phys_addr_t dist_phys_base,
 
 	gic_dist_init();
 	gic_cpu_init();
+	gic_enable_nmi_support();
 	gic_smp_init();
 	gic_cpu_pm_init();
 
@@ -2073,8 +2093,6 @@  static int __init gic_init_bases(phys_addr_t dist_phys_base,
 			gicv2m_init(handle, gic_data.domain);
 	}
 
-	gic_enable_nmi_support();
-
 	return 0;
 
 out_free: