All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jeremy Linton <jeremy.linton@arm.com>
To: linux-arm-kernel@lists.infradead.org
Cc: linux-acpi@vger.kernel.org, will.deacon@arm.com,
	mark.rutland@arm.com, lorenzo.pieralisi@arm.com,
	catalin.marinas@arm.com, peterz@infradead.org, mingo@redhat.com,
	acme@kernel.org, alexander.shishkin@linux.intel.com,
	mlangsdorf@redhat.com
Subject: [PATCH 6/8] arm64: pmu: Add routines for detecting differing PMU types in the system
Date: Thu,  9 Jun 2016 17:23:31 -0500	[thread overview]
Message-ID: <1465511013-10742-7-git-send-email-jeremy.linton@arm.com> (raw)
In-Reply-To: <1465511013-10742-1-git-send-email-jeremy.linton@arm.com>

In preparation for enabling heterogeneous PMUs on ACPI systems
add routines that detect this and group the resulting PMUs and
interrupts.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 drivers/perf/arm_pmu_acpi.c | 135 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 132 insertions(+), 3 deletions(-)

diff --git a/drivers/perf/arm_pmu_acpi.c b/drivers/perf/arm_pmu_acpi.c
index 98c452d..a257fc0 100644
--- a/drivers/perf/arm_pmu_acpi.c
+++ b/drivers/perf/arm_pmu_acpi.c
@@ -1,14 +1,19 @@
 /*
- * PMU support
+ * ARM ACPI PMU support
  *
  * Copyright (C) 2015 Red Hat Inc.
+ * Copyright (C) 2016 ARM Ltd.
  * Author: Mark Salter <msalter@redhat.com>
+ *         Jeremy Linton <jeremy.linton@arm.com>
  *
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
  */
 
+#define pr_fmt(fmt) "ACPI-PMU: " fmt
+
+#include <asm/cpu.h>
 #include <linux/perf/arm_pmu.h>
 #include <linux/platform_device.h>
 #include <linux/acpi.h>
@@ -18,8 +23,14 @@
 #define PMU_PDEV_NAME "armv8-pmu"
 
 struct pmu_irq {
-	int gsi;
-	int trigger;
+	int  gsi;
+	int  trigger;
+	bool registered;
+};
+
+struct pmu_types {
+	int cpu_type;
+	int cpu_count;
 };
 
 static struct pmu_irq pmu_irqs[NR_CPUS] __initdata;
@@ -31,6 +42,124 @@ void __init arm_pmu_parse_acpi(int cpu, struct acpi_madt_generic_interrupt *gic)
 		pmu_irqs[cpu].trigger = ACPI_EDGE_SENSITIVE;
 	else
 		pmu_irqs[cpu].trigger = ACPI_LEVEL_SENSITIVE;
+	pr_devel("Assign CPU %d girq %d level %d\n", cpu, pmu_irqs[cpu].gsi,
+						   pmu_irqs[cpu].trigger);
+}
+
+/* Count number and type of CPU cores in the system. */
+void __init arm_pmu_acpi_determine_cpu_types(struct pmu_types *pmus)
+{
+	int i, j;
+
+	for_each_possible_cpu(i) {
+		struct cpuinfo_arm64 *cinfo = per_cpu_ptr(&cpu_data, i);
+		u32 partnum = MIDR_PARTNUM(cinfo->reg_midr);
+
+		pr_devel("Present CPU %d is a %X\n", i, partnum);
+		for (j = 0; j < num_possible_cpus(); j++) {
+			if (pmus[j].cpu_type == partnum) {
+				pmus[j].cpu_count++;
+				break;
+			}
+			if (pmus[j].cpu_count == 0) {
+				pmus[j].cpu_type = partnum;
+				pmus[j].cpu_count++;
+				break;
+			}
+		}
+	}
+}
+
+/*
+ * Registers the group of PMU interfaces which corrispond to the 'last_cpu_id'.
+ * This group utlizes 'count' resources in the 'res'.
+ */
+int __init arm_pmu_acpi_register_pmu(int count, struct resource *res,
+					    int last_cpu_id)
+{
+	int i;
+	int err = -ENOMEM;
+	bool free_gsi = false;
+	struct platform_device *pdev;
+
+	if (count) {
+		pdev = platform_device_alloc(PMU_PDEV_NAME, last_cpu_id);
+		if (pdev) {
+			err = platform_device_add_resources(pdev,
+							    res, count);
+			if (!err) {
+				err = platform_device_add(pdev);
+				if (err) {
+					pr_warn("Unable to register PMU device\n");
+					free_gsi = true;
+				}
+			} else {
+				pr_warn("Unable to add resources to device\n");
+				free_gsi = true;
+				platform_device_put(pdev);
+			}
+		} else {
+			pr_warn("Unable to allocate platform device\n");
+			free_gsi = true;
+		}
+	}
+
+	/* unmark (and possibly unregister) registered GSIs */
+	for_each_possible_cpu(i) {
+		if (pmu_irqs[i].registered) {
+			if (free_gsi)
+				acpi_unregister_gsi(pmu_irqs[i].gsi);
+			pmu_irqs[i].registered = false;
+		}
+	}
+
+	return err;
+}
+
+/*
+ * For the given cpu/pmu type, walk all known GSIs, register them, and add
+ * them to the resource structure. Return the number of GSI's contained
+ * in the res structure, and the id of the last CPU/PMU we added.
+ */
+int __init arm_pmu_acpi_gsi_res(struct pmu_types *pmus,
+				       struct resource *res, int *last_cpu_id)
+{
+	int i, count;
+	int irq;
+
+	pr_info("Setting up %d PMUs for CPU type %X\n", pmus->cpu_count,
+							pmus->cpu_type);
+	/* lets group all the PMU's from similar CPU's together */
+	count = 0;
+	for_each_possible_cpu(i) {
+		struct cpuinfo_arm64 *cinfo = per_cpu_ptr(&cpu_data, i);
+
+		if (pmus->cpu_type == MIDR_PARTNUM(cinfo->reg_midr)) {
+			pr_devel("Setting up CPU %d\n", i);
+			if (pmu_irqs[i].gsi == 0)
+				continue;
+
+			irq = acpi_register_gsi(NULL, pmu_irqs[i].gsi,
+						pmu_irqs[i].trigger,
+						ACPI_ACTIVE_HIGH);
+
+			res[count].start = res[count].end = irq;
+			res[count].flags = IORESOURCE_IRQ;
+
+			if (pmu_irqs[i].trigger == ACPI_EDGE_SENSITIVE)
+				res[count].flags |= IORESOURCE_IRQ_HIGHEDGE;
+			else
+				res[count].flags |= IORESOURCE_IRQ_HIGHLEVEL;
+
+			pmu_irqs[i].registered = true;
+			count++;
+			(*last_cpu_id) = cinfo->reg_midr;
+
+			if (irq_is_percpu(irq))
+				pr_debug("PPI detected\n");
+		}
+	}
+	return count;
 }
 
 static int __init pmu_acpi_init(void)
-- 
2.5.5


WARNING: multiple messages have this Message-ID (diff)
From: jeremy.linton@arm.com (Jeremy Linton)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 6/8] arm64: pmu: Add routines for detecting differing PMU types in the system
Date: Thu,  9 Jun 2016 17:23:31 -0500	[thread overview]
Message-ID: <1465511013-10742-7-git-send-email-jeremy.linton@arm.com> (raw)
In-Reply-To: <1465511013-10742-1-git-send-email-jeremy.linton@arm.com>

In preparation for enabling heterogeneous PMUs on ACPI systems
add routines that detect this and group the resulting PMUs and
interrupts.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 drivers/perf/arm_pmu_acpi.c | 135 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 132 insertions(+), 3 deletions(-)

diff --git a/drivers/perf/arm_pmu_acpi.c b/drivers/perf/arm_pmu_acpi.c
index 98c452d..a257fc0 100644
--- a/drivers/perf/arm_pmu_acpi.c
+++ b/drivers/perf/arm_pmu_acpi.c
@@ -1,14 +1,19 @@
 /*
- * PMU support
+ * ARM ACPI PMU support
  *
  * Copyright (C) 2015 Red Hat Inc.
+ * Copyright (C) 2016 ARM Ltd.
  * Author: Mark Salter <msalter@redhat.com>
+ *         Jeremy Linton <jeremy.linton@arm.com>
  *
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
  */
 
+#define pr_fmt(fmt) "ACPI-PMU: " fmt
+
+#include <asm/cpu.h>
 #include <linux/perf/arm_pmu.h>
 #include <linux/platform_device.h>
 #include <linux/acpi.h>
@@ -18,8 +23,14 @@
 #define PMU_PDEV_NAME "armv8-pmu"
 
 struct pmu_irq {
-	int gsi;
-	int trigger;
+	int  gsi;
+	int  trigger;
+	bool registered;
+};
+
+struct pmu_types {
+	int cpu_type;
+	int cpu_count;
 };
 
 static struct pmu_irq pmu_irqs[NR_CPUS] __initdata;
@@ -31,6 +42,124 @@ void __init arm_pmu_parse_acpi(int cpu, struct acpi_madt_generic_interrupt *gic)
 		pmu_irqs[cpu].trigger = ACPI_EDGE_SENSITIVE;
 	else
 		pmu_irqs[cpu].trigger = ACPI_LEVEL_SENSITIVE;
+	pr_devel("Assign CPU %d girq %d level %d\n", cpu, pmu_irqs[cpu].gsi,
+						   pmu_irqs[cpu].trigger);
+}
+
+/* Count number and type of CPU cores in the system. */
+void __init arm_pmu_acpi_determine_cpu_types(struct pmu_types *pmus)
+{
+	int i, j;
+
+	for_each_possible_cpu(i) {
+		struct cpuinfo_arm64 *cinfo = per_cpu_ptr(&cpu_data, i);
+		u32 partnum = MIDR_PARTNUM(cinfo->reg_midr);
+
+		pr_devel("Present CPU %d is a %X\n", i, partnum);
+		for (j = 0; j < num_possible_cpus(); j++) {
+			if (pmus[j].cpu_type == partnum) {
+				pmus[j].cpu_count++;
+				break;
+			}
+			if (pmus[j].cpu_count == 0) {
+				pmus[j].cpu_type = partnum;
+				pmus[j].cpu_count++;
+				break;
+			}
+		}
+	}
+}
+
+/*
+ * Registers the group of PMU interfaces which corrispond to the 'last_cpu_id'.
+ * This group utlizes 'count' resources in the 'res'.
+ */
+int __init arm_pmu_acpi_register_pmu(int count, struct resource *res,
+					    int last_cpu_id)
+{
+	int i;
+	int err = -ENOMEM;
+	bool free_gsi = false;
+	struct platform_device *pdev;
+
+	if (count) {
+		pdev = platform_device_alloc(PMU_PDEV_NAME, last_cpu_id);
+		if (pdev) {
+			err = platform_device_add_resources(pdev,
+							    res, count);
+			if (!err) {
+				err = platform_device_add(pdev);
+				if (err) {
+					pr_warn("Unable to register PMU device\n");
+					free_gsi = true;
+				}
+			} else {
+				pr_warn("Unable to add resources to device\n");
+				free_gsi = true;
+				platform_device_put(pdev);
+			}
+		} else {
+			pr_warn("Unable to allocate platform device\n");
+			free_gsi = true;
+		}
+	}
+
+	/* unmark (and possibly unregister) registered GSIs */
+	for_each_possible_cpu(i) {
+		if (pmu_irqs[i].registered) {
+			if (free_gsi)
+				acpi_unregister_gsi(pmu_irqs[i].gsi);
+			pmu_irqs[i].registered = false;
+		}
+	}
+
+	return err;
+}
+
+/*
+ * For the given cpu/pmu type, walk all known GSIs, register them, and add
+ * them to the resource structure. Return the number of GSI's contained
+ * in the res structure, and the id of the last CPU/PMU we added.
+ */
+int __init arm_pmu_acpi_gsi_res(struct pmu_types *pmus,
+				       struct resource *res, int *last_cpu_id)
+{
+	int i, count;
+	int irq;
+
+	pr_info("Setting up %d PMUs for CPU type %X\n", pmus->cpu_count,
+							pmus->cpu_type);
+	/* lets group all the PMU's from similar CPU's together */
+	count = 0;
+	for_each_possible_cpu(i) {
+		struct cpuinfo_arm64 *cinfo = per_cpu_ptr(&cpu_data, i);
+
+		if (pmus->cpu_type == MIDR_PARTNUM(cinfo->reg_midr)) {
+			pr_devel("Setting up CPU %d\n", i);
+			if (pmu_irqs[i].gsi == 0)
+				continue;
+
+			irq = acpi_register_gsi(NULL, pmu_irqs[i].gsi,
+						pmu_irqs[i].trigger,
+						ACPI_ACTIVE_HIGH);
+
+			res[count].start = res[count].end = irq;
+			res[count].flags = IORESOURCE_IRQ;
+
+			if (pmu_irqs[i].trigger == ACPI_EDGE_SENSITIVE)
+				res[count].flags |= IORESOURCE_IRQ_HIGHEDGE;
+			else
+				res[count].flags |= IORESOURCE_IRQ_HIGHLEVEL;
+
+			pmu_irqs[i].registered = true;
+			count++;
+			(*last_cpu_id) = cinfo->reg_midr;
+
+			if (irq_is_percpu(irq))
+				pr_debug("PPI detected\n");
+		}
+	}
+	return count;
 }
 
 static int __init pmu_acpi_init(void)
-- 
2.5.5

  parent reply	other threads:[~2016-06-09 22:23 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-06-09 22:23 [PATCH 0/8] arm64: pmu: Detect multiple PMU types in an ACPI system Jeremy Linton
2016-06-09 22:23 ` Jeremy Linton
2016-06-09 22:23 ` [PATCH 1/8] arm64: pmu: add fallback probe table Jeremy Linton
2016-06-09 22:23   ` Jeremy Linton
2016-06-15 10:59   ` Will Deacon
2016-06-15 10:59     ` Will Deacon
2016-06-09 22:23 ` [PATCH 2/8] arm64: pmu: Probe default hw/cache counters Jeremy Linton
2016-06-09 22:23   ` Jeremy Linton
2016-06-15 11:14   ` Will Deacon
2016-06-15 11:14     ` Will Deacon
2016-06-09 22:23 ` [PATCH 3/8] arm64: pmu: Add support for probing with ACPI Jeremy Linton
2016-06-09 22:23   ` Jeremy Linton
2016-06-15 11:33   ` Will Deacon
2016-06-15 11:33     ` Will Deacon
2016-06-15 15:07     ` Jeremy Linton
2016-06-15 15:07       ` Jeremy Linton
2016-06-09 22:23 ` [PATCH 4/8] arm: arm64: Add routine to determine cpuid of other cpus Jeremy Linton
2016-06-09 22:23   ` Jeremy Linton
2016-06-20 16:49   ` Punit Agrawal
2016-06-20 16:49     ` Punit Agrawal
2016-06-09 22:23 ` [PATCH 5/8] arm: arm64: pmu: Assign platform PMU CPU affinity Jeremy Linton
2016-06-09 22:23   ` Jeremy Linton
2016-06-15 13:09   ` Will Deacon
2016-06-15 13:09     ` Will Deacon
2016-06-20 16:40   ` Punit Agrawal
2016-06-20 16:40     ` Punit Agrawal
2016-06-20 16:49     ` Jeremy Linton
2016-06-20 16:49       ` Jeremy Linton
2016-06-20 17:01       ` Punit Agrawal
2016-06-20 17:01         ` Punit Agrawal
2016-06-09 22:23 ` Jeremy Linton [this message]
2016-06-09 22:23   ` [PATCH 6/8] arm64: pmu: Add routines for detecting differing PMU types in the system Jeremy Linton
2016-06-09 22:23 ` [PATCH 7/8] arm64: pmu: Enable multiple PMUs in an ACPI system Jeremy Linton
2016-06-09 22:23   ` Jeremy Linton
2016-06-15 13:22   ` Will Deacon
2016-06-15 13:22     ` Will Deacon
2016-06-15 15:21     ` Jeremy Linton
2016-06-15 15:21       ` Jeremy Linton
2016-06-15 15:30       ` Will Deacon
2016-06-15 15:30         ` Will Deacon
2016-06-20 16:37   ` Punit Agrawal
2016-06-20 16:37     ` Punit Agrawal
2016-06-20 21:44     ` Jeremy Linton
2016-06-20 21:44       ` Jeremy Linton
2016-06-21  8:34       ` Punit Agrawal
2016-06-21  8:34         ` Punit Agrawal
2016-06-09 22:23 ` [PATCH 8/8] MAINTAINERS: Tweak ARM PMU maintainers Jeremy Linton
2016-06-09 22:23   ` Jeremy Linton
2016-06-20 16:47 ` [PATCH 0/8] arm64: pmu: Detect multiple PMU types in an ACPI system Punit Agrawal
2016-06-20 16:47   ` Punit Agrawal

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1465511013-10742-7-git-send-email-jeremy.linton@arm.com \
    --to=jeremy.linton@arm.com \
    --cc=acme@kernel.org \
    --cc=alexander.shishkin@linux.intel.com \
    --cc=catalin.marinas@arm.com \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=lorenzo.pieralisi@arm.com \
    --cc=mark.rutland@arm.com \
    --cc=mingo@redhat.com \
    --cc=mlangsdorf@redhat.com \
    --cc=peterz@infradead.org \
    --cc=will.deacon@arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.