Commit c425060a authored by Marc Zyngier's avatar Marc Zyngier
Browse files

Merge branch irq/aic-pmu into irq/irqchip-next



* irq/aic-pmu:
  : .
  : Prefix branch for the M1 PMU support, adding the required
  : irqchip changes. Shared with the arm64 tree.
  : .
  irqchip/apple-aic: Fix cpumask allocation for FIQs
  irqchip/apple-aic: Move PMU-specific registers to their own include file
  arm64: dts: apple: Add t8303 PMU nodes
  arm64: dts: apple: Add t8103 PMU interrupt affinities
  irqchip/apple-aic: Wire PMU interrupts
  irqchip/apple-aic: Parse FIQ affinities from device-tree
  dt-bindings: apple,aic: Add affinity description for per-cpu pseudo-interrupts
  dt-bindings: apple,aic: Add CPU PMU per-cpu pseudo-interrupts
  dt-bindings: arm-pmu: Document Apple PMU compatible strings

Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parents 92af5d47 dc29812d
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ properties:
    items:
      - enum:
          - apm,potenza-pmu
          - apple,firestorm-pmu
          - apple,icestorm-pmu
          - arm,armv8-pmuv3 # Only for s/w models
          - arm,arm1136-pmu
          - arm,arm1176-pmu
+31 −0
Original line number Diff line number Diff line
@@ -56,6 +56,8 @@ properties:
          - 1: virtual HV timer
          - 2: physical guest timer
          - 3: virtual guest timer
          - 4: 'efficient' CPU PMU
          - 5: 'performance' CPU PMU

      The 3rd cell contains the interrupt flags. This is normally
      IRQ_TYPE_LEVEL_HIGH (4).
@@ -68,6 +70,35 @@ properties:
  power-domains:
    maxItems: 1

  affinities:
    type: object
    additionalProperties: false
    description:
      FIQ affinity can be expressed as a single "affinities" node,
      containing a set of sub-nodes, one per FIQ with a non-default
      affinity.
    patternProperties:
      "^.+-affinity$":
        type: object
        additionalProperties: false
        properties:
          apple,fiq-index:
            description:
              The interrupt number specified as a FIQ, and for which
              the affinity is not the default.
            $ref: /schemas/types.yaml#/definitions/uint32
            maximum: 5

          cpus:
            $ref: /schemas/types.yaml#/definitions/phandle-array
            description:
              Should be a list of phandles to CPU nodes (as described in
              Documentation/devicetree/bindings/arm/cpus.yaml).

        required:
          - fiq-index
          - cpus

required:
  - compatible
  - '#interrupt-cells'
+24 −0
Original line number Diff line number Diff line
@@ -97,6 +97,18 @@
			     <AIC_FIQ AIC_TMR_HV_VIRT IRQ_TYPE_LEVEL_HIGH>;
	};

	pmu-e {
		compatible = "apple,icestorm-pmu";
		interrupt-parent = <&aic>;
		interrupts = <AIC_FIQ AIC_CPU_PMU_E IRQ_TYPE_LEVEL_HIGH>;
	};

	pmu-p {
		compatible = "apple,firestorm-pmu";
		interrupt-parent = <&aic>;
		interrupts = <AIC_FIQ AIC_CPU_PMU_P IRQ_TYPE_LEVEL_HIGH>;
	};

	clkref: clock-ref {
		compatible = "fixed-clock";
		#clock-cells = <0>;
@@ -213,6 +225,18 @@
			interrupt-controller;
			reg = <0x2 0x3b100000 0x0 0x8000>;
			power-domains = <&ps_aic>;

			affinities {
				e-core-pmu-affinity {
					apple,fiq-index = <AIC_CPU_PMU_E>;
					cpus = <&cpu0 &cpu1 &cpu2 &cpu3>;
				};

				p-core-pmu-affinity {
					apple,fiq-index = <AIC_CPU_PMU_P>;
					cpus = <&cpu4 &cpu5 &cpu6 &cpu7>;
				};
			};
		};

		pmgr: power-management@23b700000 {
+19 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0

#ifndef __ASM_APPLE_M1_PMU_h
#define __ASM_APPLE_M1_PMU_h

#include <linux/bits.h>
#include <asm/sysreg.h>

/* Core PMC control register */
#define SYS_IMP_APL_PMCR0_EL1	sys_reg(3, 1, 15, 0, 0)
#define PMCR0_IMODE		GENMASK(10, 8)
#define PMCR0_IMODE_OFF		0
#define PMCR0_IMODE_PMI		1
#define PMCR0_IMODE_AIC		2
#define PMCR0_IMODE_HALT	3
#define PMCR0_IMODE_FIQ		4
#define PMCR0_IACT		BIT(11)

#endif /* __ASM_APPLE_M1_PMU_h */
+72 −22
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@
#include <linux/limits.h>
#include <linux/of_address.h>
#include <linux/slab.h>
#include <asm/apple_m1_pmu.h>
#include <asm/exception.h>
#include <asm/sysreg.h>
#include <asm/virt.h>
@@ -109,16 +110,6 @@
 * Note: sysreg-based IPIs are not supported yet.
 */

/* Core PMC control register */
#define SYS_IMP_APL_PMCR0_EL1		sys_reg(3, 1, 15, 0, 0)
#define PMCR0_IMODE			GENMASK(10, 8)
#define PMCR0_IMODE_OFF			0
#define PMCR0_IMODE_PMI			1
#define PMCR0_IMODE_AIC			2
#define PMCR0_IMODE_HALT		3
#define PMCR0_IMODE_FIQ			4
#define PMCR0_IACT			BIT(11)

/* IPI request registers */
#define SYS_IMP_APL_IPI_RR_LOCAL_EL1	sys_reg(3, 5, 15, 0, 0)
#define SYS_IMP_APL_IPI_RR_GLOBAL_EL1	sys_reg(3, 5, 15, 0, 1)
@@ -155,7 +146,7 @@
#define SYS_IMP_APL_UPMSR_EL1		sys_reg(3, 7, 15, 6, 4)
#define UPMSR_IACT			BIT(0)

#define AIC_NR_FIQ		4
#define AIC_NR_FIQ		6
#define AIC_NR_SWIPI		32

/*
@@ -177,6 +168,9 @@ struct aic_irq_chip {
	void __iomem *base;
	struct irq_domain *hw_domain;
	struct irq_domain *ipi_domain;
	struct {
		cpumask_t aff;
	} *fiq_aff[AIC_NR_FIQ];
	int nr_hw;
};

@@ -412,16 +406,15 @@ static void __exception_irq_entry aic_handle_fiq(struct pt_regs *regs)
						  aic_irqc->nr_hw + AIC_TMR_EL02_VIRT);
	}

	if ((read_sysreg_s(SYS_IMP_APL_PMCR0_EL1) & (PMCR0_IMODE | PMCR0_IACT)) ==
			(FIELD_PREP(PMCR0_IMODE, PMCR0_IMODE_FIQ) | PMCR0_IACT)) {
		/*
		 * Not supported yet, let's figure out how to handle this when
		 * we implement these proprietary performance counters. For now,
		 * just mask it and move on.
		 */
		pr_err_ratelimited("PMC FIQ fired. Masking.\n");
		sysreg_clear_set_s(SYS_IMP_APL_PMCR0_EL1, PMCR0_IMODE | PMCR0_IACT,
				   FIELD_PREP(PMCR0_IMODE, PMCR0_IMODE_OFF));
	if (read_sysreg_s(SYS_IMP_APL_PMCR0_EL1) & PMCR0_IACT) {
		int irq;
		if (cpumask_test_cpu(smp_processor_id(),
				     &aic_irqc->fiq_aff[AIC_CPU_PMU_P]->aff))
			irq = AIC_CPU_PMU_P;
		else
			irq = AIC_CPU_PMU_E;
		generic_handle_domain_irq(aic_irqc->hw_domain,
					  aic_irqc->nr_hw + irq);
	}

	if (FIELD_GET(UPMCR0_IMODE, read_sysreg_s(SYS_IMP_APL_UPMCR0_EL1)) == UPMCR0_IMODE_FIQ &&
@@ -461,7 +454,18 @@ static int aic_irq_domain_map(struct irq_domain *id, unsigned int irq,
				    handle_fasteoi_irq, NULL, NULL);
		irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(irq)));
	} else {
		int fiq = hw - ic->nr_hw;

		switch (fiq) {
		case AIC_CPU_PMU_P:
		case AIC_CPU_PMU_E:
			irq_set_percpu_devid_partition(irq, &ic->fiq_aff[fiq]->aff);
			break;
		default:
			irq_set_percpu_devid(irq);
			break;
		}

		irq_domain_set_info(id, irq, hw, &fiq_chip, id->host_data,
				    handle_percpu_devid_irq, NULL, NULL);
	}
@@ -793,12 +797,50 @@ static struct gic_kvm_info vgic_info __initdata = {
	.no_hw_deactivation	= true,
};

static void build_fiq_affinity(struct aic_irq_chip *ic, struct device_node *aff)
{
	int i, n;
	u32 fiq;

	if (of_property_read_u32(aff, "apple,fiq-index", &fiq) ||
	    WARN_ON(fiq >= AIC_NR_FIQ) || ic->fiq_aff[fiq])
		return;

	n = of_property_count_elems_of_size(aff, "cpus", sizeof(u32));
	if (WARN_ON(n < 0))
		return;

	ic->fiq_aff[fiq] = kzalloc(sizeof(*ic->fiq_aff[fiq]), GFP_KERNEL);
	if (!ic->fiq_aff[fiq])
		return;

	for (i = 0; i < n; i++) {
		struct device_node *cpu_node;
		u32 cpu_phandle;
		int cpu;

		if (of_property_read_u32_index(aff, "cpus", i, &cpu_phandle))
			continue;

		cpu_node = of_find_node_by_phandle(cpu_phandle);
		if (WARN_ON(!cpu_node))
			continue;

		cpu = of_cpu_node_to_id(cpu_node);
		if (WARN_ON(cpu < 0))
			continue;

		cpumask_set_cpu(cpu, &ic->fiq_aff[fiq]->aff);
	}
}

static int __init aic_of_ic_init(struct device_node *node, struct device_node *parent)
{
	int i;
	void __iomem *regs;
	u32 info;
	struct aic_irq_chip *irqc;
	struct device_node *affs;

	regs = of_iomap(node, 0);
	if (WARN_ON(!regs))
@@ -832,6 +874,14 @@ static int __init aic_of_ic_init(struct device_node *node, struct device_node *p
		return -ENODEV;
	}

	affs = of_get_child_by_name(node, "affinities");
	if (affs) {
		struct device_node *chld;

		for_each_child_of_node(affs, chld)
			build_fiq_affinity(irqc, chld);
	}

	set_handle_irq(aic_handle_irq);
	set_handle_fiq(aic_handle_fiq);

Loading