[PATCH v2 07/11] lib: utils: fdt_fixup: Add fdt_add_pmu_mappings() helper function
Yu Chien Peter Lin
peterlin at andestech.com
Thu Oct 19 04:37:09 PDT 2023
Add fdt_add_pmu_mappings() that creates entries of riscv,*event-to-mhpm*
property from arrays right before fdt_pmu_setup() populating the mapping
tables (i.e. hw_event_map[] and fdt_pmu_evt_select[]).
The helper function will skip the creation of those properties if a
"/pmu" node with "riscv,pmu" compatible string is provided.
Signed-off-by: Yu Chien Peter Lin <peterlin at andestech.com>
---
Changes v1 -> v2:
- New patch
---
include/sbi_utils/fdt/fdt_fixup.h | 48 ++++++++++
lib/utils/fdt/fdt_fixup.c | 95 ++++++++++++++++++++
platform/generic/include/platform_override.h | 1 +
platform/generic/platform.c | 10 ++-
4 files changed, 153 insertions(+), 1 deletion(-)
diff --git a/include/sbi_utils/fdt/fdt_fixup.h b/include/sbi_utils/fdt/fdt_fixup.h
index ecd55a7..9b72df8 100644
--- a/include/sbi_utils/fdt/fdt_fixup.h
+++ b/include/sbi_utils/fdt/fdt_fixup.h
@@ -19,6 +19,54 @@ struct sbi_cpu_idle_state {
uint32_t wakeup_latency_us;
};
+struct sbi_pmu_event_select_map {
+ /**
+ * The description of an entry in
+ * riscv,event-to-mhpmevent property
+ */
+ uint32_t eidx;
+ uint64_t select;
+};
+
+struct sbi_pmu_event_counter_map {
+ /**
+ * The description of an entry in
+ * riscv,event-to-mhpmcounters property
+ */
+ uint32_t eidx_start;
+ uint32_t eidx_end;
+ uint32_t ctr_map;
+};
+
+struct sbi_pmu_raw_event_counter_map {
+ /**
+ * The description of an entry in
+ * riscv,raw-event-to-mhpmcounters property
+ */
+ uint64_t select;
+ uint64_t select_mask;
+ uint32_t ctr_map;
+};
+
+/**
+ * Add PMU properties in the DT
+ *
+ * Add information about event to selector/counter mappings to the
+ * devicetree.
+ *
+ * @param fdt: device tree blob
+ * @param selects: array of event index to selector value mapping
+ * descriptions, ending with empty element
+ * @param counters: array of event indexes to counters mapping
+ * descriptions, ending with empty element
+ * @param rcounters: array of raw events to counters mapping
+ * descriptions, ending with empty element
+ * @return zero on success and -ve on failure
+ */
+int fdt_add_pmu_mappings(void *fdt, const struct sbi_pmu_event_select_map *selects,
+ const struct sbi_pmu_event_counter_map *counters,
+ const struct sbi_pmu_raw_event_counter_map *rcounters);
+
/**
* Add CPU idle states to cpu nodes in the DT
*
diff --git a/lib/utils/fdt/fdt_fixup.c b/lib/utils/fdt/fdt_fixup.c
index e213ded..67e2e2e 100644
--- a/lib/utils/fdt/fdt_fixup.c
+++ b/lib/utils/fdt/fdt_fixup.c
@@ -20,6 +20,101 @@
#include <sbi_utils/fdt/fdt_pmu.h>
#include <sbi_utils/fdt/fdt_helper.h>
+int fdt_add_pmu_mappings(void *fdt, const struct sbi_pmu_event_select_map *selects,
+ const struct sbi_pmu_event_counter_map *counters,
+ const struct sbi_pmu_raw_event_counter_map *rcounters)
+{
+ int i, err, pmu_noff, root_noff;
+ const char *comp;
+ fdt32_t evt_to_mhpmevent[3];
+ fdt32_t evt_to_mhpmcounters[3];
+ fdt32_t raw_evt_to_mhpmcounters[5];
+
+ /* Try to locate pmu node */
+ pmu_noff = fdt_path_offset(fdt, "/pmu");
+
+ if (pmu_noff > 0) {
+ /*
+ * If compatible string is "riscv,pmu",
+ * we assume a valid pmu node has been
+ * provided.
+ */
+ comp = fdt_getprop(fdt, pmu_noff, "compatible", NULL);
+ if (comp && !strcmp(comp, "riscv,pmu"))
+ return 0;
+ else
+ return -FDT_ERR_BADVALUE;
+ }
+
+ if (pmu_noff < 0 && pmu_noff != -FDT_ERR_NOTFOUND)
+ return pmu_noff;
+
+ /*
+ * If "riscv,event-to-mhpmevent" is present, "riscv,event-to-mhpmcounters"
+ * must be provided as well, but not vice versa (OpenSBI will direct mapping
+ * event_idx as selector value).
+ */
+ if (selects && !counters) {
+ sbi_printf("%s: ERR: riscv,event-to-mhpmcounters is mandatory if"
+ " riscv,event-to-mhpmevent is present.", __func__);
+ return SBI_EINVAL;
+ }
+
+ /*
+ * Create pmu node based on given @selects, @counters
+ * and @rcounters.
+ */
+ root_noff = fdt_path_offset(fdt, "/");
+ pmu_noff = fdt_add_subnode(fdt, root_noff, "pmu");
+ if (pmu_noff < 0)
+ return pmu_noff;
+
+ err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 1024);
+ if (err < 0)
+ return err;
+
+ err = fdt_setprop_string(fdt, pmu_noff, "compatible", "riscv,pmu");
+ if (err)
+ return err;
+
+ /* Add riscv,event-to-mhpmevent */
+ for (i = 0; selects && selects[i].eidx; i++) {
+ evt_to_mhpmevent[0] = cpu_to_fdt32(selects[i].eidx);
+ evt_to_mhpmevent[1] = cpu_to_fdt32(selects[i].select >> 32);
+ evt_to_mhpmevent[2] = cpu_to_fdt32(selects[i].select & ~0UL);
+ err = fdt_appendprop(fdt, pmu_noff, "riscv,event-to-mhpmevent",
+ evt_to_mhpmevent, 3 * sizeof(fdt32_t));
+ if (err)
+ return err;
+ }
+
+ /* Add riscv,event-to-mhpmcounters */
+ for (i = 0; counters && counters[i].eidx_start; i++) {
+ evt_to_mhpmcounters[0] = cpu_to_fdt32(counters[i].eidx_start);
+ evt_to_mhpmcounters[1] = cpu_to_fdt32(counters[i].eidx_end);
+ evt_to_mhpmcounters[2] = cpu_to_fdt32(counters[i].ctr_map);
+ err = fdt_appendprop(fdt, pmu_noff, "riscv,event-to-mhpmcounters",
+ evt_to_mhpmcounters, 3 * sizeof(fdt32_t));
+ if (err)
+ return err;
+ }
+
+ /* Add riscv,raw-event-to-mhpmcounters */
+ for (i = 0; rcounters && rcounters[i].select; i++) {
+ raw_evt_to_mhpmcounters[0] = cpu_to_fdt32(rcounters[i].select >> 32);
+ raw_evt_to_mhpmcounters[1] = cpu_to_fdt32(rcounters[i].select & ~0UL);
+ raw_evt_to_mhpmcounters[2] = cpu_to_fdt32(rcounters[i].select_mask >> 32);
+ raw_evt_to_mhpmcounters[3] = cpu_to_fdt32(rcounters[i].select_mask & ~0UL);
+ raw_evt_to_mhpmcounters[4] = cpu_to_fdt32(rcounters[i].ctr_map);
+ err = fdt_appendprop(fdt, pmu_noff, "riscv,raw-event-to-mhpmcounters",
+ raw_evt_to_mhpmcounters, 5 * sizeof(fdt32_t));
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
int fdt_add_cpu_idle_states(void *fdt, const struct sbi_cpu_idle_state *state)
{
int cpu_node, cpus_node, err, idle_states_node;
diff --git a/platform/generic/include/platform_override.h b/platform/generic/include/platform_override.h
index bf4b112..bd34d2a 100644
--- a/platform/generic/include/platform_override.h
+++ b/platform/generic/include/platform_override.h
@@ -19,6 +19,7 @@ struct platform_override {
u64 (*features)(const struct fdt_match *match);
u64 (*tlbr_flush_limit)(const struct fdt_match *match);
u32 (*tlb_num_entries)(const struct fdt_match *match);
+ int (*fdt_add_pmu_mappings)(void *fdt, const struct fdt_match *match);
bool (*cold_boot_allowed)(u32 hartid, const struct fdt_match *match);
int (*early_init)(bool cold_boot, const struct fdt_match *match);
int (*final_init)(bool cold_boot, const struct fdt_match *match);
diff --git a/platform/generic/platform.c b/platform/generic/platform.c
index cb9270d..a48a8b7 100644
--- a/platform/generic/platform.c
+++ b/platform/generic/platform.c
@@ -265,9 +265,17 @@ static u32 generic_tlb_num_entries(void)
static int generic_pmu_init(void)
{
+ void *fdt = fdt_get_address();
int rc;
- rc = fdt_pmu_setup(fdt_get_address());
+ if (generic_plat && generic_plat->fdt_add_pmu_mappings) {
+ rc = generic_plat->fdt_add_pmu_mappings(fdt,
+ generic_plat_match);
+ if (rc)
+ return rc;
+ }
+
+ rc = fdt_pmu_setup(fdt);
if (rc && rc != SBI_ENOENT)
return rc;
--
2.34.1
More information about the opensbi
mailing list