Re: [PATCH 6/6] coresight: etm-perf: Add support for ETR backend

2018-07-16 Thread Mathieu Poirier
On Fri, 13 Jul 2018 at 05:23, Suzuki K Poulose  wrote:
>
> On 12/07/18 21:57, Mathieu Poirier wrote:
> > Hi Suzuki,
> >
> > On Wed, Jul 11, 2018 at 03:16:39PM +0100, Suzuki K Poulose wrote:
> >> Add support for using TMC-ETR as backend for ETM perf tracing.
> >> We use software double buffering at the moment. i.e, the TMC-ETR
> >> uses a separate buffer than the perf ring buffer. The data is
> >> copied to the perf ring buffer once a session completes.
> >>
> >> The TMC-ETR would try to match the larger of perf ring buffer
> >> or the ETR buffer size configured via sysfs, scaling down to
> >> a minimum limit of 1MB.
> >>
> >> Cc: Mathieu Poirier 
> >> Signed-off-by: Suzuki K Poulose 
> >> ---
> >>   drivers/hwtracing/coresight/coresight-tmc-etr.c | 265 
> >> +++-
> >>   drivers/hwtracing/coresight/coresight-tmc.h |   2 +
> >>   2 files changed, 265 insertions(+), 2 deletions(-)
>
> >> +/*
> >> + * tmc_etr_sync_perf_buffer: Copy the actual trace data from the hardware
> >> + * buffer to the perf ring buffer.
> >> + */
> >> +static void tmc_etr_sync_perf_buffer(struct etr_perf_buffer *etr_perf)
> >> +{
> >> +long bytes, to_copy;
> >> +long pg_idx, pg_offset, src_offset;
> >> +unsigned long head = etr_perf->head;
> >> +char **dst_pages, *src_buf;
> >> +struct etr_buf *etr_buf = etr_perf->etr_buf;
> >> +
> >> +head = PERF_IDX2OFF(etr_perf->head, etr_perf);
> >
> > I'm puzzled here.  Since etr_perf->head is set in tmc_etr_set_perf_buffer() 
> > to
> > the value of handle->head, its value is always within the range of the perf 
> > ring
>
> IIUC, the handle->head is not necessarily guaranteed to be within the 
> aux-ring buffer.

I just looked at the ETB code and you are correct.

>
> > buffer.  In tmc_etr_alloc_perf_buffer() etr_perf->nr_pages is set to the 
> > number
> > of pages present in that ring buffer.  As such I'm not sure as to why we 
> > need
> > the PERF_IDX2OFF() macro.
> >
> > It seems to me that "head = etr_perf->head;" above is sufficient.
> >
>
> We need to do the step at some point, which could be moved to set_perf_buffer.

That's a good idea.

>
> >> +pg_idx = head >> PAGE_SHIFT;
> >> +pg_offset = head & (PAGE_SIZE - 1);
> >> +dst_pages = (char **)etr_perf->pages;
> >> +src_offset = etr_buf->offset;
> >> +to_copy = etr_buf->len;
> >> +
> >> +while (to_copy > 0) {
> >> +/*
> >> + * We can copy minimum of :
> >
> > s/We can copy minimum of :/In one iteration we can copy a minimum of:/
> >
> > If I'm wrong about the PERF_IDX2OFF(), don't bother respinning just for 
> > that.
>
> I have some more fixes for handling the different modes (sysfs vs perf),
> which I can include in the v2.

Very well.

>
> Suzuki


Re: [PATCH 6/6] coresight: etm-perf: Add support for ETR backend

2018-07-16 Thread Mathieu Poirier
On Fri, 13 Jul 2018 at 05:23, Suzuki K Poulose  wrote:
>
> On 12/07/18 21:57, Mathieu Poirier wrote:
> > Hi Suzuki,
> >
> > On Wed, Jul 11, 2018 at 03:16:39PM +0100, Suzuki K Poulose wrote:
> >> Add support for using TMC-ETR as backend for ETM perf tracing.
> >> We use software double buffering at the moment. i.e, the TMC-ETR
> >> uses a separate buffer than the perf ring buffer. The data is
> >> copied to the perf ring buffer once a session completes.
> >>
> >> The TMC-ETR would try to match the larger of perf ring buffer
> >> or the ETR buffer size configured via sysfs, scaling down to
> >> a minimum limit of 1MB.
> >>
> >> Cc: Mathieu Poirier 
> >> Signed-off-by: Suzuki K Poulose 
> >> ---
> >>   drivers/hwtracing/coresight/coresight-tmc-etr.c | 265 
> >> +++-
> >>   drivers/hwtracing/coresight/coresight-tmc.h |   2 +
> >>   2 files changed, 265 insertions(+), 2 deletions(-)
>
> >> +/*
> >> + * tmc_etr_sync_perf_buffer: Copy the actual trace data from the hardware
> >> + * buffer to the perf ring buffer.
> >> + */
> >> +static void tmc_etr_sync_perf_buffer(struct etr_perf_buffer *etr_perf)
> >> +{
> >> +long bytes, to_copy;
> >> +long pg_idx, pg_offset, src_offset;
> >> +unsigned long head = etr_perf->head;
> >> +char **dst_pages, *src_buf;
> >> +struct etr_buf *etr_buf = etr_perf->etr_buf;
> >> +
> >> +head = PERF_IDX2OFF(etr_perf->head, etr_perf);
> >
> > I'm puzzled here.  Since etr_perf->head is set in tmc_etr_set_perf_buffer() 
> > to
> > the value of handle->head, its value is always within the range of the perf 
> > ring
>
> IIUC, the handle->head is not necessarily guaranteed to be within the 
> aux-ring buffer.

I just looked at the ETB code and you are correct.

>
> > buffer.  In tmc_etr_alloc_perf_buffer() etr_perf->nr_pages is set to the 
> > number
> > of pages present in that ring buffer.  As such I'm not sure as to why we 
> > need
> > the PERF_IDX2OFF() macro.
> >
> > It seems to me that "head = etr_perf->head;" above is sufficient.
> >
>
> We need to do the step at some point, which could be moved to set_perf_buffer.

That's a good idea.

>
> >> +pg_idx = head >> PAGE_SHIFT;
> >> +pg_offset = head & (PAGE_SIZE - 1);
> >> +dst_pages = (char **)etr_perf->pages;
> >> +src_offset = etr_buf->offset;
> >> +to_copy = etr_buf->len;
> >> +
> >> +while (to_copy > 0) {
> >> +/*
> >> + * We can copy minimum of :
> >
> > s/We can copy minimum of :/In one iteration we can copy a minimum of:/
> >
> > If I'm wrong about the PERF_IDX2OFF(), don't bother respinning just for 
> > that.
>
> I have some more fixes for handling the different modes (sysfs vs perf),
> which I can include in the v2.

Very well.

>
> Suzuki


Re: [PATCH 6/6] coresight: etm-perf: Add support for ETR backend

2018-07-13 Thread Suzuki K Poulose

On 12/07/18 21:57, Mathieu Poirier wrote:

Hi Suzuki,

On Wed, Jul 11, 2018 at 03:16:39PM +0100, Suzuki K Poulose wrote:

Add support for using TMC-ETR as backend for ETM perf tracing.
We use software double buffering at the moment. i.e, the TMC-ETR
uses a separate buffer than the perf ring buffer. The data is
copied to the perf ring buffer once a session completes.

The TMC-ETR would try to match the larger of perf ring buffer
or the ETR buffer size configured via sysfs, scaling down to
a minimum limit of 1MB.

Cc: Mathieu Poirier 
Signed-off-by: Suzuki K Poulose 
---
  drivers/hwtracing/coresight/coresight-tmc-etr.c | 265 +++-
  drivers/hwtracing/coresight/coresight-tmc.h |   2 +
  2 files changed, 265 insertions(+), 2 deletions(-)



+/*
+ * tmc_etr_sync_perf_buffer: Copy the actual trace data from the hardware
+ * buffer to the perf ring buffer.
+ */
+static void tmc_etr_sync_perf_buffer(struct etr_perf_buffer *etr_perf)
+{
+   long bytes, to_copy;
+   long pg_idx, pg_offset, src_offset;
+   unsigned long head = etr_perf->head;
+   char **dst_pages, *src_buf;
+   struct etr_buf *etr_buf = etr_perf->etr_buf;
+
+   head = PERF_IDX2OFF(etr_perf->head, etr_perf);


I'm puzzled here.  Since etr_perf->head is set in tmc_etr_set_perf_buffer() to
the value of handle->head, its value is always within the range of the perf ring


IIUC, the handle->head is not necessarily guaranteed to be within the aux-ring 
buffer.


buffer.  In tmc_etr_alloc_perf_buffer() etr_perf->nr_pages is set to the number
of pages present in that ring buffer.  As such I'm not sure as to why we need
the PERF_IDX2OFF() macro.

It seems to me that "head = etr_perf->head;" above is sufficient.



We need to do the step at some point, which could be moved to set_perf_buffer.


+   pg_idx = head >> PAGE_SHIFT;
+   pg_offset = head & (PAGE_SIZE - 1);
+   dst_pages = (char **)etr_perf->pages;
+   src_offset = etr_buf->offset;
+   to_copy = etr_buf->len;
+
+   while (to_copy > 0) {
+   /*
+* We can copy minimum of :


s/We can copy minimum of :/In one iteration we can copy a minimum of:/

If I'm wrong about the PERF_IDX2OFF(), don't bother respinning just for that.


I have some more fixes for handling the different modes (sysfs vs perf),
which I can include in the v2.

Suzuki


Re: [PATCH 6/6] coresight: etm-perf: Add support for ETR backend

2018-07-13 Thread Suzuki K Poulose

On 12/07/18 21:57, Mathieu Poirier wrote:

Hi Suzuki,

On Wed, Jul 11, 2018 at 03:16:39PM +0100, Suzuki K Poulose wrote:

Add support for using TMC-ETR as backend for ETM perf tracing.
We use software double buffering at the moment. i.e, the TMC-ETR
uses a separate buffer than the perf ring buffer. The data is
copied to the perf ring buffer once a session completes.

The TMC-ETR would try to match the larger of perf ring buffer
or the ETR buffer size configured via sysfs, scaling down to
a minimum limit of 1MB.

Cc: Mathieu Poirier 
Signed-off-by: Suzuki K Poulose 
---
  drivers/hwtracing/coresight/coresight-tmc-etr.c | 265 +++-
  drivers/hwtracing/coresight/coresight-tmc.h |   2 +
  2 files changed, 265 insertions(+), 2 deletions(-)



+/*
+ * tmc_etr_sync_perf_buffer: Copy the actual trace data from the hardware
+ * buffer to the perf ring buffer.
+ */
+static void tmc_etr_sync_perf_buffer(struct etr_perf_buffer *etr_perf)
+{
+   long bytes, to_copy;
+   long pg_idx, pg_offset, src_offset;
+   unsigned long head = etr_perf->head;
+   char **dst_pages, *src_buf;
+   struct etr_buf *etr_buf = etr_perf->etr_buf;
+
+   head = PERF_IDX2OFF(etr_perf->head, etr_perf);


I'm puzzled here.  Since etr_perf->head is set in tmc_etr_set_perf_buffer() to
the value of handle->head, its value is always within the range of the perf ring


IIUC, the handle->head is not necessarily guaranteed to be within the aux-ring 
buffer.


buffer.  In tmc_etr_alloc_perf_buffer() etr_perf->nr_pages is set to the number
of pages present in that ring buffer.  As such I'm not sure as to why we need
the PERF_IDX2OFF() macro.

It seems to me that "head = etr_perf->head;" above is sufficient.



We need to do the step at some point, which could be moved to set_perf_buffer.


+   pg_idx = head >> PAGE_SHIFT;
+   pg_offset = head & (PAGE_SIZE - 1);
+   dst_pages = (char **)etr_perf->pages;
+   src_offset = etr_buf->offset;
+   to_copy = etr_buf->len;
+
+   while (to_copy > 0) {
+   /*
+* We can copy minimum of :


s/We can copy minimum of :/In one iteration we can copy a minimum of:/

If I'm wrong about the PERF_IDX2OFF(), don't bother respinning just for that.


I have some more fixes for handling the different modes (sysfs vs perf),
which I can include in the v2.

Suzuki


Re: [PATCH 6/6] coresight: etm-perf: Add support for ETR backend

2018-07-12 Thread Mathieu Poirier
Hi Suzuki,

On Wed, Jul 11, 2018 at 03:16:39PM +0100, Suzuki K Poulose wrote:
> Add support for using TMC-ETR as backend for ETM perf tracing.
> We use software double buffering at the moment. i.e, the TMC-ETR
> uses a separate buffer than the perf ring buffer. The data is
> copied to the perf ring buffer once a session completes.
> 
> The TMC-ETR would try to match the larger of perf ring buffer
> or the ETR buffer size configured via sysfs, scaling down to
> a minimum limit of 1MB.
> 
> Cc: Mathieu Poirier 
> Signed-off-by: Suzuki K Poulose 
> ---
>  drivers/hwtracing/coresight/coresight-tmc-etr.c | 265 
> +++-
>  drivers/hwtracing/coresight/coresight-tmc.h |   2 +
>  2 files changed, 265 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c 
> b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index 20a0beb..af921da 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -21,6 +21,28 @@ struct etr_flat_buf {
>  };
>  
>  /*
> + * etr_perf_buffer - Perf buffer used for ETR
> + * @etr_buf  - Actual buffer used by the ETR
> + * @snaphost - Perf session mode
> + * @head - handle->head at the beginning of the session.
> + * @nr_pages - Number of pages in the ring buffer.
> + * @pages- Array of Pages in the ring buffer.
> + */
> +struct etr_perf_buffer {
> + struct etr_buf  *etr_buf;
> + boolsnapshot;
> + unsigned long   head;
> + int nr_pages;
> + void**pages;
> +};
> +
> +/* Convert the perf index to an offset within the ETR buffer */
> +#define PERF_IDX2OFF(idx, buf)   ((idx) % ((buf)->nr_pages << 
> PAGE_SHIFT))
> +
> +/* Lower limit for ETR hardware buffer */
> +#define TMC_ETR_PERF_MIN_BUF_SIZESZ_1M
> +
> +/*
>   * The TMC ETR SG has a page size of 4K. The SG table contains pointers
>   * to 4KB buffers. However, the OS may use a PAGE_SIZE different from
>   * 4K (i.e, 16KB or 64KB). This implies that a single OS page could
> @@ -1103,10 +1125,245 @@ static int tmc_enable_etr_sink_sysfs(struct 
> coresight_device *csdev)
>   return ret;
>  }
>  
> +/*
> + * tmc_etr_setup_perf_buf: Allocate ETR buffer for use by perf.
> + * The size of the hardware buffer is dependent on the size configured
> + * via sysfs and the perf ring buffer size. We prefer to allocate the
> + * largest possible size, scaling down the size by half until it
> + * reaches a minimum limit (1M), beyond which we give up.
> + */
> +static struct etr_perf_buffer *
> +tmc_etr_setup_perf_buf(struct tmc_drvdata *drvdata, int node, int nr_pages,
> +void **pages, bool snapshot)
> +{
> + struct etr_buf *etr_buf;
> + struct etr_perf_buffer *etr_perf;
> + unsigned long size;
> +
> + etr_perf = kzalloc_node(sizeof(*etr_perf), GFP_KERNEL, node);
> + if (!etr_perf)
> + return ERR_PTR(-ENOMEM);
> +
> + /*
> +  * Try to match the perf ring buffer size if it is larger
> +  * than the size requested via sysfs.
> +  */
> + if ((nr_pages << PAGE_SHIFT) > drvdata->size) {
> + etr_buf = tmc_alloc_etr_buf(drvdata, (nr_pages << PAGE_SHIFT),
> + 0, node, NULL);
> + if (!IS_ERR(etr_buf))
> + goto done;
> + }
> +
> + /*
> +  * Else switch to configured size for this ETR
> +  * and scale down until we hit the minimum limit.
> +  */
> + size = drvdata->size;
> + do {
> + etr_buf = tmc_alloc_etr_buf(drvdata, size, 0, node, NULL);
> + if (!IS_ERR(etr_buf))
> + goto done;
> + size /= 2;
> + } while (size >= TMC_ETR_PERF_MIN_BUF_SIZE);
> +
> + kfree(etr_perf);
> + return ERR_PTR(-ENOMEM);
> +
> +done:
> + etr_perf->etr_buf = etr_buf;
> + return etr_perf;
> +}
> +
> +
> +static void *tmc_etr_alloc_perf_buffer(struct coresight_device *csdev,
> +int cpu, void **pages, int nr_pages,
> +bool snapshot)
> +{
> + struct etr_perf_buffer *etr_perf;
> + struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> +
> + if (cpu == -1)
> + cpu = smp_processor_id();
> +
> + etr_perf = tmc_etr_setup_perf_buf(drvdata, cpu_to_node(cpu),
> +   nr_pages, pages, snapshot);
> + if (IS_ERR(etr_perf)) {
> + dev_dbg(drvdata->dev, "Unable to allocate ETR buffer\n");
> + return NULL;
> + }
> +
> + etr_perf->snapshot = snapshot;
> + etr_perf->nr_pages = nr_pages;
> + etr_perf->pages = pages;
> +
> + return etr_perf;
> +}
> +
> +static void tmc_etr_free_perf_buffer(void *config)
> +{
> + struct etr_perf_buffer *etr_perf = config;
> +
> + if (etr_perf->etr_buf)
> +

Re: [PATCH 6/6] coresight: etm-perf: Add support for ETR backend

2018-07-12 Thread Mathieu Poirier
Hi Suzuki,

On Wed, Jul 11, 2018 at 03:16:39PM +0100, Suzuki K Poulose wrote:
> Add support for using TMC-ETR as backend for ETM perf tracing.
> We use software double buffering at the moment. i.e, the TMC-ETR
> uses a separate buffer than the perf ring buffer. The data is
> copied to the perf ring buffer once a session completes.
> 
> The TMC-ETR would try to match the larger of perf ring buffer
> or the ETR buffer size configured via sysfs, scaling down to
> a minimum limit of 1MB.
> 
> Cc: Mathieu Poirier 
> Signed-off-by: Suzuki K Poulose 
> ---
>  drivers/hwtracing/coresight/coresight-tmc-etr.c | 265 
> +++-
>  drivers/hwtracing/coresight/coresight-tmc.h |   2 +
>  2 files changed, 265 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c 
> b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index 20a0beb..af921da 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -21,6 +21,28 @@ struct etr_flat_buf {
>  };
>  
>  /*
> + * etr_perf_buffer - Perf buffer used for ETR
> + * @etr_buf  - Actual buffer used by the ETR
> + * @snaphost - Perf session mode
> + * @head - handle->head at the beginning of the session.
> + * @nr_pages - Number of pages in the ring buffer.
> + * @pages- Array of Pages in the ring buffer.
> + */
> +struct etr_perf_buffer {
> + struct etr_buf  *etr_buf;
> + boolsnapshot;
> + unsigned long   head;
> + int nr_pages;
> + void**pages;
> +};
> +
> +/* Convert the perf index to an offset within the ETR buffer */
> +#define PERF_IDX2OFF(idx, buf)   ((idx) % ((buf)->nr_pages << 
> PAGE_SHIFT))
> +
> +/* Lower limit for ETR hardware buffer */
> +#define TMC_ETR_PERF_MIN_BUF_SIZESZ_1M
> +
> +/*
>   * The TMC ETR SG has a page size of 4K. The SG table contains pointers
>   * to 4KB buffers. However, the OS may use a PAGE_SIZE different from
>   * 4K (i.e, 16KB or 64KB). This implies that a single OS page could
> @@ -1103,10 +1125,245 @@ static int tmc_enable_etr_sink_sysfs(struct 
> coresight_device *csdev)
>   return ret;
>  }
>  
> +/*
> + * tmc_etr_setup_perf_buf: Allocate ETR buffer for use by perf.
> + * The size of the hardware buffer is dependent on the size configured
> + * via sysfs and the perf ring buffer size. We prefer to allocate the
> + * largest possible size, scaling down the size by half until it
> + * reaches a minimum limit (1M), beyond which we give up.
> + */
> +static struct etr_perf_buffer *
> +tmc_etr_setup_perf_buf(struct tmc_drvdata *drvdata, int node, int nr_pages,
> +void **pages, bool snapshot)
> +{
> + struct etr_buf *etr_buf;
> + struct etr_perf_buffer *etr_perf;
> + unsigned long size;
> +
> + etr_perf = kzalloc_node(sizeof(*etr_perf), GFP_KERNEL, node);
> + if (!etr_perf)
> + return ERR_PTR(-ENOMEM);
> +
> + /*
> +  * Try to match the perf ring buffer size if it is larger
> +  * than the size requested via sysfs.
> +  */
> + if ((nr_pages << PAGE_SHIFT) > drvdata->size) {
> + etr_buf = tmc_alloc_etr_buf(drvdata, (nr_pages << PAGE_SHIFT),
> + 0, node, NULL);
> + if (!IS_ERR(etr_buf))
> + goto done;
> + }
> +
> + /*
> +  * Else switch to configured size for this ETR
> +  * and scale down until we hit the minimum limit.
> +  */
> + size = drvdata->size;
> + do {
> + etr_buf = tmc_alloc_etr_buf(drvdata, size, 0, node, NULL);
> + if (!IS_ERR(etr_buf))
> + goto done;
> + size /= 2;
> + } while (size >= TMC_ETR_PERF_MIN_BUF_SIZE);
> +
> + kfree(etr_perf);
> + return ERR_PTR(-ENOMEM);
> +
> +done:
> + etr_perf->etr_buf = etr_buf;
> + return etr_perf;
> +}
> +
> +
> +static void *tmc_etr_alloc_perf_buffer(struct coresight_device *csdev,
> +int cpu, void **pages, int nr_pages,
> +bool snapshot)
> +{
> + struct etr_perf_buffer *etr_perf;
> + struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> +
> + if (cpu == -1)
> + cpu = smp_processor_id();
> +
> + etr_perf = tmc_etr_setup_perf_buf(drvdata, cpu_to_node(cpu),
> +   nr_pages, pages, snapshot);
> + if (IS_ERR(etr_perf)) {
> + dev_dbg(drvdata->dev, "Unable to allocate ETR buffer\n");
> + return NULL;
> + }
> +
> + etr_perf->snapshot = snapshot;
> + etr_perf->nr_pages = nr_pages;
> + etr_perf->pages = pages;
> +
> + return etr_perf;
> +}
> +
> +static void tmc_etr_free_perf_buffer(void *config)
> +{
> + struct etr_perf_buffer *etr_perf = config;
> +
> + if (etr_perf->etr_buf)
> +

[PATCH 6/6] coresight: etm-perf: Add support for ETR backend

2018-07-11 Thread Suzuki K Poulose
Add support for using TMC-ETR as backend for ETM perf tracing.
We use software double buffering at the moment. i.e, the TMC-ETR
uses a separate buffer than the perf ring buffer. The data is
copied to the perf ring buffer once a session completes.

The TMC-ETR would try to match the larger of perf ring buffer
or the ETR buffer size configured via sysfs, scaling down to
a minimum limit of 1MB.

Cc: Mathieu Poirier 
Signed-off-by: Suzuki K Poulose 
---
 drivers/hwtracing/coresight/coresight-tmc-etr.c | 265 +++-
 drivers/hwtracing/coresight/coresight-tmc.h |   2 +
 2 files changed, 265 insertions(+), 2 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c 
b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 20a0beb..af921da 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -21,6 +21,28 @@ struct etr_flat_buf {
 };
 
 /*
+ * etr_perf_buffer - Perf buffer used for ETR
+ * @etr_buf- Actual buffer used by the ETR
+ * @snaphost   - Perf session mode
+ * @head   - handle->head at the beginning of the session.
+ * @nr_pages   - Number of pages in the ring buffer.
+ * @pages  - Array of Pages in the ring buffer.
+ */
+struct etr_perf_buffer {
+   struct etr_buf  *etr_buf;
+   boolsnapshot;
+   unsigned long   head;
+   int nr_pages;
+   void**pages;
+};
+
+/* Convert the perf index to an offset within the ETR buffer */
+#define PERF_IDX2OFF(idx, buf) ((idx) % ((buf)->nr_pages << PAGE_SHIFT))
+
+/* Lower limit for ETR hardware buffer */
+#define TMC_ETR_PERF_MIN_BUF_SIZE  SZ_1M
+
+/*
  * The TMC ETR SG has a page size of 4K. The SG table contains pointers
  * to 4KB buffers. However, the OS may use a PAGE_SIZE different from
  * 4K (i.e, 16KB or 64KB). This implies that a single OS page could
@@ -1103,10 +1125,245 @@ static int tmc_enable_etr_sink_sysfs(struct 
coresight_device *csdev)
return ret;
 }
 
+/*
+ * tmc_etr_setup_perf_buf: Allocate ETR buffer for use by perf.
+ * The size of the hardware buffer is dependent on the size configured
+ * via sysfs and the perf ring buffer size. We prefer to allocate the
+ * largest possible size, scaling down the size by half until it
+ * reaches a minimum limit (1M), beyond which we give up.
+ */
+static struct etr_perf_buffer *
+tmc_etr_setup_perf_buf(struct tmc_drvdata *drvdata, int node, int nr_pages,
+  void **pages, bool snapshot)
+{
+   struct etr_buf *etr_buf;
+   struct etr_perf_buffer *etr_perf;
+   unsigned long size;
+
+   etr_perf = kzalloc_node(sizeof(*etr_perf), GFP_KERNEL, node);
+   if (!etr_perf)
+   return ERR_PTR(-ENOMEM);
+
+   /*
+* Try to match the perf ring buffer size if it is larger
+* than the size requested via sysfs.
+*/
+   if ((nr_pages << PAGE_SHIFT) > drvdata->size) {
+   etr_buf = tmc_alloc_etr_buf(drvdata, (nr_pages << PAGE_SHIFT),
+   0, node, NULL);
+   if (!IS_ERR(etr_buf))
+   goto done;
+   }
+
+   /*
+* Else switch to configured size for this ETR
+* and scale down until we hit the minimum limit.
+*/
+   size = drvdata->size;
+   do {
+   etr_buf = tmc_alloc_etr_buf(drvdata, size, 0, node, NULL);
+   if (!IS_ERR(etr_buf))
+   goto done;
+   size /= 2;
+   } while (size >= TMC_ETR_PERF_MIN_BUF_SIZE);
+
+   kfree(etr_perf);
+   return ERR_PTR(-ENOMEM);
+
+done:
+   etr_perf->etr_buf = etr_buf;
+   return etr_perf;
+}
+
+
+static void *tmc_etr_alloc_perf_buffer(struct coresight_device *csdev,
+  int cpu, void **pages, int nr_pages,
+  bool snapshot)
+{
+   struct etr_perf_buffer *etr_perf;
+   struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+   if (cpu == -1)
+   cpu = smp_processor_id();
+
+   etr_perf = tmc_etr_setup_perf_buf(drvdata, cpu_to_node(cpu),
+ nr_pages, pages, snapshot);
+   if (IS_ERR(etr_perf)) {
+   dev_dbg(drvdata->dev, "Unable to allocate ETR buffer\n");
+   return NULL;
+   }
+
+   etr_perf->snapshot = snapshot;
+   etr_perf->nr_pages = nr_pages;
+   etr_perf->pages = pages;
+
+   return etr_perf;
+}
+
+static void tmc_etr_free_perf_buffer(void *config)
+{
+   struct etr_perf_buffer *etr_perf = config;
+
+   if (etr_perf->etr_buf)
+   tmc_free_etr_buf(etr_perf->etr_buf);
+   kfree(etr_perf);
+}
+
+static int tmc_etr_set_perf_buffer(struct coresight_device *csdev,
+  struct perf_output_handle *handle,
+ 

[PATCH 6/6] coresight: etm-perf: Add support for ETR backend

2018-07-11 Thread Suzuki K Poulose
Add support for using TMC-ETR as backend for ETM perf tracing.
We use software double buffering at the moment. i.e, the TMC-ETR
uses a separate buffer than the perf ring buffer. The data is
copied to the perf ring buffer once a session completes.

The TMC-ETR would try to match the larger of perf ring buffer
or the ETR buffer size configured via sysfs, scaling down to
a minimum limit of 1MB.

Cc: Mathieu Poirier 
Signed-off-by: Suzuki K Poulose 
---
 drivers/hwtracing/coresight/coresight-tmc-etr.c | 265 +++-
 drivers/hwtracing/coresight/coresight-tmc.h |   2 +
 2 files changed, 265 insertions(+), 2 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c 
b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 20a0beb..af921da 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -21,6 +21,28 @@ struct etr_flat_buf {
 };
 
 /*
+ * etr_perf_buffer - Perf buffer used for ETR
+ * @etr_buf- Actual buffer used by the ETR
+ * @snaphost   - Perf session mode
+ * @head   - handle->head at the beginning of the session.
+ * @nr_pages   - Number of pages in the ring buffer.
+ * @pages  - Array of Pages in the ring buffer.
+ */
+struct etr_perf_buffer {
+   struct etr_buf  *etr_buf;
+   boolsnapshot;
+   unsigned long   head;
+   int nr_pages;
+   void**pages;
+};
+
+/* Convert the perf index to an offset within the ETR buffer */
+#define PERF_IDX2OFF(idx, buf) ((idx) % ((buf)->nr_pages << PAGE_SHIFT))
+
+/* Lower limit for ETR hardware buffer */
+#define TMC_ETR_PERF_MIN_BUF_SIZE  SZ_1M
+
+/*
  * The TMC ETR SG has a page size of 4K. The SG table contains pointers
  * to 4KB buffers. However, the OS may use a PAGE_SIZE different from
  * 4K (i.e, 16KB or 64KB). This implies that a single OS page could
@@ -1103,10 +1125,245 @@ static int tmc_enable_etr_sink_sysfs(struct 
coresight_device *csdev)
return ret;
 }
 
+/*
+ * tmc_etr_setup_perf_buf: Allocate ETR buffer for use by perf.
+ * The size of the hardware buffer is dependent on the size configured
+ * via sysfs and the perf ring buffer size. We prefer to allocate the
+ * largest possible size, scaling down the size by half until it
+ * reaches a minimum limit (1M), beyond which we give up.
+ */
+static struct etr_perf_buffer *
+tmc_etr_setup_perf_buf(struct tmc_drvdata *drvdata, int node, int nr_pages,
+  void **pages, bool snapshot)
+{
+   struct etr_buf *etr_buf;
+   struct etr_perf_buffer *etr_perf;
+   unsigned long size;
+
+   etr_perf = kzalloc_node(sizeof(*etr_perf), GFP_KERNEL, node);
+   if (!etr_perf)
+   return ERR_PTR(-ENOMEM);
+
+   /*
+* Try to match the perf ring buffer size if it is larger
+* than the size requested via sysfs.
+*/
+   if ((nr_pages << PAGE_SHIFT) > drvdata->size) {
+   etr_buf = tmc_alloc_etr_buf(drvdata, (nr_pages << PAGE_SHIFT),
+   0, node, NULL);
+   if (!IS_ERR(etr_buf))
+   goto done;
+   }
+
+   /*
+* Else switch to configured size for this ETR
+* and scale down until we hit the minimum limit.
+*/
+   size = drvdata->size;
+   do {
+   etr_buf = tmc_alloc_etr_buf(drvdata, size, 0, node, NULL);
+   if (!IS_ERR(etr_buf))
+   goto done;
+   size /= 2;
+   } while (size >= TMC_ETR_PERF_MIN_BUF_SIZE);
+
+   kfree(etr_perf);
+   return ERR_PTR(-ENOMEM);
+
+done:
+   etr_perf->etr_buf = etr_buf;
+   return etr_perf;
+}
+
+
+static void *tmc_etr_alloc_perf_buffer(struct coresight_device *csdev,
+  int cpu, void **pages, int nr_pages,
+  bool snapshot)
+{
+   struct etr_perf_buffer *etr_perf;
+   struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+   if (cpu == -1)
+   cpu = smp_processor_id();
+
+   etr_perf = tmc_etr_setup_perf_buf(drvdata, cpu_to_node(cpu),
+ nr_pages, pages, snapshot);
+   if (IS_ERR(etr_perf)) {
+   dev_dbg(drvdata->dev, "Unable to allocate ETR buffer\n");
+   return NULL;
+   }
+
+   etr_perf->snapshot = snapshot;
+   etr_perf->nr_pages = nr_pages;
+   etr_perf->pages = pages;
+
+   return etr_perf;
+}
+
+static void tmc_etr_free_perf_buffer(void *config)
+{
+   struct etr_perf_buffer *etr_perf = config;
+
+   if (etr_perf->etr_buf)
+   tmc_free_etr_buf(etr_perf->etr_buf);
+   kfree(etr_perf);
+}
+
+static int tmc_etr_set_perf_buffer(struct coresight_device *csdev,
+  struct perf_output_handle *handle,
+