mirror of
https://github.com/torvalds/linux.git
synced 2025-11-03 10:10:33 +02:00
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>
This commit is contained in:
parent
6a5dc6c753
commit
89f0b9ccd3
1 changed files with 55 additions and 27 deletions
|
|
@ -102,6 +102,7 @@ struct arm_ni_unit {
|
|||
struct arm_ni_cd {
|
||||
void __iomem *pmu_base;
|
||||
u16 id;
|
||||
s8 irq_friend;
|
||||
int num_units;
|
||||
int irq;
|
||||
struct pmu pmu;
|
||||
|
|
@ -448,6 +449,8 @@ static irqreturn_t arm_ni_handle_irq(int irq, void *dev_id)
|
|||
{
|
||||
struct arm_ni_cd *cd = dev_id;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
|
||||
for (;;) {
|
||||
u32 reg = readl_relaxed(cd->pmu_base + NI_PMOVSCLR);
|
||||
|
||||
if (reg & (1U << NI_CCNT_IDX)) {
|
||||
|
|
@ -467,14 +470,16 @@ static irqreturn_t arm_ni_handle_irq(int irq, void *dev_id)
|
|||
}
|
||||
}
|
||||
writel_relaxed(reg, cd->pmu_base + NI_PMOVSCLR);
|
||||
if (!cd->irq_friend)
|
||||
return ret;
|
||||
cd += cd->irq_friend;
|
||||
}
|
||||
}
|
||||
|
||||
static int arm_ni_init_cd(struct arm_ni *ni, struct arm_ni_node *node, u64 res_start)
|
||||
{
|
||||
struct arm_ni_cd *cd = ni->cds + node->id;
|
||||
const char *name;
|
||||
int err;
|
||||
|
||||
cd->id = node->id;
|
||||
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
|
|||
cd->pmu_base + NI_PMCR);
|
||||
writel_relaxed(U32_MAX, cd->pmu_base + NI_PMCNTENCLR);
|
||||
writel_relaxed(U32_MAX, cd->pmu_base + NI_PMOVSCLR);
|
||||
writel_relaxed(U32_MAX, cd->pmu_base + NI_PMINTENSET);
|
||||
|
||||
cd->irq = platform_get_irq(to_platform_device(ni->dev), cd->id);
|
||||
if (cd->irq < 0)
|
||||
return cd->irq;
|
||||
|
||||
err = devm_request_irq(ni->dev, cd->irq, arm_ni_handle_irq,
|
||||
IRQF_NOBALANCING | IRQF_NO_THREAD,
|
||||
dev_name(ni->dev), cd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
irq_set_affinity(cd->irq, cpumask_of(ni->cpu));
|
||||
|
||||
cd->pmu = (struct pmu) {
|
||||
.module = THIS_MODULE,
|
||||
.parent = ni->dev,
|
||||
|
|
@ -593,6 +589,34 @@ static void arm_ni_probe_domain(void __iomem *base, struct arm_ni_node *node)
|
|||
node->num_components = readl_relaxed(base + NI_CHILD_NODE_INFO);
|
||||
}
|
||||
|
||||
static int arm_ni_init_irqs(struct arm_ni *ni)
|
||||
{
|
||||
int err;
|
||||
|
||||
ni_for_each_cd(ni, cd) {
|
||||
for (struct arm_ni_cd *prev = cd; prev-- > ni->cds; ) {
|
||||
if (prev->irq == cd->irq) {
|
||||
prev->irq_friend = cd - prev;
|
||||
goto set_inten;
|
||||
}
|
||||
}
|
||||
err = devm_request_irq(ni->dev, cd->irq, arm_ni_handle_irq,
|
||||
IRQF_NOBALANCING | IRQF_NO_THREAD | IRQF_NO_AUTOEN,
|
||||
dev_name(ni->dev), cd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
irq_set_affinity(cd->irq, cpumask_of(ni->cpu));
|
||||
set_inten:
|
||||
writel_relaxed(U32_MAX, cd->pmu_base + NI_PMINTENSET);
|
||||
}
|
||||
|
||||
ni_for_each_cd(ni, cd)
|
||||
if (!cd->irq_friend)
|
||||
enable_irq(cd->irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int arm_ni_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct arm_ni_node cfg, vd, pd, cd;
|
||||
|
|
@ -677,7 +701,11 @@ static int arm_ni_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
ret = arm_ni_init_irqs(ni);
|
||||
if (ret)
|
||||
arm_ni_remove(pdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
|
|
|||
Loading…
Reference in a new issue