2 * Copyright (C) 2015 Etnaviv Project
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.
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
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/>.
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"
25 struct core_dump_iterator
{
27 struct etnaviv_dump_object_header
*hdr
;
31 static const unsigned short etnaviv_dump_registers
[] = {
33 VIVS_HI_CLOCK_CONTROL
,
37 VIVS_HI_CHIP_IDENTITY
,
43 VIVS_HI_CHIP_MINOR_FEATURE_0
,
44 VIVS_HI_CACHE_CONTROL
,
46 VIVS_PM_POWER_CONTROLS
,
47 VIVS_PM_MODULE_CONTROLS
,
48 VIVS_PM_MODULE_STATUS
,
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
,
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
,
64 VIVS_FE_DMA_DEBUG_STATE
,
71 static void etnaviv_core_dump_header(struct core_dump_iterator
*iter
,
72 u32 type
, void *data_end
)
74 struct etnaviv_dump_object_header
*hdr
= iter
->hdr
;
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
);
82 iter
->data
+= hdr
->file_size
;
85 static void etnaviv_core_dump_registers(struct core_dump_iterator
*iter
,
86 struct etnaviv_gpu
*gpu
)
88 struct etnaviv_dump_registers
*reg
= iter
->data
;
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
]);
96 etnaviv_core_dump_header(iter
, ETDUMP_BUF_REG
, reg
);
99 static void etnaviv_core_dump_mmu(struct core_dump_iterator
*iter
,
100 struct etnaviv_gpu
*gpu
, size_t mmu_size
)
102 etnaviv_iommu_dump(gpu
->mmu
, iter
->data
);
104 etnaviv_core_dump_header(iter
, ETDUMP_BUF_MMU
, iter
->data
+ mmu_size
);
107 static void etnaviv_core_dump_mem(struct core_dump_iterator
*iter
, u32 type
,
108 void *ptr
, size_t size
, u64 iova
)
110 memcpy(iter
->data
, ptr
, size
);
112 iter
->hdr
->iova
= cpu_to_le64(iova
);
114 etnaviv_core_dump_header(iter
, type
, iter
->data
+ size
);
117 void etnaviv_core_dump(struct etnaviv_gpu
*gpu
)
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
;
127 mmu_size
= etnaviv_iommu_dump_size(gpu
->mmu
);
129 /* We always dump registers, mmu, ring and end marker */
132 file_size
= ARRAY_SIZE(etnaviv_dump_registers
) *
133 sizeof(struct etnaviv_dump_registers
) +
134 mmu_size
+ gpu
->buffer
->size
;
136 /* Add in the active command buffers */
137 list_for_each_entry(cmd
, &gpu
->active_cmd_list
, node
) {
138 file_size
+= cmd
->size
;
142 /* Add in the active buffer objects */
143 list_for_each_entry(vram
, &gpu
->mmu
->mappings
, mmu_node
) {
148 file_size
+= obj
->base
.size
;
149 n_bomap_pages
+= obj
->base
.size
>> PAGE_SHIFT
;
153 /* If we have any buffer objects, add a bomap object */
155 file_size
+= n_bomap_pages
* sizeof(__le64
);
159 /* Add the size of the headers */
160 file_size
+= sizeof(*iter
.hdr
) * n_obj
;
162 /* Allocate the file in vmalloc memory, it's likely to be big */
163 iter
.start
= __vmalloc(file_size
, GFP_KERNEL
| __GFP_HIGHMEM
|
164 __GFP_NOWARN
| __GFP_NORETRY
, PAGE_KERNEL
);
166 dev_warn(gpu
->dev
, "failed to allocate devcoredump file\n");
170 /* Point the data member after the headers */
171 iter
.hdr
= iter
.start
;
172 iter
.data
= &iter
.hdr
[n_obj
];
174 memset(iter
.hdr
, 0, iter
.data
- iter
.start
);
176 etnaviv_core_dump_registers(&iter
, gpu
);
177 etnaviv_core_dump_mmu(&iter
, gpu
, mmu_size
);
178 etnaviv_core_dump_mem(&iter
, ETDUMP_BUF_RING
, gpu
->buffer
->vaddr
,
180 etnaviv_iommu_get_cmdbuf_va(gpu
, gpu
->buffer
));
182 list_for_each_entry(cmd
, &gpu
->active_cmd_list
, node
)
183 etnaviv_core_dump_mem(&iter
, ETDUMP_BUF_CMD
, cmd
->vaddr
,
185 etnaviv_iommu_get_cmdbuf_va(gpu
, cmd
));
187 /* Reserve space for the bomap */
189 bomap_start
= bomap
= iter
.data
;
190 memset(bomap
, 0, sizeof(*bomap
) * n_bomap_pages
);
191 etnaviv_core_dump_header(&iter
, ETDUMP_BUF_BOMAP
,
192 bomap
+ n_bomap_pages
);
194 /* Silence warning */
195 bomap_start
= bomap
= NULL
;
198 list_for_each_entry(vram
, &gpu
->mmu
->mappings
, mmu_node
) {
207 mutex_lock(&obj
->lock
);
208 pages
= etnaviv_gem_get_pages(obj
);
209 mutex_unlock(&obj
->lock
);
213 iter
.hdr
->data
[0] = bomap
- bomap_start
;
215 for (j
= 0; j
< obj
->base
.size
>> PAGE_SHIFT
; j
++)
216 *bomap
++ = cpu_to_le64(page_to_phys(*pages
++));
219 iter
.hdr
->iova
= cpu_to_le64(vram
->iova
);
221 vaddr
= etnaviv_gem_vmap(&obj
->base
);
223 memcpy(iter
.data
, vaddr
, obj
->base
.size
);
225 etnaviv_core_dump_header(&iter
, ETDUMP_BUF_BO
, iter
.data
+
229 etnaviv_core_dump_header(&iter
, ETDUMP_BUF_END
, iter
.data
);
231 dev_coredumpv(gpu
->dev
, iter
.start
, iter
.data
- iter
.start
, GFP_KERNEL
);