aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSuzuki K Poulose <suzuki.poulose@arm.com>2018-07-11 15:40:34 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-07-15 07:52:59 -0400
commit434d611cddef1ceed32bf416a363992b01a3ff9a (patch)
treea3257f7cec20386097ca1e79fded50777ea55d76 /drivers
parent8ed536b1e2838dad4f495347f0917b1cb6e3604f (diff)
coresight: catu: Plug in CATU as a backend for ETR buffer
Now that we can use a CATU with a scatter gather table, add support for the TMC ETR to make use of the connected CATU in translate mode. This is done by adding CATU as new buffer mode. Cc: Mathieu Poirier <mathieu.poirier@linaro.org> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/hwtracing/coresight/coresight-catu.c122
-rw-r--r--drivers/hwtracing/coresight/coresight-catu.h35
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-etr.c25
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc.h3
4 files changed, 174 insertions, 11 deletions
diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c
index 559d45b6bc39..ff94e58845b7 100644
--- a/drivers/hwtracing/coresight/coresight-catu.c
+++ b/drivers/hwtracing/coresight/coresight-catu.c
@@ -28,6 +28,11 @@
28#define catu_dbg(x, ...) do {} while (0) 28#define catu_dbg(x, ...) do {} while (0)
29#endif 29#endif
30 30
31struct catu_etr_buf {
32 struct tmc_sg_table *catu_table;
33 dma_addr_t sladdr;
34};
35
31/* 36/*
32 * CATU uses a page size of 4KB for page tables as well as data pages. 37 * CATU uses a page size of 4KB for page tables as well as data pages.
33 * Each 64bit entry in the table has the following format. 38 * Each 64bit entry in the table has the following format.
@@ -93,6 +98,9 @@ typedef u64 cate_t;
93 (((cate_t)(addr) & CATU_ADDR_MASK) | CATU_ENTRY_VALID) 98 (((cate_t)(addr) & CATU_ADDR_MASK) | CATU_ENTRY_VALID)
94#define CATU_ENTRY_ADDR(entry) ((cate_t)(entry) & ~((cate_t)CATU_ENTRY_VALID)) 99#define CATU_ENTRY_ADDR(entry) ((cate_t)(entry) & ~((cate_t)CATU_ENTRY_VALID))
95 100
101/* CATU expects the INADDR to be aligned to 1M. */
102#define CATU_DEFAULT_INADDR (1ULL << 20)
103
96/* 104/*
97 * catu_get_table : Retrieve the table pointers for the given @offset 105 * catu_get_table : Retrieve the table pointers for the given @offset
98 * within the buffer. The buffer is wrapped around to a valid offset. 106 * within the buffer. The buffer is wrapped around to a valid offset.
@@ -246,7 +254,7 @@ catu_populate_table(struct tmc_sg_table *catu_table)
246 tmc_sg_table_sync_table(catu_table); 254 tmc_sg_table_sync_table(catu_table);
247} 255}
248 256
249static struct tmc_sg_table __maybe_unused * 257static struct tmc_sg_table *
250catu_init_sg_table(struct device *catu_dev, int node, 258catu_init_sg_table(struct device *catu_dev, int node,
251 ssize_t size, void **pages) 259 ssize_t size, void **pages)
252{ 260{
@@ -271,6 +279,91 @@ catu_init_sg_table(struct device *catu_dev, int node,
271 return catu_table; 279 return catu_table;
272} 280}
273 281
282static void catu_free_etr_buf(struct etr_buf *etr_buf)
283{
284 struct catu_etr_buf *catu_buf;
285
286 if (!etr_buf || etr_buf->mode != ETR_MODE_CATU || !etr_buf->private)
287 return;
288
289 catu_buf = etr_buf->private;
290 tmc_free_sg_table(catu_buf->catu_table);
291 kfree(catu_buf);
292}
293
294static ssize_t catu_get_data_etr_buf(struct etr_buf *etr_buf, u64 offset,
295 size_t len, char **bufpp)
296{
297 struct catu_etr_buf *catu_buf = etr_buf->private;
298
299 return tmc_sg_table_get_data(catu_buf->catu_table, offset, len, bufpp);
300}
301
302static void catu_sync_etr_buf(struct etr_buf *etr_buf, u64 rrp, u64 rwp)
303{
304 struct catu_etr_buf *catu_buf = etr_buf->private;
305 struct tmc_sg_table *catu_table = catu_buf->catu_table;
306 u64 r_offset, w_offset;
307
308 /*
309 * ETR started off at etr_buf->hwaddr. Convert the RRP/RWP to
310 * offsets within the trace buffer.
311 */
312 r_offset = rrp - etr_buf->hwaddr;
313 w_offset = rwp - etr_buf->hwaddr;
314
315 if (!etr_buf->full) {
316 etr_buf->len = w_offset - r_offset;
317 if (w_offset < r_offset)
318 etr_buf->len += etr_buf->size;
319 } else {
320 etr_buf->len = etr_buf->size;
321 }
322
323 etr_buf->offset = r_offset;
324 tmc_sg_table_sync_data_range(catu_table, r_offset, etr_buf->len);
325}
326
327static int catu_alloc_etr_buf(struct tmc_drvdata *tmc_drvdata,
328 struct etr_buf *etr_buf, int node, void **pages)
329{
330 struct coresight_device *csdev;
331 struct device *catu_dev;
332 struct tmc_sg_table *catu_table;
333 struct catu_etr_buf *catu_buf;
334
335 csdev = tmc_etr_get_catu_device(tmc_drvdata);
336 if (!csdev)
337 return -ENODEV;
338 catu_dev = csdev->dev.parent;
339 catu_buf = kzalloc(sizeof(*catu_buf), GFP_KERNEL);
340 if (!catu_buf)
341 return -ENOMEM;
342
343 catu_table = catu_init_sg_table(catu_dev, node, etr_buf->size, pages);
344 if (IS_ERR(catu_table)) {
345 kfree(catu_buf);
346 return PTR_ERR(catu_table);
347 }
348
349 etr_buf->mode = ETR_MODE_CATU;
350 etr_buf->private = catu_buf;
351 etr_buf->hwaddr = CATU_DEFAULT_INADDR;
352
353 catu_buf->catu_table = catu_table;
354 /* Get the table base address */
355 catu_buf->sladdr = catu_table->table_daddr;
356
357 return 0;
358}
359
360const struct etr_buf_operations etr_catu_buf_ops = {
361 .alloc = catu_alloc_etr_buf,
362 .free = catu_free_etr_buf,
363 .sync = catu_sync_etr_buf,
364 .get_data = catu_get_data_etr_buf,
365};
366
274coresight_simple_reg32(struct catu_drvdata, devid, CORESIGHT_DEVID); 367coresight_simple_reg32(struct catu_drvdata, devid, CORESIGHT_DEVID);
275coresight_simple_reg32(struct catu_drvdata, control, CATU_CONTROL); 368coresight_simple_reg32(struct catu_drvdata, control, CATU_CONTROL);
276coresight_simple_reg32(struct catu_drvdata, status, CATU_STATUS); 369coresight_simple_reg32(struct catu_drvdata, status, CATU_STATUS);
@@ -311,9 +404,10 @@ static inline int catu_wait_for_ready(struct catu_drvdata *drvdata)
311 CATU_STATUS, CATU_STATUS_READY, 1); 404 CATU_STATUS, CATU_STATUS_READY, 1);
312} 405}
313 406
314static int catu_enable_hw(struct catu_drvdata *drvdata, void *__unused) 407static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
315{ 408{
316 u32 control; 409 u32 control, mode;
410 struct etr_buf *etr_buf = data;
317 411
318 if (catu_wait_for_ready(drvdata)) 412 if (catu_wait_for_ready(drvdata))
319 dev_warn(drvdata->dev, "Timeout while waiting for READY\n"); 413 dev_warn(drvdata->dev, "Timeout while waiting for READY\n");
@@ -325,9 +419,27 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, void *__unused)
325 } 419 }
326 420
327 control |= BIT(CATU_CONTROL_ENABLE); 421 control |= BIT(CATU_CONTROL_ENABLE);
328 catu_write_mode(drvdata, CATU_MODE_PASS_THROUGH); 422
423 if (etr_buf && etr_buf->mode == ETR_MODE_CATU) {
424 struct catu_etr_buf *catu_buf = etr_buf->private;
425
426 mode = CATU_MODE_TRANSLATE;
427 catu_write_axictrl(drvdata, CATU_OS_AXICTRL);
428 catu_write_sladdr(drvdata, catu_buf->sladdr);
429 catu_write_inaddr(drvdata, CATU_DEFAULT_INADDR);
430 } else {
431 mode = CATU_MODE_PASS_THROUGH;
432 catu_write_sladdr(drvdata, 0);
433 catu_write_inaddr(drvdata, 0);
434 }
435
436 catu_write_irqen(drvdata, 0);
437 catu_write_mode(drvdata, mode);
329 catu_write_control(drvdata, control); 438 catu_write_control(drvdata, control);
330 dev_dbg(drvdata->dev, "Enabled in Pass through mode\n"); 439 dev_dbg(drvdata->dev, "Enabled in %s mode\n",
440 (mode == CATU_MODE_PASS_THROUGH) ?
441 "Pass through" :
442 "Translate");
331 return 0; 443 return 0;
332} 444}
333 445
diff --git a/drivers/hwtracing/coresight/coresight-catu.h b/drivers/hwtracing/coresight/coresight-catu.h
index 4f221fccffca..1b281f0dcccc 100644
--- a/drivers/hwtracing/coresight/coresight-catu.h
+++ b/drivers/hwtracing/coresight/coresight-catu.h
@@ -27,6 +27,32 @@
27#define CATU_MODE_PASS_THROUGH 0U 27#define CATU_MODE_PASS_THROUGH 0U
28#define CATU_MODE_TRANSLATE 1U 28#define CATU_MODE_TRANSLATE 1U
29 29
30#define CATU_AXICTRL_ARCACHE_SHIFT 4
31#define CATU_AXICTRL_ARCACHE_MASK 0xf
32#define CATU_AXICTRL_ARPROT_MASK 0x3
33#define CATU_AXICTRL_ARCACHE(arcache) \
34 (((arcache) & CATU_AXICTRL_ARCACHE_MASK) << CATU_AXICTRL_ARCACHE_SHIFT)
35
36#define CATU_AXICTRL_VAL(arcache, arprot) \
37 (CATU_AXICTRL_ARCACHE(arcache) | ((arprot) & CATU_AXICTRL_ARPROT_MASK))
38
39#define AXI3_AxCACHE_WB_READ_ALLOC 0x7
40/*
41 * AXI - ARPROT bits:
42 * See AMBA AXI & ACE Protocol specification (ARM IHI 0022E)
43 * sectionA4.7 Access Permissions.
44 *
45 * Bit 0: 0 - Unprivileged access, 1 - Privileged access
46 * Bit 1: 0 - Secure access, 1 - Non-secure access.
47 * Bit 2: 0 - Data access, 1 - instruction access.
48 *
49 * CATU AXICTRL:ARPROT[2] is res0 as we always access data.
50 */
51#define CATU_OS_ARPROT 0x2
52
53#define CATU_OS_AXICTRL \
54 CATU_AXICTRL_VAL(AXI3_AxCACHE_WB_READ_ALLOC, CATU_OS_ARPROT)
55
30#define CATU_STATUS_READY 8 56#define CATU_STATUS_READY 8
31#define CATU_STATUS_ADRERR 0 57#define CATU_STATUS_ADRERR 0
32#define CATU_STATUS_AXIERR 4 58#define CATU_STATUS_AXIERR 4
@@ -67,6 +93,8 @@ catu_write_##name(struct catu_drvdata *drvdata, u64 val) \
67 93
68CATU_REG32(control, CATU_CONTROL); 94CATU_REG32(control, CATU_CONTROL);
69CATU_REG32(mode, CATU_MODE); 95CATU_REG32(mode, CATU_MODE);
96CATU_REG32(irqen, CATU_IRQEN);
97CATU_REG32(axictrl, CATU_AXICTRL);
70CATU_REG_PAIR(sladdr, CATU_SLADDRLO, CATU_SLADDRHI) 98CATU_REG_PAIR(sladdr, CATU_SLADDRLO, CATU_SLADDRHI)
71CATU_REG_PAIR(inaddr, CATU_INADDRLO, CATU_INADDRHI) 99CATU_REG_PAIR(inaddr, CATU_INADDRLO, CATU_INADDRHI)
72 100
@@ -81,4 +109,11 @@ static inline bool coresight_is_catu_device(struct coresight_device *csdev)
81 return true; 109 return true;
82} 110}
83 111
112#ifdef CONFIG_CORESIGHT_CATU
113extern const struct etr_buf_operations etr_catu_buf_ops;
114#else
115/* Dummy declaration for the CATU ops */
116static const struct etr_buf_operations etr_catu_buf_ops;
117#endif
118
84#endif 119#endif
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index e37923acb725..2eda5de304c2 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -710,7 +710,7 @@ static const struct etr_buf_operations etr_sg_buf_ops = {
710 * Returns : coresight_device ptr for the CATU device if a CATU is found. 710 * Returns : coresight_device ptr for the CATU device if a CATU is found.
711 * : NULL otherwise. 711 * : NULL otherwise.
712 */ 712 */
713static inline struct coresight_device * 713struct coresight_device *
714tmc_etr_get_catu_device(struct tmc_drvdata *drvdata) 714tmc_etr_get_catu_device(struct tmc_drvdata *drvdata)
715{ 715{
716 int i; 716 int i;
@@ -733,7 +733,7 @@ static inline void tmc_etr_enable_catu(struct tmc_drvdata *drvdata)
733 struct coresight_device *catu = tmc_etr_get_catu_device(drvdata); 733 struct coresight_device *catu = tmc_etr_get_catu_device(drvdata);
734 734
735 if (catu && helper_ops(catu)->enable) 735 if (catu && helper_ops(catu)->enable)
736 helper_ops(catu)->enable(catu, NULL); 736 helper_ops(catu)->enable(catu, drvdata->etr_buf);
737} 737}
738 738
739static inline void tmc_etr_disable_catu(struct tmc_drvdata *drvdata) 739static inline void tmc_etr_disable_catu(struct tmc_drvdata *drvdata)
@@ -741,12 +741,13 @@ static inline void tmc_etr_disable_catu(struct tmc_drvdata *drvdata)
741 struct coresight_device *catu = tmc_etr_get_catu_device(drvdata); 741 struct coresight_device *catu = tmc_etr_get_catu_device(drvdata);
742 742
743 if (catu && helper_ops(catu)->disable) 743 if (catu && helper_ops(catu)->disable)
744 helper_ops(catu)->disable(catu, NULL); 744 helper_ops(catu)->disable(catu, drvdata->etr_buf);
745} 745}
746 746
747static const struct etr_buf_operations *etr_buf_ops[] = { 747static const struct etr_buf_operations *etr_buf_ops[] = {
748 [ETR_MODE_FLAT] = &etr_flat_buf_ops, 748 [ETR_MODE_FLAT] = &etr_flat_buf_ops,
749 [ETR_MODE_ETR_SG] = &etr_sg_buf_ops, 749 [ETR_MODE_ETR_SG] = &etr_sg_buf_ops,
750 [ETR_MODE_CATU] = &etr_catu_buf_ops,
750}; 751};
751 752
752static inline int tmc_etr_mode_alloc_buf(int mode, 753static inline int tmc_etr_mode_alloc_buf(int mode,
@@ -754,12 +755,15 @@ static inline int tmc_etr_mode_alloc_buf(int mode,
754 struct etr_buf *etr_buf, int node, 755 struct etr_buf *etr_buf, int node,
755 void **pages) 756 void **pages)
756{ 757{
757 int rc; 758 int rc = -EINVAL;
758 759
759 switch (mode) { 760 switch (mode) {
760 case ETR_MODE_FLAT: 761 case ETR_MODE_FLAT:
761 case ETR_MODE_ETR_SG: 762 case ETR_MODE_ETR_SG:
762 rc = etr_buf_ops[mode]->alloc(drvdata, etr_buf, node, pages); 763 case ETR_MODE_CATU:
764 if (etr_buf_ops[mode]->alloc)
765 rc = etr_buf_ops[mode]->alloc(drvdata, etr_buf,
766 node, pages);
763 if (!rc) 767 if (!rc)
764 etr_buf->ops = etr_buf_ops[mode]; 768 etr_buf->ops = etr_buf_ops[mode];
765 return rc; 769 return rc;
@@ -782,10 +786,14 @@ static struct etr_buf *tmc_alloc_etr_buf(struct tmc_drvdata *drvdata,
782{ 786{
783 int rc = -ENOMEM; 787 int rc = -ENOMEM;
784 bool has_etr_sg, has_iommu; 788 bool has_etr_sg, has_iommu;
789 bool has_sg, has_catu;
785 struct etr_buf *etr_buf; 790 struct etr_buf *etr_buf;
786 791
787 has_etr_sg = tmc_etr_has_cap(drvdata, TMC_ETR_SG); 792 has_etr_sg = tmc_etr_has_cap(drvdata, TMC_ETR_SG);
788 has_iommu = iommu_get_domain_for_dev(drvdata->dev); 793 has_iommu = iommu_get_domain_for_dev(drvdata->dev);
794 has_catu = !!tmc_etr_get_catu_device(drvdata);
795
796 has_sg = has_catu || has_etr_sg;
789 797
790 etr_buf = kzalloc(sizeof(*etr_buf), GFP_KERNEL); 798 etr_buf = kzalloc(sizeof(*etr_buf), GFP_KERNEL);
791 if (!etr_buf) 799 if (!etr_buf)
@@ -806,17 +814,22 @@ static struct etr_buf *tmc_alloc_etr_buf(struct tmc_drvdata *drvdata,
806 * 814 *
807 */ 815 */
808 if (!pages && 816 if (!pages &&
809 (!has_etr_sg || has_iommu || size < SZ_1M)) 817 (!has_sg || has_iommu || size < SZ_1M))
810 rc = tmc_etr_mode_alloc_buf(ETR_MODE_FLAT, drvdata, 818 rc = tmc_etr_mode_alloc_buf(ETR_MODE_FLAT, drvdata,
811 etr_buf, node, pages); 819 etr_buf, node, pages);
812 if (rc && has_etr_sg) 820 if (rc && has_etr_sg)
813 rc = tmc_etr_mode_alloc_buf(ETR_MODE_ETR_SG, drvdata, 821 rc = tmc_etr_mode_alloc_buf(ETR_MODE_ETR_SG, drvdata,
814 etr_buf, node, pages); 822 etr_buf, node, pages);
823 if (rc && has_catu)
824 rc = tmc_etr_mode_alloc_buf(ETR_MODE_CATU, drvdata,
825 etr_buf, node, pages);
815 if (rc) { 826 if (rc) {
816 kfree(etr_buf); 827 kfree(etr_buf);
817 return ERR_PTR(rc); 828 return ERR_PTR(rc);
818 } 829 }
819 830
831 dev_dbg(drvdata->dev, "allocated buffer of size %ldKB in mode %d\n",
832 (unsigned long)size >> 10, etr_buf->mode);
820 return etr_buf; 833 return etr_buf;
821} 834}
822 835
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index e7456575bfc1..7027bd60c4cc 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -126,6 +126,7 @@ enum tmc_mem_intf_width {
126enum etr_mode { 126enum etr_mode {
127 ETR_MODE_FLAT, /* Uses contiguous flat buffer */ 127 ETR_MODE_FLAT, /* Uses contiguous flat buffer */
128 ETR_MODE_ETR_SG, /* Uses in-built TMC ETR SG mechanism */ 128 ETR_MODE_ETR_SG, /* Uses in-built TMC ETR SG mechanism */
129 ETR_MODE_CATU, /* Use SG mechanism in CATU */
129}; 130};
130 131
131struct etr_buf_operations; 132struct etr_buf_operations;
@@ -303,4 +304,6 @@ tmc_sg_table_buf_size(struct tmc_sg_table *sg_table)
303 return sg_table->data_pages.nr_pages << PAGE_SHIFT; 304 return sg_table->data_pages.nr_pages << PAGE_SHIFT;
304} 305}
305 306
307struct coresight_device *tmc_etr_get_catu_device(struct tmc_drvdata *drvdata);
308
306#endif 309#endif