Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[platform/kernel/linux-starfive.git] / drivers / gpu / drm / panfrost / panfrost_dump.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright 2021 Collabora ltd. */
3
4 #include <linux/err.h>
5 #include <linux/device.h>
6 #include <linux/devcoredump.h>
7 #include <linux/moduleparam.h>
8 #include <linux/iosys-map.h>
9 #include <drm/panfrost_drm.h>
10 #include <drm/drm_device.h>
11
12 #include "panfrost_job.h"
13 #include "panfrost_gem.h"
14 #include "panfrost_regs.h"
15 #include "panfrost_dump.h"
16 #include "panfrost_device.h"
17
18 static bool panfrost_dump_core = true;
19 module_param_named(dump_core, panfrost_dump_core, bool, 0600);
20
21 struct panfrost_dump_iterator {
22         void *start;
23         struct panfrost_dump_object_header *hdr;
24         void *data;
25 };
26
27 static const unsigned short panfrost_dump_registers[] = {
28         SHADER_READY_LO,
29         SHADER_READY_HI,
30         TILER_READY_LO,
31         TILER_READY_HI,
32         L2_READY_LO,
33         L2_READY_HI,
34         JOB_INT_MASK,
35         JOB_INT_STAT,
36         JS_HEAD_LO(0),
37         JS_HEAD_HI(0),
38         JS_TAIL_LO(0),
39         JS_TAIL_HI(0),
40         JS_AFFINITY_LO(0),
41         JS_AFFINITY_HI(0),
42         JS_CONFIG(0),
43         JS_STATUS(0),
44         JS_HEAD_NEXT_LO(0),
45         JS_HEAD_NEXT_HI(0),
46         JS_AFFINITY_NEXT_LO(0),
47         JS_AFFINITY_NEXT_HI(0),
48         JS_CONFIG_NEXT(0),
49         MMU_INT_MASK,
50         MMU_INT_STAT,
51         AS_TRANSTAB_LO(0),
52         AS_TRANSTAB_HI(0),
53         AS_MEMATTR_LO(0),
54         AS_MEMATTR_HI(0),
55         AS_FAULTSTATUS(0),
56         AS_FAULTADDRESS_LO(0),
57         AS_FAULTADDRESS_HI(0),
58         AS_STATUS(0),
59 };
60
61 static void panfrost_core_dump_header(struct panfrost_dump_iterator *iter,
62                                       u32 type, void *data_end)
63 {
64         struct panfrost_dump_object_header *hdr = iter->hdr;
65
66         hdr->magic = cpu_to_le32(PANFROSTDUMP_MAGIC);
67         hdr->type = cpu_to_le32(type);
68         hdr->file_offset = cpu_to_le32(iter->data - iter->start);
69         hdr->file_size = cpu_to_le32(data_end - iter->data);
70
71         iter->hdr++;
72         iter->data += le32_to_cpu(hdr->file_size);
73 }
74
75 static void
76 panfrost_core_dump_registers(struct panfrost_dump_iterator *iter,
77                              struct panfrost_device *pfdev,
78                              u32 as_nr, int slot)
79 {
80         struct panfrost_dump_registers *dumpreg = iter->data;
81         unsigned int i;
82
83         for (i = 0; i < ARRAY_SIZE(panfrost_dump_registers); i++, dumpreg++) {
84                 unsigned int js_as_offset = 0;
85                 unsigned int reg;
86
87                 if (panfrost_dump_registers[i] >= JS_BASE &&
88                     panfrost_dump_registers[i] <= JS_BASE + JS_SLOT_STRIDE)
89                         js_as_offset = slot * JS_SLOT_STRIDE;
90                 else if (panfrost_dump_registers[i] >= MMU_BASE &&
91                          panfrost_dump_registers[i] <= MMU_BASE + MMU_AS_STRIDE)
92                         js_as_offset = (as_nr << MMU_AS_SHIFT);
93
94                 reg = panfrost_dump_registers[i] + js_as_offset;
95
96                 dumpreg->reg = cpu_to_le32(reg);
97                 dumpreg->value = cpu_to_le32(gpu_read(pfdev, reg));
98         }
99
100         panfrost_core_dump_header(iter, PANFROSTDUMP_BUF_REG, dumpreg);
101 }
102
103 void panfrost_core_dump(struct panfrost_job *job)
104 {
105         struct panfrost_device *pfdev = job->pfdev;
106         struct panfrost_dump_iterator iter;
107         struct drm_gem_object *dbo;
108         unsigned int n_obj, n_bomap_pages;
109         __le64 *bomap, *bomap_start;
110         size_t file_size;
111         u32 as_nr;
112         int slot;
113         int ret, i;
114
115         as_nr = job->mmu->as;
116         slot = panfrost_job_get_slot(job);
117
118         /* Only catch the first event, or when manually re-armed */
119         if (!panfrost_dump_core)
120                 return;
121         panfrost_dump_core = false;
122
123         /* At least, we dump registers and end marker */
124         n_obj = 2;
125         n_bomap_pages = 0;
126         file_size = ARRAY_SIZE(panfrost_dump_registers) *
127                         sizeof(struct panfrost_dump_registers);
128
129         /* Add in the active buffer objects */
130         for (i = 0; i < job->bo_count; i++) {
131                 /*
132                  * Even though the CPU could be configured to use 16K or 64K pages, this
133                  * is a very unusual situation for most kernel setups on SoCs that have
134                  * a Panfrost device. Also many places across the driver make the somewhat
135                  * arbitrary assumption that Panfrost's MMU page size is the same as the CPU's,
136                  * so let's have a sanity check to ensure that's always the case
137                  */
138                 dbo = job->bos[i];
139                 WARN_ON(!IS_ALIGNED(dbo->size, PAGE_SIZE));
140
141                 file_size += dbo->size;
142                 n_bomap_pages += dbo->size >> PAGE_SHIFT;
143                 n_obj++;
144         }
145
146         /* If we have any buffer objects, add a bomap object */
147         if (n_bomap_pages) {
148                 file_size += n_bomap_pages * sizeof(*bomap);
149                 n_obj++;
150         }
151
152         /* Add the size of the headers */
153         file_size += sizeof(*iter.hdr) * n_obj;
154
155         /*
156          * Allocate the file in vmalloc memory, it's likely to be big.
157          * The reason behind these GFP flags is that we don't want to trigger the
158          * OOM killer in the event that not enough memory could be found for our
159          * dump file. We also don't want the allocator to do any error reporting,
160          * as the right behaviour is failing gracefully if a big enough buffer
161          * could not be allocated.
162          */
163         iter.start = __vmalloc(file_size, GFP_KERNEL | __GFP_NOWARN |
164                         __GFP_NORETRY);
165         if (!iter.start) {
166                 dev_warn(pfdev->dev, "failed to allocate devcoredump file\n");
167                 return;
168         }
169
170         /* Point the data member after the headers */
171         iter.hdr = iter.start;
172         iter.data = &iter.hdr[n_obj];
173
174         memset(iter.hdr, 0, iter.data - iter.start);
175
176         /*
177          * For now, we write the job identifier in the register dump header,
178          * so that we can decode the entire dump later with pandecode
179          */
180         iter.hdr->reghdr.jc = cpu_to_le64(job->jc);
181         iter.hdr->reghdr.major = cpu_to_le32(PANFROSTDUMP_MAJOR);
182         iter.hdr->reghdr.minor = cpu_to_le32(PANFROSTDUMP_MINOR);
183         iter.hdr->reghdr.gpu_id = cpu_to_le32(pfdev->features.id);
184         iter.hdr->reghdr.nbos = cpu_to_le64(job->bo_count);
185
186         panfrost_core_dump_registers(&iter, pfdev, as_nr, slot);
187
188         /* Reserve space for the bomap */
189         if (job->bo_count) {
190                 bomap_start = bomap = iter.data;
191                 memset(bomap, 0, sizeof(*bomap) * n_bomap_pages);
192                 panfrost_core_dump_header(&iter, PANFROSTDUMP_BUF_BOMAP,
193                                           bomap + n_bomap_pages);
194         }
195
196         for (i = 0; i < job->bo_count; i++) {
197                 struct iosys_map map;
198                 struct panfrost_gem_mapping *mapping;
199                 struct panfrost_gem_object *bo;
200                 struct sg_page_iter page_iter;
201                 void *vaddr;
202
203                 bo = to_panfrost_bo(job->bos[i]);
204                 mapping = job->mappings[i];
205
206                 if (!bo->base.sgt) {
207                         dev_err(pfdev->dev, "Panfrost Dump: BO has no sgt, cannot dump\n");
208                         iter.hdr->bomap.valid = 0;
209                         goto dump_header;
210                 }
211
212                 ret = drm_gem_shmem_vmap(&bo->base, &map);
213                 if (ret) {
214                         dev_err(pfdev->dev, "Panfrost Dump: couldn't map Buffer Object\n");
215                         iter.hdr->bomap.valid = 0;
216                         goto dump_header;
217                 }
218
219                 WARN_ON(!mapping->active);
220
221                 iter.hdr->bomap.data[0] = cpu_to_le32((bomap - bomap_start));
222
223                 for_each_sgtable_page(bo->base.sgt, &page_iter, 0) {
224                         struct page *page = sg_page_iter_page(&page_iter);
225
226                         if (!IS_ERR(page)) {
227                                 *bomap++ = cpu_to_le64(page_to_phys(page));
228                         } else {
229                                 dev_err(pfdev->dev, "Panfrost Dump: wrong page\n");
230                                 *bomap++ = ~cpu_to_le64(0);
231                         }
232                 }
233
234                 iter.hdr->bomap.iova = cpu_to_le64(mapping->mmnode.start << PAGE_SHIFT);
235
236                 vaddr = map.vaddr;
237                 memcpy(iter.data, vaddr, bo->base.base.size);
238
239                 drm_gem_shmem_vunmap(&bo->base, &map);
240
241                 iter.hdr->bomap.valid = cpu_to_le32(1);
242
243 dump_header:    panfrost_core_dump_header(&iter, PANFROSTDUMP_BUF_BO, iter.data +
244                                           bo->base.base.size);
245         }
246         panfrost_core_dump_header(&iter, PANFROSTDUMP_BUF_TRAILER, iter.data);
247
248         dev_coredumpv(pfdev->dev, iter.start, iter.data - iter.start, GFP_KERNEL);
249 }