dm table: fix missing dm_put_target_type() in dm_table_add_target()
[cascardo/linux.git] / drivers / gpu / drm / etnaviv / etnaviv_dump.c
1 /*
2  * Copyright (C) 2015 Etnaviv Project
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 as published by
6  * the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License along with
14  * this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16
17 #include <linux/devcoredump.h>
18 #include "etnaviv_dump.h"
19 #include "etnaviv_gem.h"
20 #include "etnaviv_gpu.h"
21 #include "etnaviv_mmu.h"
22 #include "state.xml.h"
23 #include "state_hi.xml.h"
24
25 struct core_dump_iterator {
26         void *start;
27         struct etnaviv_dump_object_header *hdr;
28         void *data;
29 };
30
31 static const unsigned short etnaviv_dump_registers[] = {
32         VIVS_HI_AXI_STATUS,
33         VIVS_HI_CLOCK_CONTROL,
34         VIVS_HI_IDLE_STATE,
35         VIVS_HI_AXI_CONFIG,
36         VIVS_HI_INTR_ENBL,
37         VIVS_HI_CHIP_IDENTITY,
38         VIVS_HI_CHIP_FEATURE,
39         VIVS_HI_CHIP_MODEL,
40         VIVS_HI_CHIP_REV,
41         VIVS_HI_CHIP_DATE,
42         VIVS_HI_CHIP_TIME,
43         VIVS_HI_CHIP_MINOR_FEATURE_0,
44         VIVS_HI_CACHE_CONTROL,
45         VIVS_HI_AXI_CONTROL,
46         VIVS_PM_POWER_CONTROLS,
47         VIVS_PM_MODULE_CONTROLS,
48         VIVS_PM_MODULE_STATUS,
49         VIVS_PM_PULSE_EATER,
50         VIVS_MC_MMU_FE_PAGE_TABLE,
51         VIVS_MC_MMU_TX_PAGE_TABLE,
52         VIVS_MC_MMU_PE_PAGE_TABLE,
53         VIVS_MC_MMU_PEZ_PAGE_TABLE,
54         VIVS_MC_MMU_RA_PAGE_TABLE,
55         VIVS_MC_DEBUG_MEMORY,
56         VIVS_MC_MEMORY_BASE_ADDR_RA,
57         VIVS_MC_MEMORY_BASE_ADDR_FE,
58         VIVS_MC_MEMORY_BASE_ADDR_TX,
59         VIVS_MC_MEMORY_BASE_ADDR_PEZ,
60         VIVS_MC_MEMORY_BASE_ADDR_PE,
61         VIVS_MC_MEMORY_TIMING_CONTROL,
62         VIVS_MC_BUS_CONFIG,
63         VIVS_FE_DMA_STATUS,
64         VIVS_FE_DMA_DEBUG_STATE,
65         VIVS_FE_DMA_ADDRESS,
66         VIVS_FE_DMA_LOW,
67         VIVS_FE_DMA_HIGH,
68         VIVS_FE_AUTO_FLUSH,
69 };
70
71 static void etnaviv_core_dump_header(struct core_dump_iterator *iter,
72         u32 type, void *data_end)
73 {
74         struct etnaviv_dump_object_header *hdr = iter->hdr;
75
76         hdr->magic = cpu_to_le32(ETDUMP_MAGIC);
77         hdr->type = cpu_to_le32(type);
78         hdr->file_offset = cpu_to_le32(iter->data - iter->start);
79         hdr->file_size = cpu_to_le32(data_end - iter->data);
80
81         iter->hdr++;
82         iter->data += hdr->file_size;
83 }
84
85 static void etnaviv_core_dump_registers(struct core_dump_iterator *iter,
86         struct etnaviv_gpu *gpu)
87 {
88         struct etnaviv_dump_registers *reg = iter->data;
89         unsigned int i;
90
91         for (i = 0; i < ARRAY_SIZE(etnaviv_dump_registers); i++, reg++) {
92                 reg->reg = etnaviv_dump_registers[i];
93                 reg->value = gpu_read(gpu, etnaviv_dump_registers[i]);
94         }
95
96         etnaviv_core_dump_header(iter, ETDUMP_BUF_REG, reg);
97 }
98
99 static void etnaviv_core_dump_mmu(struct core_dump_iterator *iter,
100         struct etnaviv_gpu *gpu, size_t mmu_size)
101 {
102         etnaviv_iommu_dump(gpu->mmu, iter->data);
103
104         etnaviv_core_dump_header(iter, ETDUMP_BUF_MMU, iter->data + mmu_size);
105 }
106
107 static void etnaviv_core_dump_mem(struct core_dump_iterator *iter, u32 type,
108         void *ptr, size_t size, u64 iova)
109 {
110         memcpy(iter->data, ptr, size);
111
112         iter->hdr->iova = cpu_to_le64(iova);
113
114         etnaviv_core_dump_header(iter, type, iter->data + size);
115 }
116
117 void etnaviv_core_dump(struct etnaviv_gpu *gpu)
118 {
119         struct core_dump_iterator iter;
120         struct etnaviv_vram_mapping *vram;
121         struct etnaviv_gem_object *obj;
122         struct etnaviv_cmdbuf *cmd;
123         unsigned int n_obj, n_bomap_pages;
124         size_t file_size, mmu_size;
125         __le64 *bomap, *bomap_start;
126
127         mmu_size = etnaviv_iommu_dump_size(gpu->mmu);
128
129         /* We always dump registers, mmu, ring and end marker */
130         n_obj = 4;
131         n_bomap_pages = 0;
132         file_size = ARRAY_SIZE(etnaviv_dump_registers) *
133                         sizeof(struct etnaviv_dump_registers) +
134                     mmu_size + gpu->buffer->size;
135
136         /* Add in the active command buffers */
137         list_for_each_entry(cmd, &gpu->active_cmd_list, node) {
138                 file_size += cmd->size;
139                 n_obj++;
140         }
141
142         /* Add in the active buffer objects */
143         list_for_each_entry(vram, &gpu->mmu->mappings, mmu_node) {
144                 if (!vram->use)
145                         continue;
146
147                 obj = vram->object;
148                 file_size += obj->base.size;
149                 n_bomap_pages += obj->base.size >> PAGE_SHIFT;
150                 n_obj++;
151         }
152
153         /* If we have any buffer objects, add a bomap object */
154         if (n_bomap_pages) {
155                 file_size += n_bomap_pages * sizeof(__le64);
156                 n_obj++;
157         }
158
159         /* Add the size of the headers */
160         file_size += sizeof(*iter.hdr) * n_obj;
161
162         /* Allocate the file in vmalloc memory, it's likely to be big */
163         iter.start = vmalloc(file_size);
164         if (!iter.start) {
165                 dev_warn(gpu->dev, "failed to allocate devcoredump file\n");
166                 return;
167         }
168
169         /* Point the data member after the headers */
170         iter.hdr = iter.start;
171         iter.data = &iter.hdr[n_obj];
172
173         memset(iter.hdr, 0, iter.data - iter.start);
174
175         etnaviv_core_dump_registers(&iter, gpu);
176         etnaviv_core_dump_mmu(&iter, gpu, mmu_size);
177         etnaviv_core_dump_mem(&iter, ETDUMP_BUF_RING, gpu->buffer->vaddr,
178                               gpu->buffer->size, gpu->buffer->paddr);
179
180         list_for_each_entry(cmd, &gpu->active_cmd_list, node)
181                 etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD, cmd->vaddr,
182                                       cmd->size, cmd->paddr);
183
184         /* Reserve space for the bomap */
185         if (n_bomap_pages) {
186                 bomap_start = bomap = iter.data;
187                 memset(bomap, 0, sizeof(*bomap) * n_bomap_pages);
188                 etnaviv_core_dump_header(&iter, ETDUMP_BUF_BOMAP,
189                                          bomap + n_bomap_pages);
190         } else {
191                 /* Silence warning */
192                 bomap_start = bomap = NULL;
193         }
194
195         list_for_each_entry(vram, &gpu->mmu->mappings, mmu_node) {
196                 struct page **pages;
197                 void *vaddr;
198
199                 if (vram->use == 0)
200                         continue;
201
202                 obj = vram->object;
203
204                 mutex_lock(&obj->lock);
205                 pages = etnaviv_gem_get_pages(obj);
206                 mutex_unlock(&obj->lock);
207                 if (pages) {
208                         int j;
209
210                         iter.hdr->data[0] = bomap - bomap_start;
211
212                         for (j = 0; j < obj->base.size >> PAGE_SHIFT; j++)
213                                 *bomap++ = cpu_to_le64(page_to_phys(*pages++));
214                 }
215
216                 iter.hdr->iova = cpu_to_le64(vram->iova);
217
218                 vaddr = etnaviv_gem_vmap(&obj->base);
219                 if (vaddr)
220                         memcpy(iter.data, vaddr, obj->base.size);
221
222                 etnaviv_core_dump_header(&iter, ETDUMP_BUF_BO, iter.data +
223                                          obj->base.size);
224         }
225
226         etnaviv_core_dump_header(&iter, ETDUMP_BUF_END, iter.data);
227
228         dev_coredumpv(gpu->dev, iter.start, iter.data - iter.start, GFP_KERNEL);
229 }