Hi Frank, > > Subject: [PATCH v3 3/4] perf: imx_perf: limit counter ID from user space and > > optimize counter usage > > > > The user can pass any counter ID to perf app. However, current pmu driver > > doesn't judge the validity of the counter ID. This will add necessary > > check for counter ID from user space. Besides, this pmu has 10 counters > > except cycle counter which can be used to count reference events and > > counter specific evnets. This will also add supports to auto allocate > > counter if the user doesn't pass it the perf. Then, the usage of counter > > will be optimized. > > > > Signed-off-by: Xu Yang <xu.yang_2@xxxxxxx> > > > > --- > > Changes in v2: > > - limit counter ID from user to 0-10 > > - combine dynamic and static allocation of counter > > Changes in v3: > > - no changes > > --- > > drivers/perf/fsl_imx9_ddr_perf.c | 69 > > +++++++++++++++++++++++++++++++- > > 1 file changed, 67 insertions(+), 2 deletions(-) > > > > diff --git a/drivers/perf/fsl_imx9_ddr_perf.c > > b/drivers/perf/fsl_imx9_ddr_perf.c > > index fd118773508d..4bb80050920c 100644 > > --- a/drivers/perf/fsl_imx9_ddr_perf.c > > +++ b/drivers/perf/fsl_imx9_ddr_perf.c > > @@ -51,6 +51,7 @@ > > > > #define NUM_COUNTERS 11 > > #define CYCLES_COUNTER 0 > > +#define CYCLES_EVENT_ID 0 > > > > #define to_ddr_pmu(p) container_of(p, struct ddr_pmu, pmu) > > > > @@ -235,6 +236,14 @@ static struct attribute *ddr_perf_events_attrs[] = { > > NULL, > > }; > > > > +static bool ddr_perf_is_specific_event(int event) > > Why call specific? Name is too general. Such as is_fixed? Or Is_with_filter? > Need know what specific? There are only two types of event: reference event and counter specific evnet. To make it clear, I'll change it to ddr_perf_is_counter_specific_event(). > > > +{ > > + if (event >= 64 && event <= 73) > > + return true; > > + else > > + return false; > > +} > > + > > static const struct attribute_group ddr_perf_events_attr_group = { > > .name = "events", > > .attrs = ddr_perf_events_attrs, > > @@ -507,6 +516,7 @@ static int ddr_perf_event_init(struct perf_event > > *event) > > struct ddr_pmu *pmu = to_ddr_pmu(event->pmu); > > struct hw_perf_event *hwc = &event->hw; > > struct perf_event *sibling; > > + int event_id, counter; > > > > if (event->attr.type != event->pmu->type) > > return -ENOENT; > > @@ -519,6 +529,18 @@ static int ddr_perf_event_init(struct perf_event > > *event) > > return -EOPNOTSUPP; > > } > > > > + counter = (event->attr.config & 0xFF00) >> 8; > > Define 0xFF00? Okay. > > > + if (counter > NUM_COUNTERS) { > > + dev_warn(pmu->dev, "Only counter 0-10 is supported!\n"); > > + return -EINVAL; > > + } > > + > > + event_id = event->attr.config & 0x00FF; > > same for hardcode 0x00FF Okay. Thanks, Xu Yang > > > + if (ddr_perf_is_specific_event(event_id) && counter == 0) { > > + dev_err(pmu->dev, "Need specify counter for counter > > specific events!\n"); > > + return -EINVAL; > > + } > > + > > /* > > * We must NOT create groups containing mixed PMUs, although > > software > > * events are acceptable (for example to create a CCN group > > @@ -552,6 +574,39 @@ static void ddr_perf_event_start(struct perf_event > > *event, int flags) > > hwc->state = 0; > > } > > > > +static int ddr_perf_alloc_counter(struct ddr_pmu *pmu, int event, int > > counter) > > +{ > > + int i; > > + > > + if (event == CYCLES_EVENT_ID) { > > + /* > > + * Always map cycle event to counter 0. > > + * Cycles counter is dedicated for cycle event > > + * can't used for the other events. > > + */ > > + if (pmu->events[CYCLES_COUNTER] == NULL) > > + return CYCLES_COUNTER; > > + } else if (counter != 0) { > > + /* > > + * 1. ddr_perf_event_init() will make sure counter > > + * is not 0 for counter specific events. > > + * 2. Allow specify counter for referene event too. > > + */ > > + if (pmu->events[counter] == NULL) > > + return counter; > > + } else { > > + /* > > + * Counter may be 0 if user doesn't specify it. > > + * Auto allocate counter for referene event. > > + */ > > + for (i = 1; i < NUM_COUNTERS; i++) > > + if (pmu->events[i] == NULL) > > + return i; > > + } > > + > > + return -ENOENT; > > +} > > + > > static int ddr_perf_event_add(struct perf_event *event, int flags) > > { > > struct ddr_pmu *pmu = to_ddr_pmu(event->pmu); > > @@ -559,9 +614,17 @@ static int ddr_perf_event_add(struct perf_event > > *event, int flags) > > int cfg = event->attr.config; > > int cfg1 = event->attr.config1; > > int cfg2 = event->attr.config2; > > - int counter; > > + int event_id, counter; > > > > - counter = (cfg & 0x0000FF00) >> 8; > > + event_id = cfg & 0x00FF; > > + counter = (cfg & 0xFF00) >> 8; > > + > > + /* check if counter is available */ > > + counter = ddr_perf_alloc_counter(pmu, event_id, counter); > > + if (counter < 0) { > > + dev_dbg(pmu->dev, "There are not enough counters\n"); > > + return -EOPNOTSUPP; > > + } > > > > pmu->events[counter] = event; > > pmu->active_events++; > > @@ -597,9 +660,11 @@ static void ddr_perf_event_del(struct perf_event > > *event, int flags) > > { > > struct ddr_pmu *pmu = to_ddr_pmu(event->pmu); > > struct hw_perf_event *hwc = &event->hw; > > + int counter = hwc->idx; > > > > ddr_perf_event_stop(event, PERF_EF_UPDATE); > > > > + pmu->events[counter] = NULL; > > pmu->active_events--; > > hwc->idx = -1; > > } > > -- > > 2.34.1