Hi Sumit,

On 2020-05-20 10:52, Sumit Garg wrote:
Hi Marc,

On Tue, 19 May 2020 at 21:48, Marc Zyngier <m...@kernel.org> wrote:

Change the way we deal with GICv3 SGIs by turning them into proper
IRQs, and calling into the arch code to register the interrupt range
instead of a callback.

Signed-off-by: Marc Zyngier <m...@kernel.org>
---
drivers/irqchip/irq-gic-v3.c | 91 +++++++++++++++++++++---------------
 1 file changed, 53 insertions(+), 38 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 23d7c87da407..d57289057b75 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -36,6 +36,9 @@
 #define FLAGS_WORKAROUND_GICR_WAKER_MSM8996    (1ULL << 0)
 #define FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539  (1ULL << 1)

+#define GIC_IRQ_TYPE_PARTITION (GIC_IRQ_TYPE_LPI + 1)
+#define GIC_IRQ_TYPE_SGI       (GIC_IRQ_TYPE_LPI + 2)
+
 struct redist_region {
        void __iomem            *redist_base;
        phys_addr_t             phys_base;
@@ -657,38 +660,14 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
        if ((irqnr >= 1020 && irqnr <= 1023))
                return;

-       /* Treat anything but SGIs in a uniform way */
-       if (likely(irqnr > 15)) {
-               int err;
-
-               if (static_branch_likely(&supports_deactivate_key))
-                       gic_write_eoir(irqnr);
-               else
-                       isb();
-
-               err = handle_domain_irq(gic_data.domain, irqnr, regs);
-               if (err) {
- WARN_ONCE(true, "Unexpected interrupt received!\n");
-                       gic_deactivate_unhandled(irqnr);
-               }
-               return;
-       }
-       if (irqnr < 16) {
+       if (static_branch_likely(&supports_deactivate_key))
                gic_write_eoir(irqnr);
-               if (static_branch_likely(&supports_deactivate_key))
-                       gic_write_dir(irqnr);
-#ifdef CONFIG_SMP
-               /*
-                * Unlike GICv2, we don't need an smp_rmb() here.
-                * The control dependency from gic_read_iar to
-                * the ISB in gic_write_eoir is enough to ensure
-                * that any shared data read by handle_IPI will
-                * be read after the ACK.
-                */
-               handle_IPI(irqnr, regs);
-#else
-               WARN_ONCE(true, "Unexpected SGI received!\n");
-#endif
+       else
+               isb();
+
+       if (handle_domain_irq(gic_data.domain, irqnr, regs)) {
+               WARN_ONCE(true, "Unexpected interrupt received!\n");
+               gic_deactivate_unhandled(irqnr);
        }
 }

@@ -1136,11 +1115,11 @@ static void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq)
        gic_write_sgi1r(val);
 }

-static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) +static void gic_ipi_send_mask(struct irq_data *d, const struct cpumask *mask)
 {
        int cpu;

-       if (WARN_ON(irq >= 16))
+       if (WARN_ON(d->hwirq >= 16))
                return;

        /*
@@ -1154,7 +1133,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
                u16 tlist;

tlist = gic_compute_target_list(&cpu, mask, cluster_id);
-               gic_send_sgi(cluster_id, tlist, irq);
+               gic_send_sgi(cluster_id, tlist, d->hwirq);
        }

        /* Force the above writes to ICC_SGI1R_EL1 to be executed */
@@ -1163,10 +1142,36 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)

 static void gic_smp_init(void)
 {
-       set_smp_cross_call(gic_raise_softirq);
+       struct irq_fwspec sgi_fwspec = {
+               .fwnode         = gic_data.fwnode,
+       };
+       int base_sgi;
+
        cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GIC_STARTING,
                                  "irqchip/arm/gicv3:starting",
                                  gic_starting_cpu, NULL);
+
+       if (is_of_node(gic_data.fwnode)) {
+               /* DT */
+               sgi_fwspec.param_count = 3;
+               sgi_fwspec.param[0] = GIC_IRQ_TYPE_SGI;
+               sgi_fwspec.param[1] = 0;
+               sgi_fwspec.param[2] = IRQ_TYPE_EDGE_RISING;
+       } else {
+               /* ACPI */
+               sgi_fwspec.param_count = 2;
+               sgi_fwspec.param[0] = 0;
+               sgi_fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
+       }
+
+       /* Register all 8 non-secure SGIs */
+       base_sgi = __irq_domain_alloc_irqs(gic_data.domain, -1, 8,
+                                          NUMA_NO_NODE, &sgi_fwspec,
+                                          false, NULL);
+       if (WARN_ON(base_sgi <= 0))
+               return;
+
+       set_smp_ipi_range(base_sgi, 8);
 }

static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, @@ -1215,6 +1220,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
 }
 #else
 #define gic_set_affinity       NULL
+#define gic_ipi_send_mask      NULL
 #define gic_smp_init()         do { } while(0)
 #endif

@@ -1257,6 +1263,7 @@ static struct irq_chip gic_chip = {
        .irq_set_irqchip_state  = gic_irq_set_irqchip_state,
        .irq_nmi_setup          = gic_irq_nmi_setup,
        .irq_nmi_teardown       = gic_irq_nmi_teardown,
+       .ipi_send_mask          = gic_ipi_send_mask,
        .flags                  = IRQCHIP_SET_TYPE_MASKED |
                                  IRQCHIP_SKIP_SET_WAKE |
                                  IRQCHIP_MASK_ON_SUSPEND,

It looks like you missed to update "struct irq_chip gic_eoimode1_chip"
with similar change as follows:

diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 2a09634..ceef63b 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -1291,6 +1291,7 @@ static struct irq_chip gic_eoimode1_chip = {
        .irq_set_vcpu_affinity  = gic_irq_set_vcpu_affinity,
        .irq_nmi_setup          = gic_irq_nmi_setup,
        .irq_nmi_teardown       = gic_irq_nmi_teardown,
+       .ipi_send_mask          = gic_ipi_send_mask,
        .flags                  = IRQCHIP_SET_TYPE_MASKED |
                                  IRQCHIP_SKIP_SET_WAKE |
                                  IRQCHIP_MASK_ON_SUSPEND,

After incorporating this change, your patch-set works fine on my
Developerbox machine.

Huh, well spotted. As I said, it has only been tested as guests,
hence not hitting this path. Time to throw it at the bigger stuff.

Thanks,

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

Reply via email to