[PATCH] arm-cci500: Workaround pmu_event_set_period
Suzuki K. Poulose
Suzuki.Poulose at arm.com
Tue Sep 29 02:13:16 PDT 2015
On 28/09/15 16:38, Mark Rutland wrote:
> On Fri, Sep 25, 2015 at 04:50:53PM +0100, Suzuki K. Poulose wrote:
>> From: "Suzuki K. Poulose" <suzuki.poulose at arm.com>
>>
>> The CCI PMU driver sets the event counter to the half of the maximum
>> value(2^31) it can count before we start the counters via
>> pmu_event_set_period(). This is done to give us the best chance to
>> handle the overflow interrupt, taking care of extreme interrupt latencies.
>>
>> However, CCI-500 comes with advanced power saving schemes, which disables
>> the clock to the event counters unless the counters are enabled to count
>> (PMCR.CEN). This prevents the driver from writing the period to the
>> counters before starting them. Also, there is no way we can reset the
>> individual event counter to 0 (PMCR.RST resets all the counters, losing
>> their current readings). However the value of the counter is preserved and
>> could be read back, when the counters are not enabled.
>
> Does reset work while the counters are clock gated?
No. It doesn't. Both PMCR.CEN and Count Control should be turned on to
alter the value of the counter.
>
> I take it that we can configure the counters while they are disabled,
> even if we can't alter the counter value?
We can program the events for the counter, but we can't alter the counter
value.
>
>> So we cannot reliably use the counters and compute the number of events
>> generated during the sampling period since we don't have the value of the
>> counter at start.
>>
>> Here are the possible solutions:
>>
>> 1) Disable clock gating on CCI-500 by setting Control_Override_Reg[bit3].
>> - The Control_Override_Reg is secure (and hence not programmable from
>> Linux), and also has an impact on power consumption.
>>
>> 2) Change the order of operations
>> i.e,
>> a) Program and enable individual counters
>> b) Enable counting on all the counters by setting PMCR.CEN
>> c) Write the period to the individual counters
>> d) Disable the counters
>> - This could cause in unnecessary noise in the other counters and is
>> costly (we should repeat this for all enabled counters).
>>
>> 3) Don't set the counter value, instead use the current count as the
>> starting count and compute the delta at the end of sampling.
>
> This leaves us less broken than we currently are, but as far as I can
> tell, this leaves us back where we started, with the overflow issues
> seen elsewhere, cf:
>
> a737823d37666255 ("ARM: 6835/1: perf: ensure overflows aren't missed due to IRQ latency")
> 5727347180ebc6b4 ("ARM: 7354/1: perf: limit sample_period to half max_period in non-sampling mode")
Thanks for the pointers. Even now, without this change, theoretically
we could run into the overflow, isn't it ? So we should fix it for ever.
>> @@ -792,15 +803,33 @@ static void pmu_read(struct perf_event *event)
>> void pmu_event_set_period(struct perf_event *event)
>> {
>> struct hw_perf_event *hwc = &event->hw;
>> + struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
>> + u64 val = 0;
>> +
>> /*
>> - * The CCI PMU counters have a period of 2^32. To account for the
>> - * possiblity of extreme interrupt latency we program for a period of
>> - * half that. Hopefully we can handle the interrupt before another 2^31
>> - * events occur and the counter overtakes its previous value.
>> + * If the PMU gates the clock to PMU event counters when the counters
>> + * are not enabled, any write to it is ineffective. Hence we cannot
>> + * set a value reliably. Also, we cannot reset an individual event
>> + * counter; PMCR.RST resets all the counters. However the existing
>> + * counter values can be read back. Hence, we use the existing counter
>> + * value as the period and set the prev_count accordingly. This is
>> + * safe, since we don't support sampling of events anyway.
>> */
>> - u64 val = 1ULL << 31;
>> + if (pmu_ignores_cntr_write(cci_pmu)) {
>> + val = pmu_read_counter(event);
>> + } else {
>> + /*
>> + * The CCI PMU counters have a period of 2^32. To account for
>> + * the possiblity of extreme interrupt latency we program for
>> + * a period of half that. Hopefully we can handle the interrupt
>> + * before another 2^31 events occur and the counter overtakes
>> + * its previous value.
>> + */
>> + val = 1ULL << 31;
>> + pmu_write_counter(event, val);
>> + }
>> +
>> local64_set(&hwc->prev_count, val);
>> - pmu_write_counter(event, val);
>> }
>
> We could get rid of the flag and always do:
>
> pmu_write_counter(event, 1UL << 31);
> val = pmu_read_counter(event);
>
> That should work for CCI-400 and CCI-500, and if the CCI-500 counters
> aren't clock-gated (e.g. because of FW configuration) then we get the
> period that we actually wanted.
Yes, thats looks neater. I will change it with some comments in there.
>
> However, can't we use an event which won't count to solve the race with
> option 2?
Even if we found one, won't we have to set the 'no-op' event on all counters,
if we want to change a counter value to prevent other counters from counting?
And it gets complicated with/without event grouping.
>
> Per the TRM, events for unimplemented interfaces don't count, though I'm
> not sure if there's an event that's guaranteed to not count in all
> configurations. Perhaps we might be able to dig one up.
IIRC, there wasn't any mention about a single event which falls into that
category. I think solution 3 is much cleaner than finding and using a dummy
event.
Suzuki
More information about the linux-arm-kernel
mailing list