[PATCH v3 3/5] lib: sbi_pmu: add ability to override methods on non-standard platforms

Heiko Stuebner heiko at sntech.de
Sun Sep 25 06:56:51 PDT 2022


Hi Drew,

Am Donnerstag, 8. September 2022, 18:02:11 CEST schrieb Andrew Jones:
> 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(...);

as Anup wrote in his mail, the sbi-pmu meanwhile already got that
struct sbi_pmu_device as abstraction from somewhere else.

Which in turn handles separately from the sscofpmf extension
(similar to what I did here originally).

So for the next version I'll only use that with some extensions :-)


Heiko


> >  	/* 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;
> > +}
> 







More information about the opensbi mailing list