0001
0002
0003
0004
0005
0006 #include <linux/devcoredump.h>
0007 #include <linux/moduleparam.h>
0008
0009 #include "etnaviv_cmdbuf.h"
0010 #include "etnaviv_dump.h"
0011 #include "etnaviv_gem.h"
0012 #include "etnaviv_gpu.h"
0013 #include "etnaviv_mmu.h"
0014 #include "etnaviv_sched.h"
0015 #include "state.xml.h"
0016 #include "state_hi.xml.h"
0017
0018 static bool etnaviv_dump_core = true;
0019 module_param_named(dump_core, etnaviv_dump_core, bool, 0600);
0020
0021 struct core_dump_iterator {
0022 void *start;
0023 struct etnaviv_dump_object_header *hdr;
0024 void *data;
0025 };
0026
0027 static const unsigned short etnaviv_dump_registers[] = {
0028 VIVS_HI_AXI_STATUS,
0029 VIVS_HI_CLOCK_CONTROL,
0030 VIVS_HI_IDLE_STATE,
0031 VIVS_HI_AXI_CONFIG,
0032 VIVS_HI_INTR_ENBL,
0033 VIVS_HI_CHIP_IDENTITY,
0034 VIVS_HI_CHIP_FEATURE,
0035 VIVS_HI_CHIP_MODEL,
0036 VIVS_HI_CHIP_REV,
0037 VIVS_HI_CHIP_DATE,
0038 VIVS_HI_CHIP_TIME,
0039 VIVS_HI_CHIP_MINOR_FEATURE_0,
0040 VIVS_HI_CACHE_CONTROL,
0041 VIVS_HI_AXI_CONTROL,
0042 VIVS_PM_POWER_CONTROLS,
0043 VIVS_PM_MODULE_CONTROLS,
0044 VIVS_PM_MODULE_STATUS,
0045 VIVS_PM_PULSE_EATER,
0046 VIVS_MC_MMU_FE_PAGE_TABLE,
0047 VIVS_MC_MMU_TX_PAGE_TABLE,
0048 VIVS_MC_MMU_PE_PAGE_TABLE,
0049 VIVS_MC_MMU_PEZ_PAGE_TABLE,
0050 VIVS_MC_MMU_RA_PAGE_TABLE,
0051 VIVS_MC_DEBUG_MEMORY,
0052 VIVS_MC_MEMORY_BASE_ADDR_RA,
0053 VIVS_MC_MEMORY_BASE_ADDR_FE,
0054 VIVS_MC_MEMORY_BASE_ADDR_TX,
0055 VIVS_MC_MEMORY_BASE_ADDR_PEZ,
0056 VIVS_MC_MEMORY_BASE_ADDR_PE,
0057 VIVS_MC_MEMORY_TIMING_CONTROL,
0058 VIVS_MC_BUS_CONFIG,
0059 VIVS_FE_DMA_STATUS,
0060 VIVS_FE_DMA_DEBUG_STATE,
0061 VIVS_FE_DMA_ADDRESS,
0062 VIVS_FE_DMA_LOW,
0063 VIVS_FE_DMA_HIGH,
0064 VIVS_FE_AUTO_FLUSH,
0065 };
0066
0067 static void etnaviv_core_dump_header(struct core_dump_iterator *iter,
0068 u32 type, void *data_end)
0069 {
0070 struct etnaviv_dump_object_header *hdr = iter->hdr;
0071
0072 hdr->magic = cpu_to_le32(ETDUMP_MAGIC);
0073 hdr->type = cpu_to_le32(type);
0074 hdr->file_offset = cpu_to_le32(iter->data - iter->start);
0075 hdr->file_size = cpu_to_le32(data_end - iter->data);
0076
0077 iter->hdr++;
0078 iter->data += le32_to_cpu(hdr->file_size);
0079 }
0080
0081 static void etnaviv_core_dump_registers(struct core_dump_iterator *iter,
0082 struct etnaviv_gpu *gpu)
0083 {
0084 struct etnaviv_dump_registers *reg = iter->data;
0085 unsigned int i;
0086
0087 for (i = 0; i < ARRAY_SIZE(etnaviv_dump_registers); i++, reg++) {
0088 reg->reg = cpu_to_le32(etnaviv_dump_registers[i]);
0089 reg->value = cpu_to_le32(gpu_read(gpu, etnaviv_dump_registers[i]));
0090 }
0091
0092 etnaviv_core_dump_header(iter, ETDUMP_BUF_REG, reg);
0093 }
0094
0095 static void etnaviv_core_dump_mmu(struct core_dump_iterator *iter,
0096 struct etnaviv_iommu_context *mmu, size_t mmu_size)
0097 {
0098 etnaviv_iommu_dump(mmu, iter->data);
0099
0100 etnaviv_core_dump_header(iter, ETDUMP_BUF_MMU, iter->data + mmu_size);
0101 }
0102
0103 static void etnaviv_core_dump_mem(struct core_dump_iterator *iter, u32 type,
0104 void *ptr, size_t size, u64 iova)
0105 {
0106 memcpy(iter->data, ptr, size);
0107
0108 iter->hdr->iova = cpu_to_le64(iova);
0109
0110 etnaviv_core_dump_header(iter, type, iter->data + size);
0111 }
0112
0113 void etnaviv_core_dump(struct etnaviv_gem_submit *submit)
0114 {
0115 struct etnaviv_gpu *gpu = submit->gpu;
0116 struct core_dump_iterator iter;
0117 struct etnaviv_gem_object *obj;
0118 unsigned int n_obj, n_bomap_pages;
0119 size_t file_size, mmu_size;
0120 __le64 *bomap, *bomap_start;
0121 int i;
0122
0123
0124 if (!etnaviv_dump_core)
0125 return;
0126 etnaviv_dump_core = false;
0127
0128 mutex_lock(&gpu->mmu_context->lock);
0129
0130 mmu_size = etnaviv_iommu_dump_size(gpu->mmu_context);
0131
0132
0133 n_obj = 5;
0134 n_bomap_pages = 0;
0135 file_size = ARRAY_SIZE(etnaviv_dump_registers) *
0136 sizeof(struct etnaviv_dump_registers) +
0137 mmu_size + gpu->buffer.size + submit->cmdbuf.size;
0138
0139
0140 for (i = 0; i < submit->nr_bos; i++) {
0141 obj = submit->bos[i].obj;
0142 file_size += obj->base.size;
0143 n_bomap_pages += obj->base.size >> PAGE_SHIFT;
0144 n_obj++;
0145 }
0146
0147
0148 if (n_bomap_pages) {
0149 file_size += n_bomap_pages * sizeof(__le64);
0150 n_obj++;
0151 }
0152
0153
0154 file_size += sizeof(*iter.hdr) * n_obj;
0155
0156
0157 iter.start = __vmalloc(file_size, GFP_KERNEL | __GFP_NOWARN |
0158 __GFP_NORETRY);
0159 if (!iter.start) {
0160 mutex_unlock(&gpu->mmu_context->lock);
0161 dev_warn(gpu->dev, "failed to allocate devcoredump file\n");
0162 return;
0163 }
0164
0165
0166 iter.hdr = iter.start;
0167 iter.data = &iter.hdr[n_obj];
0168
0169 memset(iter.hdr, 0, iter.data - iter.start);
0170
0171 etnaviv_core_dump_registers(&iter, gpu);
0172 etnaviv_core_dump_mmu(&iter, gpu->mmu_context, mmu_size);
0173 etnaviv_core_dump_mem(&iter, ETDUMP_BUF_RING, gpu->buffer.vaddr,
0174 gpu->buffer.size,
0175 etnaviv_cmdbuf_get_va(&gpu->buffer,
0176 &gpu->mmu_context->cmdbuf_mapping));
0177
0178 etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD,
0179 submit->cmdbuf.vaddr, submit->cmdbuf.size,
0180 etnaviv_cmdbuf_get_va(&submit->cmdbuf,
0181 &gpu->mmu_context->cmdbuf_mapping));
0182
0183 mutex_unlock(&gpu->mmu_context->lock);
0184
0185
0186 if (n_bomap_pages) {
0187 bomap_start = bomap = iter.data;
0188 memset(bomap, 0, sizeof(*bomap) * n_bomap_pages);
0189 etnaviv_core_dump_header(&iter, ETDUMP_BUF_BOMAP,
0190 bomap + n_bomap_pages);
0191 } else {
0192
0193 bomap_start = bomap = NULL;
0194 }
0195
0196 for (i = 0; i < submit->nr_bos; i++) {
0197 struct etnaviv_vram_mapping *vram;
0198 struct page **pages;
0199 void *vaddr;
0200
0201 obj = submit->bos[i].obj;
0202 vram = submit->bos[i].mapping;
0203
0204 mutex_lock(&obj->lock);
0205 pages = etnaviv_gem_get_pages(obj);
0206 mutex_unlock(&obj->lock);
0207 if (!IS_ERR(pages)) {
0208 int j;
0209
0210 iter.hdr->data[0] = cpu_to_le32((bomap - bomap_start));
0211
0212 for (j = 0; j < obj->base.size >> PAGE_SHIFT; j++)
0213 *bomap++ = cpu_to_le64(page_to_phys(*pages++));
0214 }
0215
0216 iter.hdr->iova = cpu_to_le64(vram->iova);
0217
0218 vaddr = etnaviv_gem_vmap(&obj->base);
0219 if (vaddr)
0220 memcpy(iter.data, vaddr, obj->base.size);
0221
0222 etnaviv_core_dump_header(&iter, ETDUMP_BUF_BO, iter.data +
0223 obj->base.size);
0224 }
0225
0226 etnaviv_core_dump_header(&iter, ETDUMP_BUF_END, iter.data);
0227
0228 dev_coredumpv(gpu->dev, iter.start, iter.data - iter.start, GFP_KERNEL);
0229 }