diff mbox series

[v2,1/8] drivers/perf: hisi: Refactor code for more uncore PMUs

Message ID 1612338668-40493-2-git-send-email-zhangshaokun@hisilicon.com (mailing list archive)
State New, archived
Headers show
Series Add support for HiSilicon Hip09 uncore PMU driver | expand

Commit Message

Shaokun Zhang Feb. 3, 2021, 7:51 a.m. UTC
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(-)

Comments

Mark Rutland Feb. 3, 2021, 12:53 p.m. UTC | #1
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
>
Shaokun Zhang Feb. 4, 2021, 3:38 a.m. UTC | #2
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
>>
> .
>
diff mbox series

Patch

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__ */