[PATCH v4 07/15] platform: andes: Add Andes custom PMU support
Anup Patel
anup at brainfault.org
Wed Dec 6 04:24:35 PST 2023
On Thu, Nov 30, 2023 at 6:13 PM Yu Chien Peter Lin
<peterlin at andestech.com> wrote:
>
> Before the ratification of Sscofpmf, the Andes PMU extension
> was designed to support the sampling and filtering with hardware
> performance counters (zihpm), it works with the current SBI PMU
> extension and Linux SBI PMU driver.
>
> We implement 1) the PMU device callbacks that update the
> corresponding bits on custom CSRs, 2) extentions_init() to detect
> the hardware support of Andes PMU and initialize the per-hart
> PMU related CSR, and 3) pmu_init() to register PMU device and
> populate event mappings.
>
> Also define a andes_pmu_setup() function which is in preparation
> for adding default PMU mappings in andes_hpm.h
>
> Signed-off-by: Yu Chien Peter Lin <peterlin at andestech.com>
> Reviewed-by: Leo Yu-Chi Liang <ycliang at andestech.com>
Looks good to me.
Reviewed-by: Anup Patel <anup at brainfault.org>
Regards,
Anup
> ---
> Changes v1 -> v2:
> - Fix mode filtering in andes_hw_counter_filter_mode()
> - Return early if pmu is not supported in andes_pmu_init() (suggested by Prabhakar)
> - Don't grant write permissions via CSR_MCOUNTERWEN as not needed
> Changes v2 -> v3:
> - Drop Anup's RB tag as we add andes_pmu_extensions_init() to initialize per-hart
> extension on scratch and move andes_pmu_init() to new added platform override pmu_init()
> Changes v3 -> v4: (suggested by Samuel)
> - Add andes_hpm.h as an placeholder for andes_pmu_setup() to avoid compile failure
> - Do not call fdt_pmu_setup() in andes_pmu_init() as it will be done in generic_pmu_init()
> ---
> platform/generic/andes/Kconfig | 8 ++
> platform/generic/andes/andes_pmu.c | 105 +++++++++++++++++++++
> platform/generic/andes/objects.mk | 1 +
> platform/generic/include/andes/andes_hpm.h | 12 +++
> platform/generic/include/andes/andes_pmu.h | 34 +++++++
> 5 files changed, 160 insertions(+)
> create mode 100644 platform/generic/andes/andes_pmu.c
> create mode 100644 platform/generic/include/andes/andes_hpm.h
> create mode 100644 platform/generic/include/andes/andes_pmu.h
>
> diff --git a/platform/generic/andes/Kconfig b/platform/generic/andes/Kconfig
> index a91fb9c..3665b33 100644
> --- a/platform/generic/andes/Kconfig
> +++ b/platform/generic/andes/Kconfig
> @@ -7,3 +7,11 @@ config ANDES45_PMA
> config ANDES_SBI
> bool "Andes SBI support"
> default n
> +
> +config ANDES_PMU
> + bool "Andes PMU extension (XAndesPMU) support"
> + default n
> + help
> + Andes PMU extension supports the event counter overflow
> + interrupt and mode filtering, similar to the standard
> + Sscofpmf and Smcntrpmf.
> diff --git a/platform/generic/andes/andes_pmu.c b/platform/generic/andes/andes_pmu.c
> new file mode 100644
> index 0000000..4b2d45b
> --- /dev/null
> +++ b/platform/generic/andes/andes_pmu.c
> @@ -0,0 +1,105 @@
> +// SPDX-License-Identifier: BSD-2-Clause
> +/*
> + * andes_pmu.c - Andes PMU device callbacks and platform overrides
> + *
> + * Copyright (C) 2023 Andes Technology Corporation
> + */
> +
> +#include <andes/andes45.h>
> +#include <andes/andes_hpm.h>
> +#include <andes/andes_pmu.h>
> +#include <sbi/sbi_bitops.h>
> +#include <sbi/sbi_error.h>
> +#include <sbi/sbi_pmu.h>
> +#include <libfdt.h>
> +
> +static void andes_hw_counter_enable_irq(uint32_t ctr_idx)
> +{
> + unsigned long mip_val;
> +
> + if (ctr_idx >= SBI_PMU_HW_CTR_MAX)
> + return;
> +
> + mip_val = csr_read(CSR_MIP);
> + if (!(mip_val & MIP_PMOVI))
> + csr_clear(CSR_MCOUNTEROVF, BIT(ctr_idx));
> +
> + csr_set(CSR_MCOUNTERINTEN, BIT(ctr_idx));
> +}
> +
> +static void andes_hw_counter_disable_irq(uint32_t ctr_idx)
> +{
> + csr_clear(CSR_MCOUNTERINTEN, BIT(ctr_idx));
> +}
> +
> +static void andes_hw_counter_filter_mode(unsigned long flags, int ctr_idx)
> +{
> + if (flags & SBI_PMU_CFG_FLAG_SET_UINH)
> + csr_set(CSR_MCOUNTERMASK_U, BIT(ctr_idx));
> + else
> + csr_clear(CSR_MCOUNTERMASK_U, BIT(ctr_idx));
> +
> + if (flags & SBI_PMU_CFG_FLAG_SET_SINH)
> + csr_set(CSR_MCOUNTERMASK_S, BIT(ctr_idx));
> + else
> + csr_clear(CSR_MCOUNTERMASK_S, BIT(ctr_idx));
> +}
> +
> +static struct sbi_pmu_device andes_pmu = {
> + .name = "andes_pmu",
> + .hw_counter_enable_irq = andes_hw_counter_enable_irq,
> + .hw_counter_disable_irq = andes_hw_counter_disable_irq,
> + /*
> + * We set delegation of supervisor local interrupts via
> + * 18th bit on mslideleg instead of mideleg, so leave
> + * hw_counter_irq_bit() callback unimplemented.
> + */
> + .hw_counter_irq_bit = NULL,
> + .hw_counter_filter_mode = andes_hw_counter_filter_mode
> +};
> +
> +int andes_pmu_extensions_init(const struct fdt_match *match,
> + struct sbi_hart_features *hfeatures)
> +{
> + struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
> +
> + if (!has_andes_pmu())
> + return 0;
> +
> + /*
> + * Don't expect both Andes PMU and standard Sscofpmf/Smcntrpmf,
> + * are supported as they serve the same purpose.
> + */
> + if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF) ||
> + sbi_hart_has_extension(scratch, SBI_HART_EXT_SMCNTRPMF))
> + return SBI_EINVAL;
> + sbi_hart_update_extension(scratch, SBI_HART_EXT_XANDESPMU, true);
> +
> + /* Inhibit all HPM counters in M-mode */
> + csr_write(CSR_MCOUNTERMASK_M, 0xfffffffd);
> + /* Delegate counter overflow interrupt to S-mode */
> + csr_write(CSR_MSLIDELEG, MIP_PMOVI);
> +
> + return 0;
> +}
> +
> +int andes_pmu_init(const struct fdt_match *match)
> +{
> + struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
> + void *fdt = fdt_get_address();
> + int pmu_offset;
> +
> + if (sbi_hart_has_extension(scratch, SBI_HART_EXT_XANDESPMU))
> + sbi_pmu_set_device(&andes_pmu);
> +
> + /*
> + * Populate default mappings if device-tree doesn't
> + * provide a valid pmu node.
> + */
> + pmu_offset = fdt_node_offset_by_compatible(fdt, -1, "riscv,pmu");
> + if (pmu_offset < 0)
> + return (pmu_offset == -FDT_ERR_NOTFOUND) ? andes_pmu_setup()
> + : SBI_EFAIL;
> +
> + return 0;
> +}
> diff --git a/platform/generic/andes/objects.mk b/platform/generic/andes/objects.mk
> index e8f86ea..6a8c66c 100644
> --- a/platform/generic/andes/objects.mk
> +++ b/platform/generic/andes/objects.mk
> @@ -7,3 +7,4 @@ platform-objs-$(CONFIG_PLATFORM_ANDES_AE350) += andes/ae350.o andes/sleep.o
>
> platform-objs-$(CONFIG_ANDES45_PMA) += andes/andes45-pma.o
> platform-objs-$(CONFIG_ANDES_SBI) += andes/andes_sbi.o
> +platform-objs-$(CONFIG_ANDES_PMU) += andes/andes_pmu.o
> diff --git a/platform/generic/include/andes/andes_hpm.h b/platform/generic/include/andes/andes_hpm.h
> new file mode 100644
> index 0000000..b4d71b9
> --- /dev/null
> +++ b/platform/generic/include/andes/andes_hpm.h
> @@ -0,0 +1,12 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2023 Andes Technology Corporation
> + */
> +
> +#ifndef _ANDES_HPM_H_
> +#define _ANDES_HPM_H_
> +
> +static inline int andes_pmu_setup(void) { return 0; }
> +
> +#endif /* _ANDES_HPM_H_ */
> diff --git a/platform/generic/include/andes/andes_pmu.h b/platform/generic/include/andes/andes_pmu.h
> new file mode 100644
> index 0000000..f355324
> --- /dev/null
> +++ b/platform/generic/include/andes/andes_pmu.h
> @@ -0,0 +1,34 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) Copyright (c) 2023 Andes Technology Corporation
> + */
> +
> +#ifndef _RISCV_ANDES_PMU_H
> +#define _RISCV_ANDES_PMU_H
> +
> +#include <sbi/sbi_hart.h>
> +#include <sbi_utils/fdt/fdt_helper.h>
> +#include <sbi_utils/fdt/fdt_pmu.h>
> +
> +#ifdef CONFIG_ANDES_PMU
> +
> +int andes_pmu_init(const struct fdt_match *match);
> +int andes_pmu_extensions_init(const struct fdt_match *match,
> + struct sbi_hart_features *hfeatures);
> +
> +#else
> +
> +static inline int andes_pmu_init(const struct fdt_match *match)
> +{
> + return 0;
> +}
> +static inline int andes_pmu_extensions_init(const struct fdt_match *match,
> + struct sbi_hart_features *hfeatures)
> +{
> + return 0;
> +}
> +
> +#endif /* CONFIG_ANDES_PMU */
> +
> +#endif /* _RISCV_ANDES_PMU_H */
> --
> 2.34.1
>
More information about the opensbi
mailing list