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_cmdbuf.h" 19 #include "etnaviv_dump.h" 20 #include "etnaviv_gem.h" 21 #include "etnaviv_gpu.h" 22 #include "etnaviv_mmu.h" 23 #include "state.xml.h" 24 #include "state_hi.xml.h" 25 26 struct core_dump_iterator { 27 void *start; 28 struct etnaviv_dump_object_header *hdr; 29 void *data; 30 }; 31 32 static const unsigned short etnaviv_dump_registers[] = { 33 VIVS_HI_AXI_STATUS, 34 VIVS_HI_CLOCK_CONTROL, 35 VIVS_HI_IDLE_STATE, 36 VIVS_HI_AXI_CONFIG, 37 VIVS_HI_INTR_ENBL, 38 VIVS_HI_CHIP_IDENTITY, 39 VIVS_HI_CHIP_FEATURE, 40 VIVS_HI_CHIP_MODEL, 41 VIVS_HI_CHIP_REV, 42 VIVS_HI_CHIP_DATE, 43 VIVS_HI_CHIP_TIME, 44 VIVS_HI_CHIP_MINOR_FEATURE_0, 45 VIVS_HI_CACHE_CONTROL, 46 VIVS_HI_AXI_CONTROL, 47 VIVS_PM_POWER_CONTROLS, 48 VIVS_PM_MODULE_CONTROLS, 49 VIVS_PM_MODULE_STATUS, 50 VIVS_PM_PULSE_EATER, 51 VIVS_MC_MMU_FE_PAGE_TABLE, 52 VIVS_MC_MMU_TX_PAGE_TABLE, 53 VIVS_MC_MMU_PE_PAGE_TABLE, 54 VIVS_MC_MMU_PEZ_PAGE_TABLE, 55 VIVS_MC_MMU_RA_PAGE_TABLE, 56 VIVS_MC_DEBUG_MEMORY, 57 VIVS_MC_MEMORY_BASE_ADDR_RA, 58 VIVS_MC_MEMORY_BASE_ADDR_FE, 59 VIVS_MC_MEMORY_BASE_ADDR_TX, 60 VIVS_MC_MEMORY_BASE_ADDR_PEZ, 61 VIVS_MC_MEMORY_BASE_ADDR_PE, 62 VIVS_MC_MEMORY_TIMING_CONTROL, 63 VIVS_MC_BUS_CONFIG, 64 VIVS_FE_DMA_STATUS, 65 VIVS_FE_DMA_DEBUG_STATE, 66 VIVS_FE_DMA_ADDRESS, 67 VIVS_FE_DMA_LOW, 68 VIVS_FE_DMA_HIGH, 69 VIVS_FE_AUTO_FLUSH, 70 }; 71 72 static void etnaviv_core_dump_header(struct core_dump_iterator *iter, 73 u32 type, void *data_end) 74 { 75 struct etnaviv_dump_object_header *hdr = iter->hdr; 76 77 hdr->magic = cpu_to_le32(ETDUMP_MAGIC); 78 hdr->type = cpu_to_le32(type); 79 hdr->file_offset = cpu_to_le32(iter->data - iter->start); 80 hdr->file_size = cpu_to_le32(data_end - iter->data); 81 82 iter->hdr++; 83 iter->data += hdr->file_size; 84 } 85 86 static void etnaviv_core_dump_registers(struct core_dump_iterator *iter, 87 struct etnaviv_gpu *gpu) 88 { 89 struct etnaviv_dump_registers *reg = iter->data; 90 unsigned int i; 91 92 for (i = 0; i < ARRAY_SIZE(etnaviv_dump_registers); i++, reg++) { 93 reg->reg = etnaviv_dump_registers[i]; 94 reg->value = gpu_read(gpu, etnaviv_dump_registers[i]); 95 } 96 97 etnaviv_core_dump_header(iter, ETDUMP_BUF_REG, reg); 98 } 99 100 static void etnaviv_core_dump_mmu(struct core_dump_iterator *iter, 101 struct etnaviv_gpu *gpu, size_t mmu_size) 102 { 103 etnaviv_iommu_dump(gpu->mmu, iter->data); 104 105 etnaviv_core_dump_header(iter, ETDUMP_BUF_MMU, iter->data + mmu_size); 106 } 107 108 static void etnaviv_core_dump_mem(struct core_dump_iterator *iter, u32 type, 109 void *ptr, size_t size, u64 iova) 110 { 111 memcpy(iter->data, ptr, size); 112 113 iter->hdr->iova = cpu_to_le64(iova); 114 115 etnaviv_core_dump_header(iter, type, iter->data + size); 116 } 117 118 void etnaviv_core_dump(struct etnaviv_gpu *gpu) 119 { 120 struct core_dump_iterator iter; 121 struct etnaviv_vram_mapping *vram; 122 struct etnaviv_gem_object *obj; 123 struct etnaviv_cmdbuf *cmd; 124 unsigned int n_obj, n_bomap_pages; 125 size_t file_size, mmu_size; 126 __le64 *bomap, *bomap_start; 127 128 mmu_size = etnaviv_iommu_dump_size(gpu->mmu); 129 130 /* We always dump registers, mmu, ring and end marker */ 131 n_obj = 4; 132 n_bomap_pages = 0; 133 file_size = ARRAY_SIZE(etnaviv_dump_registers) * 134 sizeof(struct etnaviv_dump_registers) + 135 mmu_size + gpu->buffer->size; 136 137 /* Add in the active command buffers */ 138 list_for_each_entry(cmd, &gpu->active_cmd_list, node) { 139 file_size += cmd->size; 140 n_obj++; 141 } 142 143 /* Add in the active buffer objects */ 144 list_for_each_entry(vram, &gpu->mmu->mappings, mmu_node) { 145 if (!vram->use) 146 continue; 147 148 obj = vram->object; 149 file_size += obj->base.size; 150 n_bomap_pages += obj->base.size >> PAGE_SHIFT; 151 n_obj++; 152 } 153 154 /* If we have any buffer objects, add a bomap object */ 155 if (n_bomap_pages) { 156 file_size += n_bomap_pages * sizeof(__le64); 157 n_obj++; 158 } 159 160 /* Add the size of the headers */ 161 file_size += sizeof(*iter.hdr) * n_obj; 162 163 /* Allocate the file in vmalloc memory, it's likely to be big */ 164 iter.start = __vmalloc(file_size, GFP_KERNEL | __GFP_HIGHMEM | 165 __GFP_NOWARN | __GFP_NORETRY, PAGE_KERNEL); 166 if (!iter.start) { 167 dev_warn(gpu->dev, "failed to allocate devcoredump file\n"); 168 return; 169 } 170 171 /* Point the data member after the headers */ 172 iter.hdr = iter.start; 173 iter.data = &iter.hdr[n_obj]; 174 175 memset(iter.hdr, 0, iter.data - iter.start); 176 177 etnaviv_core_dump_registers(&iter, gpu); 178 etnaviv_core_dump_mmu(&iter, gpu, mmu_size); 179 etnaviv_core_dump_mem(&iter, ETDUMP_BUF_RING, gpu->buffer->vaddr, 180 gpu->buffer->size, 181 etnaviv_iommu_get_cmdbuf_va(gpu, gpu->buffer)); 182 183 list_for_each_entry(cmd, &gpu->active_cmd_list, node) 184 etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD, cmd->vaddr, 185 cmd->size, 186 etnaviv_iommu_get_cmdbuf_va(gpu, cmd)); 187 188 /* Reserve space for the bomap */ 189 if (n_bomap_pages) { 190 bomap_start = bomap = iter.data; 191 memset(bomap, 0, sizeof(*bomap) * n_bomap_pages); 192 etnaviv_core_dump_header(&iter, ETDUMP_BUF_BOMAP, 193 bomap + n_bomap_pages); 194 } else { 195 /* Silence warning */ 196 bomap_start = bomap = NULL; 197 } 198 199 list_for_each_entry(vram, &gpu->mmu->mappings, mmu_node) { 200 struct page **pages; 201 void *vaddr; 202 203 if (vram->use == 0) 204 continue; 205 206 obj = vram->object; 207 208 mutex_lock(&obj->lock); 209 pages = etnaviv_gem_get_pages(obj); 210 mutex_unlock(&obj->lock); 211 if (pages) { 212 int j; 213 214 iter.hdr->data[0] = bomap - bomap_start; 215 216 for (j = 0; j < obj->base.size >> PAGE_SHIFT; j++) 217 *bomap++ = cpu_to_le64(page_to_phys(*pages++)); 218 } 219 220 iter.hdr->iova = cpu_to_le64(vram->iova); 221 222 vaddr = etnaviv_gem_vmap(&obj->base); 223 if (vaddr) 224 memcpy(iter.data, vaddr, obj->base.size); 225 226 etnaviv_core_dump_header(&iter, ETDUMP_BUF_BO, iter.data + 227 obj->base.size); 228 } 229 230 etnaviv_core_dump_header(&iter, ETDUMP_BUF_END, iter.data); 231 232 dev_coredumpv(gpu->dev, iter.start, iter.data - iter.start, GFP_KERNEL); 233 } 234