[PATCH 1/8] drivers/perf: hisi: Refactor code for more uncore PMUs
Shaokun Zhang
zhangshaokun at hisilicon.com
Thu Dec 31 01:19:29 EST 2020
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 at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: John Garry <john.garry at huawei.com>
Cc: Jonathan Cameron <Jonathan.Cameron at huawei.com>
Reviewed-by: John Garry <john.garry at huawei.com>
Co-developed-by: Qi Liu <liuqi115 at huawei.com>
Signed-off-by: Qi Liu <liuqi115 at huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun at 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 5ac6c9113767..69ccbe02f1e3 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 41b2dceb5f26..29c26f2e3c08 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 705501d18d03..68c00689b275 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
More information about the linux-arm-kernel
mailing list