.. | .. |
---|
306 | 306 | } |
---|
307 | 307 | #endif |
---|
308 | 308 | |
---|
| 309 | +static void armada_xp_mpic_perf_init(void) |
---|
| 310 | +{ |
---|
| 311 | + unsigned long cpuid; |
---|
| 312 | + |
---|
| 313 | + /* |
---|
| 314 | + * This Performance Counter Overflow interrupt is specific for |
---|
| 315 | + * Armada 370 and XP. It is not available on Armada 375, 38x and 39x. |
---|
| 316 | + */ |
---|
| 317 | + if (!of_machine_is_compatible("marvell,armada-370-xp")) |
---|
| 318 | + return; |
---|
| 319 | + |
---|
| 320 | + cpuid = cpu_logical_map(smp_processor_id()); |
---|
| 321 | + |
---|
| 322 | + /* Enable Performance Counter Overflow interrupts */ |
---|
| 323 | + writel(ARMADA_370_XP_INT_CAUSE_PERF(cpuid), |
---|
| 324 | + per_cpu_int_base + ARMADA_370_XP_INT_FABRIC_MASK_OFFS); |
---|
| 325 | +} |
---|
| 326 | + |
---|
309 | 327 | #ifdef CONFIG_SMP |
---|
| 328 | +static struct irq_domain *ipi_domain; |
---|
| 329 | + |
---|
| 330 | +static void armada_370_xp_ipi_mask(struct irq_data *d) |
---|
| 331 | +{ |
---|
| 332 | + u32 reg; |
---|
| 333 | + reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); |
---|
| 334 | + reg &= ~BIT(d->hwirq); |
---|
| 335 | + writel(reg, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); |
---|
| 336 | +} |
---|
| 337 | + |
---|
| 338 | +static void armada_370_xp_ipi_unmask(struct irq_data *d) |
---|
| 339 | +{ |
---|
| 340 | + u32 reg; |
---|
| 341 | + reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); |
---|
| 342 | + reg |= BIT(d->hwirq); |
---|
| 343 | + writel(reg, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); |
---|
| 344 | +} |
---|
| 345 | + |
---|
| 346 | +static void armada_370_xp_ipi_send_mask(struct irq_data *d, |
---|
| 347 | + const struct cpumask *mask) |
---|
| 348 | +{ |
---|
| 349 | + unsigned long map = 0; |
---|
| 350 | + int cpu; |
---|
| 351 | + |
---|
| 352 | + /* Convert our logical CPU mask into a physical one. */ |
---|
| 353 | + for_each_cpu(cpu, mask) |
---|
| 354 | + map |= 1 << cpu_logical_map(cpu); |
---|
| 355 | + |
---|
| 356 | + /* |
---|
| 357 | + * Ensure that stores to Normal memory are visible to the |
---|
| 358 | + * other CPUs before issuing the IPI. |
---|
| 359 | + */ |
---|
| 360 | + dsb(); |
---|
| 361 | + |
---|
| 362 | + /* submit softirq */ |
---|
| 363 | + writel((map << 8) | d->hwirq, main_int_base + |
---|
| 364 | + ARMADA_370_XP_SW_TRIG_INT_OFFS); |
---|
| 365 | +} |
---|
| 366 | + |
---|
| 367 | +static void armada_370_xp_ipi_eoi(struct irq_data *d) |
---|
| 368 | +{ |
---|
| 369 | + writel(~BIT(d->hwirq), per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); |
---|
| 370 | +} |
---|
| 371 | + |
---|
| 372 | +static struct irq_chip ipi_irqchip = { |
---|
| 373 | + .name = "IPI", |
---|
| 374 | + .irq_mask = armada_370_xp_ipi_mask, |
---|
| 375 | + .irq_unmask = armada_370_xp_ipi_unmask, |
---|
| 376 | + .irq_eoi = armada_370_xp_ipi_eoi, |
---|
| 377 | + .ipi_send_mask = armada_370_xp_ipi_send_mask, |
---|
| 378 | +}; |
---|
| 379 | + |
---|
| 380 | +static int armada_370_xp_ipi_alloc(struct irq_domain *d, |
---|
| 381 | + unsigned int virq, |
---|
| 382 | + unsigned int nr_irqs, void *args) |
---|
| 383 | +{ |
---|
| 384 | + int i; |
---|
| 385 | + |
---|
| 386 | + for (i = 0; i < nr_irqs; i++) { |
---|
| 387 | + irq_set_percpu_devid(virq + i); |
---|
| 388 | + irq_domain_set_info(d, virq + i, i, &ipi_irqchip, |
---|
| 389 | + d->host_data, |
---|
| 390 | + handle_percpu_devid_fasteoi_ipi, |
---|
| 391 | + NULL, NULL); |
---|
| 392 | + } |
---|
| 393 | + |
---|
| 394 | + return 0; |
---|
| 395 | +} |
---|
| 396 | + |
---|
| 397 | +static void armada_370_xp_ipi_free(struct irq_domain *d, |
---|
| 398 | + unsigned int virq, |
---|
| 399 | + unsigned int nr_irqs) |
---|
| 400 | +{ |
---|
| 401 | + /* Not freeing IPIs */ |
---|
| 402 | +} |
---|
| 403 | + |
---|
| 404 | +static const struct irq_domain_ops ipi_domain_ops = { |
---|
| 405 | + .alloc = armada_370_xp_ipi_alloc, |
---|
| 406 | + .free = armada_370_xp_ipi_free, |
---|
| 407 | +}; |
---|
| 408 | + |
---|
| 409 | +static void ipi_resume(void) |
---|
| 410 | +{ |
---|
| 411 | + int i; |
---|
| 412 | + |
---|
| 413 | + for (i = 0; i < IPI_DOORBELL_END; i++) { |
---|
| 414 | + int irq; |
---|
| 415 | + |
---|
| 416 | + irq = irq_find_mapping(ipi_domain, i); |
---|
| 417 | + if (irq <= 0) |
---|
| 418 | + continue; |
---|
| 419 | + if (irq_percpu_is_enabled(irq)) { |
---|
| 420 | + struct irq_data *d; |
---|
| 421 | + d = irq_domain_get_irq_data(ipi_domain, irq); |
---|
| 422 | + armada_370_xp_ipi_unmask(d); |
---|
| 423 | + } |
---|
| 424 | + } |
---|
| 425 | +} |
---|
| 426 | + |
---|
| 427 | +static __init void armada_xp_ipi_init(struct device_node *node) |
---|
| 428 | +{ |
---|
| 429 | + int base_ipi; |
---|
| 430 | + |
---|
| 431 | + ipi_domain = irq_domain_create_linear(of_node_to_fwnode(node), |
---|
| 432 | + IPI_DOORBELL_END, |
---|
| 433 | + &ipi_domain_ops, NULL); |
---|
| 434 | + if (WARN_ON(!ipi_domain)) |
---|
| 435 | + return; |
---|
| 436 | + |
---|
| 437 | + irq_domain_update_bus_token(ipi_domain, DOMAIN_BUS_IPI); |
---|
| 438 | + base_ipi = __irq_domain_alloc_irqs(ipi_domain, -1, IPI_DOORBELL_END, |
---|
| 439 | + NUMA_NO_NODE, NULL, false, NULL); |
---|
| 440 | + if (WARN_ON(!base_ipi)) |
---|
| 441 | + return; |
---|
| 442 | + |
---|
| 443 | + set_smp_ipi_range(base_ipi, IPI_DOORBELL_END); |
---|
| 444 | +} |
---|
| 445 | + |
---|
310 | 446 | static DEFINE_RAW_SPINLOCK(irq_controller_lock); |
---|
311 | 447 | |
---|
312 | 448 | static int armada_xp_set_affinity(struct irq_data *d, |
---|
.. | .. |
---|
330 | 466 | |
---|
331 | 467 | return IRQ_SET_MASK_OK; |
---|
332 | 468 | } |
---|
| 469 | + |
---|
| 470 | +static void armada_xp_mpic_smp_cpu_init(void) |
---|
| 471 | +{ |
---|
| 472 | + u32 control; |
---|
| 473 | + int nr_irqs, i; |
---|
| 474 | + |
---|
| 475 | + control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL); |
---|
| 476 | + nr_irqs = (control >> 2) & 0x3ff; |
---|
| 477 | + |
---|
| 478 | + for (i = 0; i < nr_irqs; i++) |
---|
| 479 | + writel(i, per_cpu_int_base + ARMADA_370_XP_INT_SET_MASK_OFFS); |
---|
| 480 | + |
---|
| 481 | + /* Disable all IPIs */ |
---|
| 482 | + writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); |
---|
| 483 | + |
---|
| 484 | + /* Clear pending IPIs */ |
---|
| 485 | + writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); |
---|
| 486 | + |
---|
| 487 | + /* Unmask IPI interrupt */ |
---|
| 488 | + writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); |
---|
| 489 | +} |
---|
| 490 | + |
---|
| 491 | +static void armada_xp_mpic_reenable_percpu(void) |
---|
| 492 | +{ |
---|
| 493 | + unsigned int irq; |
---|
| 494 | + |
---|
| 495 | + /* Re-enable per-CPU interrupts that were enabled before suspend */ |
---|
| 496 | + for (irq = 0; irq < ARMADA_370_XP_MAX_PER_CPU_IRQS; irq++) { |
---|
| 497 | + struct irq_data *data; |
---|
| 498 | + int virq; |
---|
| 499 | + |
---|
| 500 | + virq = irq_linear_revmap(armada_370_xp_mpic_domain, irq); |
---|
| 501 | + if (virq == 0) |
---|
| 502 | + continue; |
---|
| 503 | + |
---|
| 504 | + data = irq_get_irq_data(virq); |
---|
| 505 | + |
---|
| 506 | + if (!irq_percpu_is_enabled(virq)) |
---|
| 507 | + continue; |
---|
| 508 | + |
---|
| 509 | + armada_370_xp_irq_unmask(data); |
---|
| 510 | + } |
---|
| 511 | + |
---|
| 512 | + ipi_resume(); |
---|
| 513 | +} |
---|
| 514 | + |
---|
| 515 | +static int armada_xp_mpic_starting_cpu(unsigned int cpu) |
---|
| 516 | +{ |
---|
| 517 | + armada_xp_mpic_perf_init(); |
---|
| 518 | + armada_xp_mpic_smp_cpu_init(); |
---|
| 519 | + armada_xp_mpic_reenable_percpu(); |
---|
| 520 | + return 0; |
---|
| 521 | +} |
---|
| 522 | + |
---|
| 523 | +static int mpic_cascaded_starting_cpu(unsigned int cpu) |
---|
| 524 | +{ |
---|
| 525 | + armada_xp_mpic_perf_init(); |
---|
| 526 | + armada_xp_mpic_reenable_percpu(); |
---|
| 527 | + enable_percpu_irq(parent_irq, IRQ_TYPE_NONE); |
---|
| 528 | + return 0; |
---|
| 529 | +} |
---|
| 530 | +#else |
---|
| 531 | +static void armada_xp_mpic_smp_cpu_init(void) {} |
---|
| 532 | +static void ipi_resume(void) {} |
---|
333 | 533 | #endif |
---|
334 | 534 | |
---|
335 | 535 | static struct irq_chip armada_370_xp_irq_chip = { |
---|
.. | .. |
---|
367 | 567 | |
---|
368 | 568 | return 0; |
---|
369 | 569 | } |
---|
370 | | - |
---|
371 | | -static void armada_xp_mpic_smp_cpu_init(void) |
---|
372 | | -{ |
---|
373 | | - u32 control; |
---|
374 | | - int nr_irqs, i; |
---|
375 | | - |
---|
376 | | - control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL); |
---|
377 | | - nr_irqs = (control >> 2) & 0x3ff; |
---|
378 | | - |
---|
379 | | - for (i = 0; i < nr_irqs; i++) |
---|
380 | | - writel(i, per_cpu_int_base + ARMADA_370_XP_INT_SET_MASK_OFFS); |
---|
381 | | - |
---|
382 | | - /* Clear pending IPIs */ |
---|
383 | | - writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); |
---|
384 | | - |
---|
385 | | - /* Enable first 8 IPIs */ |
---|
386 | | - writel(IPI_DOORBELL_MASK, per_cpu_int_base + |
---|
387 | | - ARMADA_370_XP_IN_DRBEL_MSK_OFFS); |
---|
388 | | - |
---|
389 | | - /* Unmask IPI interrupt */ |
---|
390 | | - writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); |
---|
391 | | -} |
---|
392 | | - |
---|
393 | | -static void armada_xp_mpic_perf_init(void) |
---|
394 | | -{ |
---|
395 | | - unsigned long cpuid = cpu_logical_map(smp_processor_id()); |
---|
396 | | - |
---|
397 | | - /* Enable Performance Counter Overflow interrupts */ |
---|
398 | | - writel(ARMADA_370_XP_INT_CAUSE_PERF(cpuid), |
---|
399 | | - per_cpu_int_base + ARMADA_370_XP_INT_FABRIC_MASK_OFFS); |
---|
400 | | -} |
---|
401 | | - |
---|
402 | | -#ifdef CONFIG_SMP |
---|
403 | | -static void armada_mpic_send_doorbell(const struct cpumask *mask, |
---|
404 | | - unsigned int irq) |
---|
405 | | -{ |
---|
406 | | - int cpu; |
---|
407 | | - unsigned long map = 0; |
---|
408 | | - |
---|
409 | | - /* Convert our logical CPU mask into a physical one. */ |
---|
410 | | - for_each_cpu(cpu, mask) |
---|
411 | | - map |= 1 << cpu_logical_map(cpu); |
---|
412 | | - |
---|
413 | | - /* |
---|
414 | | - * Ensure that stores to Normal memory are visible to the |
---|
415 | | - * other CPUs before issuing the IPI. |
---|
416 | | - */ |
---|
417 | | - dsb(); |
---|
418 | | - |
---|
419 | | - /* submit softirq */ |
---|
420 | | - writel((map << 8) | irq, main_int_base + |
---|
421 | | - ARMADA_370_XP_SW_TRIG_INT_OFFS); |
---|
422 | | -} |
---|
423 | | - |
---|
424 | | -static void armada_xp_mpic_reenable_percpu(void) |
---|
425 | | -{ |
---|
426 | | - unsigned int irq; |
---|
427 | | - |
---|
428 | | - /* Re-enable per-CPU interrupts that were enabled before suspend */ |
---|
429 | | - for (irq = 0; irq < ARMADA_370_XP_MAX_PER_CPU_IRQS; irq++) { |
---|
430 | | - struct irq_data *data; |
---|
431 | | - int virq; |
---|
432 | | - |
---|
433 | | - virq = irq_linear_revmap(armada_370_xp_mpic_domain, irq); |
---|
434 | | - if (virq == 0) |
---|
435 | | - continue; |
---|
436 | | - |
---|
437 | | - data = irq_get_irq_data(virq); |
---|
438 | | - |
---|
439 | | - if (!irq_percpu_is_enabled(virq)) |
---|
440 | | - continue; |
---|
441 | | - |
---|
442 | | - armada_370_xp_irq_unmask(data); |
---|
443 | | - } |
---|
444 | | -} |
---|
445 | | - |
---|
446 | | -static int armada_xp_mpic_starting_cpu(unsigned int cpu) |
---|
447 | | -{ |
---|
448 | | - armada_xp_mpic_perf_init(); |
---|
449 | | - armada_xp_mpic_smp_cpu_init(); |
---|
450 | | - armada_xp_mpic_reenable_percpu(); |
---|
451 | | - return 0; |
---|
452 | | -} |
---|
453 | | - |
---|
454 | | -static int mpic_cascaded_starting_cpu(unsigned int cpu) |
---|
455 | | -{ |
---|
456 | | - armada_xp_mpic_perf_init(); |
---|
457 | | - armada_xp_mpic_reenable_percpu(); |
---|
458 | | - enable_percpu_irq(parent_irq, IRQ_TYPE_NONE); |
---|
459 | | - return 0; |
---|
460 | | -} |
---|
461 | | -#endif |
---|
462 | 570 | |
---|
463 | 571 | static const struct irq_domain_ops armada_370_xp_mpic_irq_ops = { |
---|
464 | 572 | .map = armada_370_xp_mpic_irq_map, |
---|
.. | .. |
---|
558 | 666 | #ifdef CONFIG_SMP |
---|
559 | 667 | /* IPI Handling */ |
---|
560 | 668 | if (irqnr == 0) { |
---|
561 | | - u32 ipimask, ipinr; |
---|
| 669 | + unsigned long ipimask; |
---|
| 670 | + int ipi; |
---|
562 | 671 | |
---|
563 | 672 | ipimask = readl_relaxed(per_cpu_int_base + |
---|
564 | 673 | ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS) |
---|
565 | 674 | & IPI_DOORBELL_MASK; |
---|
566 | 675 | |
---|
567 | | - writel(~ipimask, per_cpu_int_base + |
---|
568 | | - ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); |
---|
569 | | - |
---|
570 | | - /* Handle all pending doorbells */ |
---|
571 | | - for (ipinr = IPI_DOORBELL_START; |
---|
572 | | - ipinr < IPI_DOORBELL_END; ipinr++) { |
---|
573 | | - if (ipimask & (0x1 << ipinr)) |
---|
574 | | - handle_IPI(ipinr, regs); |
---|
575 | | - } |
---|
576 | | - continue; |
---|
| 676 | + for_each_set_bit(ipi, &ipimask, IPI_DOORBELL_END) |
---|
| 677 | + handle_domain_irq(ipi_domain, ipi, regs); |
---|
577 | 678 | } |
---|
578 | 679 | #endif |
---|
579 | 680 | |
---|
.. | .. |
---|
632 | 733 | writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); |
---|
633 | 734 | if (doorbell_mask_reg & PCI_MSI_DOORBELL_MASK) |
---|
634 | 735 | writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); |
---|
| 736 | + |
---|
| 737 | + ipi_resume(); |
---|
635 | 738 | } |
---|
636 | 739 | |
---|
637 | 740 | static struct syscore_ops armada_370_xp_mpic_syscore_ops = { |
---|
.. | .. |
---|
687 | 790 | irq_set_default_host(armada_370_xp_mpic_domain); |
---|
688 | 791 | set_handle_irq(armada_370_xp_handle_irq); |
---|
689 | 792 | #ifdef CONFIG_SMP |
---|
690 | | - set_smp_cross_call(armada_mpic_send_doorbell); |
---|
| 793 | + armada_xp_ipi_init(node); |
---|
691 | 794 | cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_ARMADA_XP_STARTING, |
---|
692 | 795 | "irqchip/armada/ipi:starting", |
---|
693 | 796 | armada_xp_mpic_starting_cpu, NULL); |
---|