aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShanker Donthineni <shankerd@codeaurora.org>2018-03-21 21:58:49 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2018-03-23 05:24:25 -0400
commit6eb486b66a3094cdcd68dc39c9df3a29d6a51dd5 (patch)
tree95e04c50da1d0477c2ce6a23ebe63ea4c4c8b139
parent19d99164480a34db66941cf995bdd996cc266fc0 (diff)
irqchip/gic-v3: Ensure GICR_CTLR.EnableLPI=0 is observed before enabling
Booting with GICR_CTLR.EnableLPI=1 is usually a bad idea, and may result in subtle memory corruption. Detecting this is thus pretty important. On detecting that LPIs are still enabled, we taint the kernel (because we're not sure of anything anymore), and try to disable LPIs. This can fail, as implementations are allowed to implement GICR_CTLR.EnableLPI as a one-way enable, meaning the redistributors cannot be reprogrammed with new tables. Should this happen, we fail probing the redistributor and warn the user that things are pretty dire. Signed-off-by: Shanker Donthineni <shankerd@codeaurora.org> [maz: reworded changelog, minor comment and message changes] Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c74
-rw-r--r--include/linux/irqchip/arm-gic-v3.h1
2 files changed, 61 insertions, 14 deletions
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 2c9006726450..cb952c073d77 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -1879,16 +1879,6 @@ static void its_cpu_init_lpis(void)
1879 gic_data_rdist()->pend_page = pend_page; 1879 gic_data_rdist()->pend_page = pend_page;
1880 } 1880 }
1881 1881
1882 /* Disable LPIs */
1883 val = readl_relaxed(rbase + GICR_CTLR);
1884 val &= ~GICR_CTLR_ENABLE_LPIS;
1885 writel_relaxed(val, rbase + GICR_CTLR);
1886
1887 /*
1888 * Make sure any change to the table is observable by the GIC.
1889 */
1890 dsb(sy);
1891
1892 /* set PROPBASE */ 1882 /* set PROPBASE */
1893 val = (page_to_phys(gic_rdists->prop_page) | 1883 val = (page_to_phys(gic_rdists->prop_page) |
1894 GICR_PROPBASER_InnerShareable | 1884 GICR_PROPBASER_InnerShareable |
@@ -3403,13 +3393,69 @@ static bool gic_rdists_supports_plpis(void)
3403 return !!(gic_read_typer(gic_data_rdist_rd_base() + GICR_TYPER) & GICR_TYPER_PLPIS); 3393 return !!(gic_read_typer(gic_data_rdist_rd_base() + GICR_TYPER) & GICR_TYPER_PLPIS);
3404} 3394}
3405 3395
3396static int redist_disable_lpis(void)
3397{
3398 void __iomem *rbase = gic_data_rdist_rd_base();
3399 u64 timeout = USEC_PER_SEC;
3400 u64 val;
3401
3402 if (!gic_rdists_supports_plpis()) {
3403 pr_info("CPU%d: LPIs not supported\n", smp_processor_id());
3404 return -ENXIO;
3405 }
3406
3407 val = readl_relaxed(rbase + GICR_CTLR);
3408 if (!(val & GICR_CTLR_ENABLE_LPIS))
3409 return 0;
3410
3411 pr_warn("CPU%d: Booted with LPIs enabled, memory probably corrupted\n",
3412 smp_processor_id());
3413 add_taint(TAINT_CRAP, LOCKDEP_STILL_OK);
3414
3415 /* Disable LPIs */
3416 val &= ~GICR_CTLR_ENABLE_LPIS;
3417 writel_relaxed(val, rbase + GICR_CTLR);
3418
3419 /* Make sure any change to GICR_CTLR is observable by the GIC */
3420 dsb(sy);
3421
3422 /*
3423 * Software must observe RWP==0 after clearing GICR_CTLR.EnableLPIs
3424 * from 1 to 0 before programming GICR_PEND{PROP}BASER registers.
3425 * Error out if we time out waiting for RWP to clear.
3426 */
3427 while (readl_relaxed(rbase + GICR_CTLR) & GICR_CTLR_RWP) {
3428 if (!timeout) {
3429 pr_err("CPU%d: Timeout while disabling LPIs\n",
3430 smp_processor_id());
3431 return -ETIMEDOUT;
3432 }
3433 udelay(1);
3434 timeout--;
3435 }
3436
3437 /*
3438 * After it has been written to 1, it is IMPLEMENTATION
3439 * DEFINED whether GICR_CTLR.EnableLPI becomes RES1 or can be
3440 * cleared to 0. Error out if clearing the bit failed.
3441 */
3442 if (readl_relaxed(rbase + GICR_CTLR) & GICR_CTLR_ENABLE_LPIS) {
3443 pr_err("CPU%d: Failed to disable LPIs\n", smp_processor_id());
3444 return -EBUSY;
3445 }
3446
3447 return 0;
3448}
3449
3406int its_cpu_init(void) 3450int its_cpu_init(void)
3407{ 3451{
3408 if (!list_empty(&its_nodes)) { 3452 if (!list_empty(&its_nodes)) {
3409 if (!gic_rdists_supports_plpis()) { 3453 int ret;
3410 pr_info("CPU%d: LPIs not supported\n", smp_processor_id()); 3454
3411 return -ENXIO; 3455 ret = redist_disable_lpis();
3412 } 3456 if (ret)
3457 return ret;
3458
3413 its_cpu_init_lpis(); 3459 its_cpu_init_lpis();
3414 its_cpu_init_collections(); 3460 its_cpu_init_collections();
3415 } 3461 }
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 9aacea2aa938..5988473e4abf 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -106,6 +106,7 @@
106#define GICR_PIDR2 GICD_PIDR2 106#define GICR_PIDR2 GICD_PIDR2
107 107
108#define GICR_CTLR_ENABLE_LPIS (1UL << 0) 108#define GICR_CTLR_ENABLE_LPIS (1UL << 0)
109#define GICR_CTLR_RWP (1UL << 3)
109 110
110#define GICR_TYPER_CPU_NUMBER(r) (((r) >> 8) & 0xffff) 111#define GICR_TYPER_CPU_NUMBER(r) (((r) >> 8) & 0xffff)
111 112