mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +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 {
 | 
					struct arm_ni_cd {
 | 
				
			||||||
	void __iomem *pmu_base;
 | 
						void __iomem *pmu_base;
 | 
				
			||||||
	u16 id;
 | 
						u16 id;
 | 
				
			||||||
 | 
						s8 irq_friend;
 | 
				
			||||||
	int num_units;
 | 
						int num_units;
 | 
				
			||||||
	int irq;
 | 
						int irq;
 | 
				
			||||||
	struct pmu pmu;
 | 
						struct pmu pmu;
 | 
				
			||||||
| 
						 | 
					@ -448,33 +449,37 @@ static irqreturn_t arm_ni_handle_irq(int irq, void *dev_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct arm_ni_cd *cd = dev_id;
 | 
						struct arm_ni_cd *cd = dev_id;
 | 
				
			||||||
	irqreturn_t ret = IRQ_NONE;
 | 
						irqreturn_t ret = IRQ_NONE;
 | 
				
			||||||
	u32 reg = readl_relaxed(cd->pmu_base + NI_PMOVSCLR);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (reg & (1U << NI_CCNT_IDX)) {
 | 
						for (;;) {
 | 
				
			||||||
		ret = IRQ_HANDLED;
 | 
							u32 reg = readl_relaxed(cd->pmu_base + NI_PMOVSCLR);
 | 
				
			||||||
		if (!(WARN_ON(!cd->ccnt))) {
 | 
					
 | 
				
			||||||
			arm_ni_event_read(cd->ccnt);
 | 
							if (reg & (1U << NI_CCNT_IDX)) {
 | 
				
			||||||
			arm_ni_init_ccnt(cd);
 | 
								ret = IRQ_HANDLED;
 | 
				
			||||||
 | 
								if (!(WARN_ON(!cd->ccnt))) {
 | 
				
			||||||
 | 
									arm_ni_event_read(cd->ccnt);
 | 
				
			||||||
 | 
									arm_ni_init_ccnt(cd);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
							for (int i = 0; i < NI_NUM_COUNTERS; i++) {
 | 
				
			||||||
	for (int i = 0; i < NI_NUM_COUNTERS; i++) {
 | 
								if (!(reg & (1U << i)))
 | 
				
			||||||
		if (!(reg & (1U << i)))
 | 
									continue;
 | 
				
			||||||
			continue;
 | 
								ret = IRQ_HANDLED;
 | 
				
			||||||
		ret = IRQ_HANDLED;
 | 
								if (!(WARN_ON(!cd->evcnt[i]))) {
 | 
				
			||||||
		if (!(WARN_ON(!cd->evcnt[i]))) {
 | 
									arm_ni_event_read(cd->evcnt[i]);
 | 
				
			||||||
			arm_ni_event_read(cd->evcnt[i]);
 | 
									arm_ni_init_evcnt(cd, i);
 | 
				
			||||||
			arm_ni_init_evcnt(cd, i);
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							writel_relaxed(reg, cd->pmu_base + NI_PMOVSCLR);
 | 
				
			||||||
 | 
							if (!cd->irq_friend)
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
							cd += cd->irq_friend;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	writel_relaxed(reg, cd->pmu_base + NI_PMOVSCLR);
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int arm_ni_init_cd(struct arm_ni *ni, struct arm_ni_node *node, u64 res_start)
 | 
					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;
 | 
						struct arm_ni_cd *cd = ni->cds + node->id;
 | 
				
			||||||
	const char *name;
 | 
						const char *name;
 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cd->id = node->id;
 | 
						cd->id = node->id;
 | 
				
			||||||
	cd->num_units = node->num_components;
 | 
						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);
 | 
							       cd->pmu_base + NI_PMCR);
 | 
				
			||||||
	writel_relaxed(U32_MAX, cd->pmu_base + NI_PMCNTENCLR);
 | 
						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_PMOVSCLR);
 | 
				
			||||||
	writel_relaxed(U32_MAX, cd->pmu_base + NI_PMINTENSET);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cd->irq = platform_get_irq(to_platform_device(ni->dev), cd->id);
 | 
						cd->irq = platform_get_irq(to_platform_device(ni->dev), cd->id);
 | 
				
			||||||
	if (cd->irq < 0)
 | 
						if (cd->irq < 0)
 | 
				
			||||||
		return cd->irq;
 | 
							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) {
 | 
						cd->pmu = (struct pmu) {
 | 
				
			||||||
		.module = THIS_MODULE,
 | 
							.module = THIS_MODULE,
 | 
				
			||||||
		.parent = ni->dev,
 | 
							.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);
 | 
						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)
 | 
					static int arm_ni_probe(struct platform_device *pdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct arm_ni_node cfg, vd, pd, cd;
 | 
						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
 | 
					#ifdef CONFIG_OF
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue