Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2015-2018 Etnaviv Project
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     /* Only catch the first event, or when manually re-armed */
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     /* We always dump registers, mmu, ring, hanging cmdbuf and end marker */
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     /* Add in the active buffer objects */
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     /* If we have any buffer objects, add a bomap object */
0148     if (n_bomap_pages) {
0149         file_size += n_bomap_pages * sizeof(__le64);
0150         n_obj++;
0151     }
0152 
0153     /* Add the size of the headers */
0154     file_size += sizeof(*iter.hdr) * n_obj;
0155 
0156     /* Allocate the file in vmalloc memory, it's likely to be big */
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     /* Point the data member after the headers */
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     /* Reserve space for the bomap */
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         /* Silence warning */
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 }