hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/irqchip/irq-armada-370-xp.c
....@@ -306,7 +306,143 @@
306306 }
307307 #endif
308308
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
+
309327 #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
+
310446 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
311447
312448 static int armada_xp_set_affinity(struct irq_data *d,
....@@ -330,6 +466,70 @@
330466
331467 return IRQ_SET_MASK_OK;
332468 }
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) {}
333533 #endif
334534
335535 static struct irq_chip armada_370_xp_irq_chip = {
....@@ -367,98 +567,6 @@
367567
368568 return 0;
369569 }
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
462570
463571 static const struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
464572 .map = armada_370_xp_mpic_irq_map,
....@@ -558,22 +666,15 @@
558666 #ifdef CONFIG_SMP
559667 /* IPI Handling */
560668 if (irqnr == 0) {
561
- u32 ipimask, ipinr;
669
+ unsigned long ipimask;
670
+ int ipi;
562671
563672 ipimask = readl_relaxed(per_cpu_int_base +
564673 ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
565674 & IPI_DOORBELL_MASK;
566675
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);
577678 }
578679 #endif
579680
....@@ -632,6 +733,8 @@
632733 writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
633734 if (doorbell_mask_reg & PCI_MSI_DOORBELL_MASK)
634735 writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
736
+
737
+ ipi_resume();
635738 }
636739
637740 static struct syscore_ops armada_370_xp_mpic_syscore_ops = {
....@@ -687,7 +790,7 @@
687790 irq_set_default_host(armada_370_xp_mpic_domain);
688791 set_handle_irq(armada_370_xp_handle_irq);
689792 #ifdef CONFIG_SMP
690
- set_smp_cross_call(armada_mpic_send_doorbell);
793
+ armada_xp_ipi_init(node);
691794 cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_ARMADA_XP_STARTING,
692795 "irqchip/armada/ipi:starting",
693796 armada_xp_mpic_starting_cpu, NULL);