1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2014 - 2021 Intel Corporation
4 #include <linux/debugfs.h>
5 #include <linux/delay.h>
6 #include <linux/device.h>
7 #include <linux/dma-mapping.h>
8 #include <linux/module.h>
9 #include <linux/pm_runtime.h>
10 #include <linux/sizes.h>
11 #include <linux/uaccess.h>
12 #include <linux/vmalloc.h>
15 #include "ipu-platform-regs.h"
16 #include "ipu-trace.h"
18 struct trace_register_range
{
23 #define MEMORY_RING_BUFFER_SIZE (SZ_1M * 32)
24 #define TRACE_MESSAGE_SIZE 16
26 * It looks that the trace unit sometimes writes outside the given buffer.
27 * To avoid memory corruption one extra page is reserved at the end
28 * of the buffer. Read also the extra area since it may contain valid data.
30 #define MEMORY_RING_BUFFER_GUARD PAGE_SIZE
31 #define MEMORY_RING_BUFFER_OVERREAD MEMORY_RING_BUFFER_GUARD
32 #define MAX_TRACE_REGISTERS 200
33 #define TRACE_CONF_DUMP_BUFFER_SIZE (MAX_TRACE_REGISTERS * 2 * 32)
40 struct ipu_trace_buffer
{
41 dma_addr_t dma_handle
;
45 struct ipu_subsystem_wptrace_config
{
47 char *conf_dump_buffer
;
49 unsigned int fill_level
;
50 struct config_value config
[MAX_TRACE_REGISTERS
];
53 struct ipu_subsystem_trace_config
{
56 struct ipu_trace_buffer memory
; /* ring buffer */
58 struct ipu_trace_block
*blocks
;
59 unsigned int fill_level
; /* Nbr of regs in config table below */
61 /* Cached register values */
62 struct config_value config
[MAX_TRACE_REGISTERS
];
63 /* watchpoint trace info */
64 struct ipu_subsystem_wptrace_config wpt
;
68 struct mutex lock
; /* Protect ipu trace operations */
70 char *conf_dump_buffer
;
73 struct ipu_subsystem_trace_config isys
;
74 struct ipu_subsystem_trace_config psys
;
77 static void __ipu_trace_restore(struct device
*dev
)
79 struct ipu_bus_device
*adev
= to_ipu_bus_device(dev
);
80 struct ipu_device
*isp
= adev
->isp
;
81 struct ipu_trace
*trace
= isp
->trace
;
82 struct config_value
*config
;
83 struct ipu_subsystem_trace_config
*sys
= adev
->trace_cfg
;
84 struct ipu_trace_block
*blocks
;
85 u32 mapped_trace_buffer
;
86 void __iomem
*addr
= NULL
;
90 dev_info(dev
, "Trace control file open. Skipping update\n");
97 /* leave if no trace configuration for this subsystem */
98 if (sys
->fill_level
== 0)
101 /* Find trace unit base address */
102 blocks
= sys
->blocks
;
103 while (blocks
->type
!= IPU_TRACE_BLOCK_END
) {
104 if (blocks
->type
== IPU_TRACE_BLOCK_TUN
) {
105 addr
= sys
->base
+ blocks
->offset
;
113 if (!sys
->memory
.memory_buffer
) {
114 sys
->memory
.memory_buffer
=
115 dma_alloc_coherent(dev
,
116 MEMORY_RING_BUFFER_SIZE
+
117 MEMORY_RING_BUFFER_GUARD
,
118 &sys
->memory
.dma_handle
,
122 if (!sys
->memory
.memory_buffer
) {
123 dev_err(dev
, "No memory for tracing. Trace unit disabled\n");
127 config
= sys
->config
;
128 mapped_trace_buffer
= sys
->memory
.dma_handle
;
130 /* ring buffer base */
131 writel(mapped_trace_buffer
, addr
+ TRACE_REG_TUN_DRAM_BASE_ADDR
);
133 /* ring buffer end */
134 writel(mapped_trace_buffer
+ MEMORY_RING_BUFFER_SIZE
-
135 TRACE_MESSAGE_SIZE
, addr
+ TRACE_REG_TUN_DRAM_END_ADDR
);
137 /* Infobits for ddr trace */
138 writel(IPU_INFO_REQUEST_DESTINATION_PRIMARY
,
139 addr
+ TRACE_REG_TUN_DDR_INFO_VAL
);
141 /* Find trace timer reset address */
143 blocks
= sys
->blocks
;
144 while (blocks
->type
!= IPU_TRACE_BLOCK_END
) {
145 if (blocks
->type
== IPU_TRACE_TIMER_RST
) {
146 addr
= sys
->base
+ blocks
->offset
;
152 dev_err(dev
, "No trace reset addr\n");
156 /* Remove reset from trace timers */
157 writel(TRACE_REG_GPREG_TRACE_TIMER_RST_OFF
, addr
);
159 /* Register config received from userspace */
160 for (i
= 0; i
< sys
->fill_level
; i
++) {
162 "Trace restore: reg 0x%08x, value 0x%08x\n",
163 config
[i
].reg
, config
[i
].value
);
164 writel(config
[i
].value
, isp
->base
+ config
[i
].reg
);
167 /* Register wpt config received from userspace, and only psys has wpt */
168 config
= sys
->wpt
.config
;
169 for (i
= 0; i
< sys
->wpt
.fill_level
; i
++) {
170 dev_dbg(dev
, "Trace restore: reg 0x%08x, value 0x%08x\n",
171 config
[i
].reg
, config
[i
].value
);
172 writel(config
[i
].value
, isp
->base
+ config
[i
].reg
);
177 void ipu_trace_restore(struct device
*dev
)
179 struct ipu_trace
*trace
= to_ipu_bus_device(dev
)->isp
->trace
;
184 mutex_lock(&trace
->lock
);
185 __ipu_trace_restore(dev
);
186 mutex_unlock(&trace
->lock
);
188 EXPORT_SYMBOL_GPL(ipu_trace_restore
);
190 static void __ipu_trace_stop(struct device
*dev
)
192 struct ipu_subsystem_trace_config
*sys
=
193 to_ipu_bus_device(dev
)->trace_cfg
;
194 struct ipu_trace_block
*blocks
;
201 sys
->running
= false;
203 /* Turn off all the gpc blocks */
204 blocks
= sys
->blocks
;
205 while (blocks
->type
!= IPU_TRACE_BLOCK_END
) {
206 if (blocks
->type
== IPU_TRACE_BLOCK_GPC
) {
207 writel(0, sys
->base
+ blocks
->offset
+
208 TRACE_REG_GPC_OVERALL_ENABLE
);
213 /* Turn off all the trace monitors */
214 blocks
= sys
->blocks
;
215 while (blocks
->type
!= IPU_TRACE_BLOCK_END
) {
216 if (blocks
->type
== IPU_TRACE_BLOCK_TM
) {
217 writel(0, sys
->base
+ blocks
->offset
+
218 TRACE_REG_TM_TRACE_ENABLE_NPK
);
220 writel(0, sys
->base
+ blocks
->offset
+
221 TRACE_REG_TM_TRACE_ENABLE_DDR
);
226 /* Turn off trace units */
227 blocks
= sys
->blocks
;
228 while (blocks
->type
!= IPU_TRACE_BLOCK_END
) {
229 if (blocks
->type
== IPU_TRACE_BLOCK_TUN
) {
230 writel(0, sys
->base
+ blocks
->offset
+
231 TRACE_REG_TUN_DDR_ENABLE
);
232 writel(0, sys
->base
+ blocks
->offset
+
233 TRACE_REG_TUN_NPK_ENABLE
);
239 void ipu_trace_stop(struct device
*dev
)
241 struct ipu_trace
*trace
= to_ipu_bus_device(dev
)->isp
->trace
;
246 mutex_lock(&trace
->lock
);
247 __ipu_trace_stop(dev
);
248 mutex_unlock(&trace
->lock
);
250 EXPORT_SYMBOL_GPL(ipu_trace_stop
);
252 static int update_register_cache(struct ipu_device
*isp
, u32 reg
, u32 value
)
254 struct ipu_trace
*dctrl
= isp
->trace
;
255 struct ipu_subsystem_trace_config
*sys
;
258 if (dctrl
->isys
.offset
== dctrl
->psys
.offset
) {
259 /* For the IPU with uniform address space */
260 if (reg
>= IPU_ISYS_OFFSET
&&
261 reg
< IPU_ISYS_OFFSET
+ TRACE_REG_MAX_ISYS_OFFSET
)
263 else if (reg
>= IPU_PSYS_OFFSET
&&
264 reg
< IPU_PSYS_OFFSET
+ TRACE_REG_MAX_PSYS_OFFSET
)
269 if (dctrl
->isys
.offset
&&
270 reg
>= dctrl
->isys
.offset
&&
271 reg
< dctrl
->isys
.offset
+ TRACE_REG_MAX_ISYS_OFFSET
)
273 else if (dctrl
->psys
.offset
&&
274 reg
>= dctrl
->psys
.offset
&&
275 reg
< dctrl
->psys
.offset
+ TRACE_REG_MAX_PSYS_OFFSET
)
281 if (sys
->fill_level
< MAX_TRACE_REGISTERS
) {
283 "Trace reg addr 0x%08x value 0x%08x\n", reg
, value
);
284 sys
->config
[sys
->fill_level
].reg
= reg
;
285 sys
->config
[sys
->fill_level
].value
= value
;
293 dev_info(&isp
->pdev
->dev
,
294 "Trace register address 0x%08x ignored as invalid register\n",
299 static void traceconf_dump(struct ipu_device
*isp
)
301 struct ipu_subsystem_trace_config
*sys
[2] = {
308 isp
->trace
->size_conf_dump
= 0;
309 out
= isp
->trace
->conf_dump_buffer
;
310 rem_size
= TRACE_CONF_DUMP_BUFFER_SIZE
;
312 for (j
= 0; j
< ARRAY_SIZE(sys
); j
++) {
313 for (i
= 0; i
< sys
[j
]->fill_level
&& rem_size
> 0; i
++) {
315 int n
= snprintf(out
, rem_size
, "0x%08x = 0x%08x\n",
316 sys
[j
]->config
[i
].reg
,
317 sys
[j
]->config
[i
].value
);
319 bytes_print
= min(n
, rem_size
- 1);
320 rem_size
-= bytes_print
;
324 isp
->trace
->size_conf_dump
= out
- isp
->trace
->conf_dump_buffer
;
327 static void clear_trace_buffer(struct ipu_subsystem_trace_config
*sys
)
329 if (!sys
->memory
.memory_buffer
)
332 memset(sys
->memory
.memory_buffer
, 0, MEMORY_RING_BUFFER_SIZE
+
333 MEMORY_RING_BUFFER_OVERREAD
);
335 dma_sync_single_for_device(sys
->dev
,
336 sys
->memory
.dma_handle
,
337 MEMORY_RING_BUFFER_SIZE
+
338 MEMORY_RING_BUFFER_GUARD
, DMA_FROM_DEVICE
);
341 static int traceconf_open(struct inode
*inode
, struct file
*file
)
344 struct ipu_device
*isp
;
346 if (!inode
->i_private
)
349 isp
= inode
->i_private
;
351 ret
= mutex_trylock(&isp
->trace
->lock
);
355 if (isp
->trace
->open
) {
356 mutex_unlock(&isp
->trace
->lock
);
360 file
->private_data
= isp
;
361 isp
->trace
->open
= 1;
362 if (file
->f_mode
& FMODE_WRITE
) {
363 /* TBD: Allocate temp buffer for processing.
364 * Push validated buffer to active config
367 /* Forget old config if opened for write */
368 isp
->trace
->isys
.fill_level
= 0;
369 isp
->trace
->psys
.fill_level
= 0;
370 isp
->trace
->psys
.wpt
.fill_level
= 0;
373 if (file
->f_mode
& FMODE_READ
) {
374 isp
->trace
->conf_dump_buffer
=
375 vzalloc(TRACE_CONF_DUMP_BUFFER_SIZE
);
376 if (!isp
->trace
->conf_dump_buffer
) {
377 isp
->trace
->open
= 0;
378 mutex_unlock(&isp
->trace
->lock
);
383 mutex_unlock(&isp
->trace
->lock
);
387 static ssize_t
traceconf_read(struct file
*file
, char __user
*buf
,
388 size_t len
, loff_t
*ppos
)
390 struct ipu_device
*isp
= file
->private_data
;
392 return simple_read_from_buffer(buf
, len
, ppos
,
393 isp
->trace
->conf_dump_buffer
,
394 isp
->trace
->size_conf_dump
);
397 static ssize_t
traceconf_write(struct file
*file
, const char __user
*buf
,
398 size_t len
, loff_t
*ppos
)
401 struct ipu_device
*isp
= file
->private_data
;
403 char *ipu_trace_buffer
= NULL
;
404 size_t buffer_size
= 0;
405 u32 ipu_trace_number
= 0;
406 struct config_value
*cfg_buffer
= NULL
;
408 if ((*ppos
< 0) || (len
< sizeof(ipu_trace_number
))) {
409 dev_info(&isp
->pdev
->dev
,
410 "length is error, len:%ld, loff:%lld\n",
415 ipu_trace_buffer
= vzalloc(len
);
416 if (!ipu_trace_buffer
)
419 bytes
= copy_from_user(ipu_trace_buffer
, buf
, len
);
421 vfree(ipu_trace_buffer
);
425 memcpy(&ipu_trace_number
, ipu_trace_buffer
, sizeof(u32
));
426 buffer_size
= ipu_trace_number
* sizeof(struct config_value
);
427 if ((buffer_size
+ sizeof(ipu_trace_number
)) != len
) {
428 dev_info(&isp
->pdev
->dev
,
429 "File size is not right, len:%ld, buffer_size:%zu\n",
431 vfree(ipu_trace_buffer
);
435 mutex_lock(&isp
->trace
->lock
);
436 cfg_buffer
= (struct config_value
*)(ipu_trace_buffer
+ sizeof(u32
));
437 for (i
= 0; i
< ipu_trace_number
; i
++) {
438 update_register_cache(isp
, cfg_buffer
[i
].reg
,
439 cfg_buffer
[i
].value
);
441 mutex_unlock(&isp
->trace
->lock
);
442 vfree(ipu_trace_buffer
);
447 static int traceconf_release(struct inode
*inode
, struct file
*file
)
449 struct ipu_device
*isp
= file
->private_data
;
450 struct device
*psys_dev
= isp
->psys
? &isp
->psys
->dev
: NULL
;
451 struct device
*isys_dev
= isp
->isys
? &isp
->isys
->dev
: NULL
;
452 int pm_rval
= -EINVAL
;
455 * Turn devices on outside trace->lock mutex. PM transition may
456 * cause call to function which tries to take the same lock.
457 * Also do this before trace->open is set back to 0 to avoid
458 * double restore (one here and one in pm transition). We can't
459 * rely purely on the restore done by pm call backs since trace
460 * configuration can occur in any phase compared to other activity.
463 if (file
->f_mode
& FMODE_WRITE
) {
465 pm_rval
= pm_runtime_get_sync(isys_dev
);
468 /* ISYS ok or missing */
470 pm_rval
= pm_runtime_get_sync(psys_dev
);
473 pm_runtime_put_noidle(psys_dev
);
475 pm_runtime_put(isys_dev
);
478 pm_runtime_put_noidle(&isp
->isys
->dev
);
482 mutex_lock(&isp
->trace
->lock
);
483 isp
->trace
->open
= 0;
484 vfree(isp
->trace
->conf_dump_buffer
);
485 isp
->trace
->conf_dump_buffer
= NULL
;
488 /* Update new cfg to HW */
490 __ipu_trace_stop(isys_dev
);
491 clear_trace_buffer(isp
->isys
->trace_cfg
);
492 __ipu_trace_restore(isys_dev
);
496 __ipu_trace_stop(psys_dev
);
497 clear_trace_buffer(isp
->psys
->trace_cfg
);
498 __ipu_trace_restore(psys_dev
);
502 mutex_unlock(&isp
->trace
->lock
);
505 /* Again - this must be done with trace->lock not taken */
507 pm_runtime_put(psys_dev
);
509 pm_runtime_put(isys_dev
);
514 static const struct file_operations ipu_traceconf_fops
= {
515 .owner
= THIS_MODULE
,
516 .open
= traceconf_open
,
517 .release
= traceconf_release
,
518 .read
= traceconf_read
,
519 .write
= traceconf_write
,
523 static void wptraceconf_dump(struct ipu_device
*isp
)
525 struct ipu_subsystem_wptrace_config
*sys
= &isp
->trace
->psys
.wpt
;
529 sys
->size_conf_dump
= 0;
530 out
= sys
->conf_dump_buffer
;
531 rem_size
= TRACE_CONF_DUMP_BUFFER_SIZE
;
533 for (i
= 0; i
< sys
->fill_level
&& rem_size
> 0; i
++) {
535 int n
= snprintf(out
, rem_size
, "0x%08x = 0x%08x\n",
537 sys
->config
[i
].value
);
539 bytes_print
= min(n
, rem_size
- 1);
540 rem_size
-= bytes_print
;
543 sys
->size_conf_dump
= out
- sys
->conf_dump_buffer
;
546 static int wptraceconf_open(struct inode
*inode
, struct file
*file
)
549 struct ipu_device
*isp
;
551 if (!inode
->i_private
)
554 isp
= inode
->i_private
;
555 ret
= mutex_trylock(&isp
->trace
->lock
);
559 if (isp
->trace
->psys
.wpt
.open
) {
560 mutex_unlock(&isp
->trace
->lock
);
564 file
->private_data
= isp
;
565 if (file
->f_mode
& FMODE_WRITE
) {
566 /* TBD: Allocate temp buffer for processing.
567 * Push validated buffer to active config
569 /* Forget old config if opened for write */
570 isp
->trace
->psys
.wpt
.fill_level
= 0;
573 if (file
->f_mode
& FMODE_READ
) {
574 isp
->trace
->psys
.wpt
.conf_dump_buffer
=
575 vzalloc(TRACE_CONF_DUMP_BUFFER_SIZE
);
576 if (!isp
->trace
->psys
.wpt
.conf_dump_buffer
) {
577 mutex_unlock(&isp
->trace
->lock
);
580 wptraceconf_dump(isp
);
582 mutex_unlock(&isp
->trace
->lock
);
586 static ssize_t
wptraceconf_read(struct file
*file
, char __user
*buf
,
587 size_t len
, loff_t
*ppos
)
589 struct ipu_device
*isp
= file
->private_data
;
591 return simple_read_from_buffer(buf
, len
, ppos
,
592 isp
->trace
->psys
.wpt
.conf_dump_buffer
,
593 isp
->trace
->psys
.wpt
.size_conf_dump
);
596 static ssize_t
wptraceconf_write(struct file
*file
, const char __user
*buf
,
597 size_t len
, loff_t
*ppos
)
600 struct ipu_device
*isp
= file
->private_data
;
602 char *wpt_info_buffer
= NULL
;
603 size_t buffer_size
= 0;
604 u32 wp_node_number
= 0;
605 struct config_value
*wpt_buffer
= NULL
;
606 struct ipu_subsystem_wptrace_config
*wpt
= &isp
->trace
->psys
.wpt
;
608 if ((*ppos
< 0) || (len
< sizeof(wp_node_number
))) {
609 dev_info(&isp
->pdev
->dev
,
610 "length is error, len:%ld, loff:%lld\n",
615 wpt_info_buffer
= vzalloc(len
);
616 if (!wpt_info_buffer
)
619 bytes
= copy_from_user(wpt_info_buffer
, buf
, len
);
621 vfree(wpt_info_buffer
);
625 memcpy(&wp_node_number
, wpt_info_buffer
, sizeof(u32
));
626 buffer_size
= wp_node_number
* sizeof(struct config_value
);
627 if ((buffer_size
+ sizeof(wp_node_number
)) != len
) {
628 dev_info(&isp
->pdev
->dev
,
629 "File size is not right, len:%ld, buffer_size:%zu\n",
631 vfree(wpt_info_buffer
);
635 mutex_lock(&isp
->trace
->lock
);
636 wpt_buffer
= (struct config_value
*)(wpt_info_buffer
+ sizeof(u32
));
637 for (i
= 0; i
< wp_node_number
; i
++) {
638 if (wpt
->fill_level
< MAX_TRACE_REGISTERS
) {
639 wpt
->config
[wpt
->fill_level
].reg
= wpt_buffer
[i
].reg
;
640 wpt
->config
[wpt
->fill_level
].value
=
644 dev_info(&isp
->pdev
->dev
,
645 "Address 0x%08x ignored as invalid register\n",
650 mutex_unlock(&isp
->trace
->lock
);
651 vfree(wpt_info_buffer
);
656 static int wptraceconf_release(struct inode
*inode
, struct file
*file
)
658 struct ipu_device
*isp
= file
->private_data
;
660 mutex_lock(&isp
->trace
->lock
);
661 isp
->trace
->open
= 0;
662 vfree(isp
->trace
->psys
.wpt
.conf_dump_buffer
);
663 isp
->trace
->psys
.wpt
.conf_dump_buffer
= NULL
;
664 mutex_unlock(&isp
->trace
->lock
);
669 static const struct file_operations ipu_wptraceconf_fops
= {
670 .owner
= THIS_MODULE
,
671 .open
= wptraceconf_open
,
672 .release
= wptraceconf_release
,
673 .read
= wptraceconf_read
,
674 .write
= wptraceconf_write
,
678 static int gettrace_open(struct inode
*inode
, struct file
*file
)
680 struct ipu_subsystem_trace_config
*sys
= inode
->i_private
;
685 if (!sys
->memory
.memory_buffer
)
688 dma_sync_single_for_cpu(sys
->dev
,
689 sys
->memory
.dma_handle
,
690 MEMORY_RING_BUFFER_SIZE
+
691 MEMORY_RING_BUFFER_GUARD
, DMA_FROM_DEVICE
);
693 file
->private_data
= sys
;
697 static ssize_t
gettrace_read(struct file
*file
, char __user
*buf
,
698 size_t len
, loff_t
*ppos
)
700 struct ipu_subsystem_trace_config
*sys
= file
->private_data
;
702 return simple_read_from_buffer(buf
, len
, ppos
,
703 sys
->memory
.memory_buffer
,
704 MEMORY_RING_BUFFER_SIZE
+
705 MEMORY_RING_BUFFER_OVERREAD
);
708 static ssize_t
gettrace_write(struct file
*file
, const char __user
*buf
,
709 size_t len
, loff_t
*ppos
)
711 struct ipu_subsystem_trace_config
*sys
= file
->private_data
;
712 static const char str
[] = "clear";
713 char buffer
[sizeof(str
)] = { 0 };
716 ret
= simple_write_to_buffer(buffer
, sizeof(buffer
), ppos
, buf
, len
);
720 if (ret
< sizeof(str
) - 1)
723 if (!strncmp(str
, buffer
, sizeof(str
) - 1)) {
724 clear_trace_buffer(sys
);
731 static int gettrace_release(struct inode
*inode
, struct file
*file
)
736 static const struct file_operations ipu_gettrace_fops
= {
737 .owner
= THIS_MODULE
,
738 .open
= gettrace_open
,
739 .release
= gettrace_release
,
740 .read
= gettrace_read
,
741 .write
= gettrace_write
,
745 int ipu_trace_init(struct ipu_device
*isp
, void __iomem
*base
,
746 struct device
*dev
, struct ipu_trace_block
*blocks
)
748 struct ipu_bus_device
*adev
= to_ipu_bus_device(dev
);
749 struct ipu_trace
*trace
= isp
->trace
;
750 struct ipu_subsystem_trace_config
*sys
;
756 mutex_lock(&isp
->trace
->lock
);
758 if (dev
== &isp
->isys
->dev
) {
760 } else if (dev
== &isp
->psys
->dev
) {
767 adev
->trace_cfg
= sys
;
769 sys
->offset
= base
- isp
->base
; /* sub system offset */
771 sys
->blocks
= blocks
;
774 mutex_unlock(&isp
->trace
->lock
);
778 EXPORT_SYMBOL_GPL(ipu_trace_init
);
780 void ipu_trace_uninit(struct device
*dev
)
782 struct ipu_bus_device
*adev
= to_ipu_bus_device(dev
);
783 struct ipu_device
*isp
= adev
->isp
;
784 struct ipu_trace
*trace
= isp
->trace
;
785 struct ipu_subsystem_trace_config
*sys
= adev
->trace_cfg
;
790 mutex_lock(&trace
->lock
);
792 if (sys
->memory
.memory_buffer
)
793 dma_free_coherent(sys
->dev
,
794 MEMORY_RING_BUFFER_SIZE
+
795 MEMORY_RING_BUFFER_GUARD
,
796 sys
->memory
.memory_buffer
,
797 sys
->memory
.dma_handle
);
800 sys
->memory
.memory_buffer
= NULL
;
802 mutex_unlock(&trace
->lock
);
804 EXPORT_SYMBOL_GPL(ipu_trace_uninit
);
806 int ipu_trace_debugfs_add(struct ipu_device
*isp
, struct dentry
*dir
)
808 struct dentry
*files
[4];
811 files
[i
] = debugfs_create_file("traceconf", 0644,
812 dir
, isp
, &ipu_traceconf_fops
);
817 files
[i
] = debugfs_create_file("wptraceconf", 0644,
818 dir
, isp
, &ipu_wptraceconf_fops
);
823 files
[i
] = debugfs_create_file("getisystrace", 0444,
825 &isp
->trace
->isys
, &ipu_gettrace_fops
);
831 files
[i
] = debugfs_create_file("getpsystrace", 0444,
833 &isp
->trace
->psys
, &ipu_gettrace_fops
);
841 debugfs_remove(files
[i
- 1]);
845 int ipu_trace_add(struct ipu_device
*isp
)
847 isp
->trace
= devm_kzalloc(&isp
->pdev
->dev
,
848 sizeof(struct ipu_trace
), GFP_KERNEL
);
852 mutex_init(&isp
->trace
->lock
);
857 void ipu_trace_release(struct ipu_device
*isp
)
861 mutex_destroy(&isp
->trace
->lock
);
864 MODULE_AUTHOR("Samu Onkalo <samu.onkalo@intel.com>");
865 MODULE_LICENSE("GPL");
866 MODULE_DESCRIPTION("Intel ipu trace support");