Re: [PATCH v4 5/6] perf: hisi: Add support for HiSilicon SoC DDRC PMU driver

2017-08-16 Thread Zhangshaokun
Hi Mark,

On 2017/8/15 21:02, Mark Rutland wrote:
> On Tue, Jul 25, 2017 at 08:10:41PM +0800, Shaokun Zhang wrote:
>> This patch adds support for DDRC PMU driver in HiSilicon SoC chip, Each
>> DDRC has own control, counter and interrupt registers and is an separate
>> PMU. For each DDRC PMU, it has 8-fixed-purpose counters which have been
>> mapped to 8-events by hardware, it assumes that counter index is equal
>> to event code (0 - 7) in DDRC PMU driver. Interrupt is supported to
>> handle counter (32-bits) overflow.
>>
>> Reviewed-by: Jonathan Cameron 
>> Signed-off-by: Shaokun Zhang 
>> Signed-off-by: Anurup M 
>> ---
>>  drivers/perf/hisilicon/Makefile   |   2 +-
>>  drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 420 
>> ++
>>  2 files changed, 421 insertions(+), 1 deletion(-)
>>  create mode 100644 drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
> 
> My comments for the HHA PMU driver all apply here, too.
> 

Surely.

Thanks.
Shaokun

> Thanks,
> Mark.
> 
>> diff --git a/drivers/perf/hisilicon/Makefile 
>> b/drivers/perf/hisilicon/Makefile
>> index a72afe8..2621d51 100644
>> --- a/drivers/perf/hisilicon/Makefile
>> +++ b/drivers/perf/hisilicon/Makefile
>> @@ -1 +1 @@
>> -obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o 
>> hisi_uncore_hha_pmu.o
>> +obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o 
>> hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o
>> diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c 
>> b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
>> new file mode 100644
>> index 000..e178a09
>> --- /dev/null
>> +++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
>> @@ -0,0 +1,420 @@
>> +/*
>> + * HiSilicon SoC DDRC uncore Hardware event counters support
>> + *
>> + * Copyright (C) 2017 Hisilicon Limited
>> + * Author: Shaokun Zhang 
>> + * Anurup M 
>> + *
>> + * This code is based on the uncore PMUs like arm-cci and arm-ccn.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include "hisi_uncore_pmu.h"
>> +
>> +/* DDRC register definition */
>> +#define DDRC_PERF_CTRL  0x010
>> +#define DDRC_FLUX_WR0x380
>> +#define DDRC_FLUX_RD0x384
>> +#define DDRC_FLUX_WCMD  0x388
>> +#define DDRC_FLUX_RCMD  0x38c
>> +#define DDRC_PRE_CMD0x3c0
>> +#define DDRC_ACT_CMD0x3c4
>> +#define DDRC_BNK_CHG0x3c8
>> +#define DDRC_RNK_CHG0x3cc
>> +#define DDRC_EVENT_CTRL 0x6C0
>> +#define DDRC_INT_MASK   0x6c8
>> +#define DDRC_INT_STATUS 0x6cc
>> +#define DDRC_INT_CLEAR  0x6d0
>> +
>> +/* DDRC supports 8-events and counter is fixed-purpose */
>> +#define DDRC_NR_COUNTERS0x8
>> +#define DDRC_NR_EVENTS  DDRC_NR_COUNTERS
>> +
>> +#define DDRC_PERF_CTRL_EN   0x2
>> +
>> +/*
>> + * For DDRC PMU, 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.
>> + */
>> +#define GET_DDRC_EVENTID(hwc)   (hwc->config_base & 0x7)
>> +
>> +static const u32 ddrc_reg_off[] = {
>> +DDRC_FLUX_WR, DDRC_FLUX_RD, DDRC_FLUX_WCMD, DDRC_FLUX_RCMD,
>> +DDRC_PRE_CMD, DDRC_ACT_CMD, DDRC_BNK_CHG, DDRC_RNK_CHG
>> +};
>> +
>> +/*
>> + * 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.
>> + */
>> +static u32 get_counter_reg_off(int cntr_idx)
>> +{
>> +return ddrc_reg_off[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);
>> +u32 reg;
>> +
>> +if (!hisi_uncore_pmu_counter_valid(ddrc_pmu, idx)) {
>> +dev_err(ddrc_pmu->dev, "Unsupported event index:%d!\n", idx);
>> +return 0;
>> +}
>> +
>> +reg = get_counter_reg_off(idx);
>> +
>> +return readl(ddrc_pmu->base + reg);
>> +}
>> +
>> +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);
>> +u32 reg;
>> +
>> +if (!hisi_uncore_pmu_counter_valid(ddrc_pmu, idx)) {
>> +dev_err(ddrc_pmu->dev, "Unsupported event index:%d!\n", idx);
>> +return;
>> +}
>> +
>> +reg = get_counter_reg_off(idx);
>> +writel((u32)val, ddrc_pmu->base + reg);
>> +}
>> +
>> +static void 

Re: [PATCH v4 5/6] perf: hisi: Add support for HiSilicon SoC DDRC PMU driver

2017-08-15 Thread Mark Rutland
On Tue, Jul 25, 2017 at 08:10:41PM +0800, Shaokun Zhang wrote:
> This patch adds support for DDRC PMU driver in HiSilicon SoC chip, Each
> DDRC has own control, counter and interrupt registers and is an separate
> PMU. For each DDRC PMU, it has 8-fixed-purpose counters which have been
> mapped to 8-events by hardware, it assumes that counter index is equal
> to event code (0 - 7) in DDRC PMU driver. Interrupt is supported to
> handle counter (32-bits) overflow.
> 
> Reviewed-by: Jonathan Cameron 
> Signed-off-by: Shaokun Zhang 
> Signed-off-by: Anurup M 
> ---
>  drivers/perf/hisilicon/Makefile   |   2 +-
>  drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c | 420 
> ++
>  2 files changed, 421 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c

My comments for the HHA PMU driver all apply here, too.

Thanks,
Mark.

> diff --git a/drivers/perf/hisilicon/Makefile b/drivers/perf/hisilicon/Makefile
> index a72afe8..2621d51 100644
> --- a/drivers/perf/hisilicon/Makefile
> +++ b/drivers/perf/hisilicon/Makefile
> @@ -1 +1 @@
> -obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o 
> hisi_uncore_hha_pmu.o
> +obj-$(CONFIG_HISI_PMU) += hisi_uncore_pmu.o hisi_uncore_l3c_pmu.o 
> hisi_uncore_hha_pmu.o hisi_uncore_ddrc_pmu.o
> diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c 
> b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
> new file mode 100644
> index 000..e178a09
> --- /dev/null
> +++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
> @@ -0,0 +1,420 @@
> +/*
> + * HiSilicon SoC DDRC uncore Hardware event counters support
> + *
> + * Copyright (C) 2017 Hisilicon Limited
> + * Author: Shaokun Zhang 
> + * Anurup M 
> + *
> + * This code is based on the uncore PMUs like arm-cci and arm-ccn.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include "hisi_uncore_pmu.h"
> +
> +/* DDRC register definition */
> +#define DDRC_PERF_CTRL   0x010
> +#define DDRC_FLUX_WR 0x380
> +#define DDRC_FLUX_RD 0x384
> +#define DDRC_FLUX_WCMD  0x388
> +#define DDRC_FLUX_RCMD  0x38c
> +#define DDRC_PRE_CMD0x3c0
> +#define DDRC_ACT_CMD0x3c4
> +#define DDRC_BNK_CHG0x3c8
> +#define DDRC_RNK_CHG0x3cc
> +#define DDRC_EVENT_CTRL 0x6C0
> +#define DDRC_INT_MASK0x6c8
> +#define DDRC_INT_STATUS  0x6cc
> +#define DDRC_INT_CLEAR   0x6d0
> +
> +/* DDRC supports 8-events and counter is fixed-purpose */
> +#define DDRC_NR_COUNTERS 0x8
> +#define DDRC_NR_EVENTS   DDRC_NR_COUNTERS
> +
> +#define DDRC_PERF_CTRL_EN0x2
> +
> +/*
> + * For DDRC PMU, 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.
> + */
> +#define GET_DDRC_EVENTID(hwc)(hwc->config_base & 0x7)
> +
> +static const u32 ddrc_reg_off[] = {
> + DDRC_FLUX_WR, DDRC_FLUX_RD, DDRC_FLUX_WCMD, DDRC_FLUX_RCMD,
> + DDRC_PRE_CMD, DDRC_ACT_CMD, DDRC_BNK_CHG, DDRC_RNK_CHG
> +};
> +
> +/*
> + * 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.
> + */
> +static u32 get_counter_reg_off(int cntr_idx)
> +{
> + return ddrc_reg_off[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);
> + u32 reg;
> +
> + if (!hisi_uncore_pmu_counter_valid(ddrc_pmu, idx)) {
> + dev_err(ddrc_pmu->dev, "Unsupported event index:%d!\n", idx);
> + return 0;
> + }
> +
> + reg = get_counter_reg_off(idx);
> +
> + return readl(ddrc_pmu->base + reg);
> +}
> +
> +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);
> + u32 reg;
> +
> + if (!hisi_uncore_pmu_counter_valid(ddrc_pmu, idx)) {
> + dev_err(ddrc_pmu->dev, "Unsupported event index:%d!\n", idx);
> + return;
> + }
> +
> + reg = get_counter_reg_off(idx);
> + writel((u32)val, ddrc_pmu->base + reg);
> +}
> +
> +static void hisi_ddrc_pmu_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);