Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: GIC: Convert GIC library to use the IO relaxed operations

The GIC register accesses today make use of readl()/writel()
which prove to be very expensive when used along with mandatory
barriers. This mandatory barriers also introduces an un-necessary
and expensive l2x0_sync() operation. On Cortex-A9 MP cores, GIC
IO accesses from CPU are direct and doesn't go through L2X0 write
buffer.

A DSB before writel_relaxed() in gic_raise_softirq() is added to be
compliant with the Barrier Litmus document - the mailbox scenario.

Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>

authored by

Santosh Shilimkar and committed by
Will Deacon
6ac77e46 1a01753e

+30 -24
+30 -24
arch/arm/common/gic.c
··· 89 89 u32 mask = 1 << (d->irq % 32); 90 90 91 91 spin_lock(&irq_controller_lock); 92 - writel(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4); 92 + writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4); 93 93 if (gic_arch_extn.irq_mask) 94 94 gic_arch_extn.irq_mask(d); 95 95 spin_unlock(&irq_controller_lock); ··· 102 102 spin_lock(&irq_controller_lock); 103 103 if (gic_arch_extn.irq_unmask) 104 104 gic_arch_extn.irq_unmask(d); 105 - writel(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4); 105 + writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4); 106 106 spin_unlock(&irq_controller_lock); 107 107 } 108 108 ··· 114 114 spin_unlock(&irq_controller_lock); 115 115 } 116 116 117 - writel(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI); 117 + writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI); 118 118 } 119 119 120 120 static int gic_set_type(struct irq_data *d, unsigned int type) ··· 140 140 if (gic_arch_extn.irq_set_type) 141 141 gic_arch_extn.irq_set_type(d, type); 142 142 143 - val = readl(base + GIC_DIST_CONFIG + confoff); 143 + val = readl_relaxed(base + GIC_DIST_CONFIG + confoff); 144 144 if (type == IRQ_TYPE_LEVEL_HIGH) 145 145 val &= ~confmask; 146 146 else if (type == IRQ_TYPE_EDGE_RISING) ··· 150 150 * As recommended by the spec, disable the interrupt before changing 151 151 * the configuration 152 152 */ 153 - if (readl(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) { 154 - writel(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff); 153 + if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) { 154 + writel_relaxed(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff); 155 155 enabled = true; 156 156 } 157 157 158 - writel(val, base + GIC_DIST_CONFIG + confoff); 158 + writel_relaxed(val, base + GIC_DIST_CONFIG + confoff); 159 159 160 160 if (enabled) 161 - writel(enablemask, base + GIC_DIST_ENABLE_SET + enableoff); 161 + writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff); 162 162 163 163 spin_unlock(&irq_controller_lock); 164 164 ··· 190 190 191 191 spin_lock(&irq_controller_lock); 192 192 d->node = cpu; 193 - val = readl(reg) & ~mask; 194 - writel(val | bit, reg); 193 + val = readl_relaxed(reg) & ~mask; 194 + writel_relaxed(val | bit, reg); 195 195 spin_unlock(&irq_controller_lock); 196 196 197 197 return 0; ··· 223 223 chained_irq_enter(chip, desc); 224 224 225 225 spin_lock(&irq_controller_lock); 226 - status = readl(chip_data->cpu_base + GIC_CPU_INTACK); 226 + status = readl_relaxed(chip_data->cpu_base + GIC_CPU_INTACK); 227 227 spin_unlock(&irq_controller_lock); 228 228 229 229 gic_irq = (status & 0x3ff); ··· 272 272 cpumask |= cpumask << 8; 273 273 cpumask |= cpumask << 16; 274 274 275 - writel(0, base + GIC_DIST_CTRL); 275 + writel_relaxed(0, base + GIC_DIST_CTRL); 276 276 277 277 /* 278 278 * Find out how many interrupts are supported. 279 279 * The GIC only supports up to 1020 interrupt sources. 280 280 */ 281 - gic_irqs = readl(base + GIC_DIST_CTR) & 0x1f; 281 + gic_irqs = readl_relaxed(base + GIC_DIST_CTR) & 0x1f; 282 282 gic_irqs = (gic_irqs + 1) * 32; 283 283 if (gic_irqs > 1020) 284 284 gic_irqs = 1020; ··· 287 287 * Set all global interrupts to be level triggered, active low. 288 288 */ 289 289 for (i = 32; i < gic_irqs; i += 16) 290 - writel(0, base + GIC_DIST_CONFIG + i * 4 / 16); 290 + writel_relaxed(0, base + GIC_DIST_CONFIG + i * 4 / 16); 291 291 292 292 /* 293 293 * Set all global interrupts to this CPU only. 294 294 */ 295 295 for (i = 32; i < gic_irqs; i += 4) 296 - writel(cpumask, base + GIC_DIST_TARGET + i * 4 / 4); 296 + writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4); 297 297 298 298 /* 299 299 * Set priority on all global interrupts. 300 300 */ 301 301 for (i = 32; i < gic_irqs; i += 4) 302 - writel(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4); 302 + writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4); 303 303 304 304 /* 305 305 * Disable all interrupts. Leave the PPI and SGIs alone 306 306 * as these enables are banked registers. 307 307 */ 308 308 for (i = 32; i < gic_irqs; i += 32) 309 - writel(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32); 309 + writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32); 310 310 311 311 /* 312 312 * Limit number of interrupts registered to the platform maximum ··· 324 324 set_irq_flags(i, IRQF_VALID | IRQF_PROBE); 325 325 } 326 326 327 - writel(1, base + GIC_DIST_CTRL); 327 + writel_relaxed(1, base + GIC_DIST_CTRL); 328 328 } 329 329 330 330 static void __cpuinit gic_cpu_init(struct gic_chip_data *gic) ··· 337 337 * Deal with the banked PPI and SGI interrupts - disable all 338 338 * PPI interrupts, ensure all SGI interrupts are enabled. 339 339 */ 340 - writel(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR); 341 - writel(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET); 340 + writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR); 341 + writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET); 342 342 343 343 /* 344 344 * Set priority on PPI and SGI interrupts 345 345 */ 346 346 for (i = 0; i < 32; i += 4) 347 - writel(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4); 347 + writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4); 348 348 349 - writel(0xf0, base + GIC_CPU_PRIMASK); 350 - writel(1, base + GIC_CPU_CTRL); 349 + writel_relaxed(0xf0, base + GIC_CPU_PRIMASK); 350 + writel_relaxed(1, base + GIC_CPU_CTRL); 351 351 } 352 352 353 353 void __init gic_init(unsigned int gic_nr, unsigned int irq_start, ··· 391 391 { 392 392 unsigned long map = *cpus_addr(*mask); 393 393 394 + /* 395 + * Ensure that stores to Normal memory are visible to the 396 + * other CPUs before issuing the IPI. 397 + */ 398 + dsb(); 399 + 394 400 /* this always happens on GIC0 */ 395 - writel(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT); 401 + writel_relaxed(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT); 396 402 } 397 403 #endif