drm/imagination: Implement firmware infrastructure and META FW support
[linux-2.6-block.git] / drivers / gpu / drm / imagination / pvr_fw_trace.c
1 // SPDX-License-Identifier: GPL-2.0-only OR MIT
2 /* Copyright (c) 2023 Imagination Technologies Ltd. */
3
4 #include "pvr_device.h"
5 #include "pvr_gem.h"
6 #include "pvr_rogue_fwif.h"
7 #include "pvr_fw_trace.h"
8
9 #include <drm/drm_file.h>
10
11 #include <linux/build_bug.h>
12 #include <linux/dcache.h>
13 #include <linux/sysfs.h>
14 #include <linux/types.h>
15
16 static void
17 tracebuf_ctrl_init(void *cpu_ptr, void *priv)
18 {
19         struct rogue_fwif_tracebuf *tracebuf_ctrl = cpu_ptr;
20         struct pvr_fw_trace *fw_trace = priv;
21         u32 thread_nr;
22
23         tracebuf_ctrl->tracebuf_size_in_dwords = ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS;
24         tracebuf_ctrl->tracebuf_flags = 0;
25
26         if (fw_trace->group_mask)
27                 tracebuf_ctrl->log_type = fw_trace->group_mask | ROGUE_FWIF_LOG_TYPE_TRACE;
28         else
29                 tracebuf_ctrl->log_type = ROGUE_FWIF_LOG_TYPE_NONE;
30
31         for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) {
32                 struct rogue_fwif_tracebuf_space *tracebuf_space =
33                         &tracebuf_ctrl->tracebuf[thread_nr];
34                 struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr];
35
36                 pvr_fw_object_get_fw_addr(trace_buffer->buf_obj,
37                                           &tracebuf_space->trace_buffer_fw_addr);
38
39                 tracebuf_space->trace_buffer = trace_buffer->buf;
40                 tracebuf_space->trace_pointer = 0;
41         }
42 }
43
44 int pvr_fw_trace_init(struct pvr_device *pvr_dev)
45 {
46         struct pvr_fw_trace *fw_trace = &pvr_dev->fw_dev.fw_trace;
47         struct drm_device *drm_dev = from_pvr_device(pvr_dev);
48         u32 thread_nr;
49         int err;
50
51         for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) {
52                 struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr];
53
54                 trace_buffer->buf =
55                         pvr_fw_object_create_and_map(pvr_dev,
56                                                      ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS *
57                                                      sizeof(*trace_buffer->buf),
58                                                      PVR_BO_FW_FLAGS_DEVICE_UNCACHED |
59                                                      PVR_BO_FW_NO_CLEAR_ON_RESET,
60                                                      NULL, NULL, &trace_buffer->buf_obj);
61                 if (IS_ERR(trace_buffer->buf)) {
62                         drm_err(drm_dev, "Unable to allocate trace buffer\n");
63                         err = PTR_ERR(trace_buffer->buf);
64                         trace_buffer->buf = NULL;
65                         goto err_free_buf;
66                 }
67         }
68
69         /* TODO: Provide control of group mask. */
70         fw_trace->group_mask = 0;
71
72         fw_trace->tracebuf_ctrl =
73                 pvr_fw_object_create_and_map(pvr_dev,
74                                              sizeof(*fw_trace->tracebuf_ctrl),
75                                              PVR_BO_FW_FLAGS_DEVICE_UNCACHED |
76                                              PVR_BO_FW_NO_CLEAR_ON_RESET,
77                                              tracebuf_ctrl_init, fw_trace,
78                                              &fw_trace->tracebuf_ctrl_obj);
79         if (IS_ERR(fw_trace->tracebuf_ctrl)) {
80                 drm_err(drm_dev, "Unable to allocate trace buffer control structure\n");
81                 err = PTR_ERR(fw_trace->tracebuf_ctrl);
82                 goto err_free_buf;
83         }
84
85         BUILD_BUG_ON(ARRAY_SIZE(fw_trace->tracebuf_ctrl->tracebuf) !=
86                      ARRAY_SIZE(fw_trace->buffers));
87
88         for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) {
89                 struct rogue_fwif_tracebuf_space *tracebuf_space =
90                         &fw_trace->tracebuf_ctrl->tracebuf[thread_nr];
91                 struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr];
92
93                 trace_buffer->tracebuf_space = tracebuf_space;
94         }
95
96         return 0;
97
98 err_free_buf:
99         for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) {
100                 struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr];
101
102                 if (trace_buffer->buf)
103                         pvr_fw_object_unmap_and_destroy(trace_buffer->buf_obj);
104         }
105
106         return err;
107 }
108
109 void pvr_fw_trace_fini(struct pvr_device *pvr_dev)
110 {
111         struct pvr_fw_trace *fw_trace = &pvr_dev->fw_dev.fw_trace;
112         u32 thread_nr;
113
114         for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) {
115                 struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr];
116
117                 pvr_fw_object_unmap_and_destroy(trace_buffer->buf_obj);
118         }
119         pvr_fw_object_unmap_and_destroy(fw_trace->tracebuf_ctrl_obj);
120 }