summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/imagination/pvr_fw_trace.c
blob: 0a8340369f1aca74c994673bd393b274aa596ffe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// SPDX-License-Identifier: GPL-2.0-only OR MIT
/* Copyright (c) 2023 Imagination Technologies Ltd. */

#include "pvr_device.h"
#include "pvr_gem.h"
#include "pvr_rogue_fwif.h"
#include "pvr_fw_trace.h"

#include <drm/drm_file.h>

#include <linux/build_bug.h>
#include <linux/dcache.h>
#include <linux/sysfs.h>
#include <linux/types.h>

static void
tracebuf_ctrl_init(void *cpu_ptr, void *priv)
{
	struct rogue_fwif_tracebuf *tracebuf_ctrl = cpu_ptr;
	struct pvr_fw_trace *fw_trace = priv;
	u32 thread_nr;

	tracebuf_ctrl->tracebuf_size_in_dwords = ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS;
	tracebuf_ctrl->tracebuf_flags = 0;

	if (fw_trace->group_mask)
		tracebuf_ctrl->log_type = fw_trace->group_mask | ROGUE_FWIF_LOG_TYPE_TRACE;
	else
		tracebuf_ctrl->log_type = ROGUE_FWIF_LOG_TYPE_NONE;

	for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) {
		struct rogue_fwif_tracebuf_space *tracebuf_space =
			&tracebuf_ctrl->tracebuf[thread_nr];
		struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr];

		pvr_fw_object_get_fw_addr(trace_buffer->buf_obj,
					  &tracebuf_space->trace_buffer_fw_addr);

		tracebuf_space->trace_buffer = trace_buffer->buf;
		tracebuf_space->trace_pointer = 0;
	}
}

int pvr_fw_trace_init(struct pvr_device *pvr_dev)
{
	struct pvr_fw_trace *fw_trace = &pvr_dev->fw_dev.fw_trace;
	struct drm_device *drm_dev = from_pvr_device(pvr_dev);
	u32 thread_nr;
	int err;

	for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) {
		struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr];

		trace_buffer->buf =
			pvr_fw_object_create_and_map(pvr_dev,
						     ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS *
						     sizeof(*trace_buffer->buf),
						     PVR_BO_FW_FLAGS_DEVICE_UNCACHED |
						     PVR_BO_FW_NO_CLEAR_ON_RESET,
						     NULL, NULL, &trace_buffer->buf_obj);
		if (IS_ERR(trace_buffer->buf)) {
			drm_err(drm_dev, "Unable to allocate trace buffer\n");
			err = PTR_ERR(trace_buffer->buf);
			trace_buffer->buf = NULL;
			goto err_free_buf;
		}
	}

	/* TODO: Provide control of group mask. */
	fw_trace->group_mask = 0;

	fw_trace->tracebuf_ctrl =
		pvr_fw_object_create_and_map(pvr_dev,
					     sizeof(*fw_trace->tracebuf_ctrl),
					     PVR_BO_FW_FLAGS_DEVICE_UNCACHED |
					     PVR_BO_FW_NO_CLEAR_ON_RESET,
					     tracebuf_ctrl_init, fw_trace,
					     &fw_trace->tracebuf_ctrl_obj);
	if (IS_ERR(fw_trace->tracebuf_ctrl)) {
		drm_err(drm_dev, "Unable to allocate trace buffer control structure\n");
		err = PTR_ERR(fw_trace->tracebuf_ctrl);
		goto err_free_buf;
	}

	BUILD_BUG_ON(ARRAY_SIZE(fw_trace->tracebuf_ctrl->tracebuf) !=
		     ARRAY_SIZE(fw_trace->buffers));

	for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) {
		struct rogue_fwif_tracebuf_space *tracebuf_space =
			&fw_trace->tracebuf_ctrl->tracebuf[thread_nr];
		struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr];

		trace_buffer->tracebuf_space = tracebuf_space;
	}

	return 0;

err_free_buf:
	for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) {
		struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr];

		if (trace_buffer->buf)
			pvr_fw_object_unmap_and_destroy(trace_buffer->buf_obj);
	}

	return err;
}

void pvr_fw_trace_fini(struct pvr_device *pvr_dev)
{
	struct pvr_fw_trace *fw_trace = &pvr_dev->fw_dev.fw_trace;
	u32 thread_nr;

	for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) {
		struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr];

		pvr_fw_object_unmap_and_destroy(trace_buffer->buf_obj);
	}
	pvr_fw_object_unmap_and_destroy(fw_trace->tracebuf_ctrl_obj);
}