Merge tag 'irqchip-5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm...
authorThomas Gleixner <tglx@linutronix.de>
Mon, 10 Jan 2022 12:55:41 +0000 (13:55 +0100)
committerThomas Gleixner <tglx@linutronix.de>
Mon, 10 Jan 2022 12:55:41 +0000 (13:55 +0100)
Pull irqchip updates from Marc Zyngier:

 - Fix GICv3 redistributor table reservation with RT across kexec

 - Fix GICv4.1 redistributor view of the VPE table across kexec

 - Add support for extra interrupts on spear-shirq

 - Make obtaining some interrupts optional for the Renesas drivers

 - Various cleanups and bug fixes

Link: https://lore.kernel.org/lkml/20220108130807.4109738-1-maz@kernel.org
drivers/irqchip/irq-gic-v2m.c
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-gic-v3.c
drivers/irqchip/irq-imx-gpcv2.c
drivers/irqchip/irq-ingenic-tcu.c
drivers/irqchip/irq-renesas-intc-irqpin.c
drivers/irqchip/irq-renesas-irqc.c
drivers/irqchip/spear-shirq.c
include/linux/irqchip/arm-gic-v3.h

index 9349fc6..f2d252d 100644 (file)
@@ -405,7 +405,7 @@ err_free_v2m:
        return ret;
 }
 
-static struct of_device_id gicv2m_device_id[] = {
+static const struct of_device_id gicv2m_device_id[] = {
        {       .compatible     = "arm,gic-v2m-frame",  },
        {},
 };
index 0cb584d..d25b7a8 100644 (file)
 #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING    (1 << 0)
 #define RDIST_FLAGS_RD_TABLES_PREALLOCATED     (1 << 1)
 
+#define RD_LOCAL_LPI_ENABLED                    BIT(0)
+#define RD_LOCAL_PENDTABLE_PREALLOCATED         BIT(1)
+#define RD_LOCAL_MEMRESERVE_DONE                BIT(2)
+
 static u32 lpi_id_bits;
 
 /*
@@ -3044,7 +3048,7 @@ static void its_cpu_init_lpis(void)
        phys_addr_t paddr;
        u64 val, tmp;
 
-       if (gic_data_rdist()->lpi_enabled)
+       if (gic_data_rdist()->flags & RD_LOCAL_LPI_ENABLED)
                return;
 
        val = readl_relaxed(rbase + GICR_CTLR);
@@ -3063,15 +3067,13 @@ static void its_cpu_init_lpis(void)
                paddr &= GENMASK_ULL(51, 16);
 
                WARN_ON(!gic_check_reserved_range(paddr, LPI_PENDBASE_SZ));
-               its_free_pending_table(gic_data_rdist()->pend_page);
-               gic_data_rdist()->pend_page = NULL;
+               gic_data_rdist()->flags |= RD_LOCAL_PENDTABLE_PREALLOCATED;
 
                goto out;
        }
 
        pend_page = gic_data_rdist()->pend_page;
        paddr = page_to_phys(pend_page);
-       WARN_ON(gic_reserve_range(paddr, LPI_PENDBASE_SZ));
 
        /* set PROPBASE */
        val = (gic_rdists->prop_table_pa |
@@ -3158,10 +3160,11 @@ static void its_cpu_init_lpis(void)
        /* Make sure the GIC has seen the above */
        dsb(sy);
 out:
-       gic_data_rdist()->lpi_enabled = true;
+       gic_data_rdist()->flags |= RD_LOCAL_LPI_ENABLED;
        pr_info("GICv3: CPU%d: using %s LPI pending table @%pa\n",
                smp_processor_id(),
-               gic_data_rdist()->pend_page ? "allocated" : "reserved",
+               gic_data_rdist()->flags & RD_LOCAL_PENDTABLE_PREALLOCATED ?
+               "reserved" : "allocated",
                &paddr);
 }
 
@@ -5138,7 +5141,7 @@ static int redist_disable_lpis(void)
         *
         * If running with preallocated tables, there is nothing to do.
         */
-       if (gic_data_rdist()->lpi_enabled ||
+       if ((gic_data_rdist()->flags & RD_LOCAL_LPI_ENABLED) ||
            (gic_rdists->flags & RDIST_FLAGS_RD_TABLES_PREALLOCATED))
                return 0;
 
@@ -5200,6 +5203,51 @@ int its_cpu_init(void)
        return 0;
 }
 
+static void rdist_memreserve_cpuhp_cleanup_workfn(struct work_struct *work)
+{
+       cpuhp_remove_state_nocalls(gic_rdists->cpuhp_memreserve_state);
+       gic_rdists->cpuhp_memreserve_state = CPUHP_INVALID;
+}
+
+static DECLARE_WORK(rdist_memreserve_cpuhp_cleanup_work,
+                   rdist_memreserve_cpuhp_cleanup_workfn);
+
+static int its_cpu_memreserve_lpi(unsigned int cpu)
+{
+       struct page *pend_page;
+       int ret = 0;
+
+       /* This gets to run exactly once per CPU */
+       if (gic_data_rdist()->flags & RD_LOCAL_MEMRESERVE_DONE)
+               return 0;
+
+       pend_page = gic_data_rdist()->pend_page;
+       if (WARN_ON(!pend_page)) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       /*
+        * If the pending table was pre-programmed, free the memory we
+        * preemptively allocated. Otherwise, reserve that memory for
+        * later kexecs.
+        */
+       if (gic_data_rdist()->flags & RD_LOCAL_PENDTABLE_PREALLOCATED) {
+               its_free_pending_table(pend_page);
+               gic_data_rdist()->pend_page = NULL;
+       } else {
+               phys_addr_t paddr = page_to_phys(pend_page);
+               WARN_ON(gic_reserve_range(paddr, LPI_PENDBASE_SZ));
+       }
+
+out:
+       /* Last CPU being brought up gets to issue the cleanup */
+       if (cpumask_equal(&cpus_booted_once_mask, cpu_possible_mask))
+               schedule_work(&rdist_memreserve_cpuhp_cleanup_work);
+
+       gic_data_rdist()->flags |= RD_LOCAL_MEMRESERVE_DONE;
+       return ret;
+}
+
 static const struct of_device_id its_device_id[] = {
        {       .compatible     = "arm,gic-v3-its",     },
        {},
@@ -5383,6 +5431,26 @@ static void __init its_acpi_probe(void)
 static void __init its_acpi_probe(void) { }
 #endif
 
+int __init its_lpi_memreserve_init(void)
+{
+       int state;
+
+       if (!efi_enabled(EFI_CONFIG_TABLES))
+               return 0;
+
+       gic_rdists->cpuhp_memreserve_state = CPUHP_INVALID;
+       state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
+                                 "irqchip/arm/gicv3/memreserve:online",
+                                 its_cpu_memreserve_lpi,
+                                 NULL);
+       if (state < 0)
+               return state;
+
+       gic_rdists->cpuhp_memreserve_state = state;
+
+       return 0;
+}
+
 int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
                    struct irq_domain *parent_domain)
 {
index daec330..5e935d9 100644 (file)
@@ -920,6 +920,22 @@ static int __gic_update_rdist_properties(struct redist_region *region,
 {
        u64 typer = gic_read_typer(ptr + GICR_TYPER);
 
+       /* Boot-time cleanip */
+       if ((typer & GICR_TYPER_VLPIS) && (typer & GICR_TYPER_RVPEID)) {
+               u64 val;
+
+               /* Deactivate any present vPE */
+               val = gicr_read_vpendbaser(ptr + SZ_128K + GICR_VPENDBASER);
+               if (val & GICR_VPENDBASER_Valid)
+                       gicr_write_vpendbaser(GICR_VPENDBASER_PendingLast,
+                                             ptr + SZ_128K + GICR_VPENDBASER);
+
+               /* Mark the VPE table as invalid */
+               val = gicr_read_vpropbaser(ptr + SZ_128K + GICR_VPROPBASER);
+               val &= ~GICR_VPROPBASER_4_1_VALID;
+               gicr_write_vpropbaser(val, ptr + SZ_128K + GICR_VPROPBASER);
+       }
+
        gic_data.rdists.has_vlpis &= !!(typer & GICR_TYPER_VLPIS);
 
        /* RVPEID implies some form of DirectLPI, no matter what the doc says... :-/ */
@@ -1802,6 +1818,7 @@ static int __init gic_init_bases(void __iomem *dist_base,
        if (gic_dist_supports_lpis()) {
                its_init(handle, &gic_data.rdists, gic_data.domain);
                its_cpu_init();
+               its_lpi_memreserve_init();
        } else {
                if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
                        gicv2m_init(handle, gic_data.domain);
index 5b5a365..b9c22f7 100644 (file)
@@ -26,7 +26,7 @@ struct gpcv2_irqchip_data {
        u32                     cpu2wakeup;
 };
 
-static struct gpcv2_irqchip_data *imx_gpcv2_instance;
+static struct gpcv2_irqchip_data *imx_gpcv2_instance __ro_after_init;
 
 static void __iomem *gpcv2_idx_to_reg(struct gpcv2_irqchip_data *cd, int i)
 {
index 34a7d26..3363f83 100644 (file)
@@ -28,6 +28,7 @@ static void ingenic_tcu_intc_cascade(struct irq_desc *desc)
        struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0);
        struct regmap *map = gc->private;
        uint32_t irq_reg, irq_mask;
+       unsigned long bits;
        unsigned int i;
 
        regmap_read(map, TCU_REG_TFR, &irq_reg);
@@ -36,8 +37,9 @@ static void ingenic_tcu_intc_cascade(struct irq_desc *desc)
        chained_irq_enter(irq_chip, desc);
 
        irq_reg &= ~irq_mask;
+       bits = irq_reg;
 
-       for_each_set_bit(i, (unsigned long *)&irq_reg, 32)
+       for_each_set_bit(i, &bits, 32)
                generic_handle_domain_irq(domain, i);
 
        chained_irq_exit(irq_chip, desc);
index cb7f60b..37f9a44 100644 (file)
@@ -375,7 +375,6 @@ static int intc_irqpin_probe(struct platform_device *pdev)
        struct intc_irqpin_priv *p;
        struct intc_irqpin_iomem *i;
        struct resource *io[INTC_IRQPIN_REG_NR];
-       struct resource *irq;
        struct irq_chip *irq_chip;
        void (*enable_fn)(struct irq_data *d);
        void (*disable_fn)(struct irq_data *d);
@@ -418,12 +417,14 @@ static int intc_irqpin_probe(struct platform_device *pdev)
 
        /* allow any number of IRQs between 1 and INTC_IRQPIN_MAX */
        for (k = 0; k < INTC_IRQPIN_MAX; k++) {
-               irq = platform_get_resource(pdev, IORESOURCE_IRQ, k);
-               if (!irq)
+               ret = platform_get_irq_optional(pdev, k);
+               if (ret == -ENXIO)
                        break;
+               if (ret < 0)
+                       goto err0;
 
                p->irq[k].p = p;
-               p->irq[k].requested_irq = irq->start;
+               p->irq[k].requested_irq = ret;
        }
 
        nirqs = k;
index 07a6d8b..909325f 100644 (file)
@@ -126,7 +126,6 @@ static int irqc_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        const char *name = dev_name(dev);
        struct irqc_priv *p;
-       struct resource *irq;
        int ret;
        int k;
 
@@ -142,13 +141,15 @@ static int irqc_probe(struct platform_device *pdev)
 
        /* allow any number of IRQs between 1 and IRQC_IRQ_MAX */
        for (k = 0; k < IRQC_IRQ_MAX; k++) {
-               irq = platform_get_resource(pdev, IORESOURCE_IRQ, k);
-               if (!irq)
+               ret = platform_get_irq_optional(pdev, k);
+               if (ret == -ENXIO)
                        break;
+               if (ret < 0)
+                       goto err_runtime_pm_disable;
 
                p->irq[k].p = p;
                p->irq[k].hw_irq = k;
-               p->irq[k].requested_irq = irq->start;
+               p->irq[k].requested_irq = ret;
        }
 
        p->number_of_irqs = k;
index 1518ba3..7c17a6f 100644 (file)
@@ -149,6 +149,8 @@ static struct spear_shirq spear320_shirq_ras3 = {
        .offset         = 0,
        .nr_irqs        = 7,
        .mask           = ((0x1 << 7) - 1) << 0,
+       .irq_chip       = &dummy_irq_chip,
+       .status_reg     = SPEAR320_INT_STS_MASK_REG,
 };
 
 static struct spear_shirq spear320_shirq_ras1 = {
index 81cbf85..12d91f0 100644 (file)
@@ -615,7 +615,7 @@ struct rdists {
                void __iomem    *rd_base;
                struct page     *pend_page;
                phys_addr_t     phys_base;
-               bool            lpi_enabled;
+               u64             flags;
                cpumask_t       *vpe_table_mask;
                void            *vpe_l1_base;
        } __percpu              *rdist;
@@ -624,6 +624,7 @@ struct rdists {
        u64                     flags;
        u32                     gicd_typer;
        u32                     gicd_typer2;
+       int                     cpuhp_memreserve_state;
        bool                    has_vlpis;
        bool                    has_rvpeid;
        bool                    has_direct_lpi;
@@ -632,6 +633,7 @@ struct rdists {
 
 struct irq_domain;
 struct fwnode_handle;
+int __init its_lpi_memreserve_init(void);
 int its_cpu_init(void);
 int its_init(struct fwnode_handle *handle, struct rdists *rdists,
             struct irq_domain *domain);