summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAtish Patra <atish.patra@wdc.com>2021-11-08 21:53:05 +0300
committerAnup Patel <anup@brainfault.org>2021-11-11 15:24:01 +0300
commitb28f07005cef03d5eea43a8a7954154b391871fe (patch)
treec2fb39ffdc37d5abc6138a5fd51784035edc7afa
parentb628cfd6a0c1e8bf858b33a62d6a6fa16f4db640 (diff)
downloadopensbi-b28f07005cef03d5eea43a8a7954154b391871fe.tar.xz
lib: sbi: Enable PMU extension for platforms without mcountinhibit
Some platforms such as hifive unmatched doesn't implement mcountinhibit csr. However, it has hardware events that can be monitored using 2 hpmcounter it has (i.e. mhpmcounter3 & mhpmcounter4). Currently, PMU extension disabled if mcountinhibit is absent. That's not really necessary as long as the supervisor OS keeps track of the delta value of the counters. Without mcountinhibit, the delta value won't be entirely accurate because the counters are freely running. However, that should be fine to produce an approximate counter value which can help performance analysis. Perf sampling won't work though as sscof extension is not present in hifive unmatched. Reviewed-by: Anup Patel <anup.patel@wdc.com> Reviewed-by: Bin Meng <bmeng.cn@gmail.com> Signed-off-by: Atish Patra <atish.patra@wdc.com>
-rw-r--r--lib/sbi/sbi_ecall_pmu.c10
-rw-r--r--lib/sbi/sbi_pmu.c50
-rw-r--r--lib/utils/fdt/fdt_pmu.c4
3 files changed, 41 insertions, 23 deletions
diff --git a/lib/sbi/sbi_ecall_pmu.c b/lib/sbi/sbi_ecall_pmu.c
index 39d3857..9ee9e81 100644
--- a/lib/sbi/sbi_ecall_pmu.c
+++ b/lib/sbi/sbi_ecall_pmu.c
@@ -74,14 +74,8 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
static int sbi_ecall_pmu_probe(unsigned long extid, unsigned long *out_val)
{
- struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
-
- /* SBI PMU extension is useless without mcount inhibit features */
- if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
- *out_val = 1;
- else
- *out_val = 0;
-
+ /* PMU extension is always enabled */
+ *out_val = 1;
return 0;
}
diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c
index da8a37b..e0303a7 100644
--- a/lib/sbi/sbi_pmu.c
+++ b/lib/sbi/sbi_pmu.c
@@ -279,13 +279,21 @@ static void pmu_ctr_write_hw(uint32_t cidx, uint64_t ival)
static int pmu_ctr_start_hw(uint32_t cidx, uint64_t ival, bool ival_update)
{
- unsigned long mctr_inhbt = csr_read(CSR_MCOUNTINHIBIT);
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
+ unsigned long mctr_inhbt;
/* Make sure the counter index lies within the range and is not TM bit */
if (cidx > num_hw_ctrs || cidx == 1)
return SBI_EINVAL;
+ if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
+ goto skip_inhibit_update;
+
+ /*
+ * Some of the hardware may not support mcountinhibit but perf stat
+ * still can work if supervisor mode programs the initial value.
+ */
+ mctr_inhbt = csr_read(CSR_MCOUNTINHIBIT);
if (!__test_bit(cidx, &mctr_inhbt))
return SBI_EALREADY_STARTED;
@@ -295,6 +303,7 @@ static int pmu_ctr_start_hw(uint32_t cidx, uint64_t ival, bool ival_update)
pmu_ctr_enable_irq_hw(cidx);
csr_write(CSR_MCOUNTINHIBIT, mctr_inhbt);
+skip_inhibit_update:
if (ival_update)
pmu_ctr_write_hw(cidx, ival);
@@ -346,7 +355,13 @@ int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask,
static int pmu_ctr_stop_hw(uint32_t cidx)
{
- unsigned long mctr_inhbt = csr_read(CSR_MCOUNTINHIBIT);
+ struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
+ unsigned long mctr_inhbt;
+
+ if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
+ return 0;
+
+ mctr_inhbt = csr_read(CSR_MCOUNTINHIBIT);
/* Make sure the counter index lies within the range and is not TM bit */
if (cidx > num_hw_ctrs || cidx == 1)
@@ -474,7 +489,8 @@ static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned lo
unsigned long ctr_mask;
int i, ret = 0, fixed_ctr, ctr_idx = SBI_ENOTSUPP;
struct sbi_pmu_hw_event *temp;
- unsigned long mctr_inhbt = csr_read(CSR_MCOUNTINHIBIT);
+ unsigned long mctr_inhbt;
+ u32 hartid = current_hartid();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (cbase > num_hw_ctrs)
@@ -489,6 +505,8 @@ static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned lo
!sbi_hart_has_feature(scratch, SBI_HART_HAS_SSCOFPMF))
return fixed_ctr;
+ if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
+ mctr_inhbt = csr_read(CSR_MCOUNTINHIBIT);
for (i = 0; i < num_hw_events; i++) {
temp = &hw_event_map[i];
if ((temp->start_idx > event_idx && event_idx < temp->end_idx) ||
@@ -503,10 +521,18 @@ static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned lo
ctr_mask = temp->counters & (cmask << cbase) &
(~SBI_PMU_FIXED_CTR_MASK);
for_each_set_bit_from(cbase, &ctr_mask, SBI_PMU_HW_CTR_MAX) {
- if (__test_bit(cbase, &mctr_inhbt)) {
- ctr_idx = cbase;
- break;
- }
+ /**
+ * Some of the platform may not support mcountinhibit.
+ * Checking the active_events is enough for them
+ */
+ if (active_events[hartid][cbase] != SBI_PMU_EVENT_IDX_INVALID)
+ continue;
+ /* If mcountinhibit is supported, the bit must be enabled */
+ if ((sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT)) &&
+ !__test_bit(cbase, &mctr_inhbt))
+ continue;
+ /* We found a valid counter that is not started yet */
+ ctr_idx = cbase;
}
}
@@ -678,11 +704,9 @@ void sbi_pmu_exit(struct sbi_scratch *scratch)
{
u32 hartid = current_hartid();
- /* SBI PMU is not supported if mcountinhibit is not available */
- if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
- return;
+ if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
+ csr_write(CSR_MCOUNTINHIBIT, 0xFFFFFFF8);
- csr_write(CSR_MCOUNTINHIBIT, 0xFFFFFFF8);
csr_write(CSR_MCOUNTEREN, -1);
pmu_reset_event_map(hartid);
}
@@ -692,10 +716,6 @@ int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot)
const struct sbi_platform *plat;
u32 hartid = current_hartid();
- /* SBI PMU is not supported if mcountinhibit is not available */
- if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
- return 0;
-
if (cold_boot) {
plat = sbi_platform_ptr(scratch);
/* Initialize hw pmu events */
diff --git a/lib/utils/fdt/fdt_pmu.c b/lib/utils/fdt/fdt_pmu.c
index 9ebf1c2..09c83c8 100644
--- a/lib/utils/fdt/fdt_pmu.c
+++ b/lib/utils/fdt/fdt_pmu.c
@@ -9,6 +9,7 @@
*/
#include <libfdt.h>
+#include <sbi/sbi_hart.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_pmu.h>
#include <sbi_utils/fdt/fdt_helper.h>
@@ -40,6 +41,7 @@ uint64_t fdt_pmu_get_select_value(uint32_t event_idx)
int fdt_pmu_fixup(void *fdt)
{
int pmu_offset;
+ struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (!fdt)
return SBI_EINVAL;
@@ -51,6 +53,8 @@ int fdt_pmu_fixup(void *fdt)
fdt_delprop(fdt, pmu_offset, "pmu,event-to-mhpmcounters");
fdt_delprop(fdt, pmu_offset, "pmu,event-to-mhpmevent");
fdt_delprop(fdt, pmu_offset, "pmu,raw-event-to-mhpmcounters");
+ if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_SSCOFPMF))
+ fdt_delprop(fdt, pmu_offset, "interrupts-extended");
return 0;
}