All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/8] Add support for HiSilicon Hip09 uncore PMU driver
@ 2021-02-03  7:51 Shaokun Zhang
  2021-02-03  7:51 ` [PATCH v2 1/8] drivers/perf: hisi: Refactor code for more uncore PMUs Shaokun Zhang
                   ` (7 more replies)
  0 siblings, 8 replies; 25+ messages in thread
From: Shaokun Zhang @ 2021-02-03  7:51 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, John Garry, Shaokun Zhang,
	Jonathan Cameron, Will Deacon

This patchset adds support for HiSilicon Hip09 SoC uncore PMUs driver
which is PMU v2 and it includes:
(a) Refactor interrupt registration and handler function for later
new uncore PMU driver in patch1;
(b) Update the PMU version suffiex for existing driver in patch2
(b) Some new functions are added on L3C/HHA PMU in patch3/4;
(c) New DDRC PMU model is supported using programable counter and
supports more events in patch5;
(d) Add new modules SLLC and PA PMU drivers in patch6/7;
(e) Update the perf document for the new functions and modules in
patch8;

ChangeLog
v1-->v2:
    1. Address John's comments and fix some typos
    2. Add John's Reviewed-by tags

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Cc: Qi Liu <liuqi115@huawei.com>


Shaokun Zhang (8):
  drivers/perf: hisi: Refactor code for more uncore PMUs
  drivers/perf: hisi: Add PMU version for uncore PMU drivers.
  drivers/perf: hisi: Add new functions for L3C PMU
  drivers/perf: hisi: Add new functions for HHA PMU
  drivers/perf: hisi: Update DDRC PMU for programable counter
  drivers/perf: hisi: Add support for HiSilicon SLLC PMU driver
  drivers/perf: hisi: Add support for HiSilicon PA PMU driver
  docs: perf: Add new description on HiSilicon uncore PMU v2

 Documentation/admin-guide/perf/hisi-pmu.rst   |  54 +++
 drivers/perf/hisilicon/Makefile               |   3 +-
 drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 348 +++++++++++------
 drivers/perf/hisilicon/hisi_uncore_hha_pmu.c  | 301 ++++++++++-----
 drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c  | 353 ++++++++++++-----
 drivers/perf/hisilicon/hisi_uncore_pa_pmu.c   | 500 ++++++++++++++++++++++++
 drivers/perf/hisilicon/hisi_uncore_pmu.c      |  76 +++-
 drivers/perf/hisilicon/hisi_uncore_pmu.h      |  19 +-
 drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c | 531 ++++++++++++++++++++++++++
 include/linux/cpuhotplug.h                    |   2 +
 10 files changed, 1882 insertions(+), 305 deletions(-)
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c

-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH v2 1/8] drivers/perf: hisi: Refactor code for more uncore PMUs
  2021-02-03  7:51 [PATCH v2 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
@ 2021-02-03  7:51 ` Shaokun Zhang
  2021-02-03 12:53   ` Mark Rutland
  2021-02-03  7:51 ` [PATCH v2 2/8] drivers/perf: hisi: Add PMU version for uncore PMU drivers Shaokun Zhang
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Shaokun Zhang @ 2021-02-03  7:51 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, John Garry, Shaokun Zhang,
	Jonathan Cameron, Will Deacon

On HiSilicon uncore PMU drivers, interrupt handling function and interrupt
registration function are very similar in differents PMU modules. Let's
refactor the frame, use a callback function for the HW accessors.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: John Garry <john.garry@huawei.com>
Co-developed-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 79 ++++-----------------------
 drivers/perf/hisilicon/hisi_uncore_hha_pmu.c  | 77 +++-----------------------
 drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c  | 77 +++-----------------------
 drivers/perf/hisilicon/hisi_uncore_pmu.c      | 68 ++++++++++++++++++++++-
 drivers/perf/hisilicon/hisi_uncore_pmu.h      |  6 +-
 5 files changed, 100 insertions(+), 207 deletions(-)

diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
index ac1a8c120a00..7f7827cd54d7 100644
--- a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
@@ -14,7 +14,6 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/list.h>
-#include <linux/platform_device.h>
 #include <linux/smp.h>
 
 #include "hisi_uncore_pmu.h"
@@ -65,29 +64,15 @@ static u32 hisi_ddrc_pmu_get_counter_offset(int cntr_idx)
 static u64 hisi_ddrc_pmu_read_counter(struct hisi_pmu *ddrc_pmu,
 				      struct hw_perf_event *hwc)
 {
-	/* Use event code as counter index */
-	u32 idx = GET_DDRC_EVENTID(hwc);
-
-	if (!hisi_uncore_pmu_counter_valid(ddrc_pmu, idx)) {
-		dev_err(ddrc_pmu->dev, "Unsupported event index:%d!\n", idx);
-		return 0;
-	}
-
-	return readl(ddrc_pmu->base + hisi_ddrc_pmu_get_counter_offset(idx));
+	return readl(ddrc_pmu->base +
+		     hisi_ddrc_pmu_get_counter_offset(hwc->idx));
 }
 
 static void hisi_ddrc_pmu_write_counter(struct hisi_pmu *ddrc_pmu,
 					struct hw_perf_event *hwc, u64 val)
 {
-	u32 idx = GET_DDRC_EVENTID(hwc);
-
-	if (!hisi_uncore_pmu_counter_valid(ddrc_pmu, idx)) {
-		dev_err(ddrc_pmu->dev, "Unsupported event index:%d!\n", idx);
-		return;
-	}
-
 	writel((u32)val,
-	       ddrc_pmu->base + hisi_ddrc_pmu_get_counter_offset(idx));
+	       ddrc_pmu->base + hisi_ddrc_pmu_get_counter_offset(hwc->idx));
 }
 
 /*
@@ -179,60 +164,14 @@ static void hisi_ddrc_pmu_disable_counter_int(struct hisi_pmu *ddrc_pmu,
 	writel(val, ddrc_pmu->base + DDRC_INT_MASK);
 }
 
-static irqreturn_t hisi_ddrc_pmu_isr(int irq, void *dev_id)
+static u32 hisi_ddrc_pmu_get_int_status(struct hisi_pmu *ddrc_pmu)
 {
-	struct hisi_pmu *ddrc_pmu = dev_id;
-	struct perf_event *event;
-	unsigned long overflown;
-	int idx;
-
-	/* Read the DDRC_INT_STATUS register */
-	overflown = readl(ddrc_pmu->base + DDRC_INT_STATUS);
-	if (!overflown)
-		return IRQ_NONE;
-
-	/*
-	 * Find the counter index which overflowed if the bit was set
-	 * and handle it
-	 */
-	for_each_set_bit(idx, &overflown, DDRC_NR_COUNTERS) {
-		/* Write 1 to clear the IRQ status flag */
-		writel((1 << idx), ddrc_pmu->base + DDRC_INT_CLEAR);
-
-		/* Get the corresponding event struct */
-		event = ddrc_pmu->pmu_events.hw_events[idx];
-		if (!event)
-			continue;
-
-		hisi_uncore_pmu_event_update(event);
-		hisi_uncore_pmu_set_event_period(event);
-	}
-
-	return IRQ_HANDLED;
+	return readl(ddrc_pmu->base + DDRC_INT_STATUS);
 }
 
-static int hisi_ddrc_pmu_init_irq(struct hisi_pmu *ddrc_pmu,
-				  struct platform_device *pdev)
+static void hisi_ddrc_pmu_clear_int_status(struct hisi_pmu *ddrc_pmu, int idx)
 {
-	int irq, ret;
-
-	/* Read and init IRQ */
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
-
-	ret = devm_request_irq(&pdev->dev, irq, hisi_ddrc_pmu_isr,
-			       IRQF_NOBALANCING | IRQF_NO_THREAD,
-			       dev_name(&pdev->dev), ddrc_pmu);
-	if (ret < 0) {
-		dev_err(&pdev->dev,
-			"Fail to request IRQ:%d ret:%d\n", irq, ret);
-		return ret;
-	}
-
-	ddrc_pmu->irq = irq;
-
-	return 0;
+	writel(1 << idx, ddrc_pmu->base + DDRC_INT_CLEAR);
 }
 
 static const struct acpi_device_id hisi_ddrc_pmu_acpi_match[] = {
@@ -342,6 +281,8 @@ static const struct hisi_uncore_ops hisi_uncore_ddrc_ops = {
 	.disable_counter_int	= hisi_ddrc_pmu_disable_counter_int,
 	.write_counter		= hisi_ddrc_pmu_write_counter,
 	.read_counter		= hisi_ddrc_pmu_read_counter,
+	.get_int_status		= hisi_ddrc_pmu_get_int_status,
+	.clear_int_status	= hisi_ddrc_pmu_clear_int_status,
 };
 
 static int hisi_ddrc_pmu_dev_probe(struct platform_device *pdev,
@@ -353,7 +294,7 @@ static int hisi_ddrc_pmu_dev_probe(struct platform_device *pdev,
 	if (ret)
 		return ret;
 
-	ret = hisi_ddrc_pmu_init_irq(ddrc_pmu, pdev);
+	ret = hisi_uncore_pmu_init_irq(ddrc_pmu, pdev);
 	if (ret)
 		return ret;
 
diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
index 3402f1a395a8..667eebddcc82 100644
--- a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
@@ -14,7 +14,6 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/list.h>
-#include <linux/platform_device.h>
 #include <linux/smp.h>
 
 #include "hisi_uncore_pmu.h"
@@ -51,29 +50,15 @@ static u32 hisi_hha_pmu_get_counter_offset(int cntr_idx)
 static u64 hisi_hha_pmu_read_counter(struct hisi_pmu *hha_pmu,
 				     struct hw_perf_event *hwc)
 {
-	u32 idx = hwc->idx;
-
-	if (!hisi_uncore_pmu_counter_valid(hha_pmu, idx)) {
-		dev_err(hha_pmu->dev, "Unsupported event index:%d!\n", idx);
-		return 0;
-	}
-
 	/* Read 64 bits and like L3C, top 16 bits are RAZ */
-	return readq(hha_pmu->base + hisi_hha_pmu_get_counter_offset(idx));
+	return readq(hha_pmu->base + hisi_hha_pmu_get_counter_offset(hwc->idx));
 }
 
 static void hisi_hha_pmu_write_counter(struct hisi_pmu *hha_pmu,
 				       struct hw_perf_event *hwc, u64 val)
 {
-	u32 idx = hwc->idx;
-
-	if (!hisi_uncore_pmu_counter_valid(hha_pmu, idx)) {
-		dev_err(hha_pmu->dev, "Unsupported event index:%d!\n", idx);
-		return;
-	}
-
 	/* Write 64 bits and like L3C, top 16 bits are WI */
-	writeq(val, hha_pmu->base + hisi_hha_pmu_get_counter_offset(idx));
+	writeq(val, hha_pmu->base + hisi_hha_pmu_get_counter_offset(hwc->idx));
 }
 
 static void hisi_hha_pmu_write_evtype(struct hisi_pmu *hha_pmu, int idx,
@@ -169,60 +154,14 @@ static void hisi_hha_pmu_disable_counter_int(struct hisi_pmu *hha_pmu,
 	writel(val, hha_pmu->base + HHA_INT_MASK);
 }
 
-static irqreturn_t hisi_hha_pmu_isr(int irq, void *dev_id)
+static u32 hisi_hha_pmu_get_int_status(struct hisi_pmu *hha_pmu)
 {
-	struct hisi_pmu *hha_pmu = dev_id;
-	struct perf_event *event;
-	unsigned long overflown;
-	int idx;
-
-	/* Read HHA_INT_STATUS register */
-	overflown = readl(hha_pmu->base + HHA_INT_STATUS);
-	if (!overflown)
-		return IRQ_NONE;
-
-	/*
-	 * Find the counter index which overflowed if the bit was set
-	 * and handle it
-	 */
-	for_each_set_bit(idx, &overflown, HHA_NR_COUNTERS) {
-		/* Write 1 to clear the IRQ status flag */
-		writel((1 << idx), hha_pmu->base + HHA_INT_CLEAR);
-
-		/* Get the corresponding event struct */
-		event = hha_pmu->pmu_events.hw_events[idx];
-		if (!event)
-			continue;
-
-		hisi_uncore_pmu_event_update(event);
-		hisi_uncore_pmu_set_event_period(event);
-	}
-
-	return IRQ_HANDLED;
+	return readl(hha_pmu->base + HHA_INT_STATUS);
 }
 
-static int hisi_hha_pmu_init_irq(struct hisi_pmu *hha_pmu,
-				 struct platform_device *pdev)
+static void hisi_hha_pmu_clear_int_status(struct hisi_pmu *hha_pmu, int idx)
 {
-	int irq, ret;
-
-	/* Read and init IRQ */
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
-
-	ret = devm_request_irq(&pdev->dev, irq, hisi_hha_pmu_isr,
-			      IRQF_NOBALANCING | IRQF_NO_THREAD,
-			      dev_name(&pdev->dev), hha_pmu);
-	if (ret < 0) {
-		dev_err(&pdev->dev,
-			"Fail to request IRQ:%d ret:%d\n", irq, ret);
-		return ret;
-	}
-
-	hha_pmu->irq = irq;
-
-	return 0;
+	writel(1 << idx, hha_pmu->base + HHA_INT_CLEAR);
 }
 
 static const struct acpi_device_id hisi_hha_pmu_acpi_match[] = {
@@ -354,6 +293,8 @@ static const struct hisi_uncore_ops hisi_uncore_hha_ops = {
 	.disable_counter_int	= hisi_hha_pmu_disable_counter_int,
 	.write_counter		= hisi_hha_pmu_write_counter,
 	.read_counter		= hisi_hha_pmu_read_counter,
+	.get_int_status		= hisi_hha_pmu_get_int_status,
+	.clear_int_status	= hisi_hha_pmu_clear_int_status,
 };
 
 static int hisi_hha_pmu_dev_probe(struct platform_device *pdev,
@@ -365,7 +306,7 @@ static int hisi_hha_pmu_dev_probe(struct platform_device *pdev,
 	if (ret)
 		return ret;
 
-	ret = hisi_hha_pmu_init_irq(hha_pmu, pdev);
+	ret = hisi_uncore_pmu_init_irq(hha_pmu, pdev);
 	if (ret)
 		return ret;
 
diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
index 7d792435c2aa..831622e0c445 100644
--- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
@@ -14,7 +14,6 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/list.h>
-#include <linux/platform_device.h>
 #include <linux/smp.h>
 
 #include "hisi_uncore_pmu.h"
@@ -50,29 +49,15 @@ static u32 hisi_l3c_pmu_get_counter_offset(int cntr_idx)
 static u64 hisi_l3c_pmu_read_counter(struct hisi_pmu *l3c_pmu,
 				     struct hw_perf_event *hwc)
 {
-	u32 idx = hwc->idx;
-
-	if (!hisi_uncore_pmu_counter_valid(l3c_pmu, idx)) {
-		dev_err(l3c_pmu->dev, "Unsupported event index:%d!\n", idx);
-		return 0;
-	}
-
 	/* Read 64-bits and the upper 16 bits are RAZ */
-	return readq(l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(idx));
+	return readq(l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(hwc->idx));
 }
 
 static void hisi_l3c_pmu_write_counter(struct hisi_pmu *l3c_pmu,
 				       struct hw_perf_event *hwc, u64 val)
 {
-	u32 idx = hwc->idx;
-
-	if (!hisi_uncore_pmu_counter_valid(l3c_pmu, idx)) {
-		dev_err(l3c_pmu->dev, "Unsupported event index:%d!\n", idx);
-		return;
-	}
-
 	/* Write 64-bits and the upper 16 bits are WI */
-	writeq(val, l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(idx));
+	writeq(val, l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(hwc->idx));
 }
 
 static void hisi_l3c_pmu_write_evtype(struct hisi_pmu *l3c_pmu, int idx,
@@ -168,60 +153,14 @@ static void hisi_l3c_pmu_disable_counter_int(struct hisi_pmu *l3c_pmu,
 	writel(val, l3c_pmu->base + L3C_INT_MASK);
 }
 
-static irqreturn_t hisi_l3c_pmu_isr(int irq, void *dev_id)
+static u32 hisi_l3c_pmu_get_int_status(struct hisi_pmu *l3c_pmu)
 {
-	struct hisi_pmu *l3c_pmu = dev_id;
-	struct perf_event *event;
-	unsigned long overflown;
-	int idx;
-
-	/* Read L3C_INT_STATUS register */
-	overflown = readl(l3c_pmu->base + L3C_INT_STATUS);
-	if (!overflown)
-		return IRQ_NONE;
-
-	/*
-	 * Find the counter index which overflowed if the bit was set
-	 * and handle it.
-	 */
-	for_each_set_bit(idx, &overflown, L3C_NR_COUNTERS) {
-		/* Write 1 to clear the IRQ status flag */
-		writel((1 << idx), l3c_pmu->base + L3C_INT_CLEAR);
-
-		/* Get the corresponding event struct */
-		event = l3c_pmu->pmu_events.hw_events[idx];
-		if (!event)
-			continue;
-
-		hisi_uncore_pmu_event_update(event);
-		hisi_uncore_pmu_set_event_period(event);
-	}
-
-	return IRQ_HANDLED;
+	return readl(l3c_pmu->base + L3C_INT_STATUS);
 }
 
-static int hisi_l3c_pmu_init_irq(struct hisi_pmu *l3c_pmu,
-				 struct platform_device *pdev)
+static void hisi_l3c_pmu_clear_int_status(struct hisi_pmu *l3c_pmu, int idx)
 {
-	int irq, ret;
-
-	/* Read and init IRQ */
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
-
-	ret = devm_request_irq(&pdev->dev, irq, hisi_l3c_pmu_isr,
-			       IRQF_NOBALANCING | IRQF_NO_THREAD,
-			       dev_name(&pdev->dev), l3c_pmu);
-	if (ret < 0) {
-		dev_err(&pdev->dev,
-			"Fail to request IRQ:%d ret:%d\n", irq, ret);
-		return ret;
-	}
-
-	l3c_pmu->irq = irq;
-
-	return 0;
+	writel(1 << idx, l3c_pmu->base + L3C_INT_CLEAR);
 }
 
 static const struct acpi_device_id hisi_l3c_pmu_acpi_match[] = {
@@ -344,6 +283,8 @@ static const struct hisi_uncore_ops hisi_uncore_l3c_ops = {
 	.disable_counter_int	= hisi_l3c_pmu_disable_counter_int,
 	.write_counter		= hisi_l3c_pmu_write_counter,
 	.read_counter		= hisi_l3c_pmu_read_counter,
+	.get_int_status		= hisi_l3c_pmu_get_int_status,
+	.clear_int_status	= hisi_l3c_pmu_clear_int_status,
 };
 
 static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev,
@@ -355,7 +296,7 @@ static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev,
 	if (ret)
 		return ret;
 
-	ret = hisi_l3c_pmu_init_irq(l3c_pmu, pdev);
+	ret = hisi_uncore_pmu_init_irq(l3c_pmu, pdev);
 	if (ret)
 		return ret;
 
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c
index 9dbdc3fc3bb4..82a4ff2bc3ae 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c
@@ -132,13 +132,67 @@ EXPORT_SYMBOL_GPL(hisi_uncore_pmu_identifier_attr_show);
 static void hisi_uncore_pmu_clear_event_idx(struct hisi_pmu *hisi_pmu, int idx)
 {
 	if (!hisi_uncore_pmu_counter_valid(hisi_pmu, idx)) {
-		dev_err(hisi_pmu->dev, "Unsupported event index:%d!\n", idx);
+		dev_err(hisi_pmu->dev, "Unsupported event index: %d\n", idx);
 		return;
 	}
 
 	clear_bit(idx, hisi_pmu->pmu_events.used_mask);
 }
 
+static irqreturn_t hisi_uncore_pmu_isr(int irq, void *data)
+{
+	struct hisi_pmu *hisi_pmu = data;
+	struct perf_event *event;
+	unsigned long overflown;
+	int idx;
+
+	overflown = hisi_pmu->ops->get_int_status(hisi_pmu);
+	if (!overflown)
+		return IRQ_NONE;
+
+	/*
+	 * Find the counter index which overflowed if the bit was set
+	 * and handle it.
+	 */
+	for_each_set_bit(idx, &overflown, hisi_pmu->num_counters) {
+		/* Write 1 to clear the IRQ status flag */
+		hisi_pmu->ops->clear_int_status(hisi_pmu, idx);
+		/* Get the corresponding event struct */
+		event = hisi_pmu->pmu_events.hw_events[idx];
+		if (!event)
+			continue;
+
+		hisi_uncore_pmu_event_update(event);
+		hisi_uncore_pmu_set_event_period(event);
+	}
+
+	return IRQ_HANDLED;
+}
+
+int hisi_uncore_pmu_init_irq(struct hisi_pmu *hisi_pmu,
+			     struct platform_device *pdev)
+{
+	int irq, ret;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	ret = devm_request_irq(&pdev->dev, irq, hisi_uncore_pmu_isr,
+			       IRQF_NOBALANCING | IRQF_NO_THREAD,
+			       dev_name(&pdev->dev), hisi_pmu);
+	if (ret < 0) {
+		dev_err(&pdev->dev,
+			"Fail to request IRQ:%d ret:%d\n", irq, ret);
+		return ret;
+	}
+
+	hisi_pmu->irq = irq;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(hisi_uncore_pmu_init_irq);
+
 int hisi_uncore_pmu_event_init(struct perf_event *event)
 {
 	struct hw_perf_event *hwc = &event->hw;
@@ -243,6 +297,12 @@ void hisi_uncore_pmu_event_update(struct perf_event *event)
 	struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu);
 	struct hw_perf_event *hwc = &event->hw;
 	u64 delta, prev_raw_count, new_raw_count;
+	u32 idx = hwc->idx;
+
+	if (!hisi_uncore_pmu_counter_valid(hisi_pmu, idx)) {
+		dev_err(hisi_pmu->dev, "Unsupported counter index: %d\n", idx);
+		return;
+	}
 
 	do {
 		/* Read the count from the counter register */
@@ -263,10 +323,16 @@ void hisi_uncore_pmu_start(struct perf_event *event, int flags)
 {
 	struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu);
 	struct hw_perf_event *hwc = &event->hw;
+	u32 idx = hwc->idx;
 
 	if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
 		return;
 
+	if (!hisi_uncore_pmu_counter_valid(hisi_pmu, idx)) {
+		dev_err(hisi_pmu->dev, "Unsupported counter index: %d.\n", idx);
+		return;
+	}
+
 	WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
 	hwc->state = 0;
 	hisi_uncore_pmu_set_event_period(event);
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h
index 25b7cbe1f818..aaaf637cc9ea 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.h
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h
@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/perf_event.h>
+#include <linux/platform_device.h>
 #include <linux/types.h>
 
 #undef pr_fmt
@@ -47,6 +48,8 @@ struct hisi_uncore_ops {
 	void (*disable_counter_int)(struct hisi_pmu *, struct hw_perf_event *);
 	void (*start_counters)(struct hisi_pmu *);
 	void (*stop_counters)(struct hisi_pmu *);
+	u32 (*get_int_status)(struct hisi_pmu *hisi_pmu);
+	void (*clear_int_status)(struct hisi_pmu *hisi_pmu, int idx);
 };
 
 struct hisi_pmu_hwevents {
@@ -102,6 +105,7 @@ int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node);
 ssize_t hisi_uncore_pmu_identifier_attr_show(struct device *dev,
 					     struct device_attribute *attr,
 					     char *page);
-
+int hisi_uncore_pmu_init_irq(struct hisi_pmu *hisi_pmu,
+			     struct platform_device *pdev);
 
 #endif /* __HISI_UNCORE_PMU_H__ */
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 2/8] drivers/perf: hisi: Add PMU version for uncore PMU drivers.
  2021-02-03  7:51 [PATCH v2 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
  2021-02-03  7:51 ` [PATCH v2 1/8] drivers/perf: hisi: Refactor code for more uncore PMUs Shaokun Zhang
@ 2021-02-03  7:51 ` Shaokun Zhang
  2021-02-03 12:58   ` Mark Rutland
  2021-02-03  7:51 ` [PATCH v2 3/8] drivers/perf: hisi: Add new functions for L3C PMU Shaokun Zhang
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Shaokun Zhang @ 2021-02-03  7:51 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, John Garry, Shaokun Zhang,
	Jonathan Cameron, Will Deacon

For HiSilicon uncore PMU, more versions are supported and some variables
shall be added suffix to distinguish the version which are prepared for
the new drivers.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: John Garry <john.garry@huawei.com>
Co-developed-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 97 ++++++++++++++-------------
 drivers/perf/hisilicon/hisi_uncore_hha_pmu.c  | 27 ++++----
 drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c  | 24 +++----
 3 files changed, 75 insertions(+), 73 deletions(-)

diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
index 7f7827cd54d7..a767babb57b2 100644
--- a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
@@ -36,8 +36,8 @@
 
 /* DDRC has 8-counters */
 #define DDRC_NR_COUNTERS	0x8
-#define DDRC_PERF_CTRL_EN	0x2
-
+#define DDRC_V1_PERF_CTRL_EN	0x2
+#define DDRC_V1_NR_EVENTS	0x07
 /*
  * For DDRC PMU, there are eight-events and every event has been mapped
  * to fixed-purpose counters which register offset is not consistent.
@@ -53,26 +53,26 @@ static const u32 ddrc_reg_off[] = {
 
 /*
  * Select the counter register offset using the counter index.
- * In DDRC there are no programmable counter, the count
- * is readed form the statistics counter register itself.
+ * In PMU v1, there are no programmable counter, the count
+ * is read form the statistics counter register itself.
  */
-static u32 hisi_ddrc_pmu_get_counter_offset(int cntr_idx)
+static u32 hisi_ddrc_pmu_v1_get_counter_offset(int cntr_idx)
 {
 	return ddrc_reg_off[cntr_idx];
 }
 
-static u64 hisi_ddrc_pmu_read_counter(struct hisi_pmu *ddrc_pmu,
+static u64 hisi_ddrc_pmu_v1_read_counter(struct hisi_pmu *ddrc_pmu,
 				      struct hw_perf_event *hwc)
 {
 	return readl(ddrc_pmu->base +
-		     hisi_ddrc_pmu_get_counter_offset(hwc->idx));
+		     hisi_ddrc_pmu_v1_get_counter_offset(hwc->idx));
 }
 
-static void hisi_ddrc_pmu_write_counter(struct hisi_pmu *ddrc_pmu,
+static void hisi_ddrc_pmu_v1_write_counter(struct hisi_pmu *ddrc_pmu,
 					struct hw_perf_event *hwc, u64 val)
 {
 	writel((u32)val,
-	       ddrc_pmu->base + hisi_ddrc_pmu_get_counter_offset(hwc->idx));
+	       ddrc_pmu->base + hisi_ddrc_pmu_v1_get_counter_offset(hwc->idx));
 }
 
 /*
@@ -84,28 +84,28 @@ static void hisi_ddrc_pmu_write_evtype(struct hisi_pmu *hha_pmu, int idx,
 {
 }
 
-static void hisi_ddrc_pmu_start_counters(struct hisi_pmu *ddrc_pmu)
+static void hisi_ddrc_pmu_v1_start_counters(struct hisi_pmu *ddrc_pmu)
 {
 	u32 val;
 
 	/* Set perf_enable in DDRC_PERF_CTRL to start event counting */
 	val = readl(ddrc_pmu->base + DDRC_PERF_CTRL);
-	val |= DDRC_PERF_CTRL_EN;
+	val |= DDRC_V1_PERF_CTRL_EN;
 	writel(val, ddrc_pmu->base + DDRC_PERF_CTRL);
 }
 
-static void hisi_ddrc_pmu_stop_counters(struct hisi_pmu *ddrc_pmu)
+static void hisi_ddrc_pmu_v1_stop_counters(struct hisi_pmu *ddrc_pmu)
 {
 	u32 val;
 
 	/* Clear perf_enable in DDRC_PERF_CTRL to stop event counting */
 	val = readl(ddrc_pmu->base + DDRC_PERF_CTRL);
-	val &= ~DDRC_PERF_CTRL_EN;
+	val &= ~DDRC_V1_PERF_CTRL_EN;
 	writel(val, ddrc_pmu->base + DDRC_PERF_CTRL);
 }
 
-static void hisi_ddrc_pmu_enable_counter(struct hisi_pmu *ddrc_pmu,
-					 struct hw_perf_event *hwc)
+static void hisi_ddrc_pmu_v1_enable_counter(struct hisi_pmu *ddrc_pmu,
+					    struct hw_perf_event *hwc)
 {
 	u32 val;
 
@@ -115,8 +115,8 @@ static void hisi_ddrc_pmu_enable_counter(struct hisi_pmu *ddrc_pmu,
 	writel(val, ddrc_pmu->base + DDRC_EVENT_CTRL);
 }
 
-static void hisi_ddrc_pmu_disable_counter(struct hisi_pmu *ddrc_pmu,
-					  struct hw_perf_event *hwc)
+static void hisi_ddrc_pmu_v1_disable_counter(struct hisi_pmu *ddrc_pmu,
+					     struct hw_perf_event *hwc)
 {
 	u32 val;
 
@@ -126,7 +126,7 @@ static void hisi_ddrc_pmu_disable_counter(struct hisi_pmu *ddrc_pmu,
 	writel(val, ddrc_pmu->base + DDRC_EVENT_CTRL);
 }
 
-static int hisi_ddrc_pmu_get_event_idx(struct perf_event *event)
+static int hisi_ddrc_pmu_v1_get_event_idx(struct perf_event *event)
 {
 	struct hisi_pmu *ddrc_pmu = to_hisi_pmu(event->pmu);
 	unsigned long *used_mask = ddrc_pmu->pmu_events.used_mask;
@@ -142,8 +142,8 @@ static int hisi_ddrc_pmu_get_event_idx(struct perf_event *event)
 	return idx;
 }
 
-static void hisi_ddrc_pmu_enable_counter_int(struct hisi_pmu *ddrc_pmu,
-					     struct hw_perf_event *hwc)
+static void hisi_ddrc_pmu_v1_enable_counter_int(struct hisi_pmu *ddrc_pmu,
+						struct hw_perf_event *hwc)
 {
 	u32 val;
 
@@ -153,8 +153,8 @@ static void hisi_ddrc_pmu_enable_counter_int(struct hisi_pmu *ddrc_pmu,
 	writel(val, ddrc_pmu->base + DDRC_INT_MASK);
 }
 
-static void hisi_ddrc_pmu_disable_counter_int(struct hisi_pmu *ddrc_pmu,
-					      struct hw_perf_event *hwc)
+static void hisi_ddrc_pmu_v1_disable_counter_int(struct hisi_pmu *ddrc_pmu,
+						 struct hw_perf_event *hwc)
 {
 	u32 val;
 
@@ -164,12 +164,13 @@ static void hisi_ddrc_pmu_disable_counter_int(struct hisi_pmu *ddrc_pmu,
 	writel(val, ddrc_pmu->base + DDRC_INT_MASK);
 }
 
-static u32 hisi_ddrc_pmu_get_int_status(struct hisi_pmu *ddrc_pmu)
+static u32 hisi_ddrc_pmu_v1_get_int_status(struct hisi_pmu *ddrc_pmu)
 {
 	return readl(ddrc_pmu->base + DDRC_INT_STATUS);
 }
 
-static void hisi_ddrc_pmu_clear_int_status(struct hisi_pmu *ddrc_pmu, int idx)
+static void hisi_ddrc_pmu_v1_clear_int_status(struct hisi_pmu *ddrc_pmu,
+					      int idx)
 {
 	writel(1 << idx, ddrc_pmu->base + DDRC_INT_CLEAR);
 }
@@ -212,17 +213,17 @@ static int hisi_ddrc_pmu_init_data(struct platform_device *pdev,
 	return 0;
 }
 
-static struct attribute *hisi_ddrc_pmu_format_attr[] = {
+static struct attribute *hisi_ddrc_pmu_v1_format_attr[] = {
 	HISI_PMU_FORMAT_ATTR(event, "config:0-4"),
 	NULL,
 };
 
-static const struct attribute_group hisi_ddrc_pmu_format_group = {
+static const struct attribute_group hisi_ddrc_pmu_v1_format_group = {
 	.name = "format",
-	.attrs = hisi_ddrc_pmu_format_attr,
+	.attrs = hisi_ddrc_pmu_v1_format_attr,
 };
 
-static struct attribute *hisi_ddrc_pmu_events_attr[] = {
+static struct attribute *hisi_ddrc_pmu_v1_events_attr[] = {
 	HISI_PMU_EVENT_ATTR(flux_wr,		0x00),
 	HISI_PMU_EVENT_ATTR(flux_rd,		0x01),
 	HISI_PMU_EVENT_ATTR(flux_wcmd,		0x02),
@@ -234,9 +235,9 @@ static struct attribute *hisi_ddrc_pmu_events_attr[] = {
 	NULL,
 };
 
-static const struct attribute_group hisi_ddrc_pmu_events_group = {
+static const struct attribute_group hisi_ddrc_pmu_v1_events_group = {
 	.name = "events",
-	.attrs = hisi_ddrc_pmu_events_attr,
+	.attrs = hisi_ddrc_pmu_v1_events_attr,
 };
 
 static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
@@ -262,27 +263,27 @@ static const struct attribute_group hisi_ddrc_pmu_identifier_group = {
 	.attrs = hisi_ddrc_pmu_identifier_attrs,
 };
 
-static const struct attribute_group *hisi_ddrc_pmu_attr_groups[] = {
-	&hisi_ddrc_pmu_format_group,
-	&hisi_ddrc_pmu_events_group,
+static const struct attribute_group *hisi_ddrc_pmu_v1_attr_groups[] = {
+	&hisi_ddrc_pmu_v1_format_group,
+	&hisi_ddrc_pmu_v1_events_group,
 	&hisi_ddrc_pmu_cpumask_attr_group,
 	&hisi_ddrc_pmu_identifier_group,
 	NULL,
 };
 
-static const struct hisi_uncore_ops hisi_uncore_ddrc_ops = {
+static const struct hisi_uncore_ops hisi_uncore_ddrc_v1_ops = {
 	.write_evtype           = hisi_ddrc_pmu_write_evtype,
-	.get_event_idx		= hisi_ddrc_pmu_get_event_idx,
-	.start_counters		= hisi_ddrc_pmu_start_counters,
-	.stop_counters		= hisi_ddrc_pmu_stop_counters,
-	.enable_counter		= hisi_ddrc_pmu_enable_counter,
-	.disable_counter	= hisi_ddrc_pmu_disable_counter,
-	.enable_counter_int	= hisi_ddrc_pmu_enable_counter_int,
-	.disable_counter_int	= hisi_ddrc_pmu_disable_counter_int,
-	.write_counter		= hisi_ddrc_pmu_write_counter,
-	.read_counter		= hisi_ddrc_pmu_read_counter,
-	.get_int_status		= hisi_ddrc_pmu_get_int_status,
-	.clear_int_status	= hisi_ddrc_pmu_clear_int_status,
+	.get_event_idx		= hisi_ddrc_pmu_v1_get_event_idx,
+	.start_counters		= hisi_ddrc_pmu_v1_start_counters,
+	.stop_counters		= hisi_ddrc_pmu_v1_stop_counters,
+	.enable_counter		= hisi_ddrc_pmu_v1_enable_counter,
+	.disable_counter	= hisi_ddrc_pmu_v1_disable_counter,
+	.enable_counter_int	= hisi_ddrc_pmu_v1_enable_counter_int,
+	.disable_counter_int	= hisi_ddrc_pmu_v1_disable_counter_int,
+	.write_counter		= hisi_ddrc_pmu_v1_write_counter,
+	.read_counter		= hisi_ddrc_pmu_v1_read_counter,
+	.get_int_status		= hisi_ddrc_pmu_v1_get_int_status,
+	.clear_int_status	= hisi_ddrc_pmu_v1_clear_int_status,
 };
 
 static int hisi_ddrc_pmu_dev_probe(struct platform_device *pdev,
@@ -300,10 +301,10 @@ static int hisi_ddrc_pmu_dev_probe(struct platform_device *pdev,
 
 	ddrc_pmu->num_counters = DDRC_NR_COUNTERS;
 	ddrc_pmu->counter_bits = 32;
-	ddrc_pmu->ops = &hisi_uncore_ddrc_ops;
+	ddrc_pmu->ops = &hisi_uncore_ddrc_v1_ops;
 	ddrc_pmu->dev = &pdev->dev;
 	ddrc_pmu->on_cpu = -1;
-	ddrc_pmu->check_event = 7;
+	ddrc_pmu->check_event = DDRC_V1_NR_EVENTS;
 
 	return 0;
 }
@@ -345,7 +346,7 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
 		.start		= hisi_uncore_pmu_start,
 		.stop		= hisi_uncore_pmu_stop,
 		.read		= hisi_uncore_pmu_read,
-		.attr_groups	= hisi_ddrc_pmu_attr_groups,
+		.attr_groups	= hisi_ddrc_pmu_v1_attr_groups,
 		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
 	};
 
diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
index 667eebddcc82..f779d70cf0bc 100644
--- a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
@@ -33,10 +33,11 @@
 #define HHA_CNT0_LOWER		0x1F00
 
 /* HHA has 16-counters */
-#define HHA_NR_COUNTERS		0x10
+#define HHA_V1_NR_COUNTERS	0x10
 
 #define HHA_PERF_CTRL_EN	0x1
 #define HHA_EVTYPE_NONE		0xff
+#define HHA_V1_NR_EVENT		0x65
 
 /*
  * Select the counter register offset using the counter index
@@ -206,17 +207,17 @@ static int hisi_hha_pmu_init_data(struct platform_device *pdev,
 	return 0;
 }
 
-static struct attribute *hisi_hha_pmu_format_attr[] = {
+static struct attribute *hisi_hha_pmu_v1_format_attr[] = {
 	HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
 	NULL,
 };
 
-static const struct attribute_group hisi_hha_pmu_format_group = {
+static const struct attribute_group hisi_hha_pmu_v1_format_group = {
 	.name = "format",
-	.attrs = hisi_hha_pmu_format_attr,
+	.attrs = hisi_hha_pmu_v1_format_attr,
 };
 
-static struct attribute *hisi_hha_pmu_events_attr[] = {
+static struct attribute *hisi_hha_pmu_v1_events_attr[] = {
 	HISI_PMU_EVENT_ATTR(rx_ops_num,		0x00),
 	HISI_PMU_EVENT_ATTR(rx_outer,		0x01),
 	HISI_PMU_EVENT_ATTR(rx_sccl,		0x02),
@@ -246,9 +247,9 @@ static struct attribute *hisi_hha_pmu_events_attr[] = {
 	NULL,
 };
 
-static const struct attribute_group hisi_hha_pmu_events_group = {
+static const struct attribute_group hisi_hha_pmu_v1_events_group = {
 	.name = "events",
-	.attrs = hisi_hha_pmu_events_attr,
+	.attrs = hisi_hha_pmu_v1_events_attr,
 };
 
 static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
@@ -274,9 +275,9 @@ static const struct attribute_group hisi_hha_pmu_identifier_group = {
 	.attrs = hisi_hha_pmu_identifier_attrs,
 };
 
-static const struct attribute_group *hisi_hha_pmu_attr_groups[] = {
-	&hisi_hha_pmu_format_group,
-	&hisi_hha_pmu_events_group,
+static const struct attribute_group *hisi_hha_pmu_v1_attr_groups[] = {
+	&hisi_hha_pmu_v1_format_group,
+	&hisi_hha_pmu_v1_events_group,
 	&hisi_hha_pmu_cpumask_attr_group,
 	&hisi_hha_pmu_identifier_group,
 	NULL,
@@ -310,12 +311,12 @@ static int hisi_hha_pmu_dev_probe(struct platform_device *pdev,
 	if (ret)
 		return ret;
 
-	hha_pmu->num_counters = HHA_NR_COUNTERS;
+	hha_pmu->num_counters = HHA_V1_NR_COUNTERS;
 	hha_pmu->counter_bits = 48;
 	hha_pmu->ops = &hisi_uncore_hha_ops;
 	hha_pmu->dev = &pdev->dev;
 	hha_pmu->on_cpu = -1;
-	hha_pmu->check_event = 0x65;
+	hha_pmu->check_event = HHA_V1_NR_EVENT;
 
 	return 0;
 }
@@ -357,7 +358,7 @@ static int hisi_hha_pmu_probe(struct platform_device *pdev)
 		.start		= hisi_uncore_pmu_start,
 		.stop		= hisi_uncore_pmu_stop,
 		.read		= hisi_uncore_pmu_read,
-		.attr_groups	= hisi_hha_pmu_attr_groups,
+		.attr_groups	= hisi_hha_pmu_v1_attr_groups,
 		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
 	};
 
diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
index 831622e0c445..da56fa16b97e 100644
--- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
@@ -37,7 +37,7 @@
 
 #define L3C_PERF_CTRL_EN	0x10000
 #define L3C_EVTYPE_NONE		0xff
-
+#define L3C_V1_NR_EVENTS	0x59
 /*
  * Select the counter register offset using the counter index
  */
@@ -209,17 +209,17 @@ static int hisi_l3c_pmu_init_data(struct platform_device *pdev,
 	return 0;
 }
 
-static struct attribute *hisi_l3c_pmu_format_attr[] = {
+static struct attribute *hisi_l3c_pmu_v1_format_attr[] = {
 	HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
 	NULL,
 };
 
-static const struct attribute_group hisi_l3c_pmu_format_group = {
+static const struct attribute_group hisi_l3c_pmu_v1_format_group = {
 	.name = "format",
-	.attrs = hisi_l3c_pmu_format_attr,
+	.attrs = hisi_l3c_pmu_v1_format_attr,
 };
 
-static struct attribute *hisi_l3c_pmu_events_attr[] = {
+static struct attribute *hisi_l3c_pmu_v1_events_attr[] = {
 	HISI_PMU_EVENT_ATTR(rd_cpipe,		0x00),
 	HISI_PMU_EVENT_ATTR(wr_cpipe,		0x01),
 	HISI_PMU_EVENT_ATTR(rd_hit_cpipe,	0x02),
@@ -236,9 +236,9 @@ static struct attribute *hisi_l3c_pmu_events_attr[] = {
 	NULL,
 };
 
-static const struct attribute_group hisi_l3c_pmu_events_group = {
+static const struct attribute_group hisi_l3c_pmu_v1_events_group = {
 	.name = "events",
-	.attrs = hisi_l3c_pmu_events_attr,
+	.attrs = hisi_l3c_pmu_v1_events_attr,
 };
 
 static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
@@ -264,9 +264,9 @@ static const struct attribute_group hisi_l3c_pmu_identifier_group = {
 	.attrs = hisi_l3c_pmu_identifier_attrs,
 };
 
-static const struct attribute_group *hisi_l3c_pmu_attr_groups[] = {
-	&hisi_l3c_pmu_format_group,
-	&hisi_l3c_pmu_events_group,
+static const struct attribute_group *hisi_l3c_pmu_v1_attr_groups[] = {
+	&hisi_l3c_pmu_v1_format_group,
+	&hisi_l3c_pmu_v1_events_group,
 	&hisi_l3c_pmu_cpumask_attr_group,
 	&hisi_l3c_pmu_identifier_group,
 	NULL,
@@ -305,7 +305,7 @@ static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev,
 	l3c_pmu->ops = &hisi_uncore_l3c_ops;
 	l3c_pmu->dev = &pdev->dev;
 	l3c_pmu->on_cpu = -1;
-	l3c_pmu->check_event = 0x59;
+	l3c_pmu->check_event = L3C_V1_NR_EVENTS;
 
 	return 0;
 }
@@ -347,7 +347,7 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev)
 		.start		= hisi_uncore_pmu_start,
 		.stop		= hisi_uncore_pmu_stop,
 		.read		= hisi_uncore_pmu_read,
-		.attr_groups	= hisi_l3c_pmu_attr_groups,
+		.attr_groups	= hisi_l3c_pmu_v1_attr_groups,
 		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
 	};
 
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 3/8] drivers/perf: hisi: Add new functions for L3C PMU
  2021-02-03  7:51 [PATCH v2 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
  2021-02-03  7:51 ` [PATCH v2 1/8] drivers/perf: hisi: Refactor code for more uncore PMUs Shaokun Zhang
  2021-02-03  7:51 ` [PATCH v2 2/8] drivers/perf: hisi: Add PMU version for uncore PMU drivers Shaokun Zhang
@ 2021-02-03  7:51 ` Shaokun Zhang
  2021-02-03 13:10   ` Mark Rutland
  2021-02-03  7:51 ` [PATCH v2 4/8] drivers/perf: hisi: Add new functions for HHA PMU Shaokun Zhang
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Shaokun Zhang @ 2021-02-03  7:51 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, John Garry, Shaokun Zhang,
	Jonathan Cameron, Will Deacon

On HiSilicon Hip09 platform, some new functions are enhanced on L3C PMU,
like, tracetag feature that L3C PMU can only count the specified
operations by the user, or L3C PMU can give the desired core's statistics
in the cluster.
$# perf stat -a -e hisi_sccl3_l3c0/config=0x02,tt_core=0xf/ sleep 5

$# perf stat -a -e hisi_sccl3_l3c0/config=0x02,tt_req=0x4/ sleep 5

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: John Garry <john.garry@huawei.com>
Co-developed-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c | 258 +++++++++++++++++++++++++--
 drivers/perf/hisilicon/hisi_uncore_pmu.c     |   8 +-
 drivers/perf/hisilicon/hisi_uncore_pmu.h     |  11 ++
 3 files changed, 257 insertions(+), 20 deletions(-)

diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
index da56fa16b97e..5ddbfd78730a 100644
--- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
@@ -23,12 +23,17 @@
 #define L3C_INT_MASK		0x0800
 #define L3C_INT_STATUS		0x0808
 #define L3C_INT_CLEAR		0x080c
+#define L3C_CORE_CTRL           0x1b04
+#define L3C_TRACETAG_CTRL       0x1b20
+#define L3C_DATSRC_TYPE         0x1b48
+#define L3C_DATSRC_CTRL         0x1bf0
 #define L3C_EVENT_CTRL	        0x1c00
 #define L3C_VERSION		0x1cf0
 #define L3C_EVENT_TYPE0		0x1d00
 /*
- * Each counter is 48-bits and [48:63] are reserved
- * which are Read-As-Zero and Writes-Ignored.
+ * If the HW version only supports a 48-bit counter, then
+ * bits [63:48] are reserved, which are Read-As-Zero and
+ * Writes-Ignored.
  */
 #define L3C_CNTR0_LOWER		0x1e00
 
@@ -36,8 +41,187 @@
 #define L3C_NR_COUNTERS		0x8
 
 #define L3C_PERF_CTRL_EN	0x10000
+#define L3C_TRACETAG_EN		BIT(31)
+#define L3C_TRACETAG_REQ_SHIFT	7
+#define L3C_TRACETAG_MARK_EN	BIT(0)
+#define L3C_TRACETAG_REQ_EN	(L3C_TRACETAG_MARK_EN | BIT(2))
+#define L3C_TRACETAG_CORE_EN	(L3C_TRACETAG_MARK_EN | BIT(3))
+#define L3C_CORE_EN		BIT(20)
+#define L3C_COER_NONE		0x0
+#define L3C_DATSRC_MASK		0xFF
+#define L3C_DATSRC_SKT_EN	BIT(23)
+#define L3C_DATSRC_NONE		0x0
 #define L3C_EVTYPE_NONE		0xff
 #define L3C_V1_NR_EVENTS	0x59
+#define L3C_V2_NR_EVENTS	0xFF
+
+HISI_PMU_EVENT_ATTR_EXTRACTOR(tt_core, config1, 7, 0);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(tt_req, config1, 10, 8);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(datasrc_cfg, config1, 15, 11);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(datasrc_skt, config1, 16, 16);
+
+static void hisi_l3c_pmu_config_req_tracetag(struct perf_event *event)
+{
+	struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);
+	u32 tt_req = hisi_get_tt_req(event);
+
+	if (tt_req) {
+		u32 val;
+
+		/* Set request-type for tracetag */
+		val = readl(l3c_pmu->base + L3C_TRACETAG_CTRL);
+		val |= tt_req << L3C_TRACETAG_REQ_SHIFT;
+		val |= L3C_TRACETAG_REQ_EN;
+		writel(val, l3c_pmu->base + L3C_TRACETAG_CTRL);
+
+		/* Enable request-tracetag statistics */
+		val = readl(l3c_pmu->base + L3C_PERF_CTRL);
+		val |= L3C_TRACETAG_EN;
+		writel(val, l3c_pmu->base + L3C_PERF_CTRL);
+	}
+}
+
+static void hisi_l3c_pmu_clear_req_tracetag(struct perf_event *event)
+{
+	struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);
+	u32 tt_req = hisi_get_tt_req(event);
+
+	if (tt_req) {
+		u32 val;
+
+		/* Clear request-type */
+		val = readl(l3c_pmu->base + L3C_TRACETAG_CTRL);
+		val &= ~(tt_req << L3C_TRACETAG_REQ_SHIFT);
+		val &= ~L3C_TRACETAG_REQ_EN;
+		writel(val, l3c_pmu->base + L3C_TRACETAG_CTRL);
+
+		/* Disable request-tracetag statistics */
+		val = readl(l3c_pmu->base + L3C_PERF_CTRL);
+		val &= ~L3C_TRACETAG_EN;
+		writel(val, l3c_pmu->base + L3C_PERF_CTRL);
+	}
+}
+
+static void hisi_l3c_pmu_write_ds(struct perf_event *event, u32 ds_cfg)
+{
+	struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);
+	struct hw_perf_event *hwc = &event->hw;
+	u32 reg, reg_idx, shift, val;
+	int idx = hwc->idx;
+
+	/*
+	 * Select the appropriate datasource register(L3C_DATSRC_TYPE0/1).
+	 * There are 2 datasource ctrl register for the 8 hardware counters.
+	 * Datasrc is 8-bits and for the former 4 hardware counters,
+	 * L3C_DATSRC_TYPE0 is chosen. For the latter 4 hardware counters,
+	 * L3C_DATSRC_TYPE1 is chosen.
+	 */
+	reg = L3C_DATSRC_TYPE + rounddown(idx, 4);
+	reg_idx = idx % 4;
+	shift = 8 * reg_idx;
+
+	val = readl(l3c_pmu->base + reg);
+	val &= ~(L3C_DATSRC_MASK << shift);
+	val |= ds_cfg << shift;
+	writel(val, l3c_pmu->base + reg);
+}
+
+static void hisi_l3c_pmu_config_ds(struct perf_event *event)
+{
+	struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);
+	u32 ds_cfg = hisi_get_datasrc_cfg(event);
+	u32 ds_skt = hisi_get_datasrc_skt(event);
+
+	if (ds_cfg)
+		hisi_l3c_pmu_write_ds(event, ds_cfg);
+
+	if (ds_skt) {
+		u32 val;
+
+		val = readl(l3c_pmu->base + L3C_DATSRC_CTRL);
+		val |= L3C_DATSRC_SKT_EN;
+		writel(val, l3c_pmu->base + L3C_DATSRC_CTRL);
+	}
+}
+
+static void hisi_l3c_pmu_clear_ds(struct perf_event *event)
+{
+	struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);
+	u32 ds_cfg = hisi_get_datasrc_cfg(event);
+	u32 ds_skt = hisi_get_datasrc_skt(event);
+
+	if (ds_cfg)
+		hisi_l3c_pmu_write_ds(event, L3C_DATSRC_NONE);
+
+	if (ds_skt) {
+		u32 val;
+
+		val = readl(l3c_pmu->base + L3C_DATSRC_CTRL);
+		val &= ~L3C_DATSRC_SKT_EN;
+		writel(val, l3c_pmu->base + L3C_DATSRC_CTRL);
+	}
+}
+
+static void hisi_l3c_pmu_config_core_tracetag(struct perf_event *event)
+{
+	struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);
+	u32 core = hisi_get_tt_core(event);
+
+	if (core) {
+		u32 val;
+
+		/* Config and enable core information */
+		writel(core, l3c_pmu->base + L3C_CORE_CTRL);
+		val = readl(l3c_pmu->base + L3C_PERF_CTRL);
+		val |= L3C_CORE_EN;
+		writel(val, l3c_pmu->base + L3C_PERF_CTRL);
+
+		/* Enable core-tracetag statistics */
+		val = readl(l3c_pmu->base + L3C_TRACETAG_CTRL);
+		val |= L3C_TRACETAG_CORE_EN;
+		writel(val, l3c_pmu->base + L3C_TRACETAG_CTRL);
+	}
+}
+
+static void hisi_l3c_pmu_clear_core_tracetag(struct perf_event *event)
+{
+	struct hisi_pmu *l3c_pmu = to_hisi_pmu(event->pmu);
+	u32 core = hisi_get_tt_core(event);
+
+	if (core) {
+		u32 val;
+
+		/* Clear core information */
+		writel(L3C_COER_NONE, l3c_pmu->base + L3C_CORE_CTRL);
+		val = readl(l3c_pmu->base + L3C_PERF_CTRL);
+		val &= ~L3C_CORE_EN;
+		writel(val, l3c_pmu->base + L3C_PERF_CTRL);
+
+		/* Disable core-tracetag statistics */
+		val = readl(l3c_pmu->base + L3C_TRACETAG_CTRL);
+		val &= ~L3C_TRACETAG_CORE_EN;
+		writel(val, l3c_pmu->base + L3C_TRACETAG_CTRL);
+	}
+}
+
+static void hisi_l3c_pmu_enable_filter(struct perf_event *event)
+{
+	if (event->attr.config1 != 0x0) {
+		hisi_l3c_pmu_config_req_tracetag(event);
+		hisi_l3c_pmu_config_core_tracetag(event);
+		hisi_l3c_pmu_config_ds(event);
+	}
+}
+
+static void hisi_l3c_pmu_disable_filter(struct perf_event *event)
+{
+	if (event->attr.config1 != 0x0) {
+		hisi_l3c_pmu_clear_ds(event);
+		hisi_l3c_pmu_clear_core_tracetag(event);
+		hisi_l3c_pmu_clear_req_tracetag(event);
+	}
+}
+
 /*
  * Select the counter register offset using the counter index
  */
@@ -49,14 +233,12 @@ static u32 hisi_l3c_pmu_get_counter_offset(int cntr_idx)
 static u64 hisi_l3c_pmu_read_counter(struct hisi_pmu *l3c_pmu,
 				     struct hw_perf_event *hwc)
 {
-	/* Read 64-bits and the upper 16 bits are RAZ */
 	return readq(l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(hwc->idx));
 }
 
 static void hisi_l3c_pmu_write_counter(struct hisi_pmu *l3c_pmu,
 				       struct hw_perf_event *hwc, u64 val)
 {
-	/* Write 64-bits and the upper 16 bits are WI */
 	writeq(val, l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(hwc->idx));
 }
 
@@ -165,23 +347,14 @@ static void hisi_l3c_pmu_clear_int_status(struct hisi_pmu *l3c_pmu, int idx)
 
 static const struct acpi_device_id hisi_l3c_pmu_acpi_match[] = {
 	{ "HISI0213", },
-	{},
+	{ "HISI0214", },
+	{}
 };
 MODULE_DEVICE_TABLE(acpi, hisi_l3c_pmu_acpi_match);
 
 static int hisi_l3c_pmu_init_data(struct platform_device *pdev,
 				  struct hisi_pmu *l3c_pmu)
 {
-	unsigned long long id;
-	acpi_status status;
-
-	status = acpi_evaluate_integer(ACPI_HANDLE(&pdev->dev),
-				       "_UID", NULL, &id);
-	if (ACPI_FAILURE(status))
-		return -EINVAL;
-
-	l3c_pmu->index_id = id;
-
 	/*
 	 * Use the SCCL_ID and CCL_ID to identify the L3C PMU, while
 	 * SCCL_ID is in MPIDR[aff2] and CCL_ID is in MPIDR[aff1].
@@ -219,6 +392,20 @@ static const struct attribute_group hisi_l3c_pmu_v1_format_group = {
 	.attrs = hisi_l3c_pmu_v1_format_attr,
 };
 
+static struct attribute *hisi_l3c_pmu_v2_format_attr[] = {
+	HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
+	HISI_PMU_FORMAT_ATTR(tt_core, "config1:0-7"),
+	HISI_PMU_FORMAT_ATTR(tt_req, "config1:8-10"),
+	HISI_PMU_FORMAT_ATTR(datasrc_cfg, "config1:11-15"),
+	HISI_PMU_FORMAT_ATTR(datasrc_skt, "config1:16"),
+	NULL
+};
+
+static const struct attribute_group hisi_l3c_pmu_v2_format_group = {
+	.name = "format",
+	.attrs = hisi_l3c_pmu_v2_format_attr,
+};
+
 static struct attribute *hisi_l3c_pmu_v1_events_attr[] = {
 	HISI_PMU_EVENT_ATTR(rd_cpipe,		0x00),
 	HISI_PMU_EVENT_ATTR(wr_cpipe,		0x01),
@@ -241,6 +428,17 @@ static const struct attribute_group hisi_l3c_pmu_v1_events_group = {
 	.attrs = hisi_l3c_pmu_v1_events_attr,
 };
 
+static struct attribute *hisi_l3c_pmu_v2_events_attr[] = {
+	HISI_PMU_EVENT_ATTR(dat_hit,		0x48),
+	HISI_PMU_EVENT_ATTR(dat_access,		0xb8),
+	NULL
+};
+
+static const struct attribute_group hisi_l3c_pmu_v2_events_group = {
+	.name = "events",
+	.attrs = hisi_l3c_pmu_v2_events_attr,
+};
+
 static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
 
 static struct attribute *hisi_l3c_pmu_cpumask_attrs[] = {
@@ -272,6 +470,14 @@ static const struct attribute_group *hisi_l3c_pmu_v1_attr_groups[] = {
 	NULL,
 };
 
+static const struct attribute_group *hisi_l3c_pmu_v2_attr_groups[] = {
+	&hisi_l3c_pmu_v2_format_group,
+	&hisi_l3c_pmu_v2_events_group,
+	&hisi_l3c_pmu_cpumask_attr_group,
+	&hisi_l3c_pmu_identifier_group,
+	NULL
+};
+
 static const struct hisi_uncore_ops hisi_uncore_l3c_ops = {
 	.write_evtype		= hisi_l3c_pmu_write_evtype,
 	.get_event_idx		= hisi_uncore_pmu_get_event_idx,
@@ -285,6 +491,8 @@ static const struct hisi_uncore_ops hisi_uncore_l3c_ops = {
 	.read_counter		= hisi_l3c_pmu_read_counter,
 	.get_int_status		= hisi_l3c_pmu_get_int_status,
 	.clear_int_status	= hisi_l3c_pmu_clear_int_status,
+	.enable_filter		= hisi_l3c_pmu_enable_filter,
+	.disable_filter		= hisi_l3c_pmu_disable_filter,
 };
 
 static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev,
@@ -300,12 +508,20 @@ static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev,
 	if (ret)
 		return ret;
 
+	if (l3c_pmu->identifier >= HISI_PMU_V2) {
+		l3c_pmu->counter_bits = 64;
+		l3c_pmu->check_event = L3C_V2_NR_EVENTS;
+		l3c_pmu->pmu_events.attr_groups = hisi_l3c_pmu_v2_attr_groups;
+	} else {
+		l3c_pmu->counter_bits = 48;
+		l3c_pmu->check_event = L3C_V1_NR_EVENTS;
+		l3c_pmu->pmu_events.attr_groups = hisi_l3c_pmu_v1_attr_groups;
+	}
+
 	l3c_pmu->num_counters = L3C_NR_COUNTERS;
-	l3c_pmu->counter_bits = 48;
 	l3c_pmu->ops = &hisi_uncore_l3c_ops;
 	l3c_pmu->dev = &pdev->dev;
 	l3c_pmu->on_cpu = -1;
-	l3c_pmu->check_event = L3C_V1_NR_EVENTS;
 
 	return 0;
 }
@@ -333,8 +549,12 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	/*
+	 * CCL_ID is used to identify the L3C in the same SCCL which was
+	 * used _UID by mistake.
+	 */
 	name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_l3c%u",
-			      l3c_pmu->sccl_id, l3c_pmu->index_id);
+			      l3c_pmu->sccl_id, l3c_pmu->ccl_id);
 	l3c_pmu->pmu = (struct pmu) {
 		.name		= name,
 		.module		= THIS_MODULE,
@@ -347,7 +567,7 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev)
 		.start		= hisi_uncore_pmu_start,
 		.stop		= hisi_uncore_pmu_stop,
 		.read		= hisi_uncore_pmu_read,
-		.attr_groups	= hisi_l3c_pmu_v1_attr_groups,
+		.attr_groups	= l3c_pmu->pmu_events.attr_groups,
 		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
 	};
 
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c
index 82a4ff2bc3ae..30fb152e217c 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c
@@ -21,7 +21,7 @@
 #include "hisi_uncore_pmu.h"
 
 #define HISI_GET_EVENTID(ev) (ev->hw.config_base & 0xff)
-#define HISI_MAX_PERIOD(nr) (BIT_ULL(nr) - 1)
+#define HISI_MAX_PERIOD(nr) (GENMASK_ULL((nr) - 1, 0))
 
 /*
  * PMU format attributes
@@ -256,6 +256,9 @@ static void hisi_uncore_pmu_enable_event(struct perf_event *event)
 	hisi_pmu->ops->write_evtype(hisi_pmu, hwc->idx,
 				    HISI_GET_EVENTID(event));
 
+	if (hisi_pmu->ops->enable_filter)
+		hisi_pmu->ops->enable_filter(event);
+
 	hisi_pmu->ops->enable_counter_int(hisi_pmu, hwc);
 	hisi_pmu->ops->enable_counter(hisi_pmu, hwc);
 }
@@ -268,6 +271,9 @@ static void hisi_uncore_pmu_disable_event(struct perf_event *event)
 	struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu);
 	struct hw_perf_event *hwc = &event->hw;
 
+	if (hisi_pmu->ops->disable_filter)
+		hisi_pmu->ops->disable_filter(event);
+
 	hisi_pmu->ops->disable_counter(hisi_pmu, hwc);
 	hisi_pmu->ops->disable_counter_int(hisi_pmu, hwc);
 }
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h
index aaaf637cc9ea..c9f180001ab0 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.h
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h
@@ -11,6 +11,7 @@
 #ifndef __HISI_UNCORE_PMU_H__
 #define __HISI_UNCORE_PMU_H__
 
+#include <linux/bitfield.h>
 #include <linux/cpumask.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
@@ -22,6 +23,7 @@
 #undef pr_fmt
 #define pr_fmt(fmt)     "hisi_pmu: " fmt
 
+#define HISI_PMU_V2		0x30
 #define HISI_MAX_COUNTERS 0x10
 #define to_hisi_pmu(p)	(container_of(p, struct hisi_pmu, pmu))
 
@@ -35,6 +37,12 @@
 #define HISI_PMU_EVENT_ATTR(_name, _config)		\
 	HISI_PMU_ATTR(_name, hisi_event_sysfs_show, (unsigned long)_config)
 
+#define HISI_PMU_EVENT_ATTR_EXTRACTOR(name, config, hi, lo)        \
+	static inline u32 hisi_get_##name(struct perf_event *event)            \
+	{                                                                  \
+		return FIELD_GET(GENMASK_ULL(hi, lo), event->attr.config);  \
+	}
+
 struct hisi_pmu;
 
 struct hisi_uncore_ops {
@@ -50,11 +58,14 @@ struct hisi_uncore_ops {
 	void (*stop_counters)(struct hisi_pmu *);
 	u32 (*get_int_status)(struct hisi_pmu *hisi_pmu);
 	void (*clear_int_status)(struct hisi_pmu *hisi_pmu, int idx);
+	void (*enable_filter)(struct perf_event *event);
+	void (*disable_filter)(struct perf_event *event);
 };
 
 struct hisi_pmu_hwevents {
 	struct perf_event *hw_events[HISI_MAX_COUNTERS];
 	DECLARE_BITMAP(used_mask, HISI_MAX_COUNTERS);
+	const struct attribute_group **attr_groups;
 };
 
 /* Generic pmu struct for different pmu types */
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 4/8] drivers/perf: hisi: Add new functions for HHA PMU
  2021-02-03  7:51 [PATCH v2 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
                   ` (2 preceding siblings ...)
  2021-02-03  7:51 ` [PATCH v2 3/8] drivers/perf: hisi: Add new functions for L3C PMU Shaokun Zhang
@ 2021-02-03  7:51 ` Shaokun Zhang
  2021-02-03 13:18   ` Mark Rutland
  2021-02-03  7:51 ` [PATCH v2 5/8] drivers/perf: hisi: Update DDRC PMU for programable counter Shaokun Zhang
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Shaokun Zhang @ 2021-02-03  7:51 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, John Garry, Shaokun Zhang,
	Jonathan Cameron, Will Deacon

On HiSilicon Hip09 platform, some new functions are also supported on
HHA PMU, it can filter gathered statistics by the Master ID and mask
from the SoC if the user wants to do deep-going profiling.
Tracetag support is also added with L3C PMU in the SoC system.

$# perf stat -a -e hisi_sccl3_hha0/config=0x02,tracetag_en=0x1/ sleep 5

$# perf stat -a -e hisi_sccl3_hha0/config=0x02,srcid_cmd=0x1/ sleep 5
Much more introduction is added in documentation:
Documentation/admin-guide/perf/hisi-pmu.rst

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: John Garry <john.garry@huawei.com>
Co-developed-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/hisilicon/hisi_uncore_hha_pmu.c | 203 +++++++++++++++++++++++++--
 1 file changed, 188 insertions(+), 15 deletions(-)

diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
index f779d70cf0bc..a87bba200127 100644
--- a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
@@ -25,19 +25,136 @@
 #define HHA_VERSION		0x1cf0
 #define HHA_PERF_CTRL		0x1E00
 #define HHA_EVENT_CTRL		0x1E04
+#define HHA_SRCID_CTRL		0x1E08
+#define HHA_DATSRC_CTRL		0x1BF0
 #define HHA_EVENT_TYPE0		0x1E80
 /*
- * Each counter is 48-bits and [48:63] are reserved
- * which are Read-As-Zero and Writes-Ignored.
+ * If the HW version only supports a 48-bit counter, then
+ * bits [63:48] are reserved, which are Read-As-Zero and
+ * Writes-Ignored.
  */
 #define HHA_CNT0_LOWER		0x1F00
 
-/* HHA has 16-counters */
+/* HHA PMU v1 has 16 counters and v2 only has 8 counters */
 #define HHA_V1_NR_COUNTERS	0x10
+#define HHA_V2_NR_COUNTERS	0x8
 
 #define HHA_PERF_CTRL_EN	0x1
+#define HHA_TRACETAG_EN		BIT(31)
+#define HHA_SRCID_EN		BIT(2)
+#define HHA_SRCID_CMD_SHIFT	6
+#define HHA_SRCID_MASK_SHIFT	20
+#define HHA_SRCID_CMD		GENMASK(16, 6)
+#define HHA_SRCID_MSK		GENMASK(30, 20)
+#define HHA_DATSRC_SKT_EN	BIT(23)
 #define HHA_EVTYPE_NONE		0xff
 #define HHA_V1_NR_EVENT		0x65
+#define HHA_V2_NR_EVENT		0xCE
+
+HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_cmd, config1, 10, 0);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 21, 11);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 22, 22);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(datasrc_skt, config1, 23, 23);
+
+static void hisi_hha_pmu_enable_tracetag(struct perf_event *event)
+{
+	struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu);
+	u32 tt_en = hisi_get_tracetag_en(event);
+
+	if (tt_en) {
+		u32 val;
+
+		val = readl(hha_pmu->base + HHA_SRCID_CTRL);
+		val |= HHA_TRACETAG_EN;
+		writel(val, hha_pmu->base + HHA_SRCID_CTRL);
+	}
+}
+
+static void hisi_hha_pmu_clear_tracetag(struct perf_event *event)
+{
+	struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu);
+	u32 val;
+
+	val = readl(hha_pmu->base + HHA_SRCID_CTRL);
+	val &= ~HHA_TRACETAG_EN;
+	writel(val, hha_pmu->base + HHA_SRCID_CTRL);
+}
+
+static void hisi_hha_pmu_config_ds(struct perf_event *event)
+{
+	struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu);
+	u32 ds_skt = hisi_get_datasrc_skt(event);
+
+	if (ds_skt) {
+		u32 val;
+
+		val = readl(hha_pmu->base + HHA_DATSRC_CTRL);
+		val |= HHA_DATSRC_SKT_EN;
+		writel(ds_skt, hha_pmu->base + HHA_DATSRC_CTRL);
+	}
+}
+
+static void hisi_hha_pmu_clear_ds(struct perf_event *event)
+{
+	struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu);
+	u32 ds_skt = hisi_get_datasrc_skt(event);
+
+	if (ds_skt) {
+		u32 val;
+
+		val = readl(hha_pmu->base + HHA_DATSRC_CTRL);
+		val &= ~HHA_DATSRC_SKT_EN;
+		writel(ds_skt, hha_pmu->base + HHA_DATSRC_CTRL);
+	}
+}
+
+static void hisi_hha_pmu_config_srcid(struct perf_event *event)
+{
+	struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu);
+	u32 cmd = hisi_get_srcid_cmd(event);
+
+	if (cmd) {
+		u32 val, msk;
+
+		msk = hisi_get_srcid_msk(event);
+		val = readl(hha_pmu->base + HHA_SRCID_CTRL);
+		val |= HHA_SRCID_EN | (cmd << HHA_SRCID_CMD_SHIFT) |
+			(msk << HHA_SRCID_MASK_SHIFT);
+		writel(val, hha_pmu->base + HHA_SRCID_CTRL);
+	}
+}
+
+static void hisi_hha_pmu_disable_srcid(struct perf_event *event)
+{
+	struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu);
+	u32 cmd = hisi_get_srcid_cmd(event);
+
+	if (cmd) {
+		u32 val;
+
+		val = readl(hha_pmu->base + HHA_SRCID_CTRL);
+		val &= ~(HHA_SRCID_EN | HHA_SRCID_MSK | HHA_SRCID_CMD);
+		writel(val, hha_pmu->base + HHA_SRCID_CTRL);
+	}
+}
+
+static void hisi_hha_pmu_enable_filter(struct perf_event *event)
+{
+	if (event->attr.config1 != 0x0) {
+		hisi_hha_pmu_enable_tracetag(event);
+		hisi_hha_pmu_config_ds(event);
+		hisi_hha_pmu_config_srcid(event);
+	}
+}
+
+static void hisi_hha_pmu_disable_filter(struct perf_event *event)
+{
+	if (event->attr.config1 != 0x0) {
+		hisi_hha_pmu_disable_srcid(event);
+		hisi_hha_pmu_clear_ds(event);
+		hisi_hha_pmu_clear_tracetag(event);
+	}
+}
 
 /*
  * Select the counter register offset using the counter index
@@ -167,7 +284,8 @@ static void hisi_hha_pmu_clear_int_status(struct hisi_pmu *hha_pmu, int idx)
 
 static const struct acpi_device_id hisi_hha_pmu_acpi_match[] = {
 	{ "HISI0243", },
-	{},
+	{ "HISI0244", },
+	{}
 };
 MODULE_DEVICE_TABLE(acpi, hisi_hha_pmu_acpi_match);
 
@@ -177,13 +295,6 @@ static int hisi_hha_pmu_init_data(struct platform_device *pdev,
 	unsigned long long id;
 	acpi_status status;
 
-	status = acpi_evaluate_integer(ACPI_HANDLE(&pdev->dev),
-				       "_UID", NULL, &id);
-	if (ACPI_FAILURE(status))
-		return -EINVAL;
-
-	hha_pmu->index_id = id;
-
 	/*
 	 * Use SCCL_ID and UID to identify the HHA PMU, while
 	 * SCCL_ID is in MPIDR[aff2].
@@ -193,6 +304,22 @@ static int hisi_hha_pmu_init_data(struct platform_device *pdev,
 		dev_err(&pdev->dev, "Can not read hha sccl-id!\n");
 		return -EINVAL;
 	}
+
+	/*
+	 * Early versions of BIOS support _UID by mistake, so we support
+	 * both "hisilicon, idx-id" as preference, if availbale.
+	 */
+	if (device_property_read_u32(&pdev->dev, "hisilicon,idx-id",
+				     &hha_pmu->index_id)) {
+		status = acpi_evaluate_integer(ACPI_HANDLE(&pdev->dev),
+					       "_UID", NULL, &id);
+		if (ACPI_FAILURE(status)) {
+			dev_err(&pdev->dev, "Cannot read idx-id!\n");
+			return -EINVAL;
+		}
+
+		hha_pmu->index_id = id;
+	}
 	/* HHA PMUs only share the same SCCL */
 	hha_pmu->ccl_id = -1;
 
@@ -217,6 +344,20 @@ static const struct attribute_group hisi_hha_pmu_v1_format_group = {
 	.attrs = hisi_hha_pmu_v1_format_attr,
 };
 
+static struct attribute *hisi_hha_pmu_v2_format_attr[] = {
+	HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
+	HISI_PMU_FORMAT_ATTR(srcid_cmd, "config1:0-10"),
+	HISI_PMU_FORMAT_ATTR(srcid_mask, "config1:11-21"),
+	HISI_PMU_FORMAT_ATTR(tracetag_en, "config1:22"),
+	HISI_PMU_FORMAT_ATTR(datasrc_skt, "config1:23"),
+	NULL
+};
+
+static const struct attribute_group hisi_hha_pmu_v2_format_group = {
+	.name = "format",
+	.attrs = hisi_hha_pmu_v2_format_attr,
+};
+
 static struct attribute *hisi_hha_pmu_v1_events_attr[] = {
 	HISI_PMU_EVENT_ATTR(rx_ops_num,		0x00),
 	HISI_PMU_EVENT_ATTR(rx_outer,		0x01),
@@ -252,6 +393,20 @@ static const struct attribute_group hisi_hha_pmu_v1_events_group = {
 	.attrs = hisi_hha_pmu_v1_events_attr,
 };
 
+static struct attribute *hisi_hha_pmu_v2_events_attr[] = {
+	HISI_PMU_EVENT_ATTR(rx_ops_num,		0x00),
+	HISI_PMU_EVENT_ATTR(rx_outer,		0x01),
+	HISI_PMU_EVENT_ATTR(rx_sccl,		0x02),
+	HISI_PMU_EVENT_ATTR(hha_retry,		0x2e),
+	HISI_PMU_EVENT_ATTR(cycles,		0x55),
+	NULL
+};
+
+static const struct attribute_group hisi_hha_pmu_v2_events_group = {
+	.name = "events",
+	.attrs = hisi_hha_pmu_v2_events_attr,
+};
+
 static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
 
 static struct attribute *hisi_hha_pmu_cpumask_attrs[] = {
@@ -283,6 +438,14 @@ static const struct attribute_group *hisi_hha_pmu_v1_attr_groups[] = {
 	NULL,
 };
 
+static const struct attribute_group *hisi_hha_pmu_v2_attr_groups[] = {
+	&hisi_hha_pmu_v2_format_group,
+	&hisi_hha_pmu_v2_events_group,
+	&hisi_hha_pmu_cpumask_attr_group,
+	&hisi_hha_pmu_identifier_group,
+	NULL
+};
+
 static const struct hisi_uncore_ops hisi_uncore_hha_ops = {
 	.write_evtype		= hisi_hha_pmu_write_evtype,
 	.get_event_idx		= hisi_uncore_pmu_get_event_idx,
@@ -296,6 +459,8 @@ static const struct hisi_uncore_ops hisi_uncore_hha_ops = {
 	.read_counter		= hisi_hha_pmu_read_counter,
 	.get_int_status		= hisi_hha_pmu_get_int_status,
 	.clear_int_status	= hisi_hha_pmu_clear_int_status,
+	.enable_filter		= hisi_hha_pmu_enable_filter,
+	.disable_filter		= hisi_hha_pmu_disable_filter,
 };
 
 static int hisi_hha_pmu_dev_probe(struct platform_device *pdev,
@@ -311,12 +476,20 @@ static int hisi_hha_pmu_dev_probe(struct platform_device *pdev,
 	if (ret)
 		return ret;
 
-	hha_pmu->num_counters = HHA_V1_NR_COUNTERS;
-	hha_pmu->counter_bits = 48;
+	if (hha_pmu->identifier >= HISI_PMU_V2) {
+		hha_pmu->counter_bits = 64;
+		hha_pmu->check_event = HHA_V2_NR_EVENT;
+		hha_pmu->pmu_events.attr_groups = hisi_hha_pmu_v2_attr_groups;
+		hha_pmu->num_counters = HHA_V2_NR_COUNTERS;
+	} else {
+		hha_pmu->counter_bits = 48;
+		hha_pmu->check_event = HHA_V1_NR_EVENT;
+		hha_pmu->pmu_events.attr_groups = hisi_hha_pmu_v1_attr_groups;
+		hha_pmu->num_counters = HHA_V1_NR_COUNTERS;
+	}
 	hha_pmu->ops = &hisi_uncore_hha_ops;
 	hha_pmu->dev = &pdev->dev;
 	hha_pmu->on_cpu = -1;
-	hha_pmu->check_event = HHA_V1_NR_EVENT;
 
 	return 0;
 }
@@ -358,7 +531,7 @@ static int hisi_hha_pmu_probe(struct platform_device *pdev)
 		.start		= hisi_uncore_pmu_start,
 		.stop		= hisi_uncore_pmu_stop,
 		.read		= hisi_uncore_pmu_read,
-		.attr_groups	= hisi_hha_pmu_v1_attr_groups,
+		.attr_groups	= hha_pmu->pmu_events.attr_groups,
 		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
 	};
 
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 5/8] drivers/perf: hisi: Update DDRC PMU for programable counter
  2021-02-03  7:51 [PATCH v2 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
                   ` (3 preceding siblings ...)
  2021-02-03  7:51 ` [PATCH v2 4/8] drivers/perf: hisi: Add new functions for HHA PMU Shaokun Zhang
@ 2021-02-03  7:51 ` Shaokun Zhang
  2021-02-03 13:23   ` Mark Rutland
  2021-02-03  7:51 ` [PATCH v2 6/8] drivers/perf: hisi: Add support for HiSilicon SLLC PMU driver Shaokun Zhang
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Shaokun Zhang @ 2021-02-03  7:51 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, John Garry, Shaokun Zhang,
	Jonathan Cameron, Will Deacon

DDRC PMU's events are useful for performance profiling, but the events
are limited and counters are fixed. On HiSilicon Hip09 platform, PMU
counters are the programmable and more events are supported. Let's
add the DDRC PMU v2 driver.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: John Garry <john.garry@huawei.com>
Co-developed-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 208 ++++++++++++++++++++++++--
 drivers/perf/hisilicon/hisi_uncore_pmu.h      |   2 +
 2 files changed, 197 insertions(+), 13 deletions(-)

diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
index a767babb57b2..922aefdbe786 100644
--- a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
@@ -18,7 +18,7 @@
 
 #include "hisi_uncore_pmu.h"
 
-/* DDRC register definition */
+/* DDRC register definition in v1 */
 #define DDRC_PERF_CTRL		0x010
 #define DDRC_FLUX_WR		0x380
 #define DDRC_FLUX_RD		0x384
@@ -34,12 +34,24 @@
 #define DDRC_INT_CLEAR		0x6d0
 #define DDRC_VERSION		0x710
 
+/* DDRC register definition in v2 */
+#define DDRC_V2_INT_MASK	0x528
+#define DDRC_V2_INT_STATUS	0x52c
+#define DDRC_V2_INT_CLEAR	0x530
+#define DDRC_V2_EVENT_CNT	0xE00
+#define DDRC_V2_EVENT_CTRL	0xE70
+#define DDRC_V2_EVENT_TYPE	0xE74
+#define DDRC_V2_PERF_CTRL	0xEA0
+
 /* DDRC has 8-counters */
 #define DDRC_NR_COUNTERS	0x8
 #define DDRC_V1_PERF_CTRL_EN	0x2
+#define DDRC_V2_PERF_CTRL_EN	0x1
 #define DDRC_V1_NR_EVENTS	0x07
+#define DDRC_V2_NR_EVENTS	0x90
+
 /*
- * For DDRC PMU, there are eight-events and every event has been mapped
+ * For PMU v1, there are eight-events and every event has been mapped
  * to fixed-purpose counters which register offset is not consistent.
  * Therefore there is no write event type and we assume that event
  * code (0 to 7) is equal to counter index in PMU driver.
@@ -61,6 +73,11 @@ static u32 hisi_ddrc_pmu_v1_get_counter_offset(int cntr_idx)
 	return ddrc_reg_off[cntr_idx];
 }
 
+static u32 hisi_ddrc_pmu_v2_get_counter_offset(int cntr_idx)
+{
+	return DDRC_V2_EVENT_CNT + cntr_idx * 8;
+}
+
 static u64 hisi_ddrc_pmu_v1_read_counter(struct hisi_pmu *ddrc_pmu,
 				      struct hw_perf_event *hwc)
 {
@@ -75,13 +92,34 @@ static void hisi_ddrc_pmu_v1_write_counter(struct hisi_pmu *ddrc_pmu,
 	       ddrc_pmu->base + hisi_ddrc_pmu_v1_get_counter_offset(hwc->idx));
 }
 
+static u64 hisi_ddrc_pmu_v2_read_counter(struct hisi_pmu *ddrc_pmu,
+					 struct hw_perf_event *hwc)
+{
+	return readq(ddrc_pmu->base +
+		     hisi_ddrc_pmu_v2_get_counter_offset(hwc->idx));
+}
+
+static void hisi_ddrc_pmu_v2_write_counter(struct hisi_pmu *ddrc_pmu,
+					   struct hw_perf_event *hwc, u64 val)
+{
+	writeq(val,
+	       ddrc_pmu->base + hisi_ddrc_pmu_v2_get_counter_offset(hwc->idx));
+}
+
 /*
- * For DDRC PMU, event has been mapped to fixed-purpose counter by hardware,
- * so there is no need to write event type.
+ * For DDRC PMU v1, event has been mapped to fixed-purpose counter by hardware,
+ * so there is no need to write event type, while it is programmable counter in
+ * PMU v2.
  */
 static void hisi_ddrc_pmu_write_evtype(struct hisi_pmu *hha_pmu, int idx,
 				       u32 type)
 {
+	u32 offset;
+
+	if (hha_pmu->identifier >= HISI_PMU_V2) {
+		offset = DDRC_V2_EVENT_TYPE + 4 * idx;
+		writel(type, hha_pmu->base + offset);
+	}
 }
 
 static void hisi_ddrc_pmu_v1_start_counters(struct hisi_pmu *ddrc_pmu)
@@ -142,6 +180,49 @@ static int hisi_ddrc_pmu_v1_get_event_idx(struct perf_event *event)
 	return idx;
 }
 
+static int hisi_ddrc_pmu_v2_get_event_idx(struct perf_event *event)
+{
+	return hisi_uncore_pmu_get_event_idx(event);
+}
+
+static void hisi_ddrc_pmu_v2_start_counters(struct hisi_pmu *ddrc_pmu)
+{
+	u32 val;
+
+	val = readl(ddrc_pmu->base + DDRC_V2_PERF_CTRL);
+	val |= DDRC_V2_PERF_CTRL_EN;
+	writel(val, ddrc_pmu->base + DDRC_V2_PERF_CTRL);
+}
+
+static void hisi_ddrc_pmu_v2_stop_counters(struct hisi_pmu *ddrc_pmu)
+{
+	u32 val;
+
+	val = readl(ddrc_pmu->base + DDRC_V2_PERF_CTRL);
+	val &= ~DDRC_V2_PERF_CTRL_EN;
+	writel(val, ddrc_pmu->base + DDRC_V2_PERF_CTRL);
+}
+
+static void hisi_ddrc_pmu_v2_enable_counter(struct hisi_pmu *ddrc_pmu,
+					    struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	val = readl(ddrc_pmu->base + DDRC_V2_EVENT_CTRL);
+	val |= 1 << hwc->idx;
+	writel(val, ddrc_pmu->base + DDRC_V2_EVENT_CTRL);
+}
+
+static void hisi_ddrc_pmu_v2_disable_counter(struct hisi_pmu *ddrc_pmu,
+					     struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	val = readl(ddrc_pmu->base + DDRC_V2_EVENT_CTRL);
+	val &= ~(1 << hwc->idx);
+	writel(val, ddrc_pmu->base + DDRC_V2_EVENT_CTRL);
+}
+
 static void hisi_ddrc_pmu_v1_enable_counter_int(struct hisi_pmu *ddrc_pmu,
 						struct hw_perf_event *hwc)
 {
@@ -149,7 +230,7 @@ static void hisi_ddrc_pmu_v1_enable_counter_int(struct hisi_pmu *ddrc_pmu,
 
 	/* Write 0 to enable interrupt */
 	val = readl(ddrc_pmu->base + DDRC_INT_MASK);
-	val &= ~(1 << GET_DDRC_EVENTID(hwc));
+	val &= ~(1 << hwc->idx);
 	writel(val, ddrc_pmu->base + DDRC_INT_MASK);
 }
 
@@ -160,10 +241,30 @@ static void hisi_ddrc_pmu_v1_disable_counter_int(struct hisi_pmu *ddrc_pmu,
 
 	/* Write 1 to mask interrupt */
 	val = readl(ddrc_pmu->base + DDRC_INT_MASK);
-	val |= (1 << GET_DDRC_EVENTID(hwc));
+	val |= 1 << hwc->idx;
 	writel(val, ddrc_pmu->base + DDRC_INT_MASK);
 }
 
+static void hisi_ddrc_pmu_v2_enable_counter_int(struct hisi_pmu *ddrc_pmu,
+						struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	val = readl(ddrc_pmu->base + DDRC_V2_INT_MASK);
+	val &= ~(1 << hwc->idx);
+	writel(val, ddrc_pmu->base + DDRC_V2_INT_MASK);
+}
+
+static void hisi_ddrc_pmu_v2_disable_counter_int(struct hisi_pmu *ddrc_pmu,
+						struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	val = readl(ddrc_pmu->base + DDRC_V2_INT_MASK);
+	val |= 1 << hwc->idx;
+	writel(val, ddrc_pmu->base + DDRC_V2_INT_MASK);
+}
+
 static u32 hisi_ddrc_pmu_v1_get_int_status(struct hisi_pmu *ddrc_pmu)
 {
 	return readl(ddrc_pmu->base + DDRC_INT_STATUS);
@@ -175,9 +276,21 @@ static void hisi_ddrc_pmu_v1_clear_int_status(struct hisi_pmu *ddrc_pmu,
 	writel(1 << idx, ddrc_pmu->base + DDRC_INT_CLEAR);
 }
 
+static u32 hisi_ddrc_pmu_v2_get_int_status(struct hisi_pmu *ddrc_pmu)
+{
+	return readl(ddrc_pmu->base + DDRC_V2_INT_STATUS);
+}
+
+static void hisi_ddrc_pmu_v2_clear_int_status(struct hisi_pmu *ddrc_pmu,
+					      int idx)
+{
+	writel(1 << idx, ddrc_pmu->base + DDRC_V2_INT_CLEAR);
+}
+
 static const struct acpi_device_id hisi_ddrc_pmu_acpi_match[] = {
 	{ "HISI0233", },
-	{},
+	{ "HISI0234", },
+	{}
 };
 MODULE_DEVICE_TABLE(acpi, hisi_ddrc_pmu_acpi_match);
 
@@ -209,6 +322,13 @@ static int hisi_ddrc_pmu_init_data(struct platform_device *pdev,
 	}
 
 	ddrc_pmu->identifier = readl(ddrc_pmu->base + DDRC_VERSION);
+	if (ddrc_pmu->identifier >= HISI_PMU_V2) {
+		if (device_property_read_u32(&pdev->dev, "hisilicon,sub-id",
+					     &ddrc_pmu->sub_id)) {
+			dev_err(&pdev->dev, "Can not read sub-id!\n");
+			return -EINVAL;
+		}
+	}
 
 	return 0;
 }
@@ -223,6 +343,16 @@ static const struct attribute_group hisi_ddrc_pmu_v1_format_group = {
 	.attrs = hisi_ddrc_pmu_v1_format_attr,
 };
 
+static struct attribute *hisi_ddrc_pmu_v2_format_attr[] = {
+	HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
+	NULL
+};
+
+static const struct attribute_group hisi_ddrc_pmu_v2_format_group = {
+	.name = "format",
+	.attrs = hisi_ddrc_pmu_v2_format_attr,
+};
+
 static struct attribute *hisi_ddrc_pmu_v1_events_attr[] = {
 	HISI_PMU_EVENT_ATTR(flux_wr,		0x00),
 	HISI_PMU_EVENT_ATTR(flux_rd,		0x01),
@@ -240,6 +370,18 @@ static const struct attribute_group hisi_ddrc_pmu_v1_events_group = {
 	.attrs = hisi_ddrc_pmu_v1_events_attr,
 };
 
+static struct attribute *hisi_ddrc_pmu_v2_events_attr[] = {
+	HISI_PMU_EVENT_ATTR(clocks,		0x00),
+	HISI_PMU_EVENT_ATTR(flux_wr,		0x83),
+	HISI_PMU_EVENT_ATTR(flux_rd,		0x84),
+	NULL
+};
+
+static const struct attribute_group hisi_ddrc_pmu_v2_events_group = {
+	.name = "events",
+	.attrs = hisi_ddrc_pmu_v2_events_attr,
+};
+
 static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
 
 static struct attribute *hisi_ddrc_pmu_cpumask_attrs[] = {
@@ -271,6 +413,14 @@ static const struct attribute_group *hisi_ddrc_pmu_v1_attr_groups[] = {
 	NULL,
 };
 
+static const struct attribute_group *hisi_ddrc_pmu_v2_attr_groups[] = {
+	&hisi_ddrc_pmu_v2_format_group,
+	&hisi_ddrc_pmu_v2_events_group,
+	&hisi_ddrc_pmu_cpumask_attr_group,
+	&hisi_ddrc_pmu_identifier_group,
+	NULL
+};
+
 static const struct hisi_uncore_ops hisi_uncore_ddrc_v1_ops = {
 	.write_evtype           = hisi_ddrc_pmu_write_evtype,
 	.get_event_idx		= hisi_ddrc_pmu_v1_get_event_idx,
@@ -286,6 +436,21 @@ static const struct hisi_uncore_ops hisi_uncore_ddrc_v1_ops = {
 	.clear_int_status	= hisi_ddrc_pmu_v1_clear_int_status,
 };
 
+static const struct hisi_uncore_ops hisi_uncore_ddrc_v2_ops = {
+	.write_evtype           = hisi_ddrc_pmu_write_evtype,
+	.get_event_idx		= hisi_ddrc_pmu_v2_get_event_idx,
+	.start_counters		= hisi_ddrc_pmu_v2_start_counters,
+	.stop_counters		= hisi_ddrc_pmu_v2_stop_counters,
+	.enable_counter		= hisi_ddrc_pmu_v2_enable_counter,
+	.disable_counter	= hisi_ddrc_pmu_v2_disable_counter,
+	.enable_counter_int	= hisi_ddrc_pmu_v2_enable_counter_int,
+	.disable_counter_int	= hisi_ddrc_pmu_v2_disable_counter_int,
+	.write_counter		= hisi_ddrc_pmu_v2_write_counter,
+	.read_counter		= hisi_ddrc_pmu_v2_read_counter,
+	.get_int_status		= hisi_ddrc_pmu_v2_get_int_status,
+	.clear_int_status	= hisi_ddrc_pmu_v2_clear_int_status,
+};
+
 static int hisi_ddrc_pmu_dev_probe(struct platform_device *pdev,
 				   struct hisi_pmu *ddrc_pmu)
 {
@@ -299,12 +464,21 @@ static int hisi_ddrc_pmu_dev_probe(struct platform_device *pdev,
 	if (ret)
 		return ret;
 
+	if (ddrc_pmu->identifier >= HISI_PMU_V2) {
+		ddrc_pmu->counter_bits = 48;
+		ddrc_pmu->check_event = DDRC_V2_NR_EVENTS;
+		ddrc_pmu->pmu_events.attr_groups = hisi_ddrc_pmu_v2_attr_groups;
+		ddrc_pmu->ops = &hisi_uncore_ddrc_v2_ops;
+	} else {
+		ddrc_pmu->counter_bits = 32;
+		ddrc_pmu->check_event = DDRC_V1_NR_EVENTS;
+		ddrc_pmu->pmu_events.attr_groups = hisi_ddrc_pmu_v1_attr_groups;
+		ddrc_pmu->ops = &hisi_uncore_ddrc_v1_ops;
+	}
+
 	ddrc_pmu->num_counters = DDRC_NR_COUNTERS;
-	ddrc_pmu->counter_bits = 32;
-	ddrc_pmu->ops = &hisi_uncore_ddrc_v1_ops;
 	ddrc_pmu->dev = &pdev->dev;
 	ddrc_pmu->on_cpu = -1;
-	ddrc_pmu->check_event = DDRC_V1_NR_EVENTS;
 
 	return 0;
 }
@@ -332,8 +506,16 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_ddrc%u",
-			      ddrc_pmu->sccl_id, ddrc_pmu->index_id);
+	if (ddrc_pmu->identifier >= HISI_PMU_V2)
+		name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+				      "hisi_sccl%u_ddrc%u_%u",
+				      ddrc_pmu->sccl_id, ddrc_pmu->index_id,
+				      ddrc_pmu->sub_id);
+	else
+		name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+				      "hisi_sccl%u_ddrc%u", ddrc_pmu->sccl_id,
+				      ddrc_pmu->index_id);
+
 	ddrc_pmu->pmu = (struct pmu) {
 		.name		= name,
 		.module		= THIS_MODULE,
@@ -346,7 +528,7 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
 		.start		= hisi_uncore_pmu_start,
 		.stop		= hisi_uncore_pmu_stop,
 		.read		= hisi_uncore_pmu_read,
-		.attr_groups	= hisi_ddrc_pmu_v1_attr_groups,
+		.attr_groups	= ddrc_pmu->pmu_events.attr_groups,
 		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
 	};
 
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h
index c9f180001ab0..7e2dba8841de 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.h
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h
@@ -85,6 +85,8 @@ struct hisi_pmu {
 	void __iomem *base;
 	/* the ID of the PMU modules */
 	u32 index_id;
+	/* For DDRC PMU v2: each DDRC has more than one DMC */
+	u32 sub_id;
 	int num_counters;
 	int counter_bits;
 	/* check event code range */
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 6/8] drivers/perf: hisi: Add support for HiSilicon SLLC PMU driver
  2021-02-03  7:51 [PATCH v2 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
                   ` (4 preceding siblings ...)
  2021-02-03  7:51 ` [PATCH v2 5/8] drivers/perf: hisi: Update DDRC PMU for programable counter Shaokun Zhang
@ 2021-02-03  7:51 ` Shaokun Zhang
  2021-02-03 13:28   ` Mark Rutland
  2021-02-03  7:51 ` [PATCH v2 7/8] drivers/perf: hisi: Add support for HiSilicon PA " Shaokun Zhang
  2021-02-03  7:51 ` [PATCH v2 8/8] docs: perf: Add new description on HiSilicon uncore PMU v2 Shaokun Zhang
  7 siblings, 1 reply; 25+ messages in thread
From: Shaokun Zhang @ 2021-02-03  7:51 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, John Garry, Shaokun Zhang,
	Jonathan Cameron, Will Deacon

HiSilicon's Hip09 is comprised by multi-dies that can be connected by SLLC
module (Skyros Link Layer Controller), its has separate PMU registers which
the driver can program it freely and interrupt is supported to handle
counter overflow. Let's support its driver under the framework of HiSilicon
uncore PMU driver.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: John Garry <john.garry@huawei.com>
Co-developed-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/hisilicon/Makefile               |   2 +-
 drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c | 531 ++++++++++++++++++++++++++
 include/linux/cpuhotplug.h                    |   1 +
 3 files changed, 533 insertions(+), 1 deletion(-)
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c

diff --git a/drivers/perf/hisilicon/Makefile b/drivers/perf/hisilicon/Makefile
index e8377061845f..6600a9d45dd8 100644
--- a/drivers/perf/hisilicon/Makefile
+++ b/drivers/perf/hisilicon/Makefile
@@ -1,3 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o \
-			  hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o
+			  hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o hisi_uncore_sllc_pmu.o
diff --git a/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
new file mode 100644
index 000000000000..5aca4c702181
--- /dev/null
+++ b/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
@@ -0,0 +1,531 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * HiSilicon SLLC uncore Hardware event counters support
+ *
+ * Copyright (C) 2020 Hisilicon Limited
+ * Author: Shaokun Zhang <zhangshaokun@hisilicon.com>
+ *
+ * This code is based on the uncore PMUs like arm-cci and arm-ccn.
+ */
+#include <linux/acpi.h>
+#include <linux/cpuhotplug.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+#include <linux/smp.h>
+
+#include "hisi_uncore_pmu.h"
+
+/* SLLC register definition */
+#define SLLC_INT_MASK			0x0814
+#define SLLC_INT_STATUS			0x0818
+#define SLLC_INT_CLEAR			0x081c
+#define SLLC_PERF_CTRL			0x1c00
+#define SLLC_SRCID_CTRL			0x1c04
+#define SLLC_TGTID_CTRL			0x1c08
+#define SLLC_EVENT_CTRL			0x1c14
+#define SLLC_EVENT_TYPE0		0x1c18
+#define SLLC_VERSION			0x1cf0
+#define SLLC_EVENT_CNT0_L		0x1d00
+
+#define SLLC_EVTYPE_MASK		0xff
+#define SLLC_PERF_CTRL_EN		BIT(0)
+#define SLLC_FILT_EN			BIT(1)
+#define SLLC_TRACETAG_EN		BIT(2)
+#define SLLC_SRCID_EN			BIT(4)
+#define SLLC_SRCID_NONE			0x0
+#define SLLC_TGTID_EN			BIT(5)
+#define SLLC_TGTID_NONE			0x0
+#define SLLC_TGTID_LO_SHIFT		1
+#define SLLC_TGTID_HI_SHIFT		12
+#define SLLC_SRCID_CMD_SHIFT		1
+#define SLLC_SRCID_MSK_SHIFT		12
+#define SLLC_NR_EVENTS			0x80
+
+HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_lo, config1, 10, 0);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_hi, config1, 21, 11);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_cmd, config1, 32, 22);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 43, 33);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 44, 44);
+
+static bool tgtid_is_valid(u32 hi, u32 lo)
+{
+	return lo > 0 && hi >= lo;
+}
+
+static void hisi_sllc_pmu_enable_tracetag(struct perf_event *event)
+{
+	struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
+	u32 tt_en = hisi_get_tracetag_en(event);
+
+	if (tt_en) {
+		u32 val;
+
+		val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
+		val |= SLLC_TRACETAG_EN | SLLC_FILT_EN;
+		writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
+	}
+}
+
+static void hisi_sllc_pmu_disable_tracetag(struct perf_event *event)
+{
+	struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
+	u32 tt_en = hisi_get_tracetag_en(event);
+
+	if (tt_en) {
+		u32 val;
+
+		val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
+		val &= ~(SLLC_TRACETAG_EN | SLLC_FILT_EN);
+		writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
+	}
+}
+
+static void hisi_sllc_pmu_config_tgtid(struct perf_event *event)
+{
+	struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
+	u32 lo = hisi_get_tgtid_lo(event);
+	u32 hi = hisi_get_tgtid_hi(event);
+
+	if (tgtid_is_valid(hi, lo)) {
+		u32 val = (hi << SLLC_TGTID_HI_SHIFT) | (lo << SLLC_TGTID_LO_SHIFT);
+
+		writel(val, sllc_pmu->base + SLLC_TGTID_CTRL);
+
+		/* Enable the tgtid */
+		val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
+		val |= SLLC_TGTID_EN | SLLC_FILT_EN;
+		writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
+	}
+}
+
+static void hisi_sllc_pmu_clear_tgtid(struct perf_event *event)
+{
+	struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
+	u32 lo = hisi_get_tgtid_lo(event);
+	u32 hi = hisi_get_tgtid_hi(event);
+
+	if (tgtid_is_valid(hi, lo)) {
+		u32 val;
+
+		writel(SLLC_TGTID_NONE, sllc_pmu->base + SLLC_TGTID_CTRL);
+		/* Disable the tgtid */
+		val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
+		val &= ~(SLLC_TGTID_EN | SLLC_FILT_EN);
+		writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
+	}
+}
+
+static void hisi_sllc_pmu_config_srcid(struct perf_event *event)
+{
+	struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
+	u32 cmd = hisi_get_srcid_cmd(event);
+
+	if (cmd) {
+		u32 val, msk;
+
+		msk = hisi_get_srcid_msk(event);
+		val = (cmd << SLLC_SRCID_CMD_SHIFT) | (msk << SLLC_SRCID_MSK_SHIFT);
+		writel(val, sllc_pmu->base + SLLC_SRCID_CTRL);
+		/* Enable the srcid */
+		val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
+		val |= SLLC_SRCID_EN | SLLC_FILT_EN;
+		writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
+	}
+}
+
+static void hisi_sllc_pmu_clear_srcid(struct perf_event *event)
+{
+	struct hisi_pmu *sllc_pmu = to_hisi_pmu(event->pmu);
+	u32 cmd = hisi_get_srcid_cmd(event);
+
+	if (cmd) {
+		u32 val;
+
+		writel(SLLC_SRCID_NONE, sllc_pmu->base + SLLC_SRCID_CTRL);
+		/* Disable the srcid */
+		val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
+		val &= ~(SLLC_SRCID_EN | SLLC_FILT_EN);
+		writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
+	}
+}
+
+static void hisi_sllc_pmu_enable_filter(struct perf_event *event)
+{
+	if (event->attr.config1 != 0x0) {
+		hisi_sllc_pmu_enable_tracetag(event);
+		hisi_sllc_pmu_config_srcid(event);
+		hisi_sllc_pmu_config_tgtid(event);
+	}
+}
+
+static void hisi_sllc_pmu_clear_filter(struct perf_event *event)
+{
+	if (event->attr.config1 != 0x0) {
+		hisi_sllc_pmu_disable_tracetag(event);
+		hisi_sllc_pmu_clear_srcid(event);
+		hisi_sllc_pmu_clear_tgtid(event);
+	}
+}
+
+static u32 hisi_sllc_pmu_get_counter_offset(int idx)
+{
+	return (SLLC_EVENT_CNT0_L + idx * 8);
+}
+
+static u64 hisi_sllc_pmu_read_counter(struct hisi_pmu *sllc_pmu,
+				      struct hw_perf_event *hwc)
+{
+	return readq(sllc_pmu->base +
+		     hisi_sllc_pmu_get_counter_offset(hwc->idx));
+}
+
+static void hisi_sllc_pmu_write_counter(struct hisi_pmu *sllc_pmu,
+					struct hw_perf_event *hwc, u64 val)
+{
+	writeq(val, sllc_pmu->base +
+	       hisi_sllc_pmu_get_counter_offset(hwc->idx));
+}
+
+static void hisi_sllc_pmu_write_evtype(struct hisi_pmu *sllc_pmu, int idx,
+				       u32 type)
+{
+	u32 reg, reg_idx, shift, val;
+
+	/*
+	 * Select the appropriate event select register(SLLC_EVENT_TYPE0/1).
+	 * There are 2 event select registers for the 8 hardware counters.
+	 * Event code is 8-bits and for the former 4 hardware counters,
+	 * SLLC_EVENT_TYPE0 is chosen. For the latter 4 hardware counters,
+	 * SLLC_EVENT_TYPE1 is chosen.
+	 */
+	reg = SLLC_EVENT_TYPE0 + rounddown(idx, 4);
+	reg_idx = idx % 4;
+	shift = 8 * reg_idx;
+
+	/* Write event code to SLLC_EVENT_TYPEx Register */
+	val = readl(sllc_pmu->base + reg);
+	val &= ~(SLLC_EVTYPE_MASK << shift);
+	val |= (type << shift);
+	writel(val, sllc_pmu->base + reg);
+}
+
+static void hisi_sllc_pmu_start_counters(struct hisi_pmu *sllc_pmu)
+{
+	u32 val;
+
+	val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
+	val |= SLLC_PERF_CTRL_EN;
+	writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
+}
+
+static void hisi_sllc_pmu_stop_counters(struct hisi_pmu *sllc_pmu)
+{
+	u32 val;
+
+	val = readl(sllc_pmu->base + SLLC_PERF_CTRL);
+	val &= ~(SLLC_PERF_CTRL_EN);
+	writel(val, sllc_pmu->base + SLLC_PERF_CTRL);
+}
+
+static void hisi_sllc_pmu_enable_counter(struct hisi_pmu *sllc_pmu,
+					 struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	val = readl(sllc_pmu->base + SLLC_EVENT_CTRL);
+	val |= 1 << hwc->idx;
+	writel(val, sllc_pmu->base + SLLC_EVENT_CTRL);
+}
+
+static void hisi_sllc_pmu_disable_counter(struct hisi_pmu *sllc_pmu,
+					  struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	val = readl(sllc_pmu->base + SLLC_EVENT_CTRL);
+	val &= ~(1 << hwc->idx);
+	writel(val, sllc_pmu->base + SLLC_EVENT_CTRL);
+}
+
+static void hisi_sllc_pmu_enable_counter_int(struct hisi_pmu *sllc_pmu,
+					     struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	val = readl(sllc_pmu->base + SLLC_INT_MASK);
+	/* Write 0 to enable interrupt */
+	val &= ~(1 << hwc->idx);
+	writel(val, sllc_pmu->base + SLLC_INT_MASK);
+}
+
+static void hisi_sllc_pmu_disable_counter_int(struct hisi_pmu *sllc_pmu,
+					      struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	val = readl(sllc_pmu->base + SLLC_INT_MASK);
+	/* Write 1 to mask interrupt */
+	val |= 1 << hwc->idx;
+	writel(val, sllc_pmu->base + SLLC_INT_MASK);
+}
+
+static u32 hisi_sllc_pmu_get_int_status(struct hisi_pmu *sllc_pmu)
+{
+	return readl(sllc_pmu->base + SLLC_INT_STATUS);
+}
+
+static void hisi_sllc_pmu_clear_int_status(struct hisi_pmu *sllc_pmu, int idx)
+{
+	writel(1 << idx, sllc_pmu->base + SLLC_INT_CLEAR);
+}
+
+static const struct acpi_device_id hisi_sllc_pmu_acpi_match[] = {
+	{ "HISI0263", },
+	{}
+};
+MODULE_DEVICE_TABLE(acpi, hisi_sllc_pmu_acpi_match);
+
+static int hisi_sllc_pmu_init_data(struct platform_device *pdev,
+				   struct hisi_pmu *sllc_pmu)
+{
+	/*
+	 * Use the SCCL_ID and the index ID to identify the SLLC PMU,
+	 * while SCCL_ID is from MPIDR_EL1 by CPU.
+	 */
+	if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id",
+				     &sllc_pmu->sccl_id)) {
+		dev_err(&pdev->dev, "Cannot read sccl-id!\n");
+		return -EINVAL;
+	}
+
+	if (device_property_read_u32(&pdev->dev, "hisilicon,idx-id",
+				     &sllc_pmu->index_id)) {
+		dev_err(&pdev->dev, "Cannot read idx-id!\n");
+		return -EINVAL;
+	}
+
+	/* SLLC PMUs only share the same SCCL */
+	sllc_pmu->ccl_id = -1;
+
+	sllc_pmu->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(sllc_pmu->base)) {
+		dev_err(&pdev->dev, "ioremap failed for sllc_pmu resource.\n");
+		return PTR_ERR(sllc_pmu->base);
+	}
+
+	sllc_pmu->identifier = readl(sllc_pmu->base + SLLC_VERSION);
+
+	return 0;
+}
+
+static struct attribute *hisi_sllc_pmu_v2_format_attr[] = {
+	HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
+	HISI_PMU_FORMAT_ATTR(tgtid_low, "config1:0-10"),
+	HISI_PMU_FORMAT_ATTR(tgtid_high, "config1:11-21"),
+	HISI_PMU_FORMAT_ATTR(srcid_cmd, "config1:22-32"),
+	HISI_PMU_FORMAT_ATTR(srcid_mask, "config1:33-43"),
+	HISI_PMU_FORMAT_ATTR(tracetag_en, "config1:44"),
+	NULL
+};
+
+static const struct attribute_group hisi_sllc_pmu_v2_format_group = {
+	.name = "format",
+	.attrs = hisi_sllc_pmu_v2_format_attr,
+};
+
+static struct attribute *hisi_sllc_pmu_v2_events_attr[] = {
+	HISI_PMU_EVENT_ATTR(rx_req,             0x30),
+	HISI_PMU_EVENT_ATTR(rx_data,            0x31),
+	HISI_PMU_EVENT_ATTR(tx_req,             0x34),
+	HISI_PMU_EVENT_ATTR(tx_data,            0x35),
+	HISI_PMU_EVENT_ATTR(cycles,             0x09),
+	NULL
+};
+
+static const struct attribute_group hisi_sllc_pmu_v2_events_group = {
+	.name = "events",
+	.attrs = hisi_sllc_pmu_v2_events_attr,
+};
+
+static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
+
+static struct attribute *hisi_sllc_pmu_cpumask_attrs[] = {
+	&dev_attr_cpumask.attr,
+	NULL
+};
+
+static const struct attribute_group hisi_sllc_pmu_cpumask_attr_group = {
+	.attrs = hisi_sllc_pmu_cpumask_attrs,
+};
+
+static struct device_attribute hisi_sllc_pmu_identifier_attr =
+	__ATTR(identifier, 0444, hisi_uncore_pmu_identifier_attr_show, NULL);
+
+static struct attribute *hisi_sllc_pmu_identifier_attrs[] = {
+	&hisi_sllc_pmu_identifier_attr.attr,
+	NULL
+};
+
+static struct attribute_group hisi_sllc_pmu_identifier_group = {
+	.attrs = hisi_sllc_pmu_identifier_attrs,
+};
+
+static const struct attribute_group *hisi_sllc_pmu_v2_attr_groups[] = {
+	&hisi_sllc_pmu_v2_format_group,
+	&hisi_sllc_pmu_v2_events_group,
+	&hisi_sllc_pmu_cpumask_attr_group,
+	&hisi_sllc_pmu_identifier_group,
+	NULL
+};
+
+static const struct hisi_uncore_ops hisi_uncore_sllc_ops = {
+	.write_evtype		= hisi_sllc_pmu_write_evtype,
+	.get_event_idx		= hisi_uncore_pmu_get_event_idx,
+	.start_counters		= hisi_sllc_pmu_start_counters,
+	.stop_counters		= hisi_sllc_pmu_stop_counters,
+	.enable_counter		= hisi_sllc_pmu_enable_counter,
+	.disable_counter	= hisi_sllc_pmu_disable_counter,
+	.enable_counter_int	= hisi_sllc_pmu_enable_counter_int,
+	.disable_counter_int	= hisi_sllc_pmu_disable_counter_int,
+	.write_counter		= hisi_sllc_pmu_write_counter,
+	.read_counter		= hisi_sllc_pmu_read_counter,
+	.get_int_status		= hisi_sllc_pmu_get_int_status,
+	.clear_int_status	= hisi_sllc_pmu_clear_int_status,
+	.enable_filter		= hisi_sllc_pmu_enable_filter,
+	.disable_filter		= hisi_sllc_pmu_clear_filter,
+};
+
+static int hisi_sllc_pmu_dev_probe(struct platform_device *pdev,
+				   struct hisi_pmu *sllc_pmu)
+{
+	int ret;
+
+	ret = hisi_sllc_pmu_init_data(pdev, sllc_pmu);
+	if (ret)
+		return ret;
+
+	ret = hisi_uncore_pmu_init_irq(sllc_pmu, pdev);
+	if (ret)
+		return ret;
+
+	sllc_pmu->pmu_events.attr_groups = hisi_sllc_pmu_v2_attr_groups;
+	sllc_pmu->ops = &hisi_uncore_sllc_ops;
+	sllc_pmu->check_event = SLLC_NR_EVENTS;
+	sllc_pmu->counter_bits = 64;
+	sllc_pmu->num_counters = 8;
+	sllc_pmu->dev = &pdev->dev;
+	sllc_pmu->on_cpu = -1;
+
+	return 0;
+}
+
+static int hisi_sllc_pmu_probe(struct platform_device *pdev)
+{
+	struct hisi_pmu *sllc_pmu;
+	char *name;
+	int ret;
+
+	sllc_pmu = devm_kzalloc(&pdev->dev, sizeof(*sllc_pmu), GFP_KERNEL);
+	if (!sllc_pmu)
+		return -ENOMEM;
+
+	ret = hisi_sllc_pmu_dev_probe(pdev, sllc_pmu);
+	if (ret)
+		return ret;
+
+	name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_sllc%u",
+			      sllc_pmu->sccl_id, sllc_pmu->index_id);
+	if (!name)
+		return -ENOMEM;
+
+	ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
+				       &sllc_pmu->node);
+	if (ret) {
+		dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
+		return ret;
+	}
+
+	sllc_pmu->pmu = (struct pmu) {
+		.module		= THIS_MODULE,
+		.task_ctx_nr	= perf_invalid_context,
+		.event_init	= hisi_uncore_pmu_event_init,
+		.pmu_enable	= hisi_uncore_pmu_enable,
+		.pmu_disable	= hisi_uncore_pmu_disable,
+		.add		= hisi_uncore_pmu_add,
+		.del		= hisi_uncore_pmu_del,
+		.start		= hisi_uncore_pmu_start,
+		.stop		= hisi_uncore_pmu_stop,
+		.read		= hisi_uncore_pmu_read,
+		.attr_groups    = sllc_pmu->pmu_events.attr_groups,
+		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
+	};
+
+	ret = perf_pmu_register(&sllc_pmu->pmu, name, -1);
+	if (ret) {
+		dev_err(sllc_pmu->dev, "PMU register failed, ret = %d\n", ret);
+		cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
+					    &sllc_pmu->node);
+		irq_set_affinity_hint(sllc_pmu->irq, NULL);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, sllc_pmu);
+
+	return ret;
+}
+
+static int hisi_sllc_pmu_remove(struct platform_device *pdev)
+{
+	struct hisi_pmu *sllc_pmu = platform_get_drvdata(pdev);
+
+	perf_pmu_unregister(&sllc_pmu->pmu);
+	cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
+					    &sllc_pmu->node);
+	irq_set_affinity_hint(sllc_pmu->irq, NULL);
+
+	return 0;
+}
+
+static struct platform_driver hisi_sllc_pmu_driver = {
+	.driver = {
+		.name = "hisi_sllc_pmu",
+		.acpi_match_table = hisi_sllc_pmu_acpi_match,
+		.suppress_bind_attrs = true,
+	},
+	.probe = hisi_sllc_pmu_probe,
+	.remove = hisi_sllc_pmu_remove,
+};
+
+static int __init hisi_sllc_pmu_module_init(void)
+{
+	int ret;
+
+	ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
+				      "AP_PERF_ARM_HISI_SLLC_ONLINE",
+				      hisi_uncore_pmu_online_cpu,
+				      hisi_uncore_pmu_offline_cpu);
+	if (ret) {
+		pr_err("SLLC PMU: cpuhp state setup failed, ret = %d\n", ret);
+		return ret;
+	}
+
+	ret = platform_driver_register(&hisi_sllc_pmu_driver);
+	if (ret)
+		cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE);
+
+	return ret;
+}
+module_init(hisi_sllc_pmu_module_init);
+
+static void __exit hisi_sllc_pmu_module_exit(void)
+{
+	platform_driver_unregister(&hisi_sllc_pmu_driver);
+	cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE);
+}
+module_exit(hisi_sllc_pmu_module_exit);
+
+MODULE_DESCRIPTION("HiSilicon Skyros Link Layer Controller uncore PMU driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>");
+MODULE_AUTHOR("Qi Liu <liuqi115@huawei.com>");
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 113f51f4c9e7..ac2dfcc9521e 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -174,6 +174,7 @@ enum cpuhp_state {
 	CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
 	CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE,
 	CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
+	CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
 	CPUHP_AP_PERF_ARM_L2X0_ONLINE,
 	CPUHP_AP_PERF_ARM_QCOM_L2_ONLINE,
 	CPUHP_AP_PERF_ARM_QCOM_L3_ONLINE,
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 7/8] drivers/perf: hisi: Add support for HiSilicon PA PMU driver
  2021-02-03  7:51 [PATCH v2 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
                   ` (5 preceding siblings ...)
  2021-02-03  7:51 ` [PATCH v2 6/8] drivers/perf: hisi: Add support for HiSilicon SLLC PMU driver Shaokun Zhang
@ 2021-02-03  7:51 ` Shaokun Zhang
  2021-02-03 13:43   ` Mark Rutland
  2021-02-03  7:51 ` [PATCH v2 8/8] docs: perf: Add new description on HiSilicon uncore PMU v2 Shaokun Zhang
  7 siblings, 1 reply; 25+ messages in thread
From: Shaokun Zhang @ 2021-02-03  7:51 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, John Garry, Shaokun Zhang,
	Jonathan Cameron, Will Deacon

On HiSilicon Hip09 platform, there is a PA (Protocol Adapter) module on
each chip SICL (Super I/O Cluster) which incorporates three Hydra interface
and facilitates the cache coherency between the dies on the chip. While PA
uncore PMU model is the same as other Hip09 PMU modules and many PMU events
are supported. Let's support the PMU driver using the HiSilicon uncore PMU
framework.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: John Garry <john.garry@huawei.com>
Co-developed-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 drivers/perf/hisilicon/Makefile             |   3 +-
 drivers/perf/hisilicon/hisi_uncore_pa_pmu.c | 500 ++++++++++++++++++++++++++++
 include/linux/cpuhotplug.h                  |   1 +
 3 files changed, 503 insertions(+), 1 deletion(-)
 create mode 100644 drivers/perf/hisilicon/hisi_uncore_pa_pmu.c

diff --git a/drivers/perf/hisilicon/Makefile b/drivers/perf/hisilicon/Makefile
index 6600a9d45dd8..7643c9f93e36 100644
--- a/drivers/perf/hisilicon/Makefile
+++ b/drivers/perf/hisilicon/Makefile
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o \
-			  hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o hisi_uncore_sllc_pmu.o
+			  hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o hisi_uncore_sllc_pmu.o \
+			  hisi_uncore_pa_pmu.o
diff --git a/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
new file mode 100644
index 000000000000..8f9c5299a7bd
--- /dev/null
+++ b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * HiSilicon PA uncore Hardware event counters support
+ *
+ * Copyright (C) 2020 HiSilicon Limited
+ * Author: Shaokun Zhang <zhangshaokun@hisilicon.com>
+ *
+ * This code is based on the uncore PMUs like arm-cci and arm-ccn.
+ */
+#include <linux/acpi.h>
+#include <linux/cpuhotplug.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+#include <linux/smp.h>
+
+#include "hisi_uncore_pmu.h"
+
+/* PA register definition */
+#define PA_PERF_CTRL			0x1c00
+#define PA_EVENT_CTRL			0x1c04
+#define PA_TT_CTRL			0x1c08
+#define PA_TGTID_CTRL			0x1c14
+#define PA_SRCID_CTRL			0x1c18
+#define PA_INT_MASK			0x1c70
+#define PA_INT_STATUS			0x1c78
+#define PA_INT_CLEAR			0x1c7c
+#define PA_EVENT_TYPE0			0x1c80
+#define PA_PMU_VERSION			0x1cf0
+#define PA_EVENT_CNT0_L			0x1f00
+
+#define PA_EVTYPE_MASK			0xff
+#define PA_NR_COUNTERS			0x8
+#define PA_PERF_CTRL_EN			BIT(0)
+#define PA_TRACETAG_EN			BIT(4)
+#define PA_TGTID_EN			BIT(11)
+#define PA_SRCID_EN			BIT(11)
+#define PA_TGTID_NONE			0
+#define PA_SRCID_NONE			0
+#define PA_TGTID_MASK_SHIFT		12
+#define PA_SRCID_MASK_SHIFT		12
+
+HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_cmd, config1, 10, 0);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_msk, config1, 21, 11);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_cmd, config1, 32, 22);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 43, 33);
+HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 44, 44);
+
+static void hisi_pa_pmu_enable_tracetag(struct perf_event *event)
+{
+	struct hisi_pmu *pa_pmu = to_hisi_pmu(event->pmu);
+	u32 tt_en = hisi_get_tracetag_en(event);
+
+	if (tt_en) {
+		u32 val;
+
+		val = readl(pa_pmu->base + PA_TT_CTRL);
+		val |= PA_TRACETAG_EN;
+		writel(val, pa_pmu->base + PA_TT_CTRL);
+	}
+}
+
+static void hisi_pa_pmu_clear_tracetag(struct perf_event *event)
+{
+	struct hisi_pmu *pa_pmu = to_hisi_pmu(event->pmu);
+	u32 tt_en = hisi_get_tracetag_en(event);
+
+	if (tt_en) {
+		u32 val;
+
+		val = readl(pa_pmu->base + PA_TT_CTRL);
+		val &= ~PA_TRACETAG_EN;
+		writel(val, pa_pmu->base + PA_TT_CTRL);
+	}
+}
+
+static void hisi_pa_pmu_config_tgtid(struct perf_event *event)
+{
+	struct hisi_pmu *pa_pmu = to_hisi_pmu(event->pmu);
+	u32 cmd = hisi_get_tgtid_cmd(event);
+
+	if (cmd) {
+		u32 msk = hisi_get_tgtid_msk(event);
+		u32 val = cmd | PA_TGTID_EN | (msk << PA_TGTID_MASK_SHIFT);
+
+		writel(val, pa_pmu->base + PA_TGTID_CTRL);
+	}
+}
+
+static void hisi_pa_pmu_clear_tgtid(struct perf_event *event)
+{
+	struct hisi_pmu *pa_pmu = to_hisi_pmu(event->pmu);
+	u32 cmd = hisi_get_tgtid_cmd(event);
+
+	if (cmd)
+		writel(PA_TGTID_NONE, pa_pmu->base + PA_TGTID_CTRL);
+}
+
+static void hisi_pa_pmu_config_srcid(struct perf_event *event)
+{
+	struct hisi_pmu *pa_pmu = to_hisi_pmu(event->pmu);
+	u32 cmd = hisi_get_srcid_cmd(event);
+
+	if (cmd) {
+		u32 msk = hisi_get_srcid_msk(event);
+		u32 val = cmd | PA_SRCID_EN | (msk << PA_SRCID_MASK_SHIFT);
+
+		writel(val, pa_pmu->base + PA_SRCID_CTRL);
+	}
+}
+
+static void hisi_pa_pmu_clear_srcid(struct perf_event *event)
+{
+	struct hisi_pmu *pa_pmu = to_hisi_pmu(event->pmu);
+	u32 cmd = hisi_get_srcid_cmd(event);
+
+	if (cmd)
+		writel(PA_SRCID_NONE, pa_pmu->base + PA_SRCID_CTRL);
+}
+
+static void hisi_pa_pmu_enable_filter(struct perf_event *event)
+{
+	if (event->attr.config1 != 0x0) {
+		hisi_pa_pmu_enable_tracetag(event);
+		hisi_pa_pmu_config_srcid(event);
+		hisi_pa_pmu_config_tgtid(event);
+	}
+}
+
+static void hisi_pa_pmu_disable_filter(struct perf_event *event)
+{
+	if (event->attr.config1 != 0x0) {
+		hisi_pa_pmu_clear_tgtid(event);
+		hisi_pa_pmu_clear_srcid(event);
+		hisi_pa_pmu_clear_tracetag(event);
+	}
+}
+
+static u32 hisi_pa_pmu_get_counter_offset(int idx)
+{
+	return (PA_EVENT_CNT0_L + idx * 8);
+}
+
+static u64 hisi_pa_pmu_read_counter(struct hisi_pmu *pa_pmu,
+				    struct hw_perf_event *hwc)
+{
+	return readq(pa_pmu->base + hisi_pa_pmu_get_counter_offset(hwc->idx));
+}
+
+static void hisi_pa_pmu_write_counter(struct hisi_pmu *pa_pmu,
+				      struct hw_perf_event *hwc, u64 val)
+{
+	writeq(val, pa_pmu->base + hisi_pa_pmu_get_counter_offset(hwc->idx));
+}
+
+static void hisi_pa_pmu_write_evtype(struct hisi_pmu *pa_pmu, int idx,
+				     u32 type)
+{
+	u32 reg, reg_idx, shift, val;
+
+	/*
+	 * Select the appropriate event select register(PA_EVENT_TYPE0/1).
+	 * There are 2 event select registers for the 8 hardware counters.
+	 * Event code is 8-bits and for the former 4 hardware counters,
+	 * PA_EVENT_TYPE0 is chosen. For the latter 4 hardware counters,
+	 * PA_EVENT_TYPE1 is chosen.
+	 */
+	reg = PA_EVENT_TYPE0 + rounddown(idx, 4);
+	reg_idx = idx % 4;
+	shift = 8 * reg_idx;
+
+	/* Write event code to pa_EVENT_TYPEx Register */
+	val = readl(pa_pmu->base + reg);
+	val &= ~(PA_EVTYPE_MASK << shift);
+	val |= (type << shift);
+	writel(val, pa_pmu->base + reg);
+}
+
+static void hisi_pa_pmu_start_counters(struct hisi_pmu *pa_pmu)
+{
+	u32 val;
+
+	val = readl(pa_pmu->base + PA_PERF_CTRL);
+	val |= PA_PERF_CTRL_EN;
+	writel(val, pa_pmu->base + PA_PERF_CTRL);
+}
+
+static void hisi_pa_pmu_stop_counters(struct hisi_pmu *pa_pmu)
+{
+	u32 val;
+
+	val = readl(pa_pmu->base + PA_PERF_CTRL);
+	val &= ~(PA_PERF_CTRL_EN);
+	writel(val, pa_pmu->base + PA_PERF_CTRL);
+}
+
+static void hisi_pa_pmu_enable_counter(struct hisi_pmu *pa_pmu,
+				       struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	/* Enable counter index in PA_EVENT_CTRL register */
+	val = readl(pa_pmu->base + PA_EVENT_CTRL);
+	val |= 1 << hwc->idx;
+	writel(val, pa_pmu->base + PA_EVENT_CTRL);
+}
+
+static void hisi_pa_pmu_disable_counter(struct hisi_pmu *pa_pmu,
+					struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	/* Clear counter index in PA_EVENT_CTRL register */
+	val = readl(pa_pmu->base + PA_EVENT_CTRL);
+	val &= ~(1 << hwc->idx);
+	writel(val, pa_pmu->base + PA_EVENT_CTRL);
+}
+
+static void hisi_pa_pmu_enable_counter_int(struct hisi_pmu *pa_pmu,
+					   struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	/* Write 0 to enable interrupt */
+	val = readl(pa_pmu->base + PA_INT_MASK);
+	val &= ~(1 << hwc->idx);
+	writel(val, pa_pmu->base + PA_INT_MASK);
+}
+
+static void hisi_pa_pmu_disable_counter_int(struct hisi_pmu *pa_pmu,
+					    struct hw_perf_event *hwc)
+{
+	u32 val;
+
+	/* Write 1 to mask interrupt */
+	val = readl(pa_pmu->base + PA_INT_MASK);
+	val |= 1 << hwc->idx;
+	writel(val, pa_pmu->base + PA_INT_MASK);
+}
+
+static u32 hisi_pa_pmu_get_int_status(struct hisi_pmu *pa_pmu)
+{
+	return readl(pa_pmu->base + PA_INT_STATUS);
+}
+
+static void hisi_pa_pmu_clear_int_status(struct hisi_pmu *pa_pmu, int idx)
+{
+	writel(1 << idx, pa_pmu->base + PA_INT_CLEAR);
+}
+
+static const struct acpi_device_id hisi_pa_pmu_acpi_match[] = {
+	{ "HISI0273", },
+	{}
+};
+MODULE_DEVICE_TABLE(acpi, hisi_pa_pmu_acpi_match);
+
+static int hisi_pa_pmu_init_data(struct platform_device *pdev,
+				   struct hisi_pmu *pa_pmu)
+{
+	/*
+	 * Use the SCCL_ID and the index ID to identify the PA PMU,
+	 * while SCCL_ID is the nearst SCCL_ID from this SICL and
+	 * CPU core is chosen from this SCCL to manage this PMU.
+	 */
+	if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id",
+				     &pa_pmu->sccl_id)) {
+		dev_err(&pdev->dev, "Cannot read sccl-id!\n");
+		return -EINVAL;
+	}
+
+	if (device_property_read_u32(&pdev->dev, "hisilicon,idx-id",
+				     &pa_pmu->index_id)) {
+		dev_err(&pdev->dev, "Cannot read idx-id!\n");
+		return -EINVAL;
+	}
+
+	pa_pmu->ccl_id = -1;
+
+	pa_pmu->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(pa_pmu->base)) {
+		dev_err(&pdev->dev, "ioremap failed for pa_pmu resource.\n");
+		return PTR_ERR(pa_pmu->base);
+	}
+
+	pa_pmu->identifier = readl(pa_pmu->base + PA_PMU_VERSION);
+
+	return 0;
+}
+
+static struct attribute *hisi_pa_pmu_v2_format_attr[] = {
+	HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
+	HISI_PMU_FORMAT_ATTR(tgtid_cmd, "config1:0-10"),
+	HISI_PMU_FORMAT_ATTR(tgtid_msk, "config1:11-21"),
+	HISI_PMU_FORMAT_ATTR(srcid_cmd, "config1:22-32"),
+	HISI_PMU_FORMAT_ATTR(srcid_msk, "config1:33-43"),
+	HISI_PMU_FORMAT_ATTR(tracetag_en, "config1:44"),
+	NULL,
+};
+
+static const struct attribute_group hisi_pa_pmu_v2_format_group = {
+	.name = "format",
+	.attrs = hisi_pa_pmu_v2_format_attr,
+};
+
+static struct attribute *hisi_pa_pmu_v2_events_attr[] = {
+	HISI_PMU_EVENT_ATTR(rx_req,		0x40),
+	HISI_PMU_EVENT_ATTR(tx_req,             0x5c),
+	HISI_PMU_EVENT_ATTR(cycle,		0x78),
+	NULL
+};
+
+static const struct attribute_group hisi_pa_pmu_v2_events_group = {
+	.name = "events",
+	.attrs = hisi_pa_pmu_v2_events_attr,
+};
+
+static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
+
+static struct attribute *hisi_pa_pmu_cpumask_attrs[] = {
+	&dev_attr_cpumask.attr,
+	NULL
+};
+
+static const struct attribute_group hisi_pa_pmu_cpumask_attr_group = {
+	.attrs = hisi_pa_pmu_cpumask_attrs,
+};
+
+static struct device_attribute hisi_pa_pmu_identifier_attr =
+	__ATTR(identifier, 0444, hisi_uncore_pmu_identifier_attr_show, NULL);
+
+static struct attribute *hisi_pa_pmu_identifier_attrs[] = {
+	&hisi_pa_pmu_identifier_attr.attr,
+	NULL
+};
+
+static struct attribute_group hisi_pa_pmu_identifier_group = {
+	.attrs = hisi_pa_pmu_identifier_attrs,
+};
+
+static const struct attribute_group *hisi_pa_pmu_v2_attr_groups[] = {
+	&hisi_pa_pmu_v2_format_group,
+	&hisi_pa_pmu_v2_events_group,
+	&hisi_pa_pmu_cpumask_attr_group,
+	&hisi_pa_pmu_identifier_group,
+	NULL
+};
+
+static const struct hisi_uncore_ops hisi_uncore_pa_ops = {
+	.write_evtype		= hisi_pa_pmu_write_evtype,
+	.get_event_idx		= hisi_uncore_pmu_get_event_idx,
+	.start_counters		= hisi_pa_pmu_start_counters,
+	.stop_counters		= hisi_pa_pmu_stop_counters,
+	.enable_counter		= hisi_pa_pmu_enable_counter,
+	.disable_counter	= hisi_pa_pmu_disable_counter,
+	.enable_counter_int	= hisi_pa_pmu_enable_counter_int,
+	.disable_counter_int	= hisi_pa_pmu_disable_counter_int,
+	.write_counter		= hisi_pa_pmu_write_counter,
+	.read_counter		= hisi_pa_pmu_read_counter,
+	.get_int_status		= hisi_pa_pmu_get_int_status,
+	.clear_int_status	= hisi_pa_pmu_clear_int_status,
+	.enable_filter		= hisi_pa_pmu_enable_filter,
+	.disable_filter		= hisi_pa_pmu_disable_filter,
+};
+
+static int hisi_pa_pmu_dev_probe(struct platform_device *pdev,
+				 struct hisi_pmu *pa_pmu)
+{
+	int ret;
+
+	ret = hisi_pa_pmu_init_data(pdev, pa_pmu);
+	if (ret)
+		return ret;
+
+	ret = hisi_uncore_pmu_init_irq(pa_pmu, pdev);
+	if (ret)
+		return ret;
+
+	pa_pmu->pmu_events.attr_groups = hisi_pa_pmu_v2_attr_groups;
+	pa_pmu->num_counters = PA_NR_COUNTERS;
+	pa_pmu->ops = &hisi_uncore_pa_ops;
+	pa_pmu->check_event = 0xB0;
+	pa_pmu->counter_bits = 64;
+	pa_pmu->dev = &pdev->dev;
+	pa_pmu->on_cpu = -1;
+
+	return 0;
+}
+
+static int hisi_pa_pmu_probe(struct platform_device *pdev)
+{
+	struct hisi_pmu *pa_pmu;
+	char *name;
+	int ret;
+
+	pa_pmu = devm_kzalloc(&pdev->dev, sizeof(*pa_pmu), GFP_KERNEL);
+	if (!pa_pmu)
+		return -ENOMEM;
+
+	ret = hisi_pa_pmu_dev_probe(pdev, pa_pmu);
+	if (ret)
+		return ret;
+	/*
+	 * PA is attached in SICL and the CPU core is chosen to manage this
+	 * PMU which is the nearest SCCL, while its SCCL_ID is greater than
+	 * one with the SICL_ID.
+	 */
+	name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sicl%u_pa%u",
+			      pa_pmu->sccl_id - 1, pa_pmu->index_id);
+	if (!name)
+		return -ENOMEM;
+
+	ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
+				       &pa_pmu->node);
+	if (ret) {
+		dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
+		return ret;
+	}
+
+	pa_pmu->pmu = (struct pmu) {
+		.module		= THIS_MODULE,
+		.task_ctx_nr	= perf_invalid_context,
+		.event_init	= hisi_uncore_pmu_event_init,
+		.pmu_enable	= hisi_uncore_pmu_enable,
+		.pmu_disable	= hisi_uncore_pmu_disable,
+		.add		= hisi_uncore_pmu_add,
+		.del		= hisi_uncore_pmu_del,
+		.start		= hisi_uncore_pmu_start,
+		.stop		= hisi_uncore_pmu_stop,
+		.read		= hisi_uncore_pmu_read,
+		.attr_groups    = pa_pmu->pmu_events.attr_groups,
+		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
+	};
+
+	ret = perf_pmu_register(&pa_pmu->pmu, name, -1);
+	if (ret) {
+		dev_err(pa_pmu->dev, "PMU register failed, ret = %d\n", ret);
+		cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
+					    &pa_pmu->node);
+		irq_set_affinity_hint(pa_pmu->irq, NULL);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, pa_pmu);
+	return ret;
+}
+
+static int hisi_pa_pmu_remove(struct platform_device *pdev)
+{
+	struct hisi_pmu *pa_pmu = platform_get_drvdata(pdev);
+
+	perf_pmu_unregister(&pa_pmu->pmu);
+	cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
+					    &pa_pmu->node);
+	irq_set_affinity_hint(pa_pmu->irq, NULL);
+
+	return 0;
+}
+
+static struct platform_driver hisi_pa_pmu_driver = {
+	.driver = {
+		.name = "hisi_pa_pmu",
+		.acpi_match_table = hisi_pa_pmu_acpi_match,
+		.suppress_bind_attrs = true,
+	},
+	.probe = hisi_pa_pmu_probe,
+	.remove = hisi_pa_pmu_remove,
+};
+
+static int __init hisi_pa_pmu_module_init(void)
+{
+	int ret;
+
+	ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
+				      "AP_PERF_ARM_HISI_PA_ONLINE",
+				      hisi_uncore_pmu_online_cpu,
+				      hisi_uncore_pmu_offline_cpu);
+	if (ret) {
+		pr_err("PA PMU: cpuhp state setup failed, ret = %d\n", ret);
+		return ret;
+	}
+
+	ret = platform_driver_register(&hisi_pa_pmu_driver);
+	if (ret)
+		cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE);
+
+	return ret;
+}
+module_init(hisi_pa_pmu_module_init);
+
+static void __exit hisi_pa_pmu_module_exit(void)
+{
+	platform_driver_unregister(&hisi_pa_pmu_driver);
+	cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE);
+}
+module_exit(hisi_pa_pmu_module_exit);
+
+MODULE_DESCRIPTION("HiSilicon Protocol Adapter uncore PMU driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>");
+MODULE_AUTHOR("Qi Liu <liuqi115@huawei.com>");
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index ac2dfcc9521e..415de2ded378 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -174,6 +174,7 @@ enum cpuhp_state {
 	CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
 	CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE,
 	CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
+	CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
 	CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
 	CPUHP_AP_PERF_ARM_L2X0_ONLINE,
 	CPUHP_AP_PERF_ARM_QCOM_L2_ONLINE,
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 8/8] docs: perf: Add new description on HiSilicon uncore PMU v2
  2021-02-03  7:51 [PATCH v2 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
                   ` (6 preceding siblings ...)
  2021-02-03  7:51 ` [PATCH v2 7/8] drivers/perf: hisi: Add support for HiSilicon PA " Shaokun Zhang
@ 2021-02-03  7:51 ` Shaokun Zhang
  7 siblings, 0 replies; 25+ messages in thread
From: Shaokun Zhang @ 2021-02-03  7:51 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Qi Liu, John Garry, Shaokun Zhang,
	Jonathan Cameron, Will Deacon

Some news functions are added on HiSilicon uncore PMUs. Document them
to provide guidance on how to use them.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: John Garry <john.garry@huawei.com>
Co-developed-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 Documentation/admin-guide/perf/hisi-pmu.rst | 54 +++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/Documentation/admin-guide/perf/hisi-pmu.rst b/Documentation/admin-guide/perf/hisi-pmu.rst
index 404a5c3d9d00..47aadbcda301 100644
--- a/Documentation/admin-guide/perf/hisi-pmu.rst
+++ b/Documentation/admin-guide/perf/hisi-pmu.rst
@@ -53,6 +53,60 @@ Example usage of perf::
   $# perf stat -a -e hisi_sccl3_l3c0/rd_hit_cpipe/ sleep 5
   $# perf stat -a -e hisi_sccl3_l3c0/config=0x02/ sleep 5
 
+For HiSilicon uncore PMU v2 whose identifier is 0x30, the topology is the same
+as PMU v1, but some new functions are added to the hardware.
+
+(a) L3C PMU supports filtering by core/thread within the cluster which can be
+specified as a bitmap.
+  $# perf stat -a -e hisi_sccl3_l3c0/config=0x02,tt_core=0x3/ sleep 5
+This will only count the operations from core/thread 0 and 1 in this cluster.
+
+(b) Tracetag allow the user to chose to count only read, write or atomic
+operations via the tt_req parameeter in perf. The default value counts all
+operations. tt_req is 3bits, 3'b100 represents read operations, 3'b101
+represents write operations, 3'b110 represents atomic store operations and
+3'b111 represents atomic non-store operations, other values are reserved.
+  $# perf stat -a -e hisi_sccl3_l3c0/config=0x02,tt_req=0x4/ sleep 5
+This will only count the read operations in this cluster.
+
+(c) Datasrc allows the user to check where the data comes from. It is 5 bits.
+Some important codes are as follows:
+5'b00001: comes from L3C in this die;
+5'b01000: comes from L3C in the cross-die;
+5'b01001: comes from L3C which is in another socket;
+5'b01110: comes from the local DDR;
+5'b01111: comes from the cross-die DDR;
+5'b10000: comes from cross-socket DDR;
+etc, it is mainly helpful to find that the data source is nearest from the CPU
+cores. If datasrc is used in the multi-chips, the ds_skt shall be configured in
+perf command.
+  $# perf stat -a -e hisi_sccl3_l3c0/config=0xb9,ds_cfg=0xE/,
+  hisi_sccl3_l3c0/config=0xb9,ds_cfg=0xF/ sleep 5
+
+(d)Some HiSilicon SoCs encapsulate multiple CPU and IO dies.  Each CPU die contains
+many Compute Clusters (CCLs). The I/O dies are called Super I/O clusters (SICL)
+containing multiple I/O clusters (ICLs).   Each CCL/ICL in the SoC has a
+unique master-ID.  The uncore PMU can filter by specified master-ID or
+combination of master-IDs.  The master-ID is 14bits of which the lower 3-bits
+specify the individual core within a CCL. The upper 11 bits include a
+6-bit SCCL-ID and 5-bit CCL/ICL-ID.
+The user may filter by a specific CCL/ICL through the mstid_cmd and mstid_msk
+parameters. A set bit in mstid_mask means the PMU will not check the bit when
+matching against the mstid_cmd.
+
+(e) For new uncore PMU, SLLC and PA, normal PMU events are supported and other
+new functions are also added simultaneously, such as, tgt_id and src_id can
+be determined by the requirements which are also 11-bits including SCCL-ID and
+CCL/ICL-ID. For I/O die, the ICL-ID is followed by:
+5'b00000: I/O_MGMT_ICL;
+5'b00001: Network_ICL;
+5'b00011: HAC_ICL;
+5'b10000: PCIe_ICL;
+
+If all of these options are disabled, it can works by the default value that
+doesn't distinguish the filter condition and ID information and will return
+the total counter values in the PMU counters.
+
 The current driver does not support sampling. So "perf record" is unsupported.
 Also attach to a task is unsupported as the events are all uncore.
 
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 1/8] drivers/perf: hisi: Refactor code for more uncore PMUs
  2021-02-03  7:51 ` [PATCH v2 1/8] drivers/perf: hisi: Refactor code for more uncore PMUs Shaokun Zhang
@ 2021-02-03 12:53   ` Mark Rutland
  2021-02-04  3:38     ` Shaokun Zhang
  0 siblings, 1 reply; 25+ messages in thread
From: Mark Rutland @ 2021-02-03 12:53 UTC (permalink / raw)
  To: Shaokun Zhang
  Cc: Qi Liu, John Garry, Will Deacon, linux-arm-kernel, Jonathan Cameron

On Wed, Feb 03, 2021 at 03:51:01PM +0800, Shaokun Zhang wrote:
> On HiSilicon uncore PMU drivers, interrupt handling function and interrupt
> registration function are very similar in differents PMU modules. Let's
> refactor the frame, use a callback function for the HW accessors.

It would be helpful if the commit message could briefly elaborate on
the refactoring, e.g.

It would be helpful if the commit message could briefly explain the
refactoring, e.g.

| Two new callbacks are added:
|
| * hisi_uncore_ops::get_int_status returns a bitmap of events which
|   have overflowed and raised an interrupt
|
| * hisi_uncore_ops::clear_int_status clears the overflow status for a
|   specific event
|
| ... and are used by a common IRQ handler, hisi_uncore_pmu_isr().

The refactoring itself looks good to me.

I also see that sanity-checks are removed from the read_counter() and
write_counter() functions, but the commit message doesn't mention that
at all. It looks like that should be a separate change.

Thanks,
Mark.

> 
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Will Deacon <will@kernel.org>
> Cc: John Garry <john.garry@huawei.com>
> Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> Reviewed-by: John Garry <john.garry@huawei.com>
> Co-developed-by: Qi Liu <liuqi115@huawei.com>
> Signed-off-by: Qi Liu <liuqi115@huawei.com>
> Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
> ---
>  drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 79 ++++-----------------------
>  drivers/perf/hisilicon/hisi_uncore_hha_pmu.c  | 77 +++-----------------------
>  drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c  | 77 +++-----------------------
>  drivers/perf/hisilicon/hisi_uncore_pmu.c      | 68 ++++++++++++++++++++++-
>  drivers/perf/hisilicon/hisi_uncore_pmu.h      |  6 +-
>  5 files changed, 100 insertions(+), 207 deletions(-)
> 
> diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
> index ac1a8c120a00..7f7827cd54d7 100644
> --- a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
> +++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
> @@ -14,7 +14,6 @@
>  #include <linux/interrupt.h>
>  #include <linux/irq.h>
>  #include <linux/list.h>
> -#include <linux/platform_device.h>
>  #include <linux/smp.h>
>  
>  #include "hisi_uncore_pmu.h"
> @@ -65,29 +64,15 @@ static u32 hisi_ddrc_pmu_get_counter_offset(int cntr_idx)
>  static u64 hisi_ddrc_pmu_read_counter(struct hisi_pmu *ddrc_pmu,
>  				      struct hw_perf_event *hwc)
>  {
> -	/* Use event code as counter index */
> -	u32 idx = GET_DDRC_EVENTID(hwc);
> -
> -	if (!hisi_uncore_pmu_counter_valid(ddrc_pmu, idx)) {
> -		dev_err(ddrc_pmu->dev, "Unsupported event index:%d!\n", idx);
> -		return 0;
> -	}
> -
> -	return readl(ddrc_pmu->base + hisi_ddrc_pmu_get_counter_offset(idx));
> +	return readl(ddrc_pmu->base +
> +		     hisi_ddrc_pmu_get_counter_offset(hwc->idx));
>  }
>  
>  static void hisi_ddrc_pmu_write_counter(struct hisi_pmu *ddrc_pmu,
>  					struct hw_perf_event *hwc, u64 val)
>  {
> -	u32 idx = GET_DDRC_EVENTID(hwc);
> -
> -	if (!hisi_uncore_pmu_counter_valid(ddrc_pmu, idx)) {
> -		dev_err(ddrc_pmu->dev, "Unsupported event index:%d!\n", idx);
> -		return;
> -	}
> -
>  	writel((u32)val,
> -	       ddrc_pmu->base + hisi_ddrc_pmu_get_counter_offset(idx));
> +	       ddrc_pmu->base + hisi_ddrc_pmu_get_counter_offset(hwc->idx));
>  }
>  
>  /*
> @@ -179,60 +164,14 @@ static void hisi_ddrc_pmu_disable_counter_int(struct hisi_pmu *ddrc_pmu,
>  	writel(val, ddrc_pmu->base + DDRC_INT_MASK);
>  }
>  
> -static irqreturn_t hisi_ddrc_pmu_isr(int irq, void *dev_id)
> +static u32 hisi_ddrc_pmu_get_int_status(struct hisi_pmu *ddrc_pmu)
>  {
> -	struct hisi_pmu *ddrc_pmu = dev_id;
> -	struct perf_event *event;
> -	unsigned long overflown;
> -	int idx;
> -
> -	/* Read the DDRC_INT_STATUS register */
> -	overflown = readl(ddrc_pmu->base + DDRC_INT_STATUS);
> -	if (!overflown)
> -		return IRQ_NONE;
> -
> -	/*
> -	 * Find the counter index which overflowed if the bit was set
> -	 * and handle it
> -	 */
> -	for_each_set_bit(idx, &overflown, DDRC_NR_COUNTERS) {
> -		/* Write 1 to clear the IRQ status flag */
> -		writel((1 << idx), ddrc_pmu->base + DDRC_INT_CLEAR);
> -
> -		/* Get the corresponding event struct */
> -		event = ddrc_pmu->pmu_events.hw_events[idx];
> -		if (!event)
> -			continue;
> -
> -		hisi_uncore_pmu_event_update(event);
> -		hisi_uncore_pmu_set_event_period(event);
> -	}
> -
> -	return IRQ_HANDLED;
> +	return readl(ddrc_pmu->base + DDRC_INT_STATUS);
>  }
>  
> -static int hisi_ddrc_pmu_init_irq(struct hisi_pmu *ddrc_pmu,
> -				  struct platform_device *pdev)
> +static void hisi_ddrc_pmu_clear_int_status(struct hisi_pmu *ddrc_pmu, int idx)
>  {
> -	int irq, ret;
> -
> -	/* Read and init IRQ */
> -	irq = platform_get_irq(pdev, 0);
> -	if (irq < 0)
> -		return irq;
> -
> -	ret = devm_request_irq(&pdev->dev, irq, hisi_ddrc_pmu_isr,
> -			       IRQF_NOBALANCING | IRQF_NO_THREAD,
> -			       dev_name(&pdev->dev), ddrc_pmu);
> -	if (ret < 0) {
> -		dev_err(&pdev->dev,
> -			"Fail to request IRQ:%d ret:%d\n", irq, ret);
> -		return ret;
> -	}
> -
> -	ddrc_pmu->irq = irq;
> -
> -	return 0;
> +	writel(1 << idx, ddrc_pmu->base + DDRC_INT_CLEAR);
>  }
>  
>  static const struct acpi_device_id hisi_ddrc_pmu_acpi_match[] = {
> @@ -342,6 +281,8 @@ static const struct hisi_uncore_ops hisi_uncore_ddrc_ops = {
>  	.disable_counter_int	= hisi_ddrc_pmu_disable_counter_int,
>  	.write_counter		= hisi_ddrc_pmu_write_counter,
>  	.read_counter		= hisi_ddrc_pmu_read_counter,
> +	.get_int_status		= hisi_ddrc_pmu_get_int_status,
> +	.clear_int_status	= hisi_ddrc_pmu_clear_int_status,
>  };
>  
>  static int hisi_ddrc_pmu_dev_probe(struct platform_device *pdev,
> @@ -353,7 +294,7 @@ static int hisi_ddrc_pmu_dev_probe(struct platform_device *pdev,
>  	if (ret)
>  		return ret;
>  
> -	ret = hisi_ddrc_pmu_init_irq(ddrc_pmu, pdev);
> +	ret = hisi_uncore_pmu_init_irq(ddrc_pmu, pdev);
>  	if (ret)
>  		return ret;
>  
> diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
> index 3402f1a395a8..667eebddcc82 100644
> --- a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
> +++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
> @@ -14,7 +14,6 @@
>  #include <linux/interrupt.h>
>  #include <linux/irq.h>
>  #include <linux/list.h>
> -#include <linux/platform_device.h>
>  #include <linux/smp.h>
>  
>  #include "hisi_uncore_pmu.h"
> @@ -51,29 +50,15 @@ static u32 hisi_hha_pmu_get_counter_offset(int cntr_idx)
>  static u64 hisi_hha_pmu_read_counter(struct hisi_pmu *hha_pmu,
>  				     struct hw_perf_event *hwc)
>  {
> -	u32 idx = hwc->idx;
> -
> -	if (!hisi_uncore_pmu_counter_valid(hha_pmu, idx)) {
> -		dev_err(hha_pmu->dev, "Unsupported event index:%d!\n", idx);
> -		return 0;
> -	}
> -
>  	/* Read 64 bits and like L3C, top 16 bits are RAZ */
> -	return readq(hha_pmu->base + hisi_hha_pmu_get_counter_offset(idx));
> +	return readq(hha_pmu->base + hisi_hha_pmu_get_counter_offset(hwc->idx));
>  }
>  
>  static void hisi_hha_pmu_write_counter(struct hisi_pmu *hha_pmu,
>  				       struct hw_perf_event *hwc, u64 val)
>  {
> -	u32 idx = hwc->idx;
> -
> -	if (!hisi_uncore_pmu_counter_valid(hha_pmu, idx)) {
> -		dev_err(hha_pmu->dev, "Unsupported event index:%d!\n", idx);
> -		return;
> -	}
> -
>  	/* Write 64 bits and like L3C, top 16 bits are WI */
> -	writeq(val, hha_pmu->base + hisi_hha_pmu_get_counter_offset(idx));
> +	writeq(val, hha_pmu->base + hisi_hha_pmu_get_counter_offset(hwc->idx));
>  }
>  
>  static void hisi_hha_pmu_write_evtype(struct hisi_pmu *hha_pmu, int idx,
> @@ -169,60 +154,14 @@ static void hisi_hha_pmu_disable_counter_int(struct hisi_pmu *hha_pmu,
>  	writel(val, hha_pmu->base + HHA_INT_MASK);
>  }
>  
> -static irqreturn_t hisi_hha_pmu_isr(int irq, void *dev_id)
> +static u32 hisi_hha_pmu_get_int_status(struct hisi_pmu *hha_pmu)
>  {
> -	struct hisi_pmu *hha_pmu = dev_id;
> -	struct perf_event *event;
> -	unsigned long overflown;
> -	int idx;
> -
> -	/* Read HHA_INT_STATUS register */
> -	overflown = readl(hha_pmu->base + HHA_INT_STATUS);
> -	if (!overflown)
> -		return IRQ_NONE;
> -
> -	/*
> -	 * Find the counter index which overflowed if the bit was set
> -	 * and handle it
> -	 */
> -	for_each_set_bit(idx, &overflown, HHA_NR_COUNTERS) {
> -		/* Write 1 to clear the IRQ status flag */
> -		writel((1 << idx), hha_pmu->base + HHA_INT_CLEAR);
> -
> -		/* Get the corresponding event struct */
> -		event = hha_pmu->pmu_events.hw_events[idx];
> -		if (!event)
> -			continue;
> -
> -		hisi_uncore_pmu_event_update(event);
> -		hisi_uncore_pmu_set_event_period(event);
> -	}
> -
> -	return IRQ_HANDLED;
> +	return readl(hha_pmu->base + HHA_INT_STATUS);
>  }
>  
> -static int hisi_hha_pmu_init_irq(struct hisi_pmu *hha_pmu,
> -				 struct platform_device *pdev)
> +static void hisi_hha_pmu_clear_int_status(struct hisi_pmu *hha_pmu, int idx)
>  {
> -	int irq, ret;
> -
> -	/* Read and init IRQ */
> -	irq = platform_get_irq(pdev, 0);
> -	if (irq < 0)
> -		return irq;
> -
> -	ret = devm_request_irq(&pdev->dev, irq, hisi_hha_pmu_isr,
> -			      IRQF_NOBALANCING | IRQF_NO_THREAD,
> -			      dev_name(&pdev->dev), hha_pmu);
> -	if (ret < 0) {
> -		dev_err(&pdev->dev,
> -			"Fail to request IRQ:%d ret:%d\n", irq, ret);
> -		return ret;
> -	}
> -
> -	hha_pmu->irq = irq;
> -
> -	return 0;
> +	writel(1 << idx, hha_pmu->base + HHA_INT_CLEAR);
>  }
>  
>  static const struct acpi_device_id hisi_hha_pmu_acpi_match[] = {
> @@ -354,6 +293,8 @@ static const struct hisi_uncore_ops hisi_uncore_hha_ops = {
>  	.disable_counter_int	= hisi_hha_pmu_disable_counter_int,
>  	.write_counter		= hisi_hha_pmu_write_counter,
>  	.read_counter		= hisi_hha_pmu_read_counter,
> +	.get_int_status		= hisi_hha_pmu_get_int_status,
> +	.clear_int_status	= hisi_hha_pmu_clear_int_status,
>  };
>  
>  static int hisi_hha_pmu_dev_probe(struct platform_device *pdev,
> @@ -365,7 +306,7 @@ static int hisi_hha_pmu_dev_probe(struct platform_device *pdev,
>  	if (ret)
>  		return ret;
>  
> -	ret = hisi_hha_pmu_init_irq(hha_pmu, pdev);
> +	ret = hisi_uncore_pmu_init_irq(hha_pmu, pdev);
>  	if (ret)
>  		return ret;
>  
> diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
> index 7d792435c2aa..831622e0c445 100644
> --- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
> +++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
> @@ -14,7 +14,6 @@
>  #include <linux/interrupt.h>
>  #include <linux/irq.h>
>  #include <linux/list.h>
> -#include <linux/platform_device.h>
>  #include <linux/smp.h>
>  
>  #include "hisi_uncore_pmu.h"
> @@ -50,29 +49,15 @@ static u32 hisi_l3c_pmu_get_counter_offset(int cntr_idx)
>  static u64 hisi_l3c_pmu_read_counter(struct hisi_pmu *l3c_pmu,
>  				     struct hw_perf_event *hwc)
>  {
> -	u32 idx = hwc->idx;
> -
> -	if (!hisi_uncore_pmu_counter_valid(l3c_pmu, idx)) {
> -		dev_err(l3c_pmu->dev, "Unsupported event index:%d!\n", idx);
> -		return 0;
> -	}
> -
>  	/* Read 64-bits and the upper 16 bits are RAZ */
> -	return readq(l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(idx));
> +	return readq(l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(hwc->idx));
>  }
>  
>  static void hisi_l3c_pmu_write_counter(struct hisi_pmu *l3c_pmu,
>  				       struct hw_perf_event *hwc, u64 val)
>  {
> -	u32 idx = hwc->idx;
> -
> -	if (!hisi_uncore_pmu_counter_valid(l3c_pmu, idx)) {
> -		dev_err(l3c_pmu->dev, "Unsupported event index:%d!\n", idx);
> -		return;
> -	}
> -
>  	/* Write 64-bits and the upper 16 bits are WI */
> -	writeq(val, l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(idx));
> +	writeq(val, l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(hwc->idx));
>  }
>  
>  static void hisi_l3c_pmu_write_evtype(struct hisi_pmu *l3c_pmu, int idx,
> @@ -168,60 +153,14 @@ static void hisi_l3c_pmu_disable_counter_int(struct hisi_pmu *l3c_pmu,
>  	writel(val, l3c_pmu->base + L3C_INT_MASK);
>  }
>  
> -static irqreturn_t hisi_l3c_pmu_isr(int irq, void *dev_id)
> +static u32 hisi_l3c_pmu_get_int_status(struct hisi_pmu *l3c_pmu)
>  {
> -	struct hisi_pmu *l3c_pmu = dev_id;
> -	struct perf_event *event;
> -	unsigned long overflown;
> -	int idx;
> -
> -	/* Read L3C_INT_STATUS register */
> -	overflown = readl(l3c_pmu->base + L3C_INT_STATUS);
> -	if (!overflown)
> -		return IRQ_NONE;
> -
> -	/*
> -	 * Find the counter index which overflowed if the bit was set
> -	 * and handle it.
> -	 */
> -	for_each_set_bit(idx, &overflown, L3C_NR_COUNTERS) {
> -		/* Write 1 to clear the IRQ status flag */
> -		writel((1 << idx), l3c_pmu->base + L3C_INT_CLEAR);
> -
> -		/* Get the corresponding event struct */
> -		event = l3c_pmu->pmu_events.hw_events[idx];
> -		if (!event)
> -			continue;
> -
> -		hisi_uncore_pmu_event_update(event);
> -		hisi_uncore_pmu_set_event_period(event);
> -	}
> -
> -	return IRQ_HANDLED;
> +	return readl(l3c_pmu->base + L3C_INT_STATUS);
>  }
>  
> -static int hisi_l3c_pmu_init_irq(struct hisi_pmu *l3c_pmu,
> -				 struct platform_device *pdev)
> +static void hisi_l3c_pmu_clear_int_status(struct hisi_pmu *l3c_pmu, int idx)
>  {
> -	int irq, ret;
> -
> -	/* Read and init IRQ */
> -	irq = platform_get_irq(pdev, 0);
> -	if (irq < 0)
> -		return irq;
> -
> -	ret = devm_request_irq(&pdev->dev, irq, hisi_l3c_pmu_isr,
> -			       IRQF_NOBALANCING | IRQF_NO_THREAD,
> -			       dev_name(&pdev->dev), l3c_pmu);
> -	if (ret < 0) {
> -		dev_err(&pdev->dev,
> -			"Fail to request IRQ:%d ret:%d\n", irq, ret);
> -		return ret;
> -	}
> -
> -	l3c_pmu->irq = irq;
> -
> -	return 0;
> +	writel(1 << idx, l3c_pmu->base + L3C_INT_CLEAR);
>  }
>  
>  static const struct acpi_device_id hisi_l3c_pmu_acpi_match[] = {
> @@ -344,6 +283,8 @@ static const struct hisi_uncore_ops hisi_uncore_l3c_ops = {
>  	.disable_counter_int	= hisi_l3c_pmu_disable_counter_int,
>  	.write_counter		= hisi_l3c_pmu_write_counter,
>  	.read_counter		= hisi_l3c_pmu_read_counter,
> +	.get_int_status		= hisi_l3c_pmu_get_int_status,
> +	.clear_int_status	= hisi_l3c_pmu_clear_int_status,
>  };
>  
>  static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev,
> @@ -355,7 +296,7 @@ static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev,
>  	if (ret)
>  		return ret;
>  
> -	ret = hisi_l3c_pmu_init_irq(l3c_pmu, pdev);
> +	ret = hisi_uncore_pmu_init_irq(l3c_pmu, pdev);
>  	if (ret)
>  		return ret;
>  
> diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c
> index 9dbdc3fc3bb4..82a4ff2bc3ae 100644
> --- a/drivers/perf/hisilicon/hisi_uncore_pmu.c
> +++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c
> @@ -132,13 +132,67 @@ EXPORT_SYMBOL_GPL(hisi_uncore_pmu_identifier_attr_show);
>  static void hisi_uncore_pmu_clear_event_idx(struct hisi_pmu *hisi_pmu, int idx)
>  {
>  	if (!hisi_uncore_pmu_counter_valid(hisi_pmu, idx)) {
> -		dev_err(hisi_pmu->dev, "Unsupported event index:%d!\n", idx);
> +		dev_err(hisi_pmu->dev, "Unsupported event index: %d\n", idx);
>  		return;
>  	}
>  
>  	clear_bit(idx, hisi_pmu->pmu_events.used_mask);
>  }
>  
> +static irqreturn_t hisi_uncore_pmu_isr(int irq, void *data)
> +{
> +	struct hisi_pmu *hisi_pmu = data;
> +	struct perf_event *event;
> +	unsigned long overflown;
> +	int idx;
> +
> +	overflown = hisi_pmu->ops->get_int_status(hisi_pmu);
> +	if (!overflown)
> +		return IRQ_NONE;
> +
> +	/*
> +	 * Find the counter index which overflowed if the bit was set
> +	 * and handle it.
> +	 */
> +	for_each_set_bit(idx, &overflown, hisi_pmu->num_counters) {
> +		/* Write 1 to clear the IRQ status flag */
> +		hisi_pmu->ops->clear_int_status(hisi_pmu, idx);
> +		/* Get the corresponding event struct */
> +		event = hisi_pmu->pmu_events.hw_events[idx];
> +		if (!event)
> +			continue;
> +
> +		hisi_uncore_pmu_event_update(event);
> +		hisi_uncore_pmu_set_event_period(event);
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +int hisi_uncore_pmu_init_irq(struct hisi_pmu *hisi_pmu,
> +			     struct platform_device *pdev)
> +{
> +	int irq, ret;
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0)
> +		return irq;
> +
> +	ret = devm_request_irq(&pdev->dev, irq, hisi_uncore_pmu_isr,
> +			       IRQF_NOBALANCING | IRQF_NO_THREAD,
> +			       dev_name(&pdev->dev), hisi_pmu);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev,
> +			"Fail to request IRQ:%d ret:%d\n", irq, ret);
> +		return ret;
> +	}
> +
> +	hisi_pmu->irq = irq;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(hisi_uncore_pmu_init_irq);
> +
>  int hisi_uncore_pmu_event_init(struct perf_event *event)
>  {
>  	struct hw_perf_event *hwc = &event->hw;
> @@ -243,6 +297,12 @@ void hisi_uncore_pmu_event_update(struct perf_event *event)
>  	struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu);
>  	struct hw_perf_event *hwc = &event->hw;
>  	u64 delta, prev_raw_count, new_raw_count;
> +	u32 idx = hwc->idx;
> +
> +	if (!hisi_uncore_pmu_counter_valid(hisi_pmu, idx)) {
> +		dev_err(hisi_pmu->dev, "Unsupported counter index: %d\n", idx);
> +		return;
> +	}
>  
>  	do {
>  		/* Read the count from the counter register */
> @@ -263,10 +323,16 @@ void hisi_uncore_pmu_start(struct perf_event *event, int flags)
>  {
>  	struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu);
>  	struct hw_perf_event *hwc = &event->hw;
> +	u32 idx = hwc->idx;
>  
>  	if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
>  		return;
>  
> +	if (!hisi_uncore_pmu_counter_valid(hisi_pmu, idx)) {
> +		dev_err(hisi_pmu->dev, "Unsupported counter index: %d.\n", idx);
> +		return;
> +	}
> +
>  	WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
>  	hwc->state = 0;
>  	hisi_uncore_pmu_set_event_period(event);
> diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h
> index 25b7cbe1f818..aaaf637cc9ea 100644
> --- a/drivers/perf/hisilicon/hisi_uncore_pmu.h
> +++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h
> @@ -16,6 +16,7 @@
>  #include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/perf_event.h>
> +#include <linux/platform_device.h>
>  #include <linux/types.h>
>  
>  #undef pr_fmt
> @@ -47,6 +48,8 @@ struct hisi_uncore_ops {
>  	void (*disable_counter_int)(struct hisi_pmu *, struct hw_perf_event *);
>  	void (*start_counters)(struct hisi_pmu *);
>  	void (*stop_counters)(struct hisi_pmu *);
> +	u32 (*get_int_status)(struct hisi_pmu *hisi_pmu);
> +	void (*clear_int_status)(struct hisi_pmu *hisi_pmu, int idx);
>  };
>  
>  struct hisi_pmu_hwevents {
> @@ -102,6 +105,7 @@ int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node);
>  ssize_t hisi_uncore_pmu_identifier_attr_show(struct device *dev,
>  					     struct device_attribute *attr,
>  					     char *page);
> -
> +int hisi_uncore_pmu_init_irq(struct hisi_pmu *hisi_pmu,
> +			     struct platform_device *pdev);
>  
>  #endif /* __HISI_UNCORE_PMU_H__ */
> -- 
> 2.7.4
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 2/8] drivers/perf: hisi: Add PMU version for uncore PMU drivers.
  2021-02-03  7:51 ` [PATCH v2 2/8] drivers/perf: hisi: Add PMU version for uncore PMU drivers Shaokun Zhang
@ 2021-02-03 12:58   ` Mark Rutland
  2021-02-04  3:48     ` Shaokun Zhang
  0 siblings, 1 reply; 25+ messages in thread
From: Mark Rutland @ 2021-02-03 12:58 UTC (permalink / raw)
  To: Shaokun Zhang
  Cc: Qi Liu, John Garry, Will Deacon, linux-arm-kernel, Jonathan Cameron

On Wed, Feb 03, 2021 at 03:51:02PM +0800, Shaokun Zhang wrote:
> For HiSilicon uncore PMU, more versions are supported and some variables
> shall be added suffix to distinguish the version which are prepared for
> the new drivers.
> 
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Will Deacon <will@kernel.org>
> Cc: John Garry <john.garry@huawei.com>
> Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> Reviewed-by: John Garry <john.garry@huawei.com>
> Co-developed-by: Qi Liu <liuqi115@huawei.com>
> Signed-off-by: Qi Liu <liuqi115@huawei.com>
> Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
> ---
>  drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 97 ++++++++++++++-------------
>  drivers/perf/hisilicon/hisi_uncore_hha_pmu.c  | 27 ++++----
>  drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c  | 24 +++----
>  3 files changed, 75 insertions(+), 73 deletions(-)

[...]

> diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
> index 831622e0c445..da56fa16b97e 100644
> --- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
> +++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
> @@ -37,7 +37,7 @@
>  
>  #define L3C_PERF_CTRL_EN	0x10000
>  #define L3C_EVTYPE_NONE		0xff
> -
> +#define L3C_V1_NR_EVENTS	0x59
>  /*
>   * Select the counter register offset using the counter index
>   */

I don't think you meant to remove the line space before the comment here.

With that restored:

Acked-by: Mark Rutland <mark.rutland@arm.com>

Mark.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 3/8] drivers/perf: hisi: Add new functions for L3C PMU
  2021-02-03  7:51 ` [PATCH v2 3/8] drivers/perf: hisi: Add new functions for L3C PMU Shaokun Zhang
@ 2021-02-03 13:10   ` Mark Rutland
  2021-02-04  6:30     ` Shaokun Zhang
  0 siblings, 1 reply; 25+ messages in thread
From: Mark Rutland @ 2021-02-03 13:10 UTC (permalink / raw)
  To: Shaokun Zhang
  Cc: Qi Liu, John Garry, Will Deacon, linux-arm-kernel, Jonathan Cameron

On Wed, Feb 03, 2021 at 03:51:03PM +0800, Shaokun Zhang wrote:
> On HiSilicon Hip09 platform, some new functions are enhanced on L3C PMU,
> like, tracetag feature that L3C PMU can only count the specified
> operations by the user, or L3C PMU can give the desired core's statistics
> in the cluster.
> $# perf stat -a -e hisi_sccl3_l3c0/config=0x02,tt_core=0xf/ sleep 5
> 
> $# perf stat -a -e hisi_sccl3_l3c0/config=0x02,tt_req=0x4/ sleep 5

Are these values documented somewhere?

[...]

> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tt_core, config1, 7, 0);
> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tt_req, config1, 10, 8);
> +HISI_PMU_EVENT_ATTR_EXTRACTOR(datasrc_cfg, config1, 15, 11);
> +HISI_PMU_EVENT_ATTR_EXTRACTOR(datasrc_skt, config1, 16, 16);

Could you please mention all of these in the commit message?

IIUC tt_core is a mask of physical cores in the cluster, and I guess
tt_req is a request type, but I have no idea what the datasrc_cfg or
datasrc_skt (socket?) fields represent.

A rough description would be very helpful, something like:

| We expose the tracetag filters with new fields exposed to userspace:
|
| * tt_core is a mask of cores within the PMU's cluster
| * tt_req is ???
| * datasrc_cfg is ???
| * datasrc_skt is ???

Thanks,
Mark.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 4/8] drivers/perf: hisi: Add new functions for HHA PMU
  2021-02-03  7:51 ` [PATCH v2 4/8] drivers/perf: hisi: Add new functions for HHA PMU Shaokun Zhang
@ 2021-02-03 13:18   ` Mark Rutland
  2021-02-04  6:44     ` Shaokun Zhang
  0 siblings, 1 reply; 25+ messages in thread
From: Mark Rutland @ 2021-02-03 13:18 UTC (permalink / raw)
  To: Shaokun Zhang
  Cc: Qi Liu, John Garry, Will Deacon, linux-arm-kernel, Jonathan Cameron

On Wed, Feb 03, 2021 at 03:51:04PM +0800, Shaokun Zhang wrote:
> On HiSilicon Hip09 platform, some new functions are also supported on
> HHA PMU, it can filter gathered statistics by the Master ID and mask
> from the SoC if the user wants to do deep-going profiling.
> Tracetag support is also added with L3C PMU in the SoC system.
> 
> $# perf stat -a -e hisi_sccl3_hha0/config=0x02,tracetag_en=0x1/ sleep 5
> 
> $# perf stat -a -e hisi_sccl3_hha0/config=0x02,srcid_cmd=0x1/ sleep 5
>
> Much more introduction is added in documentation:
> Documentation/admin-guide/perf/hisi-pmu.rst

Could we please enumerate the relevant fields here, with a brief
description? From a quick scan these are different to those added fo
rthe L3C PMU.

I appreciate the last partch in the series adds some documentation, but
it'd be nice to have the context where it's needed.

[...]

> @@ -193,6 +304,22 @@ static int hisi_hha_pmu_init_data(struct platform_device *pdev,
>  		dev_err(&pdev->dev, "Can not read hha sccl-id!\n");
>  		return -EINVAL;
>  	}
> +
> +	/*
> +	 * Early versions of BIOS support _UID by mistake, so we support
> +	 * both "hisilicon, idx-id" as preference, if availbale.

Typo: s/availbale/available/

Thanks,
Mark.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 5/8] drivers/perf: hisi: Update DDRC PMU for programable counter
  2021-02-03  7:51 ` [PATCH v2 5/8] drivers/perf: hisi: Update DDRC PMU for programable counter Shaokun Zhang
@ 2021-02-03 13:23   ` Mark Rutland
  2021-02-04  7:00     ` Shaokun Zhang
  0 siblings, 1 reply; 25+ messages in thread
From: Mark Rutland @ 2021-02-03 13:23 UTC (permalink / raw)
  To: Shaokun Zhang
  Cc: Qi Liu, John Garry, Will Deacon, linux-arm-kernel, Jonathan Cameron

On Wed, Feb 03, 2021 at 03:51:05PM +0800, Shaokun Zhang wrote:
> DDRC PMU's events are useful for performance profiling, but the events
> are limited and counters are fixed. On HiSilicon Hip09 platform, PMU
> counters are the programmable and more events are supported. Let's
> add the DDRC PMU v2 driver.

>  static struct attribute *hisi_ddrc_pmu_v1_events_attr[] = {
>  	HISI_PMU_EVENT_ATTR(flux_wr,		0x00),
>  	HISI_PMU_EVENT_ATTR(flux_rd,		0x01),
> @@ -240,6 +370,18 @@ static const struct attribute_group hisi_ddrc_pmu_v1_events_group = {
>  	.attrs = hisi_ddrc_pmu_v1_events_attr,
>  };
>  
> +static struct attribute *hisi_ddrc_pmu_v2_events_attr[] = {
> +	HISI_PMU_EVENT_ATTR(clocks,		0x00),

Should that be 'cycles' ?

> +	HISI_PMU_EVENT_ATTR(flux_wr,		0x83),
> +	HISI_PMU_EVENT_ATTR(flux_rd,		0x84),
> +	NULL
> +};

The commit message mentioned that v2 supports more events, but this only
adds three of them (and v2 listed eight distinct events).

Is there a rationale for only listing these events specifically?

Thanks,
Mark.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 6/8] drivers/perf: hisi: Add support for HiSilicon SLLC PMU driver
  2021-02-03  7:51 ` [PATCH v2 6/8] drivers/perf: hisi: Add support for HiSilicon SLLC PMU driver Shaokun Zhang
@ 2021-02-03 13:28   ` Mark Rutland
  2021-02-04  7:10     ` Shaokun Zhang
  0 siblings, 1 reply; 25+ messages in thread
From: Mark Rutland @ 2021-02-03 13:28 UTC (permalink / raw)
  To: Shaokun Zhang
  Cc: Qi Liu, John Garry, Will Deacon, linux-arm-kernel, Jonathan Cameron

On Wed, Feb 03, 2021 at 03:51:06PM +0800, Shaokun Zhang wrote:
> HiSilicon's Hip09 is comprised by multi-dies that can be connected by SLLC
> module (Skyros Link Layer Controller), its has separate PMU registers which
> the driver can program it freely and interrupt is supported to handle
> counter overflow. Let's support its driver under the framework of HiSilicon
> uncore PMU driver.

[...]

> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_lo, config1, 10, 0);
> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_hi, config1, 21, 11);
> +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_cmd, config1, 32, 22);
> +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 43, 33);
> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 44, 44);

If you could describe these fields in the commit message that would be
helpful.

What is a 'tgtid'? Is that a 'target ID' or something to that effect?

[...]

> +	HISI_PMU_FORMAT_ATTR(tgtid_low, "config1:0-10"),
> +	HISI_PMU_FORMAT_ATTR(tgtid_high, "config1:11-21"),

Does this need to be exposed to userspace in two halves, rather than
being a single 'tgtid' field that the driver can decompose as necessary?

Thanks,
Mark.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 7/8] drivers/perf: hisi: Add support for HiSilicon PA PMU driver
  2021-02-03  7:51 ` [PATCH v2 7/8] drivers/perf: hisi: Add support for HiSilicon PA " Shaokun Zhang
@ 2021-02-03 13:43   ` Mark Rutland
  2021-02-04  7:20     ` Shaokun Zhang
  0 siblings, 1 reply; 25+ messages in thread
From: Mark Rutland @ 2021-02-03 13:43 UTC (permalink / raw)
  To: Shaokun Zhang
  Cc: Qi Liu, John Garry, Will Deacon, linux-arm-kernel, Jonathan Cameron

On Wed, Feb 03, 2021 at 03:51:07PM +0800, Shaokun Zhang wrote:
> On HiSilicon Hip09 platform, there is a PA (Protocol Adapter) module on
> each chip SICL (Super I/O Cluster) which incorporates three Hydra interface
> and facilitates the cache coherency between the dies on the chip. While PA
> uncore PMU model is the same as other Hip09 PMU modules and many PMU events
> are supported. Let's support the PMU driver using the HiSilicon uncore PMU
> framework.

> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_cmd, config1, 10, 0);
> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_msk, config1, 21, 11);
> +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_cmd, config1, 32, 22);
> +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 43, 33);
> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 44, 44);

As with the other patches, a brief introduction for these in the commit
message would be helpful.

> +static void hisi_pa_pmu_enable_filter(struct perf_event *event)
> +{
> +	if (event->attr.config1 != 0x0) {
> +		hisi_pa_pmu_enable_tracetag(event);
> +		hisi_pa_pmu_config_srcid(event);
> +		hisi_pa_pmu_config_tgtid(event);
> +	}
> +}
> +
> +static void hisi_pa_pmu_disable_filter(struct perf_event *event)
> +{
> +	if (event->attr.config1 != 0x0) {
> +		hisi_pa_pmu_clear_tgtid(event);
> +		hisi_pa_pmu_clear_srcid(event);
> +		hisi_pa_pmu_clear_tracetag(event);
> +	}
> +}

Does this get reset when the driver probes? I couldn't spot where we
ensured this was in a sane initial state.

> +static void hisi_pa_pmu_write_evtype(struct hisi_pmu *pa_pmu, int idx,
> +				     u32 type)
> +{
> +	u32 reg, reg_idx, shift, val;
> +
> +	/*
> +	 * Select the appropriate event select register(PA_EVENT_TYPE0/1).
> +	 * There are 2 event select registers for the 8 hardware counters.
> +	 * Event code is 8-bits and for the former 4 hardware counters,
> +	 * PA_EVENT_TYPE0 is chosen. For the latter 4 hardware counters,
> +	 * PA_EVENT_TYPE1 is chosen.
> +	 */
> +	reg = PA_EVENT_TYPE0 + rounddown(idx, 4);

The use of rounddown() here is confusing, as it relies on the number of
elements per register happening to be equal to the size of the register
in bytes. That works here since each element is a byte, but as it's not
the common case it sticks out.

Please divide the index by the number of elements per register, then
multiply that by the size of the register.

Thanks,
Mark.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 1/8] drivers/perf: hisi: Refactor code for more uncore PMUs
  2021-02-03 12:53   ` Mark Rutland
@ 2021-02-04  3:38     ` Shaokun Zhang
  0 siblings, 0 replies; 25+ messages in thread
From: Shaokun Zhang @ 2021-02-04  3:38 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Qi Liu, John Garry, Will Deacon, linux-arm-kernel, Jonathan Cameron

Hi Mark,

在 2021/2/3 20:53, Mark Rutland 写道:
> On Wed, Feb 03, 2021 at 03:51:01PM +0800, Shaokun Zhang wrote:
>> On HiSilicon uncore PMU drivers, interrupt handling function and interrupt
>> registration function are very similar in differents PMU modules. Let's
>> refactor the frame, use a callback function for the HW accessors.
> 
> It would be helpful if the commit message could briefly elaborate on
> the refactoring, e.g.
> 
> It would be helpful if the commit message could briefly explain the
> refactoring, e.g.

Agree,

> 
> | Two new callbacks are added:
> |
> | * hisi_uncore_ops::get_int_status returns a bitmap of events which
> |   have overflowed and raised an interrupt
> |
> | * hisi_uncore_ops::clear_int_status clears the overflow status for a
> |   specific event
> |
> | ... and are used by a common IRQ handler, hisi_uncore_pmu_isr().
> 

Ok, I will update these in next version,

> The refactoring itself looks good to me.

Thanks,

> 
> I also see that sanity-checks are removed from the read_counter() and
> write_counter() functions, but the commit message doesn't mention that
> at all. It looks like that should be a separate change.

Oh, I will do one separate patch before this refactor code, the later
new drivers need this.

Cheers,
Shaokun

> 
> Thanks,
> Mark.
> 
>>
>> Cc: Mark Rutland <mark.rutland@arm.com>
>> Cc: Will Deacon <will@kernel.org>
>> Cc: John Garry <john.garry@huawei.com>
>> Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
>> Reviewed-by: John Garry <john.garry@huawei.com>
>> Co-developed-by: Qi Liu <liuqi115@huawei.com>
>> Signed-off-by: Qi Liu <liuqi115@huawei.com>
>> Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
>> ---
>>  drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 79 ++++-----------------------
>>  drivers/perf/hisilicon/hisi_uncore_hha_pmu.c  | 77 +++-----------------------
>>  drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c  | 77 +++-----------------------
>>  drivers/perf/hisilicon/hisi_uncore_pmu.c      | 68 ++++++++++++++++++++++-
>>  drivers/perf/hisilicon/hisi_uncore_pmu.h      |  6 +-
>>  5 files changed, 100 insertions(+), 207 deletions(-)
>>
>> diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
>> index ac1a8c120a00..7f7827cd54d7 100644
>> --- a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
>> +++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
>> @@ -14,7 +14,6 @@
>>  #include <linux/interrupt.h>
>>  #include <linux/irq.h>
>>  #include <linux/list.h>
>> -#include <linux/platform_device.h>
>>  #include <linux/smp.h>
>>  
>>  #include "hisi_uncore_pmu.h"
>> @@ -65,29 +64,15 @@ static u32 hisi_ddrc_pmu_get_counter_offset(int cntr_idx)
>>  static u64 hisi_ddrc_pmu_read_counter(struct hisi_pmu *ddrc_pmu,
>>  				      struct hw_perf_event *hwc)
>>  {
>> -	/* Use event code as counter index */
>> -	u32 idx = GET_DDRC_EVENTID(hwc);
>> -
>> -	if (!hisi_uncore_pmu_counter_valid(ddrc_pmu, idx)) {
>> -		dev_err(ddrc_pmu->dev, "Unsupported event index:%d!\n", idx);
>> -		return 0;
>> -	}
>> -
>> -	return readl(ddrc_pmu->base + hisi_ddrc_pmu_get_counter_offset(idx));
>> +	return readl(ddrc_pmu->base +
>> +		     hisi_ddrc_pmu_get_counter_offset(hwc->idx));
>>  }
>>  
>>  static void hisi_ddrc_pmu_write_counter(struct hisi_pmu *ddrc_pmu,
>>  					struct hw_perf_event *hwc, u64 val)
>>  {
>> -	u32 idx = GET_DDRC_EVENTID(hwc);
>> -
>> -	if (!hisi_uncore_pmu_counter_valid(ddrc_pmu, idx)) {
>> -		dev_err(ddrc_pmu->dev, "Unsupported event index:%d!\n", idx);
>> -		return;
>> -	}
>> -
>>  	writel((u32)val,
>> -	       ddrc_pmu->base + hisi_ddrc_pmu_get_counter_offset(idx));
>> +	       ddrc_pmu->base + hisi_ddrc_pmu_get_counter_offset(hwc->idx));
>>  }
>>  
>>  /*
>> @@ -179,60 +164,14 @@ static void hisi_ddrc_pmu_disable_counter_int(struct hisi_pmu *ddrc_pmu,
>>  	writel(val, ddrc_pmu->base + DDRC_INT_MASK);
>>  }
>>  
>> -static irqreturn_t hisi_ddrc_pmu_isr(int irq, void *dev_id)
>> +static u32 hisi_ddrc_pmu_get_int_status(struct hisi_pmu *ddrc_pmu)
>>  {
>> -	struct hisi_pmu *ddrc_pmu = dev_id;
>> -	struct perf_event *event;
>> -	unsigned long overflown;
>> -	int idx;
>> -
>> -	/* Read the DDRC_INT_STATUS register */
>> -	overflown = readl(ddrc_pmu->base + DDRC_INT_STATUS);
>> -	if (!overflown)
>> -		return IRQ_NONE;
>> -
>> -	/*
>> -	 * Find the counter index which overflowed if the bit was set
>> -	 * and handle it
>> -	 */
>> -	for_each_set_bit(idx, &overflown, DDRC_NR_COUNTERS) {
>> -		/* Write 1 to clear the IRQ status flag */
>> -		writel((1 << idx), ddrc_pmu->base + DDRC_INT_CLEAR);
>> -
>> -		/* Get the corresponding event struct */
>> -		event = ddrc_pmu->pmu_events.hw_events[idx];
>> -		if (!event)
>> -			continue;
>> -
>> -		hisi_uncore_pmu_event_update(event);
>> -		hisi_uncore_pmu_set_event_period(event);
>> -	}
>> -
>> -	return IRQ_HANDLED;
>> +	return readl(ddrc_pmu->base + DDRC_INT_STATUS);
>>  }
>>  
>> -static int hisi_ddrc_pmu_init_irq(struct hisi_pmu *ddrc_pmu,
>> -				  struct platform_device *pdev)
>> +static void hisi_ddrc_pmu_clear_int_status(struct hisi_pmu *ddrc_pmu, int idx)
>>  {
>> -	int irq, ret;
>> -
>> -	/* Read and init IRQ */
>> -	irq = platform_get_irq(pdev, 0);
>> -	if (irq < 0)
>> -		return irq;
>> -
>> -	ret = devm_request_irq(&pdev->dev, irq, hisi_ddrc_pmu_isr,
>> -			       IRQF_NOBALANCING | IRQF_NO_THREAD,
>> -			       dev_name(&pdev->dev), ddrc_pmu);
>> -	if (ret < 0) {
>> -		dev_err(&pdev->dev,
>> -			"Fail to request IRQ:%d ret:%d\n", irq, ret);
>> -		return ret;
>> -	}
>> -
>> -	ddrc_pmu->irq = irq;
>> -
>> -	return 0;
>> +	writel(1 << idx, ddrc_pmu->base + DDRC_INT_CLEAR);
>>  }
>>  
>>  static const struct acpi_device_id hisi_ddrc_pmu_acpi_match[] = {
>> @@ -342,6 +281,8 @@ static const struct hisi_uncore_ops hisi_uncore_ddrc_ops = {
>>  	.disable_counter_int	= hisi_ddrc_pmu_disable_counter_int,
>>  	.write_counter		= hisi_ddrc_pmu_write_counter,
>>  	.read_counter		= hisi_ddrc_pmu_read_counter,
>> +	.get_int_status		= hisi_ddrc_pmu_get_int_status,
>> +	.clear_int_status	= hisi_ddrc_pmu_clear_int_status,
>>  };
>>  
>>  static int hisi_ddrc_pmu_dev_probe(struct platform_device *pdev,
>> @@ -353,7 +294,7 @@ static int hisi_ddrc_pmu_dev_probe(struct platform_device *pdev,
>>  	if (ret)
>>  		return ret;
>>  
>> -	ret = hisi_ddrc_pmu_init_irq(ddrc_pmu, pdev);
>> +	ret = hisi_uncore_pmu_init_irq(ddrc_pmu, pdev);
>>  	if (ret)
>>  		return ret;
>>  
>> diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
>> index 3402f1a395a8..667eebddcc82 100644
>> --- a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
>> +++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
>> @@ -14,7 +14,6 @@
>>  #include <linux/interrupt.h>
>>  #include <linux/irq.h>
>>  #include <linux/list.h>
>> -#include <linux/platform_device.h>
>>  #include <linux/smp.h>
>>  
>>  #include "hisi_uncore_pmu.h"
>> @@ -51,29 +50,15 @@ static u32 hisi_hha_pmu_get_counter_offset(int cntr_idx)
>>  static u64 hisi_hha_pmu_read_counter(struct hisi_pmu *hha_pmu,
>>  				     struct hw_perf_event *hwc)
>>  {
>> -	u32 idx = hwc->idx;
>> -
>> -	if (!hisi_uncore_pmu_counter_valid(hha_pmu, idx)) {
>> -		dev_err(hha_pmu->dev, "Unsupported event index:%d!\n", idx);
>> -		return 0;
>> -	}
>> -
>>  	/* Read 64 bits and like L3C, top 16 bits are RAZ */
>> -	return readq(hha_pmu->base + hisi_hha_pmu_get_counter_offset(idx));
>> +	return readq(hha_pmu->base + hisi_hha_pmu_get_counter_offset(hwc->idx));
>>  }
>>  
>>  static void hisi_hha_pmu_write_counter(struct hisi_pmu *hha_pmu,
>>  				       struct hw_perf_event *hwc, u64 val)
>>  {
>> -	u32 idx = hwc->idx;
>> -
>> -	if (!hisi_uncore_pmu_counter_valid(hha_pmu, idx)) {
>> -		dev_err(hha_pmu->dev, "Unsupported event index:%d!\n", idx);
>> -		return;
>> -	}
>> -
>>  	/* Write 64 bits and like L3C, top 16 bits are WI */
>> -	writeq(val, hha_pmu->base + hisi_hha_pmu_get_counter_offset(idx));
>> +	writeq(val, hha_pmu->base + hisi_hha_pmu_get_counter_offset(hwc->idx));
>>  }
>>  
>>  static void hisi_hha_pmu_write_evtype(struct hisi_pmu *hha_pmu, int idx,
>> @@ -169,60 +154,14 @@ static void hisi_hha_pmu_disable_counter_int(struct hisi_pmu *hha_pmu,
>>  	writel(val, hha_pmu->base + HHA_INT_MASK);
>>  }
>>  
>> -static irqreturn_t hisi_hha_pmu_isr(int irq, void *dev_id)
>> +static u32 hisi_hha_pmu_get_int_status(struct hisi_pmu *hha_pmu)
>>  {
>> -	struct hisi_pmu *hha_pmu = dev_id;
>> -	struct perf_event *event;
>> -	unsigned long overflown;
>> -	int idx;
>> -
>> -	/* Read HHA_INT_STATUS register */
>> -	overflown = readl(hha_pmu->base + HHA_INT_STATUS);
>> -	if (!overflown)
>> -		return IRQ_NONE;
>> -
>> -	/*
>> -	 * Find the counter index which overflowed if the bit was set
>> -	 * and handle it
>> -	 */
>> -	for_each_set_bit(idx, &overflown, HHA_NR_COUNTERS) {
>> -		/* Write 1 to clear the IRQ status flag */
>> -		writel((1 << idx), hha_pmu->base + HHA_INT_CLEAR);
>> -
>> -		/* Get the corresponding event struct */
>> -		event = hha_pmu->pmu_events.hw_events[idx];
>> -		if (!event)
>> -			continue;
>> -
>> -		hisi_uncore_pmu_event_update(event);
>> -		hisi_uncore_pmu_set_event_period(event);
>> -	}
>> -
>> -	return IRQ_HANDLED;
>> +	return readl(hha_pmu->base + HHA_INT_STATUS);
>>  }
>>  
>> -static int hisi_hha_pmu_init_irq(struct hisi_pmu *hha_pmu,
>> -				 struct platform_device *pdev)
>> +static void hisi_hha_pmu_clear_int_status(struct hisi_pmu *hha_pmu, int idx)
>>  {
>> -	int irq, ret;
>> -
>> -	/* Read and init IRQ */
>> -	irq = platform_get_irq(pdev, 0);
>> -	if (irq < 0)
>> -		return irq;
>> -
>> -	ret = devm_request_irq(&pdev->dev, irq, hisi_hha_pmu_isr,
>> -			      IRQF_NOBALANCING | IRQF_NO_THREAD,
>> -			      dev_name(&pdev->dev), hha_pmu);
>> -	if (ret < 0) {
>> -		dev_err(&pdev->dev,
>> -			"Fail to request IRQ:%d ret:%d\n", irq, ret);
>> -		return ret;
>> -	}
>> -
>> -	hha_pmu->irq = irq;
>> -
>> -	return 0;
>> +	writel(1 << idx, hha_pmu->base + HHA_INT_CLEAR);
>>  }
>>  
>>  static const struct acpi_device_id hisi_hha_pmu_acpi_match[] = {
>> @@ -354,6 +293,8 @@ static const struct hisi_uncore_ops hisi_uncore_hha_ops = {
>>  	.disable_counter_int	= hisi_hha_pmu_disable_counter_int,
>>  	.write_counter		= hisi_hha_pmu_write_counter,
>>  	.read_counter		= hisi_hha_pmu_read_counter,
>> +	.get_int_status		= hisi_hha_pmu_get_int_status,
>> +	.clear_int_status	= hisi_hha_pmu_clear_int_status,
>>  };
>>  
>>  static int hisi_hha_pmu_dev_probe(struct platform_device *pdev,
>> @@ -365,7 +306,7 @@ static int hisi_hha_pmu_dev_probe(struct platform_device *pdev,
>>  	if (ret)
>>  		return ret;
>>  
>> -	ret = hisi_hha_pmu_init_irq(hha_pmu, pdev);
>> +	ret = hisi_uncore_pmu_init_irq(hha_pmu, pdev);
>>  	if (ret)
>>  		return ret;
>>  
>> diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
>> index 7d792435c2aa..831622e0c445 100644
>> --- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
>> +++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
>> @@ -14,7 +14,6 @@
>>  #include <linux/interrupt.h>
>>  #include <linux/irq.h>
>>  #include <linux/list.h>
>> -#include <linux/platform_device.h>
>>  #include <linux/smp.h>
>>  
>>  #include "hisi_uncore_pmu.h"
>> @@ -50,29 +49,15 @@ static u32 hisi_l3c_pmu_get_counter_offset(int cntr_idx)
>>  static u64 hisi_l3c_pmu_read_counter(struct hisi_pmu *l3c_pmu,
>>  				     struct hw_perf_event *hwc)
>>  {
>> -	u32 idx = hwc->idx;
>> -
>> -	if (!hisi_uncore_pmu_counter_valid(l3c_pmu, idx)) {
>> -		dev_err(l3c_pmu->dev, "Unsupported event index:%d!\n", idx);
>> -		return 0;
>> -	}
>> -
>>  	/* Read 64-bits and the upper 16 bits are RAZ */
>> -	return readq(l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(idx));
>> +	return readq(l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(hwc->idx));
>>  }
>>  
>>  static void hisi_l3c_pmu_write_counter(struct hisi_pmu *l3c_pmu,
>>  				       struct hw_perf_event *hwc, u64 val)
>>  {
>> -	u32 idx = hwc->idx;
>> -
>> -	if (!hisi_uncore_pmu_counter_valid(l3c_pmu, idx)) {
>> -		dev_err(l3c_pmu->dev, "Unsupported event index:%d!\n", idx);
>> -		return;
>> -	}
>> -
>>  	/* Write 64-bits and the upper 16 bits are WI */
>> -	writeq(val, l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(idx));
>> +	writeq(val, l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(hwc->idx));
>>  }
>>  
>>  static void hisi_l3c_pmu_write_evtype(struct hisi_pmu *l3c_pmu, int idx,
>> @@ -168,60 +153,14 @@ static void hisi_l3c_pmu_disable_counter_int(struct hisi_pmu *l3c_pmu,
>>  	writel(val, l3c_pmu->base + L3C_INT_MASK);
>>  }
>>  
>> -static irqreturn_t hisi_l3c_pmu_isr(int irq, void *dev_id)
>> +static u32 hisi_l3c_pmu_get_int_status(struct hisi_pmu *l3c_pmu)
>>  {
>> -	struct hisi_pmu *l3c_pmu = dev_id;
>> -	struct perf_event *event;
>> -	unsigned long overflown;
>> -	int idx;
>> -
>> -	/* Read L3C_INT_STATUS register */
>> -	overflown = readl(l3c_pmu->base + L3C_INT_STATUS);
>> -	if (!overflown)
>> -		return IRQ_NONE;
>> -
>> -	/*
>> -	 * Find the counter index which overflowed if the bit was set
>> -	 * and handle it.
>> -	 */
>> -	for_each_set_bit(idx, &overflown, L3C_NR_COUNTERS) {
>> -		/* Write 1 to clear the IRQ status flag */
>> -		writel((1 << idx), l3c_pmu->base + L3C_INT_CLEAR);
>> -
>> -		/* Get the corresponding event struct */
>> -		event = l3c_pmu->pmu_events.hw_events[idx];
>> -		if (!event)
>> -			continue;
>> -
>> -		hisi_uncore_pmu_event_update(event);
>> -		hisi_uncore_pmu_set_event_period(event);
>> -	}
>> -
>> -	return IRQ_HANDLED;
>> +	return readl(l3c_pmu->base + L3C_INT_STATUS);
>>  }
>>  
>> -static int hisi_l3c_pmu_init_irq(struct hisi_pmu *l3c_pmu,
>> -				 struct platform_device *pdev)
>> +static void hisi_l3c_pmu_clear_int_status(struct hisi_pmu *l3c_pmu, int idx)
>>  {
>> -	int irq, ret;
>> -
>> -	/* Read and init IRQ */
>> -	irq = platform_get_irq(pdev, 0);
>> -	if (irq < 0)
>> -		return irq;
>> -
>> -	ret = devm_request_irq(&pdev->dev, irq, hisi_l3c_pmu_isr,
>> -			       IRQF_NOBALANCING | IRQF_NO_THREAD,
>> -			       dev_name(&pdev->dev), l3c_pmu);
>> -	if (ret < 0) {
>> -		dev_err(&pdev->dev,
>> -			"Fail to request IRQ:%d ret:%d\n", irq, ret);
>> -		return ret;
>> -	}
>> -
>> -	l3c_pmu->irq = irq;
>> -
>> -	return 0;
>> +	writel(1 << idx, l3c_pmu->base + L3C_INT_CLEAR);
>>  }
>>  
>>  static const struct acpi_device_id hisi_l3c_pmu_acpi_match[] = {
>> @@ -344,6 +283,8 @@ static const struct hisi_uncore_ops hisi_uncore_l3c_ops = {
>>  	.disable_counter_int	= hisi_l3c_pmu_disable_counter_int,
>>  	.write_counter		= hisi_l3c_pmu_write_counter,
>>  	.read_counter		= hisi_l3c_pmu_read_counter,
>> +	.get_int_status		= hisi_l3c_pmu_get_int_status,
>> +	.clear_int_status	= hisi_l3c_pmu_clear_int_status,
>>  };
>>  
>>  static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev,
>> @@ -355,7 +296,7 @@ static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev,
>>  	if (ret)
>>  		return ret;
>>  
>> -	ret = hisi_l3c_pmu_init_irq(l3c_pmu, pdev);
>> +	ret = hisi_uncore_pmu_init_irq(l3c_pmu, pdev);
>>  	if (ret)
>>  		return ret;
>>  
>> diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c
>> index 9dbdc3fc3bb4..82a4ff2bc3ae 100644
>> --- a/drivers/perf/hisilicon/hisi_uncore_pmu.c
>> +++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c
>> @@ -132,13 +132,67 @@ EXPORT_SYMBOL_GPL(hisi_uncore_pmu_identifier_attr_show);
>>  static void hisi_uncore_pmu_clear_event_idx(struct hisi_pmu *hisi_pmu, int idx)
>>  {
>>  	if (!hisi_uncore_pmu_counter_valid(hisi_pmu, idx)) {
>> -		dev_err(hisi_pmu->dev, "Unsupported event index:%d!\n", idx);
>> +		dev_err(hisi_pmu->dev, "Unsupported event index: %d\n", idx);
>>  		return;
>>  	}
>>  
>>  	clear_bit(idx, hisi_pmu->pmu_events.used_mask);
>>  }
>>  
>> +static irqreturn_t hisi_uncore_pmu_isr(int irq, void *data)
>> +{
>> +	struct hisi_pmu *hisi_pmu = data;
>> +	struct perf_event *event;
>> +	unsigned long overflown;
>> +	int idx;
>> +
>> +	overflown = hisi_pmu->ops->get_int_status(hisi_pmu);
>> +	if (!overflown)
>> +		return IRQ_NONE;
>> +
>> +	/*
>> +	 * Find the counter index which overflowed if the bit was set
>> +	 * and handle it.
>> +	 */
>> +	for_each_set_bit(idx, &overflown, hisi_pmu->num_counters) {
>> +		/* Write 1 to clear the IRQ status flag */
>> +		hisi_pmu->ops->clear_int_status(hisi_pmu, idx);
>> +		/* Get the corresponding event struct */
>> +		event = hisi_pmu->pmu_events.hw_events[idx];
>> +		if (!event)
>> +			continue;
>> +
>> +		hisi_uncore_pmu_event_update(event);
>> +		hisi_uncore_pmu_set_event_period(event);
>> +	}
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +int hisi_uncore_pmu_init_irq(struct hisi_pmu *hisi_pmu,
>> +			     struct platform_device *pdev)
>> +{
>> +	int irq, ret;
>> +
>> +	irq = platform_get_irq(pdev, 0);
>> +	if (irq < 0)
>> +		return irq;
>> +
>> +	ret = devm_request_irq(&pdev->dev, irq, hisi_uncore_pmu_isr,
>> +			       IRQF_NOBALANCING | IRQF_NO_THREAD,
>> +			       dev_name(&pdev->dev), hisi_pmu);
>> +	if (ret < 0) {
>> +		dev_err(&pdev->dev,
>> +			"Fail to request IRQ:%d ret:%d\n", irq, ret);
>> +		return ret;
>> +	}
>> +
>> +	hisi_pmu->irq = irq;
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(hisi_uncore_pmu_init_irq);
>> +
>>  int hisi_uncore_pmu_event_init(struct perf_event *event)
>>  {
>>  	struct hw_perf_event *hwc = &event->hw;
>> @@ -243,6 +297,12 @@ void hisi_uncore_pmu_event_update(struct perf_event *event)
>>  	struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu);
>>  	struct hw_perf_event *hwc = &event->hw;
>>  	u64 delta, prev_raw_count, new_raw_count;
>> +	u32 idx = hwc->idx;
>> +
>> +	if (!hisi_uncore_pmu_counter_valid(hisi_pmu, idx)) {
>> +		dev_err(hisi_pmu->dev, "Unsupported counter index: %d\n", idx);
>> +		return;
>> +	}
>>  
>>  	do {
>>  		/* Read the count from the counter register */
>> @@ -263,10 +323,16 @@ void hisi_uncore_pmu_start(struct perf_event *event, int flags)
>>  {
>>  	struct hisi_pmu *hisi_pmu = to_hisi_pmu(event->pmu);
>>  	struct hw_perf_event *hwc = &event->hw;
>> +	u32 idx = hwc->idx;
>>  
>>  	if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
>>  		return;
>>  
>> +	if (!hisi_uncore_pmu_counter_valid(hisi_pmu, idx)) {
>> +		dev_err(hisi_pmu->dev, "Unsupported counter index: %d.\n", idx);
>> +		return;
>> +	}
>> +
>>  	WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
>>  	hwc->state = 0;
>>  	hisi_uncore_pmu_set_event_period(event);
>> diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h
>> index 25b7cbe1f818..aaaf637cc9ea 100644
>> --- a/drivers/perf/hisilicon/hisi_uncore_pmu.h
>> +++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h
>> @@ -16,6 +16,7 @@
>>  #include <linux/kernel.h>
>>  #include <linux/module.h>
>>  #include <linux/perf_event.h>
>> +#include <linux/platform_device.h>
>>  #include <linux/types.h>
>>  
>>  #undef pr_fmt
>> @@ -47,6 +48,8 @@ struct hisi_uncore_ops {
>>  	void (*disable_counter_int)(struct hisi_pmu *, struct hw_perf_event *);
>>  	void (*start_counters)(struct hisi_pmu *);
>>  	void (*stop_counters)(struct hisi_pmu *);
>> +	u32 (*get_int_status)(struct hisi_pmu *hisi_pmu);
>> +	void (*clear_int_status)(struct hisi_pmu *hisi_pmu, int idx);
>>  };
>>  
>>  struct hisi_pmu_hwevents {
>> @@ -102,6 +105,7 @@ int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node);
>>  ssize_t hisi_uncore_pmu_identifier_attr_show(struct device *dev,
>>  					     struct device_attribute *attr,
>>  					     char *page);
>> -
>> +int hisi_uncore_pmu_init_irq(struct hisi_pmu *hisi_pmu,
>> +			     struct platform_device *pdev);
>>  
>>  #endif /* __HISI_UNCORE_PMU_H__ */
>> -- 
>> 2.7.4
>>
> .
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 2/8] drivers/perf: hisi: Add PMU version for uncore PMU drivers.
  2021-02-03 12:58   ` Mark Rutland
@ 2021-02-04  3:48     ` Shaokun Zhang
  0 siblings, 0 replies; 25+ messages in thread
From: Shaokun Zhang @ 2021-02-04  3:48 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Qi Liu, John Garry, Will Deacon, linux-arm-kernel, Jonathan Cameron

Hi Mark,

在 2021/2/3 20:58, Mark Rutland 写道:
> On Wed, Feb 03, 2021 at 03:51:02PM +0800, Shaokun Zhang wrote:
>> For HiSilicon uncore PMU, more versions are supported and some variables
>> shall be added suffix to distinguish the version which are prepared for
>> the new drivers.
>>
>> Cc: Mark Rutland <mark.rutland@arm.com>
>> Cc: Will Deacon <will@kernel.org>
>> Cc: John Garry <john.garry@huawei.com>
>> Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
>> Reviewed-by: John Garry <john.garry@huawei.com>
>> Co-developed-by: Qi Liu <liuqi115@huawei.com>
>> Signed-off-by: Qi Liu <liuqi115@huawei.com>
>> Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
>> ---
>>  drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 97 ++++++++++++++-------------
>>  drivers/perf/hisilicon/hisi_uncore_hha_pmu.c  | 27 ++++----
>>  drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c  | 24 +++----
>>  3 files changed, 75 insertions(+), 73 deletions(-)
> 
> [...]
> 
>> diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
>> index 831622e0c445..da56fa16b97e 100644
>> --- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
>> +++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
>> @@ -37,7 +37,7 @@
>>  
>>  #define L3C_PERF_CTRL_EN	0x10000
>>  #define L3C_EVTYPE_NONE		0xff
>> -
>> +#define L3C_V1_NR_EVENTS	0x59
>>  /*
>>   * Select the counter register offset using the counter index
>>   */
> 
> I don't think you meant to remove the line space before the comment here.
> 

Apologies, I will restore this in next version.

> With that restored:
> 
> Acked-by: Mark Rutland <mark.rutland@arm.com>

Thanks Mark,

> 
> Mark.
> .
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 3/8] drivers/perf: hisi: Add new functions for L3C PMU
  2021-02-03 13:10   ` Mark Rutland
@ 2021-02-04  6:30     ` Shaokun Zhang
  0 siblings, 0 replies; 25+ messages in thread
From: Shaokun Zhang @ 2021-02-04  6:30 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Qi Liu, John Garry, Will Deacon, linux-arm-kernel, Jonathan Cameron

Hi Mark,

在 2021/2/3 21:10, Mark Rutland 写道:
> On Wed, Feb 03, 2021 at 03:51:03PM +0800, Shaokun Zhang wrote:
>> On HiSilicon Hip09 platform, some new functions are enhanced on L3C PMU,
>> like, tracetag feature that L3C PMU can only count the specified
>> operations by the user, or L3C PMU can give the desired core's statistics
>> in the cluster.
>> $# perf stat -a -e hisi_sccl3_l3c0/config=0x02,tt_core=0xf/ sleep 5
>>
>> $# perf stat -a -e hisi_sccl3_l3c0/config=0x02,tt_req=0x4/ sleep 5
> 
> Are these values documented somewhere?
> 

Yes, all filter choices have been listed in the hisi-pmu document in
patch8.

> [...]
> 
>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tt_core, config1, 7, 0);
>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tt_req, config1, 10, 8);
>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(datasrc_cfg, config1, 15, 11);
>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(datasrc_skt, config1, 16, 16);
> 
> Could you please mention all of these in the commit message?

Ok,

> 
> IIUC tt_core is a mask of physical cores in the cluster, and I guess

Correct,

> tt_req is a request type, but I have no idea what the datasrc_cfg or

Yes, including read, write and atomic operation.

> datasrc_skt (socket?) fields represent.

Data source (datasrc) is used to allow the user to check where the data
comes from, for instance:
perf stat -a -e hisi_sccl3_l3c0/dat_access,datasrc_cfg=0xE/ xxx command.
it will show the dat_access event that comes from the local DDR.
The code meaning is listed in hisi-pmu document later in patch8.
......
5'b01110: comes from the local DDR;
5'b01111: comes from the cross-die DDR;
......

If datasrc is used in the multi-chips and check the data source is another
socket, datasrc_skt shall be configured in perf command, like:
5'b01001: comes from L3C which is in another socket;
5'b10000: comes from cross-socket DDR;

> 
> A rough description would be very helpful, something like:
> 
> | We expose the tracetag filters with new fields exposed to userspace:
> |
> | * tt_core is a mask of cores within the PMU's cluster
> | * tt_req is ???
> | * datasrc_cfg is ???
> | * datasrc_skt is ???

Sure, I will add these descriptions in the log.

Thanks,
Shaokun

> 
> Thanks,
> Mark.
> .
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 4/8] drivers/perf: hisi: Add new functions for HHA PMU
  2021-02-03 13:18   ` Mark Rutland
@ 2021-02-04  6:44     ` Shaokun Zhang
  0 siblings, 0 replies; 25+ messages in thread
From: Shaokun Zhang @ 2021-02-04  6:44 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Qi Liu, John Garry, Will Deacon, linux-arm-kernel, Jonathan Cameron

Hi Mark,

在 2021/2/3 21:18, Mark Rutland 写道:
> On Wed, Feb 03, 2021 at 03:51:04PM +0800, Shaokun Zhang wrote:
>> On HiSilicon Hip09 platform, some new functions are also supported on
>> HHA PMU, it can filter gathered statistics by the Master ID and mask
>> from the SoC if the user wants to do deep-going profiling.
>> Tracetag support is also added with L3C PMU in the SoC system.
>>
>> $# perf stat -a -e hisi_sccl3_hha0/config=0x02,tracetag_en=0x1/ sleep 5
>>
>> $# perf stat -a -e hisi_sccl3_hha0/config=0x02,srcid_cmd=0x1/ sleep 5
>>
>> Much more introduction is added in documentation:
>> Documentation/admin-guide/perf/hisi-pmu.rst
> 
> Could we please enumerate the relevant fields here, with a brief
> description? From a quick scan these are different to those added fo
> rthe L3C PMU.

Apologies that the bad commit log is confused and I will update the
the fields description in next version.

> 
> I appreciate the last partch in the series adds some documentation, but
> it'd be nice to have the context where it's needed.
> 
> [...]
> 
>> @@ -193,6 +304,22 @@ static int hisi_hha_pmu_init_data(struct platform_device *pdev,
>>  		dev_err(&pdev->dev, "Can not read hha sccl-id!\n");
>>  		return -EINVAL;
>>  	}
>> +
>> +	/*
>> +	 * Early versions of BIOS support _UID by mistake, so we support
>> +	 * both "hisilicon, idx-id" as preference, if availbale.
> 
> Typo: s/availbale/available/

Ok.

Thanks,
Shaokun

> 
> Thanks,
> Mark.
> .
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 5/8] drivers/perf: hisi: Update DDRC PMU for programable counter
  2021-02-03 13:23   ` Mark Rutland
@ 2021-02-04  7:00     ` Shaokun Zhang
  0 siblings, 0 replies; 25+ messages in thread
From: Shaokun Zhang @ 2021-02-04  7:00 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Qi Liu, John Garry, Will Deacon, linux-arm-kernel, Jonathan Cameron

Hi Mark,

在 2021/2/3 21:23, Mark Rutland 写道:
> On Wed, Feb 03, 2021 at 03:51:05PM +0800, Shaokun Zhang wrote:
>> DDRC PMU's events are useful for performance profiling, but the events
>> are limited and counters are fixed. On HiSilicon Hip09 platform, PMU
>> counters are the programmable and more events are supported. Let's
>> add the DDRC PMU v2 driver.
> 
>>  static struct attribute *hisi_ddrc_pmu_v1_events_attr[] = {
>>  	HISI_PMU_EVENT_ATTR(flux_wr,		0x00),
>>  	HISI_PMU_EVENT_ATTR(flux_rd,		0x01),
>> @@ -240,6 +370,18 @@ static const struct attribute_group hisi_ddrc_pmu_v1_events_group = {
>>  	.attrs = hisi_ddrc_pmu_v1_events_attr,
>>  };
>>  
>> +static struct attribute *hisi_ddrc_pmu_v2_events_attr[] = {
>> +	HISI_PMU_EVENT_ATTR(clocks,		0x00),
> 
> Should that be 'cycles' ?

Yes, I will fix this.

> 
>> +	HISI_PMU_EVENT_ATTR(flux_wr,		0x83),
>> +	HISI_PMU_EVENT_ATTR(flux_rd,		0x84),
>> +	NULL
>> +};
> 
> The commit message mentioned that v2 supports more events, but this only
> adds three of them (and v2 listed eight distinct events).
> 
> Is there a rationale for only listing these events specifically?

We only put some events to calculate the bandwidth in this list and some
more events will be listed in JSON file which will be upstreamed later.
Because on HiSilicon Hip09 platform, it supports multi-chips and multi-dies
and each die has 4 or 6 DDRCs, if we lists more events in kernel driver,
it will list too many events in perf list and it is a little not friendly
to user.

Thanks,
Shaokun

> 
> Thanks,
> Mark.
> .
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 6/8] drivers/perf: hisi: Add support for HiSilicon SLLC PMU driver
  2021-02-03 13:28   ` Mark Rutland
@ 2021-02-04  7:10     ` Shaokun Zhang
  2021-02-05 14:30       ` Jonathan Cameron
  0 siblings, 1 reply; 25+ messages in thread
From: Shaokun Zhang @ 2021-02-04  7:10 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Qi Liu, John Garry, Will Deacon, linux-arm-kernel, Jonathan Cameron

Hi Mark,

在 2021/2/3 21:28, Mark Rutland 写道:
> On Wed, Feb 03, 2021 at 03:51:06PM +0800, Shaokun Zhang wrote:
>> HiSilicon's Hip09 is comprised by multi-dies that can be connected by SLLC
>> module (Skyros Link Layer Controller), its has separate PMU registers which
>> the driver can program it freely and interrupt is supported to handle
>> counter overflow. Let's support its driver under the framework of HiSilicon
>> uncore PMU driver.
> 
> [...]
> 
>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_lo, config1, 10, 0);
>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_hi, config1, 21, 11);
>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_cmd, config1, 32, 22);
>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 43, 33);
>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 44, 44);
> 
> If you could describe these fields in the commit message that would be
> helpful.

Ok,

> 
> What is a 'tgtid'? Is that a 'target ID' or something to that effect?

Yes, target ID.

> 
> [...]
> 
>> +	HISI_PMU_FORMAT_ATTR(tgtid_low, "config1:0-10"),
>> +	HISI_PMU_FORMAT_ATTR(tgtid_high, "config1:11-21"),
> 
> Does this need to be exposed to userspace in two halves, rather than
> being a single 'tgtid' field that the driver can decompose as necessary?

We expose two fields because we support to count the specified target ID
or some target IDs combination, if a single 'tgtid' field, the later scene
is not supported.

Thanks,
Shaokun

> 
> Thanks,
> Mark.
> .
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 7/8] drivers/perf: hisi: Add support for HiSilicon PA PMU driver
  2021-02-03 13:43   ` Mark Rutland
@ 2021-02-04  7:20     ` Shaokun Zhang
  0 siblings, 0 replies; 25+ messages in thread
From: Shaokun Zhang @ 2021-02-04  7:20 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Qi Liu, John Garry, Will Deacon, linux-arm-kernel, Jonathan Cameron

Hi Mark,

在 2021/2/3 21:43, Mark Rutland 写道:
> On Wed, Feb 03, 2021 at 03:51:07PM +0800, Shaokun Zhang wrote:
>> On HiSilicon Hip09 platform, there is a PA (Protocol Adapter) module on
>> each chip SICL (Super I/O Cluster) which incorporates three Hydra interface
>> and facilitates the cache coherency between the dies on the chip. While PA
>> uncore PMU model is the same as other Hip09 PMU modules and many PMU events
>> are supported. Let's support the PMU driver using the HiSilicon uncore PMU
>> framework.
> 
>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_cmd, config1, 10, 0);
>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_msk, config1, 21, 11);
>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_cmd, config1, 32, 22);
>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 43, 33);
>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 44, 44);
> 
> As with the other patches, a brief introduction for these in the commit
> message would be helpful.

Sure, it will be added in next version.

> 
>> +static void hisi_pa_pmu_enable_filter(struct perf_event *event)
>> +{
>> +	if (event->attr.config1 != 0x0) {
>> +		hisi_pa_pmu_enable_tracetag(event);
>> +		hisi_pa_pmu_config_srcid(event);
>> +		hisi_pa_pmu_config_tgtid(event);
>> +	}
>> +}
>> +
>> +static void hisi_pa_pmu_disable_filter(struct perf_event *event)
>> +{
>> +	if (event->attr.config1 != 0x0) {
>> +		hisi_pa_pmu_clear_tgtid(event);
>> +		hisi_pa_pmu_clear_srcid(event);
>> +		hisi_pa_pmu_clear_tracetag(event);
>> +	}
>> +}
> 
> Does this get reset when the driver probes? I couldn't spot where we
> ensured this was in a sane initial state.

For these filters, the default value is disabled and if the user needs
this feature, the driver will configure and enable this corresponding
control bit.

> 
>> +static void hisi_pa_pmu_write_evtype(struct hisi_pmu *pa_pmu, int idx,
>> +				     u32 type)
>> +{
>> +	u32 reg, reg_idx, shift, val;
>> +
>> +	/*
>> +	 * Select the appropriate event select register(PA_EVENT_TYPE0/1).
>> +	 * There are 2 event select registers for the 8 hardware counters.
>> +	 * Event code is 8-bits and for the former 4 hardware counters,
>> +	 * PA_EVENT_TYPE0 is chosen. For the latter 4 hardware counters,
>> +	 * PA_EVENT_TYPE1 is chosen.
>> +	 */
>> +	reg = PA_EVENT_TYPE0 + rounddown(idx, 4);
> 
> The use of rounddown() here is confusing, as it relies on the number of
> elements per register happening to be equal to the size of the register
> in bytes. That works here since each element is a byte, but as it's not
> the common case it sticks out.
> 
> Please divide the index by the number of elements per register, then
> multiply that by the size of the register.

Ok, will fix this in v3.

Thanks,
Shaokun

> 
> Thanks,
> Mark.
> .
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 6/8] drivers/perf: hisi: Add support for HiSilicon SLLC PMU driver
  2021-02-04  7:10     ` Shaokun Zhang
@ 2021-02-05 14:30       ` Jonathan Cameron
  2021-02-07  1:43         ` Shaokun Zhang
  0 siblings, 1 reply; 25+ messages in thread
From: Jonathan Cameron @ 2021-02-05 14:30 UTC (permalink / raw)
  To: Shaokun Zhang
  Cc: Mark Rutland, Qi Liu, John Garry, Will Deacon, linux-arm-kernel

On Thu, 4 Feb 2021 15:10:32 +0800
Shaokun Zhang <zhangshaokun@hisilicon.com> wrote:

> Hi Mark,
> 
> 在 2021/2/3 21:28, Mark Rutland 写道:
> > On Wed, Feb 03, 2021 at 03:51:06PM +0800, Shaokun Zhang wrote:  
> >> HiSilicon's Hip09 is comprised by multi-dies that can be connected by SLLC
> >> module (Skyros Link Layer Controller), its has separate PMU registers which
> >> the driver can program it freely and interrupt is supported to handle
> >> counter overflow. Let's support its driver under the framework of HiSilicon
> >> uncore PMU driver.  
> > 
> > [...]
> >   
> >> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_lo, config1, 10, 0);
> >> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_hi, config1, 21, 11);
> >> +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_cmd, config1, 32, 22);
> >> +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 43, 33);
> >> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 44, 44);  
> > 
> > If you could describe these fields in the commit message that would be
> > helpful.  
> 
> Ok,
> 
> > 
> > What is a 'tgtid'? Is that a 'target ID' or something to that effect?  
> 
> Yes, target ID.
> 
> > 
> > [...]
> >   
> >> +	HISI_PMU_FORMAT_ATTR(tgtid_low, "config1:0-10"),
> >> +	HISI_PMU_FORMAT_ATTR(tgtid_high, "config1:11-21"),  
> > 
> > Does this need to be exposed to userspace in two halves, rather than
> > being a single 'tgtid' field that the driver can decompose as necessary?  
> 
> We expose two fields because we support to count the specified target ID
> or some target IDs combination, if a single 'tgtid' field, the later scene
> is not supported.

Would _min and _max make that clearer perhaps?

> 
> Thanks,
> Shaokun
> 
> > 
> > Thanks,
> > Mark.
> > .
> >   


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 6/8] drivers/perf: hisi: Add support for HiSilicon SLLC PMU driver
  2021-02-05 14:30       ` Jonathan Cameron
@ 2021-02-07  1:43         ` Shaokun Zhang
  0 siblings, 0 replies; 25+ messages in thread
From: Shaokun Zhang @ 2021-02-07  1:43 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Mark Rutland, Qi Liu, John Garry, Will Deacon, linux-arm-kernel

Hi Jonathan,

在 2021/2/5 22:30, Jonathan Cameron 写道:
> On Thu, 4 Feb 2021 15:10:32 +0800
> Shaokun Zhang <zhangshaokun@hisilicon.com> wrote:
> 
>> Hi Mark,
>>
>> 在 2021/2/3 21:28, Mark Rutland 写道:
>>> On Wed, Feb 03, 2021 at 03:51:06PM +0800, Shaokun Zhang wrote:  
>>>> HiSilicon's Hip09 is comprised by multi-dies that can be connected by SLLC
>>>> module (Skyros Link Layer Controller), its has separate PMU registers which
>>>> the driver can program it freely and interrupt is supported to handle
>>>> counter overflow. Let's support its driver under the framework of HiSilicon
>>>> uncore PMU driver.  
>>>
>>> [...]
>>>   
>>>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_lo, config1, 10, 0);
>>>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tgtid_hi, config1, 21, 11);
>>>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_cmd, config1, 32, 22);
>>>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 43, 33);
>>>> +HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 44, 44);  
>>>
>>> If you could describe these fields in the commit message that would be
>>> helpful.  
>>
>> Ok,
>>
>>>
>>> What is a 'tgtid'? Is that a 'target ID' or something to that effect?  
>>
>> Yes, target ID.
>>
>>>
>>> [...]
>>>   
>>>> +	HISI_PMU_FORMAT_ATTR(tgtid_low, "config1:0-10"),
>>>> +	HISI_PMU_FORMAT_ATTR(tgtid_high, "config1:11-21"),  
>>>
>>> Does this need to be exposed to userspace in two halves, rather than
>>> being a single 'tgtid' field that the driver can decompose as necessary?  
>>
>> We expose two fields because we support to count the specified target ID
>> or some target IDs combination, if a single 'tgtid' field, the later scene
>> is not supported.
> 
> Would _min and _max make that clearer perhaps?
> 

Sure, will update this.

Shaokun,


>>
>> Thanks,
>> Shaokun
>>
>>>
>>> Thanks,
>>> Mark.
>>> .
>>>   
> 
> .
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2021-02-07  1:45 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-03  7:51 [PATCH v2 0/8] Add support for HiSilicon Hip09 uncore PMU driver Shaokun Zhang
2021-02-03  7:51 ` [PATCH v2 1/8] drivers/perf: hisi: Refactor code for more uncore PMUs Shaokun Zhang
2021-02-03 12:53   ` Mark Rutland
2021-02-04  3:38     ` Shaokun Zhang
2021-02-03  7:51 ` [PATCH v2 2/8] drivers/perf: hisi: Add PMU version for uncore PMU drivers Shaokun Zhang
2021-02-03 12:58   ` Mark Rutland
2021-02-04  3:48     ` Shaokun Zhang
2021-02-03  7:51 ` [PATCH v2 3/8] drivers/perf: hisi: Add new functions for L3C PMU Shaokun Zhang
2021-02-03 13:10   ` Mark Rutland
2021-02-04  6:30     ` Shaokun Zhang
2021-02-03  7:51 ` [PATCH v2 4/8] drivers/perf: hisi: Add new functions for HHA PMU Shaokun Zhang
2021-02-03 13:18   ` Mark Rutland
2021-02-04  6:44     ` Shaokun Zhang
2021-02-03  7:51 ` [PATCH v2 5/8] drivers/perf: hisi: Update DDRC PMU for programable counter Shaokun Zhang
2021-02-03 13:23   ` Mark Rutland
2021-02-04  7:00     ` Shaokun Zhang
2021-02-03  7:51 ` [PATCH v2 6/8] drivers/perf: hisi: Add support for HiSilicon SLLC PMU driver Shaokun Zhang
2021-02-03 13:28   ` Mark Rutland
2021-02-04  7:10     ` Shaokun Zhang
2021-02-05 14:30       ` Jonathan Cameron
2021-02-07  1:43         ` Shaokun Zhang
2021-02-03  7:51 ` [PATCH v2 7/8] drivers/perf: hisi: Add support for HiSilicon PA " Shaokun Zhang
2021-02-03 13:43   ` Mark Rutland
2021-02-04  7:20     ` Shaokun Zhang
2021-02-03  7:51 ` [PATCH v2 8/8] docs: perf: Add new description on HiSilicon uncore PMU v2 Shaokun Zhang

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.