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

perf/arm-ni: Support sharing IRQs within an NI instance

NI-700 has a distinct PMU interrupt output for each Clock Domain,
however some integrations may still combine these together externally.
The initial driver didn't attempt to support this, in anticipation of a
more general solution for IRQ sharing between system PMU instances, but
that's still a way off, so let's make this intermediate step for now to
at least allow sharing IRQs within an individual NI instance.

Now that CPU affinity and migration are cleaned up, it's fairly
straightforward to adopt similar logic to arm-cmn, to identify CDs with
a common interrupt and loop over them directly in the handler.

Signed-off-by: Shouping Wang <allen.wang@hj-micro.com>
[ rm: Rework for affinity handling, cosmetics, new commit message ]
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Link: https://lore.kernel.org/r/f62db639d3b54c959ec477db7b8ccecbef1ca310.1752256072.git.robin.murphy@arm.com
Signed-off-by: Will Deacon <will@kernel.org>

authored by

Shouping Wang and committed by
Will Deacon
89f0b9cc 6a5dc6c7

+55 -27
+55 -27
drivers/perf/arm-ni.c
··· 102 102 struct arm_ni_cd { 103 103 void __iomem *pmu_base; 104 104 u16 id; 105 + s8 irq_friend; 105 106 int num_units; 106 107 int irq; 107 108 struct pmu pmu; ··· 449 448 { 450 449 struct arm_ni_cd *cd = dev_id; 451 450 irqreturn_t ret = IRQ_NONE; 452 - u32 reg = readl_relaxed(cd->pmu_base + NI_PMOVSCLR); 453 451 454 - if (reg & (1U << NI_CCNT_IDX)) { 455 - ret = IRQ_HANDLED; 456 - if (!(WARN_ON(!cd->ccnt))) { 457 - arm_ni_event_read(cd->ccnt); 458 - arm_ni_init_ccnt(cd); 452 + for (;;) { 453 + u32 reg = readl_relaxed(cd->pmu_base + NI_PMOVSCLR); 454 + 455 + if (reg & (1U << NI_CCNT_IDX)) { 456 + ret = IRQ_HANDLED; 457 + if (!(WARN_ON(!cd->ccnt))) { 458 + arm_ni_event_read(cd->ccnt); 459 + arm_ni_init_ccnt(cd); 460 + } 459 461 } 460 - } 461 - for (int i = 0; i < NI_NUM_COUNTERS; i++) { 462 - if (!(reg & (1U << i))) 463 - continue; 464 - ret = IRQ_HANDLED; 465 - if (!(WARN_ON(!cd->evcnt[i]))) { 466 - arm_ni_event_read(cd->evcnt[i]); 467 - arm_ni_init_evcnt(cd, i); 462 + for (int i = 0; i < NI_NUM_COUNTERS; i++) { 463 + if (!(reg & (1U << i))) 464 + continue; 465 + ret = IRQ_HANDLED; 466 + if (!(WARN_ON(!cd->evcnt[i]))) { 467 + arm_ni_event_read(cd->evcnt[i]); 468 + arm_ni_init_evcnt(cd, i); 469 + } 468 470 } 471 + writel_relaxed(reg, cd->pmu_base + NI_PMOVSCLR); 472 + if (!cd->irq_friend) 473 + return ret; 474 + cd += cd->irq_friend; 469 475 } 470 - writel_relaxed(reg, cd->pmu_base + NI_PMOVSCLR); 471 - return ret; 472 476 } 473 477 474 478 static int arm_ni_init_cd(struct arm_ni *ni, struct arm_ni_node *node, u64 res_start) 475 479 { 476 480 struct arm_ni_cd *cd = ni->cds + node->id; 477 481 const char *name; 478 - int err; 479 482 480 483 cd->id = node->id; 481 484 cd->num_units = node->num_components; ··· 539 534 cd->pmu_base + NI_PMCR); 540 535 writel_relaxed(U32_MAX, cd->pmu_base + NI_PMCNTENCLR); 541 536 writel_relaxed(U32_MAX, cd->pmu_base + NI_PMOVSCLR); 542 - writel_relaxed(U32_MAX, cd->pmu_base + NI_PMINTENSET); 543 537 544 538 cd->irq = platform_get_irq(to_platform_device(ni->dev), cd->id); 545 539 if (cd->irq < 0) 546 540 return cd->irq; 547 - 548 - err = devm_request_irq(ni->dev, cd->irq, arm_ni_handle_irq, 549 - IRQF_NOBALANCING | IRQF_NO_THREAD, 550 - dev_name(ni->dev), cd); 551 - if (err) 552 - return err; 553 - 554 - irq_set_affinity(cd->irq, cpumask_of(ni->cpu)); 555 541 556 542 cd->pmu = (struct pmu) { 557 543 .module = THIS_MODULE, ··· 587 591 node->type = FIELD_GET(NI_NODE_TYPE_NODE_TYPE, reg); 588 592 node->id = FIELD_GET(NI_NODE_TYPE_NODE_ID, reg); 589 593 node->num_components = readl_relaxed(base + NI_CHILD_NODE_INFO); 594 + } 595 + 596 + static int arm_ni_init_irqs(struct arm_ni *ni) 597 + { 598 + int err; 599 + 600 + ni_for_each_cd(ni, cd) { 601 + for (struct arm_ni_cd *prev = cd; prev-- > ni->cds; ) { 602 + if (prev->irq == cd->irq) { 603 + prev->irq_friend = cd - prev; 604 + goto set_inten; 605 + } 606 + } 607 + err = devm_request_irq(ni->dev, cd->irq, arm_ni_handle_irq, 608 + IRQF_NOBALANCING | IRQF_NO_THREAD | IRQF_NO_AUTOEN, 609 + dev_name(ni->dev), cd); 610 + if (err) 611 + return err; 612 + 613 + irq_set_affinity(cd->irq, cpumask_of(ni->cpu)); 614 + set_inten: 615 + writel_relaxed(U32_MAX, cd->pmu_base + NI_PMINTENSET); 616 + } 617 + 618 + ni_for_each_cd(ni, cd) 619 + if (!cd->irq_friend) 620 + enable_irq(cd->irq); 621 + return 0; 590 622 } 591 623 592 624 static int arm_ni_probe(struct platform_device *pdev) ··· 701 677 } 702 678 } 703 679 704 - return 0; 680 + ret = arm_ni_init_irqs(ni); 681 + if (ret) 682 + arm_ni_remove(pdev); 683 + 684 + return ret; 705 685 } 706 686 707 687 #ifdef CONFIG_OF