Re: [PATCH v4 5/6] perf: hisi: Add support for HiSilicon SoC DDRC PMU driver
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
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);