Skip to content

Commit 89f0b9c

Browse files
Shouping Wangwilldeacon
authored andcommitted
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 <[email protected]> [ rm: Rework for affinity handling, cosmetics, new commit message ] Signed-off-by: Robin Murphy <[email protected]> Link: https://lore.kernel.org/r/f62db639d3b54c959ec477db7b8ccecbef1ca310.1752256072.git.robin.murphy@arm.com Signed-off-by: Will Deacon <[email protected]>
1 parent 6a5dc6c commit 89f0b9c

File tree

1 file changed

+55
-27
lines changed

1 file changed

+55
-27
lines changed

drivers/perf/arm-ni.c

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ struct arm_ni_unit {
102102
struct arm_ni_cd {
103103
void __iomem *pmu_base;
104104
u16 id;
105+
s8 irq_friend;
105106
int num_units;
106107
int irq;
107108
struct pmu pmu;
@@ -448,33 +449,37 @@ static irqreturn_t arm_ni_handle_irq(int irq, void *dev_id)
448449
{
449450
struct arm_ni_cd *cd = dev_id;
450451
irqreturn_t ret = IRQ_NONE;
451-
u32 reg = readl_relaxed(cd->pmu_base + NI_PMOVSCLR);
452452

453-
if (reg & (1U << NI_CCNT_IDX)) {
454-
ret = IRQ_HANDLED;
455-
if (!(WARN_ON(!cd->ccnt))) {
456-
arm_ni_event_read(cd->ccnt);
457-
arm_ni_init_ccnt(cd);
453+
for (;;) {
454+
u32 reg = readl_relaxed(cd->pmu_base + NI_PMOVSCLR);
455+
456+
if (reg & (1U << NI_CCNT_IDX)) {
457+
ret = IRQ_HANDLED;
458+
if (!(WARN_ON(!cd->ccnt))) {
459+
arm_ni_event_read(cd->ccnt);
460+
arm_ni_init_ccnt(cd);
461+
}
458462
}
459-
}
460-
for (int i = 0; i < NI_NUM_COUNTERS; i++) {
461-
if (!(reg & (1U << i)))
462-
continue;
463-
ret = IRQ_HANDLED;
464-
if (!(WARN_ON(!cd->evcnt[i]))) {
465-
arm_ni_event_read(cd->evcnt[i]);
466-
arm_ni_init_evcnt(cd, i);
463+
for (int i = 0; i < NI_NUM_COUNTERS; i++) {
464+
if (!(reg & (1U << i)))
465+
continue;
466+
ret = IRQ_HANDLED;
467+
if (!(WARN_ON(!cd->evcnt[i]))) {
468+
arm_ni_event_read(cd->evcnt[i]);
469+
arm_ni_init_evcnt(cd, i);
470+
}
467471
}
472+
writel_relaxed(reg, cd->pmu_base + NI_PMOVSCLR);
473+
if (!cd->irq_friend)
474+
return ret;
475+
cd += cd->irq_friend;
468476
}
469-
writel_relaxed(reg, cd->pmu_base + NI_PMOVSCLR);
470-
return ret;
471477
}
472478

473479
static int arm_ni_init_cd(struct arm_ni *ni, struct arm_ni_node *node, u64 res_start)
474480
{
475481
struct arm_ni_cd *cd = ni->cds + node->id;
476482
const char *name;
477-
int err;
478483

479484
cd->id = node->id;
480485
cd->num_units = node->num_components;
@@ -534,20 +539,11 @@ static int arm_ni_init_cd(struct arm_ni *ni, struct arm_ni_node *node, u64 res_s
534539
cd->pmu_base + NI_PMCR);
535540
writel_relaxed(U32_MAX, cd->pmu_base + NI_PMCNTENCLR);
536541
writel_relaxed(U32_MAX, cd->pmu_base + NI_PMOVSCLR);
537-
writel_relaxed(U32_MAX, cd->pmu_base + NI_PMINTENSET);
538542

539543
cd->irq = platform_get_irq(to_platform_device(ni->dev), cd->id);
540544
if (cd->irq < 0)
541545
return cd->irq;
542546

543-
err = devm_request_irq(ni->dev, cd->irq, arm_ni_handle_irq,
544-
IRQF_NOBALANCING | IRQF_NO_THREAD,
545-
dev_name(ni->dev), cd);
546-
if (err)
547-
return err;
548-
549-
irq_set_affinity(cd->irq, cpumask_of(ni->cpu));
550-
551547
cd->pmu = (struct pmu) {
552548
.module = THIS_MODULE,
553549
.parent = ni->dev,
@@ -593,6 +589,34 @@ static void arm_ni_probe_domain(void __iomem *base, struct arm_ni_node *node)
593589
node->num_components = readl_relaxed(base + NI_CHILD_NODE_INFO);
594590
}
595591

592+
static int arm_ni_init_irqs(struct arm_ni *ni)
593+
{
594+
int err;
595+
596+
ni_for_each_cd(ni, cd) {
597+
for (struct arm_ni_cd *prev = cd; prev-- > ni->cds; ) {
598+
if (prev->irq == cd->irq) {
599+
prev->irq_friend = cd - prev;
600+
goto set_inten;
601+
}
602+
}
603+
err = devm_request_irq(ni->dev, cd->irq, arm_ni_handle_irq,
604+
IRQF_NOBALANCING | IRQF_NO_THREAD | IRQF_NO_AUTOEN,
605+
dev_name(ni->dev), cd);
606+
if (err)
607+
return err;
608+
609+
irq_set_affinity(cd->irq, cpumask_of(ni->cpu));
610+
set_inten:
611+
writel_relaxed(U32_MAX, cd->pmu_base + NI_PMINTENSET);
612+
}
613+
614+
ni_for_each_cd(ni, cd)
615+
if (!cd->irq_friend)
616+
enable_irq(cd->irq);
617+
return 0;
618+
}
619+
596620
static int arm_ni_probe(struct platform_device *pdev)
597621
{
598622
struct arm_ni_node cfg, vd, pd, cd;
@@ -677,7 +701,11 @@ static int arm_ni_probe(struct platform_device *pdev)
677701
}
678702
}
679703

680-
return 0;
704+
ret = arm_ni_init_irqs(ni);
705+
if (ret)
706+
arm_ni_remove(pdev);
707+
708+
return ret;
681709
}
682710

683711
#ifdef CONFIG_OF

0 commit comments

Comments
 (0)