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

ARM: perf: extend interrupt-affinity property for PPIs

On systems containing multiple, heterogeneous clusters we need a way to
associate a PMU "device" with the CPU(s) on which it exists. For PMUs
that signal overflow with SPIs, this relationship is determined via the
"interrupt-affinity" property, which contains a list of phandles to CPU
nodes for the PMU. For PMUs using PPIs, the per-cpu nature of the
interrupt isn't enough to determine the set of CPUs which actually
contain the device.

This patch allows the interrupt-affinity property to be specified on a
PMU node irrespective of the interrupt type. For PPIs, it identifies
the set of CPUs signalling the PPI in question.

Tested-by: Stephen Boyd <sboyd@codeaurora.org> # Krait PMU
Signed-off-by: Will Deacon <will.deacon@arm.com>

+55 -26
+9 -3
Documentation/devicetree/bindings/arm/pmu.txt
··· 26 26 27 27 Optional properties: 28 28 29 - - interrupt-affinity : Valid only when using SPIs, specifies a list of phandles 30 - to CPU nodes corresponding directly to the affinity of 29 + - interrupt-affinity : When using SPIs, specifies a list of phandles to CPU 30 + nodes corresponding directly to the affinity of 31 31 the SPIs listed in the interrupts property. 32 32 33 - This property should be present when there is more than 33 + When using a PPI, specifies a list of phandles to CPU 34 + nodes corresponding to the set of CPUs which have 35 + a PMU of this type signalling the PPI listed in the 36 + interrupts property. 37 + 38 + This property should be present when there is more than 34 39 a single SPI. 40 + 35 41 36 42 - qcom,no-pc-write : Indicates that this PMU doesn't support the 0xc and 0xd 37 43 events.
+46 -23
arch/arm/kernel/perf_event.c
··· 790 790 791 791 static int of_pmu_irq_cfg(struct arm_pmu *pmu) 792 792 { 793 - int i, irq, *irqs; 793 + int *irqs, i = 0; 794 + bool using_spi = false; 794 795 struct platform_device *pdev = pmu->plat_device; 795 - 796 - /* Don't bother with PPIs; they're already affine */ 797 - irq = platform_get_irq(pdev, 0); 798 - if (irq >= 0 && irq_is_percpu(irq)) { 799 - cpumask_setall(&pmu->supported_cpus); 800 - return 0; 801 - } 802 796 803 797 irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL); 804 798 if (!irqs) 805 799 return -ENOMEM; 806 800 807 - for (i = 0; i < pdev->num_resources; ++i) { 801 + do { 808 802 struct device_node *dn; 809 - int cpu; 803 + int cpu, irq; 810 804 811 - dn = of_parse_phandle(pdev->dev.of_node, "interrupt-affinity", 812 - i); 813 - if (!dn) { 814 - pr_warn("Failed to parse %s/interrupt-affinity[%d]\n", 815 - of_node_full_name(pdev->dev.of_node), i); 805 + /* See if we have an affinity entry */ 806 + dn = of_parse_phandle(pdev->dev.of_node, "interrupt-affinity", i); 807 + if (!dn) 816 808 break; 809 + 810 + /* Check the IRQ type and prohibit a mix of PPIs and SPIs */ 811 + irq = platform_get_irq(pdev, i); 812 + if (irq >= 0) { 813 + bool spi = !irq_is_percpu(irq); 814 + 815 + if (i > 0 && spi != using_spi) { 816 + pr_err("PPI/SPI IRQ type mismatch for %s!\n", 817 + dn->name); 818 + kfree(irqs); 819 + return -EINVAL; 820 + } 821 + 822 + using_spi = spi; 817 823 } 818 824 825 + /* Now look up the logical CPU number */ 819 826 for_each_possible_cpu(cpu) 820 827 if (arch_find_n_match_cpu_physical_id(dn, cpu, NULL)) 821 828 break; ··· 831 824 pr_warn("Failed to find logical CPU for %s\n", 832 825 dn->name); 833 826 of_node_put(dn); 827 + cpumask_setall(&pmu->supported_cpus); 834 828 break; 835 829 } 836 830 of_node_put(dn); 837 831 838 - irqs[i] = cpu; 839 - cpumask_set_cpu(cpu, &pmu->supported_cpus); 840 - } 832 + /* For SPIs, we need to track the affinity per IRQ */ 833 + if (using_spi) { 834 + if (i >= pdev->num_resources) { 835 + of_node_put(dn); 836 + break; 837 + } 841 838 842 - if (i == pdev->num_resources) { 843 - pmu->irq_affinity = irqs; 844 - } else { 845 - kfree(irqs); 839 + irqs[i] = cpu; 840 + } 841 + 842 + /* Keep track of the CPUs containing this PMU type */ 843 + cpumask_set_cpu(cpu, &pmu->supported_cpus); 844 + of_node_put(dn); 845 + i++; 846 + } while (1); 847 + 848 + /* If we didn't manage to parse anything, claim to support all CPUs */ 849 + if (cpumask_weight(&pmu->supported_cpus) == 0) 846 850 cpumask_setall(&pmu->supported_cpus); 847 - } 851 + 852 + /* If we matched up the IRQ affinities, use them to route the SPIs */ 853 + if (using_spi && i == pdev->num_resources) 854 + pmu->irq_affinity = irqs; 855 + else 856 + kfree(irqs); 848 857 849 858 return 0; 850 859 }