[PATCH 4/5] lib: sbi_pmu: Implement SBI PMU event info function
Samuel Holland
samuel.holland at sifive.com
Mon Dec 2 14:28:14 PST 2024
Hi Atish,
On 2024-11-19 1:34 PM, Atish Patra wrote:
> Allow the supervisor software to query about the event using the
> new function. This supports both firmware and hardware events.
> The hardware event presence is verified hw_event_map which is populated
> via PMU device tree node. The firmware event presence is checked through
> event validation function which should take care of both standard and
> platform firmware events.
>
> Signed-off-by: Atish Patra <atishp at rivosinc.com>
> ---
> include/sbi/sbi_pmu.h | 2 ++
> lib/sbi/sbi_ecall_pmu.c | 3 ++
> lib/sbi/sbi_pmu.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 81 insertions(+)
>
> diff --git a/include/sbi/sbi_pmu.h b/include/sbi/sbi_pmu.h
> index 8b1e08c81f30..3649d476475a 100644
> --- a/include/sbi/sbi_pmu.h
> +++ b/include/sbi/sbi_pmu.h
> @@ -142,6 +142,8 @@ int sbi_pmu_ctr_start(unsigned long cidx_base, unsigned long cidx_mask,
> unsigned long flags, uint64_t ival);
>
> int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info);
> +int sbi_pmu_event_get_info(unsigned long shmem_lo, unsigned long shmem_high,
> + unsigned long num_events, unsigned long flags);
>
> unsigned long sbi_pmu_num_ctr(void);
>
> diff --git a/lib/sbi/sbi_ecall_pmu.c b/lib/sbi/sbi_ecall_pmu.c
> index 40a63a626f6b..ae7aeca9b8f8 100644
> --- a/lib/sbi/sbi_ecall_pmu.c
> +++ b/lib/sbi/sbi_ecall_pmu.c
> @@ -73,6 +73,9 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
> case SBI_EXT_PMU_COUNTER_STOP:
> ret = sbi_pmu_ctr_stop(regs->a0, regs->a1, regs->a2);
> break;
> + case SBI_EXT_PMU_EVENT_GET_INFO:
> + ret = sbi_pmu_event_get_info(regs->a0, regs->a1, regs->a2, regs->a3);
> + break;
> case SBI_EXT_PMU_SNAPSHOT_SET_SHMEM:
> /* fallthrough as OpenSBI doesn't support snapshot yet */
> default:
> diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c
> index 1ed578bac23e..3fc50c0b25e2 100644
> --- a/lib/sbi/sbi_pmu.c
> +++ b/lib/sbi/sbi_pmu.c
> @@ -10,6 +10,7 @@
> #include <sbi/riscv_asm.h>
> #include <sbi/sbi_bitops.h>
> #include <sbi/sbi_console.h>
> +#include <sbi/sbi_domain.h>
> #include <sbi/sbi_ecall_interface.h>
> #include <sbi/sbi_hart.h>
> #include <sbi/sbi_heap.h>
> @@ -968,6 +969,81 @@ int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info)
> return 0;
> }
>
> +int sbi_pmu_event_get_info(unsigned long shmem_phys_lo, unsigned long shmem_phys_hi,
> + unsigned long num_events, unsigned long flags)
> +{
> + unsigned long shmem_size = num_events * sizeof(struct sbi_pmu_event_info);
> + int i, j, event_type;
> + struct sbi_pmu_event_info *einfo;
> + struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr();
> + uint32_t event_idx;
> + struct sbi_pmu_hw_event *temp;
> + bool found = false;
> +
> + if (flags != 0)
> + return SBI_ERR_INVALID_PARAM;
> +
> + /** Check shared memory size and address aligned to 16 byte */
> + if (!num_events || (shmem_phys_lo & 0xF))
> + return SBI_ERR_INVALID_PARAM;
> +
> + /*
> + * On RV32, the M-mode can only access the first 4GB of
> + * the physical address space because M-mode does not have
> + * MMU to access full 34-bit physical address space.
> + *
> + * Based on above, we simply fail if the upper 32bits of
> + * the physical address (i.e. a2 register) is non-zero on
> + * RV32.
> + */
> + if (shmem_phys_hi)
> + return SBI_EINVALID_ADDR;
> +
> + if (!sbi_domain_check_addr_range(sbi_domain_thishart_ptr(),
> + shmem_phys_lo, shmem_size, PRV_S,
> + SBI_DOMAIN_READ | SBI_DOMAIN_WRITE))
> + return SBI_ERR_INVALID_ADDRESS;
> +
> + sbi_hart_map_saddr(shmem_phys_lo, shmem_size);
> +
> + einfo = (struct sbi_pmu_event_info *)(shmem_phys_lo);
> + for (i = 0; i < num_events; i++) {
> + event_idx = einfo[i].event_idx;
> + event_type = pmu_event_validate(phs, event_idx, einfo[i].event_data);
> + if (event_type < 0) {
> + einfo[i].output = 0;
> + } else {
> + for (j = 0; j < num_hw_events; j++) {
> + temp = &hw_event_map[j];
> + if (temp->start_idx <= event_idx && event_idx <= temp->end_idx) {
> + found = true;
> + break;
Won't this check succeed for every raw event (since they all have the same
event_idx), so the `break` will prevent the block below from ever executing?
Regards,
Samuel
> + }
> + /* For raw events, event data is used as the select value */
> + if (event_idx == SBI_PMU_EVENT_RAW_IDX ||
> + event_idx == SBI_PMU_EVENT_RAW_V2_IDX) {
> + uint64_t select_mask = temp->select_mask;
> +
> + /* just match the selector */
> + if (temp->select == (einfo[i].event_data & select_mask)) {
> + found = true;
> + break;
> + }
> + }
> + }
> + if (found)
> + einfo[i].output = 1;
> + else
> + einfo[i].output = 0;
> + found = false;
> + }
> + }
> +
> + sbi_hart_unmap_saddr();
> +
> + return 0;
> +}
> +
> static void pmu_reset_event_map(struct sbi_pmu_hart_state *phs)
> {
> int j;
>
More information about the opensbi
mailing list