[PATCH 5/8] drivers/perf: riscv: Implement PMU event info function
Atish Kumar Patra
atishp at rivosinc.com
Mon Dec 9 17:16:43 PST 2024
On Mon, Dec 2, 2024 at 2:49 PM Samuel Holland <samuel.holland at sifive.com> wrote:
>
> Hi Atish,
>
> On 2024-11-19 2:29 PM, Atish Patra wrote:
> > With the new SBI PMU event info function, we can query the availability
> > of the all standard SBI PMU events at boot time with a single ecall.
> > This improves the bootime by avoiding making an SBI call for each
> > standard PMU event. Since this function is defined only in SBI v3.0,
> > invoke this only if the underlying SBI implementation is v3.0 or higher.
> >
> > Signed-off-by: Atish Patra <atishp at rivosinc.com>
> > ---
> > arch/riscv/include/asm/sbi.h | 7 +++++
> > drivers/perf/riscv_pmu_sbi.c | 71 ++++++++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 78 insertions(+)
> >
> > diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
> > index 3ee9bfa5e77c..c04f64fbc01d 100644
> > --- a/arch/riscv/include/asm/sbi.h
> > +++ b/arch/riscv/include/asm/sbi.h
> > @@ -134,6 +134,7 @@ enum sbi_ext_pmu_fid {
> > SBI_EXT_PMU_COUNTER_FW_READ,
> > SBI_EXT_PMU_COUNTER_FW_READ_HI,
> > SBI_EXT_PMU_SNAPSHOT_SET_SHMEM,
> > + SBI_EXT_PMU_EVENT_GET_INFO,
> > };
> >
> > union sbi_pmu_ctr_info {
> > @@ -157,6 +158,12 @@ struct riscv_pmu_snapshot_data {
> > u64 reserved[447];
> > };
> >
> > +struct riscv_pmu_event_info {
> > + u32 event_idx;
> > + u32 output;
> > + u64 event_data;
> > +};
> > +
> > #define RISCV_PMU_RAW_EVENT_MASK GENMASK_ULL(47, 0)
> > #define RISCV_PMU_PLAT_FW_EVENT_MASK GENMASK_ULL(61, 0)
> > /* SBI v3.0 allows extended hpmeventX width value */
> > diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
> > index f0e845ff6b79..2a6527cc9d97 100644
> > --- a/drivers/perf/riscv_pmu_sbi.c
> > +++ b/drivers/perf/riscv_pmu_sbi.c
> > @@ -100,6 +100,7 @@ static unsigned int riscv_pmu_irq;
> > /* Cache the available counters in a bitmask */
> > static unsigned long cmask;
> >
> > +static int pmu_event_find_cache(u64 config);
>
> This new declaration does not appear to be used.
>
This is a forward declaration as pmu_event_find_cache but it should
be in the next patch instead of this patch.
I have moved it to that patch.
> > struct sbi_pmu_event_data {
> > union {
> > union {
> > @@ -299,6 +300,68 @@ static struct sbi_pmu_event_data pmu_cache_event_map[PERF_COUNT_HW_CACHE_MAX]
> > },
> > };
> >
> > +static int pmu_sbi_check_event_info(void)
> > +{
> > + int num_events = ARRAY_SIZE(pmu_hw_event_map) + PERF_COUNT_HW_CACHE_MAX *
> > + PERF_COUNT_HW_CACHE_OP_MAX * PERF_COUNT_HW_CACHE_RESULT_MAX;
> > + struct riscv_pmu_event_info *event_info_shmem;
> > + phys_addr_t base_addr;
> > + int i, j, k, result = 0, count = 0;
> > + struct sbiret ret;
> > +
> > + event_info_shmem = (struct riscv_pmu_event_info *)
> > + kcalloc(num_events, sizeof(*event_info_shmem), GFP_KERNEL);
>
> Please drop the unnecessary cast.
>
Done.
> > + if (!event_info_shmem) {
> > + pr_err("Can not allocate memory for event info query\n");
>
> Usually there's no need to print an error for allocation failure, since the
> allocator already warns. And this isn't really an error, since we can (and do)
> fall back to the existing way of checking for events.
>
Fixed.
> > + return -ENOMEM;
> > + }
> > +
> > + for (i = 0; i < ARRAY_SIZE(pmu_hw_event_map); i++)
> > + event_info_shmem[count++].event_idx = pmu_hw_event_map[i].event_idx;
> > +
> > + for (i = 0; i < ARRAY_SIZE(pmu_cache_event_map); i++) {
> > + for (int j = 0; j < ARRAY_SIZE(pmu_cache_event_map[i]); j++) {
> > + for (int k = 0; k < ARRAY_SIZE(pmu_cache_event_map[i][j]); k++)
> > + event_info_shmem[count++].event_idx =
> > + pmu_cache_event_map[i][j][k].event_idx;
> > + }
> > + }
> > +
> > + base_addr = __pa(event_info_shmem);
> > + if (IS_ENABLED(CONFIG_32BIT))
> > + ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_EVENT_GET_INFO, lower_32_bits(base_addr),
> > + upper_32_bits(base_addr), count, 0, 0, 0);
> > + else
> > + ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_EVENT_GET_INFO, base_addr, 0,
> > + count, 0, 0, 0);
> > + if (ret.error) {
> > + result = -EOPNOTSUPP;
> > + goto free_mem;
> > + }
> > + /* Do we need some barriers here or priv mode transition will ensure that */
>
> No barrier is needed -- the SBI implementation is running on the same hart, so
> coherency isn't even a consideration.
>
> > + for (i = 0; i < ARRAY_SIZE(pmu_hw_event_map); i++) {
> > + if (!(event_info_shmem[i].output & 0x01))
>
> This bit mask should probably use a macro.
>
> > + pmu_hw_event_map[i].event_idx = -ENOENT;
> > + }
> > +
> > + count = ARRAY_SIZE(pmu_hw_event_map);
> > +
> > + for (i = 0; i < ARRAY_SIZE(pmu_cache_event_map); i++) {
> > + for (j = 0; j < ARRAY_SIZE(pmu_cache_event_map[i]); j++) {
> > + for (k = 0; k < ARRAY_SIZE(pmu_cache_event_map[i][j]); k++) {
> > + if (!(event_info_shmem[count].output & 0x01))
>
> Same comment applies here.
>
Done.
> Regards,
> Samuel
>
> > + pmu_cache_event_map[i][j][k].event_idx = -ENOENT;
> > + count++;
> > + }
> > + }
> > + }
> > +
> > +free_mem:
> > + kfree(event_info_shmem);
> > +
> > + return result;
> > +}
> > +
> > static void pmu_sbi_check_event(struct sbi_pmu_event_data *edata)
> > {
> > struct sbiret ret;
> > @@ -316,6 +379,14 @@ static void pmu_sbi_check_event(struct sbi_pmu_event_data *edata)
> >
> > static void pmu_sbi_check_std_events(struct work_struct *work)
> > {
> > + int ret;
> > +
> > + if (sbi_v3_available) {
> > + ret = pmu_sbi_check_event_info();
> > + if (!ret)
> > + return;
> > + }
> > +
> > for (int i = 0; i < ARRAY_SIZE(pmu_hw_event_map); i++)
> > pmu_sbi_check_event(&pmu_hw_event_map[i]);
> >
> >
>
More information about the linux-arm-kernel
mailing list