mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 19:29:37 +00:00
irqchip updates for 5.17
- 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 -----BEGIN PGP SIGNATURE----- iQJDBAABCgAtFiEEn9UcU+C1Yxj9lZw9I9DQutE9ekMFAmHZitYPHG1hekBrZXJu ZWwub3JnAAoJECPQ0LrRPXpDH4UP/3hsBH9KGWFakokvJJqXb8OS9LW2K8bEDm1B 9FaDAL6KamZVCGQmBUrzxuBSw1YSQszFZ752ozQpioEQ5IyTUcVbocxNznUOIOFc F38f3jOS7KmjqTIMi7AM+lZPqrBH17cnMpRCorNF4CWVM+iHUUrxdYfV7AGifHyX zpl9okkNpgdpO4gPBbPA0BBhIT+a9lmzqfFrfo+sMin6bgmk1mq3tJ4pVJV5K8KL PXwa123eEtnr2P7JVnp+ChoECdv4QEFS0gFHw9CgE0XsKa5NjDoJsEkhl5lnNkTV q387HGFyERsplknPzxLbF26IJQcUuJTX3PQFvuvv43ZNOqA/QI42956yIZ4KU6Er cDWle9uj7xeHSbU48yz7wIGddpDY6abxlq4C8897itWiepR2iswW0hmEebFfDQ9n A2imKdxZ6sUwwJ/lYiapdu6L5R9v1yx/4cmHfGyE1/FO5qKGzMOSKBJFt6eu+PdH Lb04N+3IyhhI0REzZ/q803Gr9MsZ8SHl2x14BO6olLOvvVDn4p4QoL2mvsidpO3/ /SIKvElW9/jZSmmaW4pOchXbm6RX0cuiu2PtKk5srh7MoX2zoiRh5hsVzpCBNwxX w5xbFCYX7s+KstG2kgnbRYrfsrgPl+6gX8M4bftYl3K9/bJ8ULSYEHAvI4emYlN2 6u89hrQL =MDM3 -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
67d50b5f91
9 changed files with 112 additions and 19 deletions
|
@ -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", },
|
||||
{},
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue