summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/pmu_support.md24
-rw-r--r--include/sbi/sbi_pmu.h2
-rw-r--r--lib/sbi/sbi_pmu.c35
-rw-r--r--lib/utils/fdt/fdt_pmu.c16
4 files changed, 50 insertions, 27 deletions
diff --git a/docs/pmu_support.md b/docs/pmu_support.md
index a60b75c..7e3367c 100644
--- a/docs/pmu_support.md
+++ b/docs/pmu_support.md
@@ -50,12 +50,20 @@ event-to-mhpmevent is present. Otherwise, it can be omitted. This property
shouldn't encode any raw event.
* **riscv,raw-event-to-mhpmcounters**(Optional) - It represents an ONE-to-MANY
-mapping between a raw event and all the MHPMCOUNTERx in a bitmap format that can
-be used to monitor that raw event. The information is encoded in a table format
-where each raw represent a specific raw event. The first column stores the
-expected event selector value that should be encoded in the expected value to be
-written in MHPMEVENTx. The second column stores a bitmap of all the MHPMCOUNTERx
-that can be used for monitoring the specified event.
+or MANY-to-MANY mapping between the raw event(s) and all the MHPMCOUNTERx in
+a bitmap format that can be used to monitor that raw event, which depends on
+how the platform encodes the monitor events. Currently, only the following three
+encoding methods are supported, encoding each event as a number, using a bitmap
+to encode monitor events, and mixing the previous two methods. The information
+is encoded in a table format where each row represent the specific raw event(s).
+The first column represents a 64-bit selector value which can indicate an
+monitor event ID (encoded by a number) or an event set (encoded by a bitmap).
+In case of the latter, the lower bits used to encode a set of events should be
+set to zero. The second column is a 64-bit selector mask where any bits used
+for event encoding will be cleared. If a platform directly encodes each raw PMU
+event as a unique ID, the value of select_mask will be 0xffffffff_ffffffff.
+The third column represent a bitmap of all the MHPMCOUNTERx that can be used for
+monitoring the specified event(s).
*Note:* A platform may choose to provide the mapping between event & counters
via platform hooks rather than the device tree.
@@ -72,8 +80,8 @@ pmu {
<0x00002 0x00002 0x00000004>,
<0x00003 0x0000A 0x00000ff8>,
<0x10000 0x10033 0x000ff000>,
- riscv,raw-event-to-mhpmcounters = <0x0000 0x0002 0x00000f8>,
- <0x0000 0x0003 0x00000ff0>,
+ riscv,raw-event-to-mhpmcounters = <0x0000 0x0002 0xffffffff 0xffffffff 0x00000f8>,
+ <0xffffffff 0xfffffff0 0xffffffff 0xfffffff0 0x00000ff0>,
};
```
diff --git a/include/sbi/sbi_pmu.h b/include/sbi/sbi_pmu.h
index f018556..6a1c62c 100644
--- a/include/sbi/sbi_pmu.h
+++ b/include/sbi/sbi_pmu.h
@@ -51,7 +51,7 @@ int sbi_pmu_add_hw_event_counter_map(u32 eidx_start, u32 eidx_end, u32 cmap);
* @return 0 on success, error otherwise.
*/
-int sbi_pmu_add_raw_event_counter_map(uint64_t select, u32 cmap);
+int sbi_pmu_add_raw_event_counter_map(uint64_t select, uint64_t select_mask, u32 cmap);
int sbi_pmu_ctr_read(uint32_t cidx, unsigned long *cval);
diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c
index 5950a20..10668a3 100644
--- a/lib/sbi/sbi_pmu.c
+++ b/lib/sbi/sbi_pmu.c
@@ -21,8 +21,16 @@ struct sbi_pmu_hw_event {
uint32_t counters;
uint32_t start_idx;
uint32_t end_idx;
- /* Event selector value used only for raw events */
+ /* Event selector value used only for raw events. The event select value
+ * can be a even id or a selector value for set of events encoded in few
+ * bits. In case latter, the bits used for encoding of the events should
+ * be zeroed out in the select value.
+ */
uint64_t select;
+ /**
+ * The select_mask indicates which bits are encoded for the event(s).
+ */
+ uint64_t select_mask;
};
/** Representation of a firmware event */
@@ -91,9 +99,9 @@ static bool pmu_event_range_overlap(struct sbi_pmu_hw_event *evtA,
}
static bool pmu_event_select_overlap(struct sbi_pmu_hw_event *evt,
- uint64_t select_val)
+ uint64_t select_val, uint64_t select_mask)
{
- if (evt->select == select_val)
+ if ((evt->select == select_val) && (evt->select_mask == select_mask))
return TRUE;
return FALSE;
@@ -168,7 +176,7 @@ int sbi_pmu_ctr_read(uint32_t cidx, unsigned long *cval)
}
static int pmu_add_hw_event_map(u32 eidx_start, u32 eidx_end, u32 cmap,
- uint64_t select)
+ uint64_t select, uint64_t select_mask)
{
int i = 0;
bool is_overlap;
@@ -191,13 +199,15 @@ static int pmu_add_hw_event_map(u32 eidx_start, u32 eidx_end, u32 cmap,
for (i = 0; i < num_hw_events; i++) {
if (eidx_start == SBI_PMU_EVENT_RAW_IDX)
/* All raw events have same event idx. Just do sanity check on select */
- is_overlap = pmu_event_select_overlap(&hw_event_map[i], select);
+ is_overlap = pmu_event_select_overlap(&hw_event_map[i],
+ select, select_mask);
else
is_overlap = pmu_event_range_overlap(&hw_event_map[i], event);
if (is_overlap)
goto reset_event;
}
+ event->select_mask = select_mask;
event->counters = cmap;
event->select = select;
num_hw_events++;
@@ -221,13 +231,13 @@ int sbi_pmu_add_hw_event_counter_map(u32 eidx_start, u32 eidx_end, u32 cmap)
eidx_end == SBI_PMU_EVENT_RAW_IDX)
return SBI_EINVAL;
- return pmu_add_hw_event_map(eidx_start, eidx_end, cmap, 0);
+ return pmu_add_hw_event_map(eidx_start, eidx_end, cmap, 0, 0);
}
-int sbi_pmu_add_raw_event_counter_map(uint64_t select, u32 cmap)
+int sbi_pmu_add_raw_event_counter_map(uint64_t select, uint64_t select_mask, u32 cmap)
{
return pmu_add_hw_event_map(SBI_PMU_EVENT_RAW_IDX,
- SBI_PMU_EVENT_RAW_IDX, cmap, select);
+ SBI_PMU_EVENT_RAW_IDX, cmap, select, select_mask);
}
static int pmu_ctr_enable_irq_hw(int ctr_idx)
@@ -514,9 +524,13 @@ static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned lo
continue;
/* For raw events, event data is used as the select value */
- if ((event_idx == SBI_PMU_EVENT_RAW_IDX) && temp->select != data)
- continue;
+ if (event_idx == SBI_PMU_EVENT_RAW_IDX) {
+ uint64_t select_mask = temp->select_mask;
+ /* The non-event map bits of data should match the selector */
+ if (temp->select != (data & select_mask))
+ continue;
+ }
/* Fixed counters should not be part of the search */
ctr_mask = temp->counters & (cmask << cbase) &
(~SBI_PMU_FIXED_CTR_MASK);
@@ -546,7 +560,6 @@ static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned lo
else
return SBI_EFAIL;
}
-
ret = pmu_update_hw_mhpmevent(temp, ctr_idx, flags, event_idx, data);
if (!ret)
diff --git a/lib/utils/fdt/fdt_pmu.c b/lib/utils/fdt/fdt_pmu.c
index 529ee42..a2b048f 100644
--- a/lib/utils/fdt/fdt_pmu.c
+++ b/lib/utils/fdt/fdt_pmu.c
@@ -65,7 +65,7 @@ int fdt_pmu_setup(void *fdt)
const u32 *event_val;
const u32 *event_ctr_map;
struct fdt_pmu_hw_event_select *event;
- uint64_t raw_selector;
+ uint64_t raw_selector, select_mask;
u32 event_idx_start, event_idx_end, ctr_map;
if (!fdt)
@@ -99,14 +99,16 @@ int fdt_pmu_setup(void *fdt)
}
event_val = fdt_getprop(fdt, pmu_offset, "riscv,raw-event-to-mhpmcounters", &len);
- if (!event_val || len < 8)
+ if (!event_val || len < 20)
return SBI_EFAIL;
- len = len / (sizeof(u32) * 3);
+ len = len / (sizeof(u32) * 5);
for (i = 0; i < len; i++) {
- raw_selector = fdt32_to_cpu(event_val[3 * i]);
- raw_selector = (raw_selector << 32) | fdt32_to_cpu(event_val[3 * i + 1]);
- ctr_map = fdt32_to_cpu(event_val[3 * i + 2]);
- result = sbi_pmu_add_raw_event_counter_map(raw_selector, ctr_map);
+ raw_selector = fdt32_to_cpu(event_val[5 * i]);
+ raw_selector = (raw_selector << 32) | fdt32_to_cpu(event_val[5 * i + 1]);
+ select_mask = fdt32_to_cpu(event_val[5 * i + 2]);
+ select_mask = (select_mask << 32) | fdt32_to_cpu(event_val[5 * i + 3]);
+ ctr_map = fdt32_to_cpu(event_val[5 * i + 4]);
+ result = sbi_pmu_add_raw_event_counter_map(raw_selector, select_mask, ctr_map);
if (!result)
hw_event_count++;
}