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 |
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.
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
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 --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: