mirror of
https://github.com/Fishwaldo/opensbi.git
synced 2025-03-15 19:31:32 +00:00
platform: andes: Add Andes custom PMU support
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@andestech.com> Reviewed-by: Leo Yu-Chi Liang <ycliang@andestech.com> Reviewed-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
parent
effd89aa05
commit
1b9e743c3d
5 changed files with 160 additions and 0 deletions
|
@ -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.
|
||||
|
|
105
platform/generic/andes/andes_pmu.c
Normal file
105
platform/generic/andes/andes_pmu.c
Normal file
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
12
platform/generic/include/andes/andes_hpm.h
Normal file
12
platform/generic/include/andes/andes_hpm.h
Normal file
|
@ -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_ */
|
34
platform/generic/include/andes/andes_pmu.h
Normal file
34
platform/generic/include/andes/andes_pmu.h
Normal file
|
@ -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 */
|
Loading…
Add table
Reference in a new issue