[PATCH v3 3/5] lib: sbi_pmu: add ability to override methods on non-standard platforms
Andrew Jones
ajones at ventanamicro.com
Thu Sep 8 09:02:11 PDT 2022
On Thu, Sep 08, 2022 at 03:42:40PM +0200, Heiko Stuebner wrote:
> Some platforms may not implement the PMU in a standard way,
> but instead deviate on some functionality like overflow
> handling.
>
> Implement an abstraction that those platforms can hook into.
> This way they can still use the standard pmu interface between
> kernel and firmware and profit from things like firmware counters,
> without needing to create their own.
>
> Signed-off-by: Heiko Stuebner <heiko at sntech.de>
> ---
> include/sbi/sbi_pmu.h | 13 +++++++++++++
> lib/sbi/sbi_hart.c | 7 +++++++
> lib/sbi/sbi_pmu.c | 21 +++++++++++++++++++++
> 3 files changed, 41 insertions(+)
>
> diff --git a/include/sbi/sbi_pmu.h b/include/sbi/sbi_pmu.h
> index 1c9a997..7c8cfe7 100644
> --- a/include/sbi/sbi_pmu.h
> +++ b/include/sbi/sbi_pmu.h
> @@ -28,6 +28,16 @@
> #define SBI_PMU_CTR_MAX (SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX)
> #define SBI_PMU_FIXED_CTR_MASK 0x07
>
> +struct sbi_pmu_platform_ops {
> + int (*ctr_enable_irq_hw)(int ctr_idx);
> + int (*ctr_enable_ovf)(int ctr_idx);
> + int (*irq_bit)(void);
> + void (*counter_data)(unsigned int *count, unsigned int *bits);
> +};
> +
> +/** Set platform-specific override ops */
> +void sbi_pmu_set_platform_ops(struct sbi_pmu_platform_ops *ops);
> +
> /** Initialize PMU */
> int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot);
>
> @@ -37,6 +47,9 @@ void sbi_pmu_exit(struct sbi_scratch *scratch);
> /** Return the pmu irq bit depending on extension existence */
> int sbi_pmu_irq_bit(void);
>
> +/** Allow non-standard platforms to override probed counter information */
> +void sbi_pmu_override_counter_data(unsigned int *count, unsigned int *bits);
> +
> /**
> * Add the hardware event to counter mapping information. This should be called
> * from the platform code to update the mapping table.
> diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
> index 45fbcde..6506a19 100644
> --- a/lib/sbi/sbi_hart.c
> +++ b/lib/sbi/sbi_hart.c
> @@ -632,6 +632,13 @@ __mhpm_skip:
> #undef __check_csr_2
> #undef __check_csr
>
> + /**
> + * Allow non-standard implementations to override the detected
> + * values for number of counters and bits.
> + */
> + sbi_pmu_override_counter_data(&hfeatures->mhpm_count,
> + &hfeatures->mhpm_bits);
> +
> /* Detect if hart supports Priv v1.10 */
> val = csr_read_allowed(CSR_MCOUNTEREN, (unsigned long)&trap);
> if (!trap.cause)
> diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c
> index efbfbb6..08fb242 100644
> --- a/lib/sbi/sbi_pmu.c
> +++ b/lib/sbi/sbi_pmu.c
> @@ -77,6 +77,8 @@ static uint32_t num_hw_ctrs;
> /* Maximum number of counters available */
> static uint32_t total_ctrs;
>
> +static struct sbi_pmu_platform_ops *pmu_platform_ops;
> +
> /* Helper macros to retrieve event idx and code type */
> #define get_cidx_type(x) ((x & SBI_PMU_EVENT_IDX_TYPE_MASK) >> 16)
> #define get_cidx_code(x) (x & SBI_PMU_EVENT_IDX_CODE_MASK)
> @@ -358,6 +360,9 @@ static int pmu_ctr_start_hw(uint32_t cidx, uint64_t ival, bool ival_update)
>
> if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
> pmu_ctr_enable_irq_hw(cidx);
> + else if (pmu_platform_ops && pmu_platform_ops->ctr_enable_irq_hw)
> + pmu_platform_ops->ctr_enable_irq_hw(cidx);
> +
> csr_write(CSR_MCOUNTINHIBIT, mctr_inhbt);
>
> skip_inhibit_update:
> @@ -373,6 +378,8 @@ int sbi_pmu_irq_bit(void)
>
> if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
> return MIP_LCOFIP;
> + else if (pmu_platform_ops && pmu_platform_ops->irq_bit)
> + return pmu_platform_ops->irq_bit();
>
> return 0;
> }
> @@ -534,6 +541,8 @@ static int pmu_update_hw_mhpmevent(struct sbi_pmu_hw_event *hw_evt, int ctr_idx,
> if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
> mhpmevent_val = (mhpmevent_val & ~MHPMEVENT_SSCOF_MASK) |
> MHPMEVENT_MINH | MHPMEVENT_OF;
> + else if (pmu_platform_ops && pmu_platform_ops->ctr_enable_ovf)
> + pmu_platform_ops->ctr_enable_ovf(ctr_idx);
>
Based on these 'if sscofpmf else pmu_platform' conditionals it looks like
the pmu platform framework is actually specifically for a sscofpmf quirk.
How about introducing a general quirk / pmu quirk framework and then
adding a sscofpmf quirk. Then, where needed we'd have something like
if (pmu_quirks[SSCOFPMF])
sscofpmf_ops = (struct sscofpmf_quirk_ops *)pmu_quirks[SSCOFPMF];
if sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF)
...
else if (sscofpmf_ops && sscofpmf_ops->func_needed_here)
sscofpmf_ops->func_needed_here(...);
Thanks,
drew
> /* Update the inhibit flags based on inhibit flags received from supervisor */
> pmu_update_inhibit_flags(flags, &mhpmevent_val);
> @@ -822,3 +831,15 @@ int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot)
>
> return 0;
> }
> +
> +void sbi_pmu_override_counter_data(unsigned int *count,
> + unsigned int *bits)
> +{
> + if (pmu_platform_ops && pmu_platform_ops->counter_data)
> + pmu_platform_ops->counter_data(count, bits);
> +}
> +
> +void sbi_pmu_set_platform_ops(struct sbi_pmu_platform_ops *ops)
> +{
> + pmu_platform_ops = ops;
> +}
> --
> 2.35.1
>
>
> --
> opensbi mailing list
> opensbi at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi
More information about the opensbi
mailing list