Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 25struct core_dump_iterator {
 26	void *start;
 27	struct etnaviv_dump_object_header *hdr;
 28	void *data;
 29};
 30
 31static 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
 71static 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
 85static 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
 99static 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
107static 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
117void 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, GFP_KERNEL | __GFP_HIGHMEM |
164			       __GFP_NOWARN | __GFP_NORETRY, PAGE_KERNEL);
165	if (!iter.start) {
166		dev_warn(gpu->dev, "failed to allocate devcoredump file\n");
167		return;
168	}
169
170	/* Point the data member after the headers */
171	iter.hdr = iter.start;
172	iter.data = &iter.hdr[n_obj];
173
174	memset(iter.hdr, 0, iter.data - iter.start);
175
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,
179			      gpu->buffer->size,
180			      etnaviv_iommu_get_cmdbuf_va(gpu, gpu->buffer));
181
182	list_for_each_entry(cmd, &gpu->active_cmd_list, node)
183		etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD, cmd->vaddr,
184				      cmd->size,
185				      etnaviv_iommu_get_cmdbuf_va(gpu, cmd));
186
187	/* Reserve space for the bomap */
188	if (n_bomap_pages) {
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);
193	} else {
194		/* Silence warning */
195		bomap_start = bomap = NULL;
196	}
197
198	list_for_each_entry(vram, &gpu->mmu->mappings, mmu_node) {
199		struct page **pages;
200		void *vaddr;
201
202		if (vram->use == 0)
203			continue;
204
205		obj = vram->object;
206
207		mutex_lock(&obj->lock);
208		pages = etnaviv_gem_get_pages(obj);
209		mutex_unlock(&obj->lock);
210		if (pages) {
211			int j;
212
213			iter.hdr->data[0] = bomap - bomap_start;
214
215			for (j = 0; j < obj->base.size >> PAGE_SHIFT; j++)
216				*bomap++ = cpu_to_le64(page_to_phys(*pages++));
217		}
218
219		iter.hdr->iova = cpu_to_le64(vram->iova);
220
221		vaddr = etnaviv_gem_vmap(&obj->base);
222		if (vaddr)
223			memcpy(iter.data, vaddr, obj->base.size);
224
225		etnaviv_core_dump_header(&iter, ETDUMP_BUF_BO, iter.data +
226					 obj->base.size);
227	}
228
229	etnaviv_core_dump_header(&iter, ETDUMP_BUF_END, iter.data);
230
231	dev_coredumpv(gpu->dev, iter.start, iter.data - iter.start, GFP_KERNEL);
232}