[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