[PATCH V2 10/11] coresight: sink: Add TRBE driver

Anshuman Khandual anshuman.khandual at arm.com
Sun Jan 17 07:10:23 EST 2021



On 1/15/21 6:13 PM, Suzuki K Poulose wrote:
> On 1/15/21 5:29 AM, Anshuman Khandual wrote:
>>
>>
>> On 1/13/21 8:58 PM, Suzuki K Poulose wrote:
>>> Hi Anshuman,
>>>
>>> The driver looks overall good to me. Please find some minor comments below

Sure.

>>>
>>> On 1/13/21 4:18 AM, Anshuman Khandual wrote:
>>>> Trace Buffer Extension (TRBE) implements a trace buffer per CPU which is
>>>> accessible via the system registers. The TRBE supports different addressing
>>>> modes including CPU virtual address and buffer modes including the circular
>>>> buffer mode. The TRBE buffer is addressed by a base pointer (TRBBASER_EL1),
>>>> an write pointer (TRBPTR_EL1) and a limit pointer (TRBLIMITR_EL1). But the
>>>> access to the trace buffer could be prohibited by a higher exception level
>>>> (EL3 or EL2), indicated by TRBIDR_EL1.P. The TRBE can also generate a CPU
>>>> private interrupt (PPI) on address translation errors and when the buffer
>>>> is full. Overall implementation here is inspired from the Arm SPE driver.
>>>>
>>>> Cc: Mathieu Poirier <mathieu.poirier at linaro.org>
>>>> Cc: Mike Leach <mike.leach at linaro.org>
>>>> Cc: Suzuki K Poulose <suzuki.poulose at arm.com>
>>>> Signed-off-by: Anshuman Khandual <anshuman.khandual at arm.com>
> 
> ...
> 
>>>> +
>>>> +/*
>>>> + * TRBE Buffer Management
>>>> + *
>>>> + * The TRBE buffer spans from the base pointer till the limit pointer. When enabled,
>>>> + * it starts writing trace data from the write pointer onward till the limit pointer.
>>>
>>>
>>>> + * When the write pointer reaches the address just before the limit pointer, it gets
>>>> + * wrapped around again to the base pointer. This is called a TRBE wrap event, which
>>>> + * generates a maintenance interrupt when operated in WRAP or STOP mode.
>>>
>>> According to the TRM, it is FILL mode, instead of STOP. So please change the above to:
>>>
>>> "operated in WRAP or FILL mode".

Changed.

>>
>> Updated.
>>
>>>
>>>
>>>>      The write
>>>> + * pointer again starts writing trace data from the base pointer until just before
>>>> + * the limit pointer before getting wrapped again with an IRQ and this process just
>>>> + * goes on as long as the TRBE is enabled.
>>>
>>> This could be dropped as it applies to WRAP/CIRCULAR buffer mode, which we don't use.
>>
>> Probably this could be changed a bit to match the FILL mode. Because it is essential
>> to describe the continuous nature of the buffer operation, even in the FILL mode.
>>
>>   * After TRBE
>>   * IRQ gets handled and enabled again, write pointer again starts writing trace data
>>   * from the base pointer until just before the limit pointer before getting wrapped
>>   * again with an IRQ and this process just goes on as long as the TRBE is enabled.
>>
> 
> The above doesn't parse well and kind of repeats the operation of TRBE which is
> already explained above. How about :
> 
>>>> + * When the write pointer reaches the address just before the limit pointer, it gets
>>>> + * wrapped around again to the base pointer. This is called a TRBE wrap event, which
>>>> + * generates a maintenance interrupt when operated in WRAP or STOP mode.
> 
> This driver uses FILL mode, where the TRBE stops the trace collection at wrap event.
> The IRQ handler updates the AUX buffer and re-enables the TRBE with updated WRITE and
> LIMIT pointers.

Updated.

> 
> 
>>>> +
>>>> +static void *arm_trbe_alloc_buffer(struct coresight_device *csdev,
>>>> +                   struct perf_event *event, void **pages,
>>>> +                   int nr_pages, bool snapshot)
>>>> +{
>>>> +    struct trbe_buf *buf;
>>>> +    struct page **pglist;
>>>> +    int i;
>>>> +
>>>> +    if ((nr_pages < 2) || (snapshot && (nr_pages & 1)))
>>>
>>> This restriction on snapshot could be removed now, since we use the
>>> full buffer.
>>
>> Dropped only the second condition here i.e (snapshot && (nr_pages & 1).
>> Just wondering if the aux buffer could work with a single page so that
>> the first condition can also be dropped.
> 
> I think it is good to keep the restriction of 2 pages, as the WRITE_PTR
> and the LIMIT_PTR must be page aligned. With a single page, you can't do
> much, with writing into a partially filled buffer. This may be added
> as a comment to explain the restriction.

Added the above comment.

> 
>>>> +
>>>> +static enum trbe_fault_action trbe_get_fault_act(struct perf_output_handle *handle)
>>>> +{
>>>> +    int ec = get_trbe_ec();
>>>> +    int bsc = get_trbe_bsc();
>>>> +
>>>> +    WARN_ON(is_trbe_running());
>>>> +    if (is_trbe_trg() || is_trbe_abort())
>>>
>>> We seem to be reading the TRBSR every single in these helpers. Could we optimise them
>>> by passing the register value in ?
>>
>> The same goes for get_trbe_ec() and get_trbe_bsc() as well. Probably all
>> TRBSR field probing helpers should be modified to accept a TRBSR register
>> value instead.
>>
>>>
>>> i.e
>>>      u64 trbsr = get_trbe_status();
>>>
>>>      WARN_ON(is_trbe_runnign(trbsr))
>>>      if (is_trbe_trg(trbsr) || is_trbe_abort(trbsr))
>>>
>>> For is_trbe_wrap() too
>>
>> Yes.
>>
>>>
> 
> 
>>>
>>> We should skip the driver init, if the kernel is unmapped at EL0,
>>> as the TRBE can't safely write to the kernel virtual addressed
>>> buffer when the CPU is running at EL0. This is unlikely, but we
>>> should cover that case.
>>
>> This should be sufficient or it needs a pr_err() as well ?
>>
> 
> Please add a pr_err() message to indicate why this failed. Otherwise
> the user could be left with no clue.

Sure, will add the following before exiting the TRBE init.

pr_err("TRBE wouldn't work if kernel gets unmapped at EL0\n")



More information about the linux-arm-kernel mailing list