diff options
Diffstat (limited to 'drivers/irqchip/irq-gic-v3.c')
-rw-r--r-- | drivers/irqchip/irq-gic-v3.c | 99 |
1 files changed, 86 insertions, 13 deletions
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index d99cc07903ec..e5d101418390 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -61,7 +61,7 @@ struct gic_chip_data { }; static struct gic_chip_data gic_data __read_mostly; -static struct static_key supports_deactivate = STATIC_KEY_INIT_TRUE; +static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key); static struct gic_kvm_info gic_v3_kvm_info; static DEFINE_PER_CPU(bool, has_rss); @@ -354,7 +354,7 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) { int err; - if (static_key_true(&supports_deactivate)) + if (static_branch_likely(&supports_deactivate_key)) gic_write_eoir(irqnr); else isb(); @@ -362,7 +362,7 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs err = handle_domain_irq(gic_data.domain, irqnr, regs); if (err) { WARN_ONCE(true, "Unexpected interrupt received!\n"); - if (static_key_true(&supports_deactivate)) { + if (static_branch_likely(&supports_deactivate_key)) { if (irqnr < 8192) gic_write_dir(irqnr); } else { @@ -373,7 +373,7 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs } if (irqnr < 16) { gic_write_eoir(irqnr); - if (static_key_true(&supports_deactivate)) + if (static_branch_likely(&supports_deactivate_key)) gic_write_dir(irqnr); #ifdef CONFIG_SMP /* @@ -532,6 +532,8 @@ static void gic_cpu_sys_reg_init(void) int i, cpu = smp_processor_id(); u64 mpidr = cpu_logical_map(cpu); u64 need_rss = MPIDR_RS(mpidr); + bool group0; + u32 val, pribits; /* * Need to check that the SRE bit has actually been set. If @@ -543,8 +545,28 @@ static void gic_cpu_sys_reg_init(void) if (!gic_enable_sre()) pr_err("GIC: unable to set SRE (disabled at EL2), panic ahead\n"); + pribits = gic_read_ctlr(); + pribits &= ICC_CTLR_EL1_PRI_BITS_MASK; + pribits >>= ICC_CTLR_EL1_PRI_BITS_SHIFT; + pribits++; + + /* + * Let's find out if Group0 is under control of EL3 or not by + * setting the highest possible, non-zero priority in PMR. + * + * If SCR_EL3.FIQ is set, the priority gets shifted down in + * order for the CPU interface to set bit 7, and keep the + * actual priority in the non-secure range. In the process, it + * looses the least significant bit and the actual priority + * becomes 0x80. Reading it back returns 0, indicating that + * we're don't have access to Group0. + */ + write_gicreg(BIT(8 - pribits), ICC_PMR_EL1); + val = read_gicreg(ICC_PMR_EL1); + group0 = val != 0; + /* Set priority mask register */ - gic_write_pmr(DEFAULT_PMR_VALUE); + write_gicreg(DEFAULT_PMR_VALUE, ICC_PMR_EL1); /* * Some firmwares hand over to the kernel with the BPR changed from @@ -554,7 +576,7 @@ static void gic_cpu_sys_reg_init(void) */ gic_write_bpr1(0); - if (static_key_true(&supports_deactivate)) { + if (static_branch_likely(&supports_deactivate_key)) { /* EOI drops priority only (mode 1) */ gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop); } else { @@ -562,6 +584,37 @@ static void gic_cpu_sys_reg_init(void) gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir); } + /* Always whack Group0 before Group1 */ + if (group0) { + switch(pribits) { + case 8: + case 7: + write_gicreg(0, ICC_AP0R3_EL1); + write_gicreg(0, ICC_AP0R2_EL1); + case 6: + write_gicreg(0, ICC_AP0R1_EL1); + case 5: + case 4: + write_gicreg(0, ICC_AP0R0_EL1); + } + + isb(); + } + + switch(pribits) { + case 8: + case 7: + write_gicreg(0, ICC_AP1R3_EL1); + write_gicreg(0, ICC_AP1R2_EL1); + case 6: + write_gicreg(0, ICC_AP1R1_EL1); + case 5: + case 4: + write_gicreg(0, ICC_AP1R0_EL1); + } + + isb(); + /* ... and let's hit the road... */ gic_write_grpen1(1); @@ -590,9 +643,17 @@ static void gic_cpu_sys_reg_init(void) pr_crit_once("RSS is required but GICD doesn't support it\n"); } +static bool gicv3_nolpi; + +static int __init gicv3_nolpi_cfg(char *buf) +{ + return strtobool(buf, &gicv3_nolpi); +} +early_param("irqchip.gicv3_nolpi", gicv3_nolpi_cfg); + static int gic_dist_supports_lpis(void) { - return !!(readl_relaxed(gic_data.dist_base + GICD_TYPER) & GICD_TYPER_LPIS); + return !!(readl_relaxed(gic_data.dist_base + GICD_TYPER) & GICD_TYPER_LPIS) && !gicv3_nolpi; } static void gic_cpu_init(void) @@ -823,7 +884,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, { struct irq_chip *chip = &gic_chip; - if (static_key_true(&supports_deactivate)) + if (static_branch_likely(&supports_deactivate_key)) chip = &gic_eoimode1_chip; /* SGIs are private to the core kernel */ @@ -861,6 +922,8 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, return 0; } +#define GIC_IRQ_TYPE_PARTITION (GIC_IRQ_TYPE_LPI + 1) + static int gic_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec, unsigned long *hwirq, @@ -875,6 +938,7 @@ static int gic_irq_domain_translate(struct irq_domain *d, *hwirq = fwspec->param[1] + 32; break; case 1: /* PPI */ + case GIC_IRQ_TYPE_PARTITION: *hwirq = fwspec->param[1] + 16; break; case GIC_IRQ_TYPE_LPI: /* LPI */ @@ -885,6 +949,13 @@ static int gic_irq_domain_translate(struct irq_domain *d, } *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; + + /* + * Make it clear that broken DTs are... broken. + * Partitionned PPIs are an unfortunate exception. + */ + WARN_ON(*type == IRQ_TYPE_NONE && + fwspec->param[0] != GIC_IRQ_TYPE_PARTITION); return 0; } @@ -894,6 +965,8 @@ static int gic_irq_domain_translate(struct irq_domain *d, *hwirq = fwspec->param[0]; *type = fwspec->param[1]; + + WARN_ON(*type == IRQ_TYPE_NONE); return 0; } @@ -1002,9 +1075,9 @@ static int __init gic_init_bases(void __iomem *dist_base, int err; if (!is_hyp_mode_available()) - static_key_slow_dec(&supports_deactivate); + static_branch_disable(&supports_deactivate_key); - if (static_key_true(&supports_deactivate)) + if (static_branch_likely(&supports_deactivate_key)) pr_info("GIC: Using split EOI/Deactivate mode\n"); gic_data.fwnode = handle; @@ -1140,7 +1213,7 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node) .fwnode = gic_data.fwnode, .param_count = 3, .param = { - [0] = 1, + [0] = GIC_IRQ_TYPE_PARTITION, [1] = i, [2] = IRQ_TYPE_NONE, }, @@ -1239,7 +1312,7 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare gic_populate_ppi_partitions(node); - if (static_key_true(&supports_deactivate)) + if (static_branch_likely(&supports_deactivate_key)) gic_of_setup_kvm_info(node); return 0; @@ -1541,7 +1614,7 @@ gic_acpi_init(struct acpi_subtable_header *header, const unsigned long end) acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle); - if (static_key_true(&supports_deactivate)) + if (static_branch_likely(&supports_deactivate_key)) gic_acpi_setup_kvm_info(); return 0; |