| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (C) 2002 ARM Limited, All Rights Reserved. |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 5 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 6 | | - * published by the Free Software Foundation. |
|---|
| 7 | 4 | * |
|---|
| 8 | 5 | * Interrupt architecture for the GIC: |
|---|
| 9 | 6 | * |
|---|
| .. | .. |
|---|
| 50 | 47 | |
|---|
| 51 | 48 | #include "irq-gic-common.h" |
|---|
| 52 | 49 | |
|---|
| 50 | +#ifdef CONFIG_ROCKCHIP_AMP |
|---|
| 51 | +#include <soc/rockchip/rockchip_amp.h> |
|---|
| 52 | +#endif |
|---|
| 53 | + |
|---|
| 53 | 54 | #ifdef CONFIG_ARM64 |
|---|
| 54 | 55 | #include <asm/cpufeature.h> |
|---|
| 55 | 56 | |
|---|
| .. | .. |
|---|
| 86 | 87 | #endif |
|---|
| 87 | 88 | struct irq_domain *domain; |
|---|
| 88 | 89 | unsigned int gic_irqs; |
|---|
| 89 | | -#ifdef CONFIG_GIC_NON_BANKED |
|---|
| 90 | | - void __iomem *(*get_base)(union gic_base *); |
|---|
| 91 | | -#endif |
|---|
| 92 | 90 | }; |
|---|
| 93 | 91 | |
|---|
| 94 | 92 | #ifdef CONFIG_BL_SWITCHER |
|---|
| .. | .. |
|---|
| 113 | 111 | |
|---|
| 114 | 112 | #endif |
|---|
| 115 | 113 | |
|---|
| 114 | +static DEFINE_STATIC_KEY_FALSE(needs_rmw_access); |
|---|
| 115 | + |
|---|
| 116 | 116 | /* |
|---|
| 117 | 117 | * The GIC mapping of CPU interfaces does not necessarily match |
|---|
| 118 | 118 | * the logical CPU numbering. Let's use a mapping as returned |
|---|
| .. | .. |
|---|
| 127 | 127 | |
|---|
| 128 | 128 | static struct gic_kvm_info gic_v2_kvm_info; |
|---|
| 129 | 129 | |
|---|
| 130 | +static DEFINE_PER_CPU(u32, sgi_intid); |
|---|
| 131 | + |
|---|
| 130 | 132 | #ifdef CONFIG_GIC_NON_BANKED |
|---|
| 131 | | -static void __iomem *gic_get_percpu_base(union gic_base *base) |
|---|
| 133 | +static DEFINE_STATIC_KEY_FALSE(frankengic_key); |
|---|
| 134 | + |
|---|
| 135 | +static void enable_frankengic(void) |
|---|
| 132 | 136 | { |
|---|
| 133 | | - return raw_cpu_read(*base->percpu_base); |
|---|
| 137 | + static_branch_enable(&frankengic_key); |
|---|
| 134 | 138 | } |
|---|
| 135 | 139 | |
|---|
| 136 | | -static void __iomem *gic_get_common_base(union gic_base *base) |
|---|
| 140 | +static inline void __iomem *__get_base(union gic_base *base) |
|---|
| 137 | 141 | { |
|---|
| 142 | + if (static_branch_unlikely(&frankengic_key)) |
|---|
| 143 | + return raw_cpu_read(*base->percpu_base); |
|---|
| 144 | + |
|---|
| 138 | 145 | return base->common_base; |
|---|
| 139 | 146 | } |
|---|
| 140 | 147 | |
|---|
| 141 | | -static inline void __iomem *gic_data_dist_base(struct gic_chip_data *data) |
|---|
| 142 | | -{ |
|---|
| 143 | | - return data->get_base(&data->dist_base); |
|---|
| 144 | | -} |
|---|
| 145 | | - |
|---|
| 146 | | -static inline void __iomem *gic_data_cpu_base(struct gic_chip_data *data) |
|---|
| 147 | | -{ |
|---|
| 148 | | - return data->get_base(&data->cpu_base); |
|---|
| 149 | | -} |
|---|
| 150 | | - |
|---|
| 151 | | -static inline void gic_set_base_accessor(struct gic_chip_data *data, |
|---|
| 152 | | - void __iomem *(*f)(union gic_base *)) |
|---|
| 153 | | -{ |
|---|
| 154 | | - data->get_base = f; |
|---|
| 155 | | -} |
|---|
| 148 | +#define gic_data_dist_base(d) __get_base(&(d)->dist_base) |
|---|
| 149 | +#define gic_data_cpu_base(d) __get_base(&(d)->cpu_base) |
|---|
| 156 | 150 | #else |
|---|
| 157 | 151 | #define gic_data_dist_base(d) ((d)->dist_base.common_base) |
|---|
| 158 | 152 | #define gic_data_cpu_base(d) ((d)->cpu_base.common_base) |
|---|
| 159 | | -#define gic_set_base_accessor(d, f) |
|---|
| 153 | +#define enable_frankengic() do { } while(0) |
|---|
| 160 | 154 | #endif |
|---|
| 161 | 155 | |
|---|
| 162 | 156 | static inline void __iomem *gic_dist_base(struct irq_data *d) |
|---|
| .. | .. |
|---|
| 204 | 198 | |
|---|
| 205 | 199 | static void gic_mask_irq(struct irq_data *d) |
|---|
| 206 | 200 | { |
|---|
| 201 | +#ifdef CONFIG_ROCKCHIP_AMP |
|---|
| 202 | + if (rockchip_amp_check_amp_irq(gic_irq(d))) |
|---|
| 203 | + return; |
|---|
| 204 | +#endif |
|---|
| 207 | 205 | gic_poke_irq(d, GIC_DIST_ENABLE_CLEAR); |
|---|
| 208 | 206 | } |
|---|
| 209 | 207 | |
|---|
| 210 | 208 | static void gic_eoimode1_mask_irq(struct irq_data *d) |
|---|
| 211 | 209 | { |
|---|
| 210 | +#ifdef CONFIG_ROCKCHIP_AMP |
|---|
| 211 | + if (rockchip_amp_check_amp_irq(gic_irq(d))) |
|---|
| 212 | + return; |
|---|
| 213 | +#endif |
|---|
| 212 | 214 | gic_mask_irq(d); |
|---|
| 213 | 215 | /* |
|---|
| 214 | 216 | * When masking a forwarded interrupt, make sure it is |
|---|
| .. | .. |
|---|
| 224 | 226 | |
|---|
| 225 | 227 | static void gic_unmask_irq(struct irq_data *d) |
|---|
| 226 | 228 | { |
|---|
| 229 | +#ifdef CONFIG_ROCKCHIP_AMP |
|---|
| 230 | + if (rockchip_amp_check_amp_irq(gic_irq(d))) |
|---|
| 231 | + return; |
|---|
| 232 | +#endif |
|---|
| 227 | 233 | gic_poke_irq(d, GIC_DIST_ENABLE_SET); |
|---|
| 228 | 234 | } |
|---|
| 229 | 235 | |
|---|
| 230 | | -#ifdef CONFIG_ARCH_ROCKCHIP |
|---|
| 231 | | -static int gic_retrigger(struct irq_data *d) |
|---|
| 232 | | -{ |
|---|
| 233 | | - gic_poke_irq(d, GIC_DIST_PENDING_SET); |
|---|
| 234 | | - /* the genirq layer expects 0 if we can't retrigger in hardware */ |
|---|
| 235 | | - return 0; |
|---|
| 236 | | -} |
|---|
| 237 | | -#endif |
|---|
| 238 | | - |
|---|
| 239 | 236 | static void gic_eoi_irq(struct irq_data *d) |
|---|
| 240 | 237 | { |
|---|
| 241 | | - writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI); |
|---|
| 238 | + u32 hwirq = gic_irq(d); |
|---|
| 239 | + |
|---|
| 240 | +#ifdef CONFIG_ROCKCHIP_AMP |
|---|
| 241 | + if (rockchip_amp_check_amp_irq(hwirq)) |
|---|
| 242 | + return; |
|---|
| 243 | +#endif |
|---|
| 244 | + if (hwirq < 16) |
|---|
| 245 | + hwirq = this_cpu_read(sgi_intid); |
|---|
| 246 | + |
|---|
| 247 | + writel_relaxed(hwirq, gic_cpu_base(d) + GIC_CPU_EOI); |
|---|
| 242 | 248 | } |
|---|
| 243 | 249 | |
|---|
| 244 | 250 | static void gic_eoimode1_eoi_irq(struct irq_data *d) |
|---|
| 245 | 251 | { |
|---|
| 252 | + u32 hwirq = gic_irq(d); |
|---|
| 253 | + |
|---|
| 254 | +#ifdef CONFIG_ROCKCHIP_AMP |
|---|
| 255 | + if (rockchip_amp_check_amp_irq(gic_irq(d))) |
|---|
| 256 | + return; |
|---|
| 257 | +#endif |
|---|
| 246 | 258 | /* Do not deactivate an IRQ forwarded to a vcpu. */ |
|---|
| 247 | 259 | if (irqd_is_forwarded_to_vcpu(d)) |
|---|
| 248 | 260 | return; |
|---|
| 249 | 261 | |
|---|
| 250 | | - writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_DEACTIVATE); |
|---|
| 262 | + if (hwirq < 16) |
|---|
| 263 | + hwirq = this_cpu_read(sgi_intid); |
|---|
| 264 | + |
|---|
| 265 | + writel_relaxed(hwirq, gic_cpu_base(d) + GIC_CPU_DEACTIVATE); |
|---|
| 251 | 266 | } |
|---|
| 252 | 267 | |
|---|
| 253 | 268 | static int gic_irq_set_irqchip_state(struct irq_data *d, |
|---|
| .. | .. |
|---|
| 255 | 270 | { |
|---|
| 256 | 271 | u32 reg; |
|---|
| 257 | 272 | |
|---|
| 273 | +#ifdef CONFIG_ROCKCHIP_AMP |
|---|
| 274 | + if (which != IRQCHIP_STATE_PENDING && |
|---|
| 275 | + rockchip_amp_check_amp_irq(gic_irq(d))) |
|---|
| 276 | + return -EINVAL; |
|---|
| 277 | +#endif |
|---|
| 258 | 278 | switch (which) { |
|---|
| 259 | 279 | case IRQCHIP_STATE_PENDING: |
|---|
| 260 | 280 | reg = val ? GIC_DIST_PENDING_SET : GIC_DIST_PENDING_CLEAR; |
|---|
| .. | .. |
|---|
| 303 | 323 | { |
|---|
| 304 | 324 | void __iomem *base = gic_dist_base(d); |
|---|
| 305 | 325 | unsigned int gicirq = gic_irq(d); |
|---|
| 326 | + int ret; |
|---|
| 327 | + |
|---|
| 328 | +#ifdef CONFIG_ROCKCHIP_AMP |
|---|
| 329 | + if (rockchip_amp_check_amp_irq(gic_irq(d))) |
|---|
| 330 | + return -EINVAL; |
|---|
| 331 | +#endif |
|---|
| 306 | 332 | |
|---|
| 307 | 333 | /* Interrupt configuration for SGIs can't be changed */ |
|---|
| 308 | 334 | if (gicirq < 16) |
|---|
| 309 | | - return -EINVAL; |
|---|
| 335 | + return type != IRQ_TYPE_EDGE_RISING ? -EINVAL : 0; |
|---|
| 310 | 336 | |
|---|
| 311 | 337 | /* SPIs have restrictions on the supported types */ |
|---|
| 312 | 338 | if (gicirq >= 32 && type != IRQ_TYPE_LEVEL_HIGH && |
|---|
| 313 | 339 | type != IRQ_TYPE_EDGE_RISING) |
|---|
| 314 | 340 | return -EINVAL; |
|---|
| 315 | 341 | |
|---|
| 316 | | - return gic_configure_irq(gicirq, type, base, NULL); |
|---|
| 342 | + ret = gic_configure_irq(gicirq, type, base + GIC_DIST_CONFIG, NULL); |
|---|
| 343 | + if (ret && gicirq < 32) { |
|---|
| 344 | + /* Misconfigured PPIs are usually not fatal */ |
|---|
| 345 | + pr_warn("GIC: PPI%d is secure or misconfigured\n", gicirq - 16); |
|---|
| 346 | + ret = 0; |
|---|
| 347 | + } |
|---|
| 348 | + |
|---|
| 349 | + return ret; |
|---|
| 317 | 350 | } |
|---|
| 318 | 351 | |
|---|
| 319 | 352 | static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) |
|---|
| 320 | 353 | { |
|---|
| 321 | 354 | /* Only interrupts on the primary GIC can be forwarded to a vcpu. */ |
|---|
| 322 | | - if (cascading_gic_irq(d)) |
|---|
| 355 | + if (cascading_gic_irq(d) || gic_irq(d) < 16) |
|---|
| 323 | 356 | return -EINVAL; |
|---|
| 324 | 357 | |
|---|
| 325 | 358 | if (vcpu) |
|---|
| .. | .. |
|---|
| 329 | 362 | return 0; |
|---|
| 330 | 363 | } |
|---|
| 331 | 364 | |
|---|
| 332 | | -#ifdef CONFIG_SMP |
|---|
| 333 | | -static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, |
|---|
| 334 | | - bool force) |
|---|
| 365 | +static int gic_retrigger(struct irq_data *data) |
|---|
| 335 | 366 | { |
|---|
| 336 | | - void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + gic_irq(d); |
|---|
| 337 | | - unsigned int cpu; |
|---|
| 338 | | - |
|---|
| 339 | | - if (!force) |
|---|
| 340 | | - cpu = cpumask_any_and(mask_val, cpu_online_mask); |
|---|
| 341 | | - else |
|---|
| 342 | | - cpu = cpumask_first(mask_val); |
|---|
| 343 | | - |
|---|
| 344 | | - if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids) |
|---|
| 345 | | - return -EINVAL; |
|---|
| 346 | | - |
|---|
| 347 | | - writeb_relaxed(gic_cpu_map[cpu], reg); |
|---|
| 348 | | - irq_data_update_effective_affinity(d, cpumask_of(cpu)); |
|---|
| 349 | | - |
|---|
| 350 | | - return IRQ_SET_MASK_OK_DONE; |
|---|
| 367 | + return !gic_irq_set_irqchip_state(data, IRQCHIP_STATE_PENDING, true); |
|---|
| 351 | 368 | } |
|---|
| 352 | | -#endif |
|---|
| 353 | 369 | |
|---|
| 354 | 370 | static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) |
|---|
| 355 | 371 | { |
|---|
| .. | .. |
|---|
| 358 | 374 | void __iomem *cpu_base = gic_data_cpu_base(gic); |
|---|
| 359 | 375 | |
|---|
| 360 | 376 | do { |
|---|
| 377 | +#ifdef CONFIG_FIQ_GLUE |
|---|
| 378 | + irqstat = readl_relaxed(cpu_base + GIC_CPU_ALIAS_INTACK); |
|---|
| 379 | +#else |
|---|
| 361 | 380 | irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK); |
|---|
| 381 | +#endif |
|---|
| 362 | 382 | irqnr = irqstat & GICC_IAR_INT_ID_MASK; |
|---|
| 363 | 383 | |
|---|
| 364 | | - if (likely(irqnr > 15 && irqnr < 1020)) { |
|---|
| 365 | | - if (static_branch_likely(&supports_deactivate_key)) |
|---|
| 366 | | - writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI); |
|---|
| 367 | | - isb(); |
|---|
| 368 | | - handle_domain_irq(gic->domain, irqnr, regs); |
|---|
| 369 | | - continue; |
|---|
| 370 | | - } |
|---|
| 371 | | - if (irqnr < 16) { |
|---|
| 384 | + if (unlikely(irqnr >= 1020)) |
|---|
| 385 | + break; |
|---|
| 386 | + |
|---|
| 387 | + if (static_branch_likely(&supports_deactivate_key)) |
|---|
| 372 | 388 | writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI); |
|---|
| 373 | | - if (static_branch_likely(&supports_deactivate_key)) |
|---|
| 374 | | - writel_relaxed(irqstat, cpu_base + GIC_CPU_DEACTIVATE); |
|---|
| 375 | | -#ifdef CONFIG_SMP |
|---|
| 376 | | - /* |
|---|
| 377 | | - * Ensure any shared data written by the CPU sending |
|---|
| 378 | | - * the IPI is read after we've read the ACK register |
|---|
| 379 | | - * on the GIC. |
|---|
| 380 | | - * |
|---|
| 381 | | - * Pairs with the write barrier in gic_raise_softirq |
|---|
| 382 | | - */ |
|---|
| 389 | + isb(); |
|---|
| 390 | + |
|---|
| 391 | + /* |
|---|
| 392 | + * Ensure any shared data written by the CPU sending the IPI |
|---|
| 393 | + * is read after we've read the ACK register on the GIC. |
|---|
| 394 | + * |
|---|
| 395 | + * Pairs with the write barrier in gic_ipi_send_mask |
|---|
| 396 | + */ |
|---|
| 397 | + if (irqnr <= 15) { |
|---|
| 383 | 398 | smp_rmb(); |
|---|
| 384 | | - handle_IPI(irqnr, regs); |
|---|
| 385 | | -#endif |
|---|
| 386 | | - continue; |
|---|
| 399 | + |
|---|
| 400 | + /* |
|---|
| 401 | + * The GIC encodes the source CPU in GICC_IAR, |
|---|
| 402 | + * leading to the deactivation to fail if not |
|---|
| 403 | + * written back as is to GICC_EOI. Stash the INTID |
|---|
| 404 | + * away for gic_eoi_irq() to write back. This only |
|---|
| 405 | + * works because we don't nest SGIs... |
|---|
| 406 | + */ |
|---|
| 407 | + this_cpu_write(sgi_intid, irqstat); |
|---|
| 387 | 408 | } |
|---|
| 388 | | - break; |
|---|
| 409 | + |
|---|
| 410 | + handle_domain_irq(gic->domain, irqnr, regs); |
|---|
| 389 | 411 | } while (1); |
|---|
| 390 | 412 | } |
|---|
| 391 | 413 | |
|---|
| .. | .. |
|---|
| 397 | 419 | unsigned long status; |
|---|
| 398 | 420 | |
|---|
| 399 | 421 | chained_irq_enter(chip, desc); |
|---|
| 400 | | - |
|---|
| 422 | +#ifdef CONFIG_FIQ_GLUE |
|---|
| 423 | + status = readl_relaxed(gic_data_cpu_base(chip_data) + GIC_CPU_ALIAS_INTACK); |
|---|
| 424 | +#else |
|---|
| 401 | 425 | status = readl_relaxed(gic_data_cpu_base(chip_data) + GIC_CPU_INTACK); |
|---|
| 402 | | - |
|---|
| 426 | +#endif |
|---|
| 403 | 427 | gic_irq = (status & GICC_IAR_INT_ID_MASK); |
|---|
| 404 | 428 | if (gic_irq == GICC_INT_SPURIOUS) |
|---|
| 405 | 429 | goto out; |
|---|
| .. | .. |
|---|
| 421 | 445 | .irq_unmask = gic_unmask_irq, |
|---|
| 422 | 446 | .irq_eoi = gic_eoi_irq, |
|---|
| 423 | 447 | .irq_set_type = gic_set_type, |
|---|
| 424 | | -#ifdef CONFIG_ARCH_ROCKCHIP |
|---|
| 425 | 448 | .irq_retrigger = gic_retrigger, |
|---|
| 426 | | -#endif |
|---|
| 427 | 449 | .irq_get_irqchip_state = gic_irq_get_irqchip_state, |
|---|
| 428 | 450 | .irq_set_irqchip_state = gic_irq_set_irqchip_state, |
|---|
| 429 | 451 | .flags = IRQCHIP_SET_TYPE_MASKED | |
|---|
| .. | .. |
|---|
| 483 | 505 | bypass = readl(cpu_base + GIC_CPU_CTRL); |
|---|
| 484 | 506 | bypass &= GICC_DIS_BYPASS_MASK; |
|---|
| 485 | 507 | |
|---|
| 508 | +#ifdef CONFIG_FIQ_GLUE |
|---|
| 509 | + writel_relaxed(0x0f, cpu_base + GIC_CPU_CTRL); |
|---|
| 510 | +#else |
|---|
| 486 | 511 | writel_relaxed(bypass | mode | GICC_ENABLE, cpu_base + GIC_CPU_CTRL); |
|---|
| 512 | +#endif |
|---|
| 487 | 513 | } |
|---|
| 488 | 514 | |
|---|
| 489 | 515 | |
|---|
| .. | .. |
|---|
| 500 | 526 | * Set all global interrupts to this CPU only. |
|---|
| 501 | 527 | */ |
|---|
| 502 | 528 | cpumask = gic_get_cpumask(gic); |
|---|
| 529 | + |
|---|
| 530 | +#ifdef CONFIG_ROCKCHIP_AMP |
|---|
| 531 | + for (i = 32; i < gic_irqs; i += 4) { |
|---|
| 532 | + u32 maskval; |
|---|
| 533 | + unsigned int j; |
|---|
| 534 | + |
|---|
| 535 | + maskval = 0; |
|---|
| 536 | + for (j = 0; j < 4; j++) { |
|---|
| 537 | + if (rockchip_amp_need_init_amp_irq(i + j)) { |
|---|
| 538 | + maskval |= rockchip_amp_get_irq_cpumask(i + j) << |
|---|
| 539 | + (j * 8); |
|---|
| 540 | + } else { |
|---|
| 541 | + maskval |= cpumask << (j * 8); |
|---|
| 542 | + } |
|---|
| 543 | + } |
|---|
| 544 | + writel_relaxed(maskval, base + GIC_DIST_TARGET + i * 4 / 4); |
|---|
| 545 | + } |
|---|
| 546 | +#else |
|---|
| 503 | 547 | cpumask |= cpumask << 8; |
|---|
| 504 | 548 | cpumask |= cpumask << 16; |
|---|
| 505 | 549 | for (i = 32; i < gic_irqs; i += 4) |
|---|
| 506 | 550 | writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4); |
|---|
| 551 | +#endif |
|---|
| 507 | 552 | |
|---|
| 508 | 553 | gic_dist_config(base, gic_irqs, NULL); |
|---|
| 509 | 554 | |
|---|
| 555 | +#ifdef CONFIG_FIQ_GLUE |
|---|
| 556 | + /* set all the interrupt to non-secure state */ |
|---|
| 557 | + for (i = 0; i < gic_irqs; i += 32) |
|---|
| 558 | + writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32); |
|---|
| 559 | + dsb(sy); |
|---|
| 560 | + writel_relaxed(3, base + GIC_DIST_CTRL); |
|---|
| 561 | +#else |
|---|
| 510 | 562 | writel_relaxed(GICD_ENABLE, base + GIC_DIST_CTRL); |
|---|
| 563 | +#endif |
|---|
| 511 | 564 | } |
|---|
| 512 | 565 | |
|---|
| 513 | 566 | static int gic_cpu_init(struct gic_chip_data *gic) |
|---|
| .. | .. |
|---|
| 542 | 595 | gic_cpu_map[i] &= ~cpu_mask; |
|---|
| 543 | 596 | } |
|---|
| 544 | 597 | |
|---|
| 545 | | - gic_cpu_config(dist_base, NULL); |
|---|
| 598 | + gic_cpu_config(dist_base, 32, NULL); |
|---|
| 546 | 599 | |
|---|
| 547 | 600 | writel_relaxed(GICC_INT_PRI_THRESHOLD, base + GIC_CPU_PRIMASK); |
|---|
| 548 | 601 | gic_cpu_if_up(gic); |
|---|
| .. | .. |
|---|
| 608 | 661 | /* |
|---|
| 609 | 662 | * Restores the GIC distributor registers during resume or when coming out of |
|---|
| 610 | 663 | * idle. Must be called before enabling interrupts. If a level interrupt |
|---|
| 611 | | - * that occured while the GIC was suspended is still present, it will be |
|---|
| 612 | | - * handled normally, but any edge interrupts that occured will not be seen by |
|---|
| 664 | + * that occurred while the GIC was suspended is still present, it will be |
|---|
| 665 | + * handled normally, but any edge interrupts that occurred will not be seen by |
|---|
| 613 | 666 | * the GIC and need to be handled by the platform-specific wakeup source. |
|---|
| 614 | 667 | */ |
|---|
| 615 | 668 | void gic_dist_restore(struct gic_chip_data *gic) |
|---|
| .. | .. |
|---|
| 655 | 708 | dist_base + GIC_DIST_ACTIVE_SET + i * 4); |
|---|
| 656 | 709 | } |
|---|
| 657 | 710 | |
|---|
| 711 | +#ifdef CONFIG_FIQ_GLUE |
|---|
| 712 | + writel_relaxed(3, dist_base + GIC_DIST_CTRL); |
|---|
| 713 | +#else |
|---|
| 658 | 714 | writel_relaxed(GICD_ENABLE, dist_base + GIC_DIST_CTRL); |
|---|
| 715 | +#endif |
|---|
| 659 | 716 | } |
|---|
| 660 | 717 | |
|---|
| 661 | 718 | void gic_cpu_save(struct gic_chip_data *gic) |
|---|
| .. | .. |
|---|
| 735 | 792 | int i; |
|---|
| 736 | 793 | |
|---|
| 737 | 794 | for (i = 0; i < CONFIG_ARM_GIC_MAX_NR; i++) { |
|---|
| 738 | | -#ifdef CONFIG_GIC_NON_BANKED |
|---|
| 739 | | - /* Skip over unused GICs */ |
|---|
| 740 | | - if (!gic_data[i].get_base) |
|---|
| 741 | | - continue; |
|---|
| 742 | | -#endif |
|---|
| 743 | 795 | switch (cmd) { |
|---|
| 744 | 796 | case CPU_PM_ENTER: |
|---|
| 745 | 797 | gic_cpu_save(&gic_data[i]); |
|---|
| .. | .. |
|---|
| 801 | 853 | } |
|---|
| 802 | 854 | #endif |
|---|
| 803 | 855 | |
|---|
| 856 | +#ifdef CONFIG_FIQ_GLUE |
|---|
| 857 | +/* |
|---|
| 858 | + * ICDISR each bit 0 -- Secure 1--Non-Secure |
|---|
| 859 | + */ |
|---|
| 860 | +void gic_set_irq_secure(struct irq_data *d) |
|---|
| 861 | +{ |
|---|
| 862 | + u32 mask = 0; |
|---|
| 863 | + void __iomem *base = gic_dist_base(d); |
|---|
| 864 | + |
|---|
| 865 | + base += GIC_DIST_IGROUP + ((gic_irq(d) / 32) * 4); |
|---|
| 866 | + mask = readl_relaxed(base); |
|---|
| 867 | + mask &= ~(1 << (gic_irq(d) % 32)); |
|---|
| 868 | + writel_relaxed(mask, base); |
|---|
| 869 | +} |
|---|
| 870 | + |
|---|
| 871 | +void gic_set_irq_priority(struct irq_data *d, u8 pri) |
|---|
| 872 | +{ |
|---|
| 873 | + writeb_relaxed(pri, gic_dist_base(d) + GIC_DIST_PRI + gic_irq(d)); |
|---|
| 874 | +} |
|---|
| 875 | +#endif |
|---|
| 876 | + |
|---|
| 804 | 877 | #ifdef CONFIG_SMP |
|---|
| 805 | | -static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) |
|---|
| 878 | +static void rmw_writeb(u8 bval, void __iomem *addr) |
|---|
| 879 | +{ |
|---|
| 880 | + static DEFINE_RAW_SPINLOCK(rmw_lock); |
|---|
| 881 | + unsigned long offset = (unsigned long)addr & 3UL; |
|---|
| 882 | + unsigned long shift = offset * 8; |
|---|
| 883 | + unsigned long flags; |
|---|
| 884 | + u32 val; |
|---|
| 885 | + |
|---|
| 886 | + raw_spin_lock_irqsave(&rmw_lock, flags); |
|---|
| 887 | + |
|---|
| 888 | + addr -= offset; |
|---|
| 889 | + val = readl_relaxed(addr); |
|---|
| 890 | + val &= ~GENMASK(shift + 7, shift); |
|---|
| 891 | + val |= bval << shift; |
|---|
| 892 | + writel_relaxed(val, addr); |
|---|
| 893 | + |
|---|
| 894 | + raw_spin_unlock_irqrestore(&rmw_lock, flags); |
|---|
| 895 | +} |
|---|
| 896 | + |
|---|
| 897 | +static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, |
|---|
| 898 | + bool force) |
|---|
| 899 | +{ |
|---|
| 900 | + void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + gic_irq(d); |
|---|
| 901 | + unsigned int cpu; |
|---|
| 902 | + |
|---|
| 903 | +#ifdef CONFIG_ROCKCHIP_AMP |
|---|
| 904 | + if (rockchip_amp_check_amp_irq(gic_irq(d))) |
|---|
| 905 | + return -EINVAL; |
|---|
| 906 | +#endif |
|---|
| 907 | + |
|---|
| 908 | + if (!force) |
|---|
| 909 | + cpu = cpumask_any_and(mask_val, cpu_online_mask); |
|---|
| 910 | + else |
|---|
| 911 | + cpu = cpumask_first(mask_val); |
|---|
| 912 | + |
|---|
| 913 | + if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids) |
|---|
| 914 | + return -EINVAL; |
|---|
| 915 | + |
|---|
| 916 | + if (static_branch_unlikely(&needs_rmw_access)) |
|---|
| 917 | + rmw_writeb(gic_cpu_map[cpu], reg); |
|---|
| 918 | + else |
|---|
| 919 | + writeb_relaxed(gic_cpu_map[cpu], reg); |
|---|
| 920 | + irq_data_update_effective_affinity(d, cpumask_of(cpu)); |
|---|
| 921 | + |
|---|
| 922 | + return IRQ_SET_MASK_OK_DONE; |
|---|
| 923 | +} |
|---|
| 924 | + |
|---|
| 925 | +static void gic_ipi_send_mask(struct irq_data *d, const struct cpumask *mask) |
|---|
| 806 | 926 | { |
|---|
| 807 | 927 | int cpu; |
|---|
| 808 | 928 | unsigned long flags, map = 0; |
|---|
| 809 | 929 | |
|---|
| 810 | 930 | if (unlikely(nr_cpu_ids == 1)) { |
|---|
| 811 | 931 | /* Only one CPU? let's do a self-IPI... */ |
|---|
| 812 | | - writel_relaxed(2 << 24 | irq, |
|---|
| 932 | + writel_relaxed(2 << 24 | d->hwirq, |
|---|
| 813 | 933 | gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT); |
|---|
| 814 | 934 | return; |
|---|
| 815 | 935 | } |
|---|
| .. | .. |
|---|
| 827 | 947 | dmb(ishst); |
|---|
| 828 | 948 | |
|---|
| 829 | 949 | /* this always happens on GIC0 */ |
|---|
| 830 | | - writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT); |
|---|
| 831 | | - |
|---|
| 950 | +#ifdef CONFIG_FIQ_GLUE |
|---|
| 951 | + /* enable non-secure SGI for GIC with security extensions */ |
|---|
| 952 | + writel_relaxed(map << 16 | d->hwirq | 0x8000, |
|---|
| 953 | + gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT); |
|---|
| 954 | +#else |
|---|
| 955 | + writel_relaxed(map << 16 | d->hwirq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT); |
|---|
| 956 | +#endif |
|---|
| 832 | 957 | gic_unlock_irqrestore(flags); |
|---|
| 833 | 958 | } |
|---|
| 959 | + |
|---|
| 960 | +static int gic_starting_cpu(unsigned int cpu) |
|---|
| 961 | +{ |
|---|
| 962 | + gic_cpu_init(&gic_data[0]); |
|---|
| 963 | + if (IS_ENABLED(CONFIG_FIQ_GLUE)) { |
|---|
| 964 | + /* set SGI to none secure state */ |
|---|
| 965 | + writel_relaxed(0xffffffff, gic_data_dist_base(&gic_data[0]) + GIC_DIST_IGROUP); |
|---|
| 966 | + writel_relaxed(0xf, gic_data_cpu_base(&gic_data[0]) + GIC_CPU_CTRL); |
|---|
| 967 | + } |
|---|
| 968 | + return 0; |
|---|
| 969 | +} |
|---|
| 970 | + |
|---|
| 971 | +static __init void gic_smp_init(void) |
|---|
| 972 | +{ |
|---|
| 973 | + struct irq_fwspec sgi_fwspec = { |
|---|
| 974 | + .fwnode = gic_data[0].domain->fwnode, |
|---|
| 975 | + .param_count = 1, |
|---|
| 976 | + }; |
|---|
| 977 | + int base_sgi; |
|---|
| 978 | + |
|---|
| 979 | + cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GIC_STARTING, |
|---|
| 980 | + "irqchip/arm/gic:starting", |
|---|
| 981 | + gic_starting_cpu, NULL); |
|---|
| 982 | + |
|---|
| 983 | + base_sgi = __irq_domain_alloc_irqs(gic_data[0].domain, -1, 8, |
|---|
| 984 | + NUMA_NO_NODE, &sgi_fwspec, |
|---|
| 985 | + false, NULL); |
|---|
| 986 | + if (WARN_ON(base_sgi <= 0)) |
|---|
| 987 | + return; |
|---|
| 988 | + |
|---|
| 989 | + set_smp_ipi_range(base_sgi, 8); |
|---|
| 990 | +} |
|---|
| 991 | +#else |
|---|
| 992 | +#define gic_smp_init() do { } while(0) |
|---|
| 993 | +#define gic_set_affinity NULL |
|---|
| 994 | +#define gic_ipi_send_mask NULL |
|---|
| 834 | 995 | #endif |
|---|
| 835 | 996 | |
|---|
| 836 | 997 | #ifdef CONFIG_BL_SWITCHER |
|---|
| .. | .. |
|---|
| 903 | 1064 | gic_cpu_map[cpu] = 1 << new_cpu_id; |
|---|
| 904 | 1065 | |
|---|
| 905 | 1066 | /* |
|---|
| 906 | | - * Find all the peripheral interrupts targetting the current |
|---|
| 1067 | + * Find all the peripheral interrupts targeting the current |
|---|
| 907 | 1068 | * CPU interface and migrate them to the new CPU interface. |
|---|
| 908 | 1069 | * We skip DIST_TARGET 0 to 7 as they are read-only. |
|---|
| 909 | 1070 | */ |
|---|
| .. | .. |
|---|
| 976 | 1137 | irq_hw_number_t hw) |
|---|
| 977 | 1138 | { |
|---|
| 978 | 1139 | struct gic_chip_data *gic = d->host_data; |
|---|
| 1140 | + struct irq_data *irqd = irq_desc_get_irq_data(irq_to_desc(irq)); |
|---|
| 979 | 1141 | |
|---|
| 980 | | - if (hw < 32) { |
|---|
| 1142 | + switch (hw) { |
|---|
| 1143 | + case 0 ... 15: |
|---|
| 1144 | + irq_set_percpu_devid(irq); |
|---|
| 1145 | + irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data, |
|---|
| 1146 | + handle_percpu_devid_fasteoi_ipi, |
|---|
| 1147 | + NULL, NULL); |
|---|
| 1148 | + break; |
|---|
| 1149 | + case 16 ... 31: |
|---|
| 981 | 1150 | irq_set_percpu_devid(irq); |
|---|
| 982 | 1151 | irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data, |
|---|
| 983 | 1152 | handle_percpu_devid_irq, NULL, NULL); |
|---|
| 984 | | - irq_set_status_flags(irq, IRQ_NOAUTOEN); |
|---|
| 985 | | - } else { |
|---|
| 1153 | + break; |
|---|
| 1154 | + default: |
|---|
| 986 | 1155 | irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data, |
|---|
| 987 | 1156 | handle_fasteoi_irq, NULL, NULL); |
|---|
| 988 | 1157 | irq_set_probe(irq); |
|---|
| 989 | | - irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(irq))); |
|---|
| 1158 | + irqd_set_single_target(irqd); |
|---|
| 1159 | + break; |
|---|
| 990 | 1160 | } |
|---|
| 1161 | + |
|---|
| 1162 | + /* Prevents SW retriggers which mess up the ACK/EOI ordering */ |
|---|
| 1163 | + irqd_set_handle_enforce_irqctx(irqd); |
|---|
| 991 | 1164 | return 0; |
|---|
| 992 | 1165 | } |
|---|
| 993 | 1166 | |
|---|
| .. | .. |
|---|
| 1000 | 1173 | unsigned long *hwirq, |
|---|
| 1001 | 1174 | unsigned int *type) |
|---|
| 1002 | 1175 | { |
|---|
| 1176 | + if (fwspec->param_count == 1 && fwspec->param[0] < 16) { |
|---|
| 1177 | + *hwirq = fwspec->param[0]; |
|---|
| 1178 | + *type = IRQ_TYPE_EDGE_RISING; |
|---|
| 1179 | + return 0; |
|---|
| 1180 | + } |
|---|
| 1181 | + |
|---|
| 1003 | 1182 | if (is_of_node(fwspec->fwnode)) { |
|---|
| 1004 | 1183 | if (fwspec->param_count < 3) |
|---|
| 1005 | 1184 | return -EINVAL; |
|---|
| 1006 | 1185 | |
|---|
| 1007 | | - /* Get the interrupt number and add 16 to skip over SGIs */ |
|---|
| 1008 | | - *hwirq = fwspec->param[1] + 16; |
|---|
| 1009 | | - |
|---|
| 1010 | | - /* |
|---|
| 1011 | | - * For SPIs, we need to add 16 more to get the GIC irq |
|---|
| 1012 | | - * ID number |
|---|
| 1013 | | - */ |
|---|
| 1014 | | - if (!fwspec->param[0]) |
|---|
| 1015 | | - *hwirq += 16; |
|---|
| 1186 | + switch (fwspec->param[0]) { |
|---|
| 1187 | + case 0: /* SPI */ |
|---|
| 1188 | + *hwirq = fwspec->param[1] + 32; |
|---|
| 1189 | + break; |
|---|
| 1190 | + case 1: /* PPI */ |
|---|
| 1191 | + *hwirq = fwspec->param[1] + 16; |
|---|
| 1192 | + break; |
|---|
| 1193 | + default: |
|---|
| 1194 | + return -EINVAL; |
|---|
| 1195 | + } |
|---|
| 1016 | 1196 | |
|---|
| 1017 | 1197 | *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; |
|---|
| 1018 | 1198 | |
|---|
| .. | .. |
|---|
| 1025 | 1205 | if(fwspec->param_count != 2) |
|---|
| 1026 | 1206 | return -EINVAL; |
|---|
| 1027 | 1207 | |
|---|
| 1208 | + if (fwspec->param[0] < 16) { |
|---|
| 1209 | + pr_err(FW_BUG "Illegal GSI%d translation request\n", |
|---|
| 1210 | + fwspec->param[0]); |
|---|
| 1211 | + return -EINVAL; |
|---|
| 1212 | + } |
|---|
| 1213 | + |
|---|
| 1028 | 1214 | *hwirq = fwspec->param[0]; |
|---|
| 1029 | 1215 | *type = fwspec->param[1]; |
|---|
| 1030 | 1216 | |
|---|
| .. | .. |
|---|
| 1033 | 1219 | } |
|---|
| 1034 | 1220 | |
|---|
| 1035 | 1221 | return -EINVAL; |
|---|
| 1036 | | -} |
|---|
| 1037 | | - |
|---|
| 1038 | | -static int gic_starting_cpu(unsigned int cpu) |
|---|
| 1039 | | -{ |
|---|
| 1040 | | - gic_cpu_init(&gic_data[0]); |
|---|
| 1041 | | - return 0; |
|---|
| 1042 | 1222 | } |
|---|
| 1043 | 1223 | |
|---|
| 1044 | 1224 | static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, |
|---|
| .. | .. |
|---|
| 1085 | 1265 | gic->chip.irq_mask = gic_eoimode1_mask_irq; |
|---|
| 1086 | 1266 | gic->chip.irq_eoi = gic_eoimode1_eoi_irq; |
|---|
| 1087 | 1267 | gic->chip.irq_set_vcpu_affinity = gic_irq_set_vcpu_affinity; |
|---|
| 1088 | | -#ifdef CONFIG_ARCH_ROCKCHIP |
|---|
| 1089 | | - gic->chip.irq_retrigger = gic_retrigger; |
|---|
| 1090 | | -#endif |
|---|
| 1091 | 1268 | } |
|---|
| 1092 | 1269 | |
|---|
| 1093 | | -#ifdef CONFIG_SMP |
|---|
| 1094 | | - if (gic == &gic_data[0]) |
|---|
| 1270 | + if (gic == &gic_data[0]) { |
|---|
| 1095 | 1271 | gic->chip.irq_set_affinity = gic_set_affinity; |
|---|
| 1096 | | -#endif |
|---|
| 1272 | + gic->chip.ipi_send_mask = gic_ipi_send_mask; |
|---|
| 1273 | + } |
|---|
| 1097 | 1274 | } |
|---|
| 1098 | 1275 | |
|---|
| 1099 | | -static int gic_init_bases(struct gic_chip_data *gic, int irq_start, |
|---|
| 1276 | +static int gic_init_bases(struct gic_chip_data *gic, |
|---|
| 1100 | 1277 | struct fwnode_handle *handle) |
|---|
| 1101 | 1278 | { |
|---|
| 1102 | | - irq_hw_number_t hwirq_base; |
|---|
| 1103 | | - int gic_irqs, irq_base, ret; |
|---|
| 1279 | + int gic_irqs, ret; |
|---|
| 1104 | 1280 | |
|---|
| 1105 | 1281 | if (IS_ENABLED(CONFIG_GIC_NON_BANKED) && gic->percpu_offset) { |
|---|
| 1106 | 1282 | /* Frankein-GIC without banked registers... */ |
|---|
| .. | .. |
|---|
| 1124 | 1300 | gic->raw_cpu_base + offset; |
|---|
| 1125 | 1301 | } |
|---|
| 1126 | 1302 | |
|---|
| 1127 | | - gic_set_base_accessor(gic, gic_get_percpu_base); |
|---|
| 1303 | + enable_frankengic(); |
|---|
| 1128 | 1304 | } else { |
|---|
| 1129 | 1305 | /* Normal, sane GIC... */ |
|---|
| 1130 | 1306 | WARN(gic->percpu_offset, |
|---|
| .. | .. |
|---|
| 1132 | 1308 | gic->percpu_offset); |
|---|
| 1133 | 1309 | gic->dist_base.common_base = gic->raw_dist_base; |
|---|
| 1134 | 1310 | gic->cpu_base.common_base = gic->raw_cpu_base; |
|---|
| 1135 | | - gic_set_base_accessor(gic, gic_get_common_base); |
|---|
| 1136 | 1311 | } |
|---|
| 1137 | 1312 | |
|---|
| 1138 | 1313 | /* |
|---|
| .. | .. |
|---|
| 1152 | 1327 | } else { /* Legacy support */ |
|---|
| 1153 | 1328 | /* |
|---|
| 1154 | 1329 | * For primary GICs, skip over SGIs. |
|---|
| 1155 | | - * For secondary GICs, skip over PPIs, too. |
|---|
| 1330 | + * No secondary GIC support whatsoever. |
|---|
| 1156 | 1331 | */ |
|---|
| 1157 | | - if (gic == &gic_data[0] && (irq_start & 31) > 0) { |
|---|
| 1158 | | - hwirq_base = 16; |
|---|
| 1159 | | - if (irq_start != -1) |
|---|
| 1160 | | - irq_start = (irq_start & ~31) + 16; |
|---|
| 1161 | | - } else { |
|---|
| 1162 | | - hwirq_base = 32; |
|---|
| 1163 | | - } |
|---|
| 1332 | + int irq_base; |
|---|
| 1164 | 1333 | |
|---|
| 1165 | | - gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */ |
|---|
| 1334 | + gic_irqs -= 16; /* calculate # of irqs to allocate */ |
|---|
| 1166 | 1335 | |
|---|
| 1167 | | - irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, |
|---|
| 1336 | + irq_base = irq_alloc_descs(16, 16, gic_irqs, |
|---|
| 1168 | 1337 | numa_node_id()); |
|---|
| 1169 | 1338 | if (irq_base < 0) { |
|---|
| 1170 | | - WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", |
|---|
| 1171 | | - irq_start); |
|---|
| 1172 | | - irq_base = irq_start; |
|---|
| 1339 | + WARN(1, "Cannot allocate irq_descs @ IRQ16, assuming pre-allocated\n"); |
|---|
| 1340 | + irq_base = 16; |
|---|
| 1173 | 1341 | } |
|---|
| 1174 | 1342 | |
|---|
| 1175 | 1343 | gic->domain = irq_domain_add_legacy(NULL, gic_irqs, irq_base, |
|---|
| 1176 | | - hwirq_base, &gic_irq_domain_ops, gic); |
|---|
| 1344 | + 16, &gic_irq_domain_ops, gic); |
|---|
| 1177 | 1345 | } |
|---|
| 1178 | 1346 | |
|---|
| 1179 | 1347 | if (WARN_ON(!gic->domain)) { |
|---|
| .. | .. |
|---|
| 1181 | 1349 | goto error; |
|---|
| 1182 | 1350 | } |
|---|
| 1183 | 1351 | |
|---|
| 1352 | +#ifdef CONFIG_ROCKCHIP_AMP |
|---|
| 1353 | + rockchip_amp_get_gic_info(gic->gic_irqs, GIC_V2); |
|---|
| 1354 | +#endif |
|---|
| 1184 | 1355 | gic_dist_init(gic); |
|---|
| 1185 | 1356 | ret = gic_cpu_init(gic); |
|---|
| 1186 | 1357 | if (ret) |
|---|
| .. | .. |
|---|
| 1202 | 1373 | } |
|---|
| 1203 | 1374 | |
|---|
| 1204 | 1375 | static int __init __gic_init_bases(struct gic_chip_data *gic, |
|---|
| 1205 | | - int irq_start, |
|---|
| 1206 | 1376 | struct fwnode_handle *handle) |
|---|
| 1207 | 1377 | { |
|---|
| 1208 | 1378 | char *name; |
|---|
| .. | .. |
|---|
| 1219 | 1389 | */ |
|---|
| 1220 | 1390 | for (i = 0; i < NR_GIC_CPU_IF; i++) |
|---|
| 1221 | 1391 | gic_cpu_map[i] = 0xff; |
|---|
| 1222 | | -#ifdef CONFIG_SMP |
|---|
| 1223 | | - set_smp_cross_call(gic_raise_softirq); |
|---|
| 1224 | | -#endif |
|---|
| 1225 | | - cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GIC_STARTING, |
|---|
| 1226 | | - "irqchip/arm/gic:starting", |
|---|
| 1227 | | - gic_starting_cpu, NULL); |
|---|
| 1392 | + |
|---|
| 1228 | 1393 | set_handle_irq(gic_handle_irq); |
|---|
| 1229 | 1394 | if (static_branch_likely(&supports_deactivate_key)) |
|---|
| 1230 | 1395 | pr_info("GIC: Using split EOI/Deactivate mode\n"); |
|---|
| .. | .. |
|---|
| 1238 | 1403 | gic_init_chip(gic, NULL, name, false); |
|---|
| 1239 | 1404 | } |
|---|
| 1240 | 1405 | |
|---|
| 1241 | | - ret = gic_init_bases(gic, irq_start, handle); |
|---|
| 1406 | + ret = gic_init_bases(gic, handle); |
|---|
| 1242 | 1407 | if (ret) |
|---|
| 1243 | 1408 | kfree(name); |
|---|
| 1409 | + else if (gic == &gic_data[0]) |
|---|
| 1410 | + gic_smp_init(); |
|---|
| 1244 | 1411 | |
|---|
| 1245 | 1412 | return ret; |
|---|
| 1246 | 1413 | } |
|---|
| 1247 | 1414 | |
|---|
| 1248 | | -void __init gic_init(unsigned int gic_nr, int irq_start, |
|---|
| 1249 | | - void __iomem *dist_base, void __iomem *cpu_base) |
|---|
| 1415 | +void __init gic_init(void __iomem *dist_base, void __iomem *cpu_base) |
|---|
| 1250 | 1416 | { |
|---|
| 1251 | 1417 | struct gic_chip_data *gic; |
|---|
| 1252 | | - |
|---|
| 1253 | | - if (WARN_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR)) |
|---|
| 1254 | | - return; |
|---|
| 1255 | 1418 | |
|---|
| 1256 | 1419 | /* |
|---|
| 1257 | 1420 | * Non-DT/ACPI systems won't run a hypervisor, so let's not |
|---|
| .. | .. |
|---|
| 1259 | 1422 | */ |
|---|
| 1260 | 1423 | static_branch_disable(&supports_deactivate_key); |
|---|
| 1261 | 1424 | |
|---|
| 1262 | | - gic = &gic_data[gic_nr]; |
|---|
| 1425 | + gic = &gic_data[0]; |
|---|
| 1263 | 1426 | gic->raw_dist_base = dist_base; |
|---|
| 1264 | 1427 | gic->raw_cpu_base = cpu_base; |
|---|
| 1265 | 1428 | |
|---|
| 1266 | | - __gic_init_bases(gic, irq_start, NULL); |
|---|
| 1429 | + __gic_init_bases(gic, NULL); |
|---|
| 1267 | 1430 | } |
|---|
| 1268 | 1431 | |
|---|
| 1269 | 1432 | static void gic_teardown(struct gic_chip_data *gic) |
|---|
| .. | .. |
|---|
| 1365 | 1528 | return true; |
|---|
| 1366 | 1529 | } |
|---|
| 1367 | 1530 | |
|---|
| 1531 | +static bool gic_enable_rmw_access(void *data) |
|---|
| 1532 | +{ |
|---|
| 1533 | + /* |
|---|
| 1534 | + * The EMEV2 class of machines has a broken interconnect, and |
|---|
| 1535 | + * locks up on accesses that are less than 32bit. So far, only |
|---|
| 1536 | + * the affinity setting requires it. |
|---|
| 1537 | + */ |
|---|
| 1538 | + if (of_machine_is_compatible("renesas,emev2")) { |
|---|
| 1539 | + static_branch_enable(&needs_rmw_access); |
|---|
| 1540 | + return true; |
|---|
| 1541 | + } |
|---|
| 1542 | + |
|---|
| 1543 | + return false; |
|---|
| 1544 | +} |
|---|
| 1545 | + |
|---|
| 1546 | +static const struct gic_quirk gic_quirks[] = { |
|---|
| 1547 | + { |
|---|
| 1548 | + .desc = "broken byte access", |
|---|
| 1549 | + .compatible = "arm,pl390", |
|---|
| 1550 | + .init = gic_enable_rmw_access, |
|---|
| 1551 | + }, |
|---|
| 1552 | + { }, |
|---|
| 1553 | +}; |
|---|
| 1554 | + |
|---|
| 1368 | 1555 | static int gic_of_setup(struct gic_chip_data *gic, struct device_node *node) |
|---|
| 1369 | 1556 | { |
|---|
| 1370 | 1557 | if (!gic || !node) |
|---|
| .. | .. |
|---|
| 1380 | 1567 | |
|---|
| 1381 | 1568 | if (of_property_read_u32(node, "cpu-offset", &gic->percpu_offset)) |
|---|
| 1382 | 1569 | gic->percpu_offset = 0; |
|---|
| 1570 | + |
|---|
| 1571 | + gic_enable_of_quirks(node, gic_quirks, gic); |
|---|
| 1383 | 1572 | |
|---|
| 1384 | 1573 | return 0; |
|---|
| 1385 | 1574 | |
|---|
| .. | .. |
|---|
| 1406 | 1595 | if (ret) |
|---|
| 1407 | 1596 | return ret; |
|---|
| 1408 | 1597 | |
|---|
| 1409 | | - ret = gic_init_bases(*gic, -1, &dev->of_node->fwnode); |
|---|
| 1598 | + ret = gic_init_bases(*gic, &dev->of_node->fwnode); |
|---|
| 1410 | 1599 | if (ret) { |
|---|
| 1411 | 1600 | gic_teardown(*gic); |
|---|
| 1412 | 1601 | return ret; |
|---|
| .. | .. |
|---|
| 1466 | 1655 | if (gic_cnt == 0 && !gic_check_eoimode(node, &gic->raw_cpu_base)) |
|---|
| 1467 | 1656 | static_branch_disable(&supports_deactivate_key); |
|---|
| 1468 | 1657 | |
|---|
| 1469 | | - ret = __gic_init_bases(gic, -1, &node->fwnode); |
|---|
| 1658 | + ret = __gic_init_bases(gic, &node->fwnode); |
|---|
| 1470 | 1659 | if (ret) { |
|---|
| 1471 | 1660 | gic_teardown(gic); |
|---|
| 1472 | 1661 | return ret; |
|---|
| .. | .. |
|---|
| 1515 | 1704 | } acpi_data __initdata; |
|---|
| 1516 | 1705 | |
|---|
| 1517 | 1706 | static int __init |
|---|
| 1518 | | -gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header, |
|---|
| 1707 | +gic_acpi_parse_madt_cpu(union acpi_subtable_headers *header, |
|---|
| 1519 | 1708 | const unsigned long end) |
|---|
| 1520 | 1709 | { |
|---|
| 1521 | 1710 | struct acpi_madt_generic_interrupt *processor; |
|---|
| .. | .. |
|---|
| 1547 | 1736 | } |
|---|
| 1548 | 1737 | |
|---|
| 1549 | 1738 | /* The things you have to do to just *count* something... */ |
|---|
| 1550 | | -static int __init acpi_dummy_func(struct acpi_subtable_header *header, |
|---|
| 1739 | +static int __init acpi_dummy_func(union acpi_subtable_headers *header, |
|---|
| 1551 | 1740 | const unsigned long end) |
|---|
| 1552 | 1741 | { |
|---|
| 1553 | 1742 | return 0; |
|---|
| .. | .. |
|---|
| 1608 | 1797 | gic_set_kvm_info(&gic_v2_kvm_info); |
|---|
| 1609 | 1798 | } |
|---|
| 1610 | 1799 | |
|---|
| 1611 | | -static int __init gic_v2_acpi_init(struct acpi_subtable_header *header, |
|---|
| 1800 | +static int __init gic_v2_acpi_init(union acpi_subtable_headers *header, |
|---|
| 1612 | 1801 | const unsigned long end) |
|---|
| 1613 | 1802 | { |
|---|
| 1614 | 1803 | struct acpi_madt_generic_distributor *dist; |
|---|
| .. | .. |
|---|
| 1650 | 1839 | /* |
|---|
| 1651 | 1840 | * Initialize GIC instance zero (no multi-GIC support). |
|---|
| 1652 | 1841 | */ |
|---|
| 1653 | | - domain_handle = irq_domain_alloc_fwnode(gic->raw_dist_base); |
|---|
| 1842 | + domain_handle = irq_domain_alloc_fwnode(&dist->base_address); |
|---|
| 1654 | 1843 | if (!domain_handle) { |
|---|
| 1655 | 1844 | pr_err("Unable to allocate domain handle\n"); |
|---|
| 1656 | 1845 | gic_teardown(gic); |
|---|
| 1657 | 1846 | return -ENOMEM; |
|---|
| 1658 | 1847 | } |
|---|
| 1659 | 1848 | |
|---|
| 1660 | | - ret = __gic_init_bases(gic, -1, domain_handle); |
|---|
| 1849 | + ret = __gic_init_bases(gic, domain_handle); |
|---|
| 1661 | 1850 | if (ret) { |
|---|
| 1662 | 1851 | pr_err("Failed to initialise GIC\n"); |
|---|
| 1663 | 1852 | irq_domain_free_fwnode(domain_handle); |
|---|