Commit 67d50b5f authored by Thomas Gleixner's avatar Thomas Gleixner
Browse files

Merge tag 'irqchip-5.17' of...

Merge tag 'irqchip-5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms into irq/core

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
parents 0422fe26 cd448b24
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -405,7 +405,7 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
	return ret;
}

static struct of_device_id gicv2m_device_id[] = {
static const struct of_device_id gicv2m_device_id[] = {
	{	.compatible	= "arm,gic-v2m-frame",	},
	{},
};
+75 −7
Original line number Diff line number Diff line
@@ -46,6 +46,10 @@
#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)
{
+17 −0
Original line number Diff line number Diff line
@@ -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);
+1 −1
Original line number Diff line number Diff line
@@ -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)
{
+3 −1
Original line number Diff line number Diff line
@@ -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);
Loading