Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4187878b authored by Jordan Crouse's avatar Jordan Crouse Committed by Gerrit - the friendly Code Review server
Browse files

msm: kgsl: Add support for 64 bit objects to snapshot



The good news is that we have 64 bit memory objects. The bad news is
that sometimes they break. Add support for 64 bit objects to snapshot
so we can dump what we need.

Change-Id: Ic0dedbad740dfa657475ba8e5b79bb66a177841e
Signed-off-by: default avatarJordan Crouse <jcrouse@codeaurora.org>
parent ecb1eab0
Loading
Loading
Loading
Loading
+48 −48
Original line number Diff line number Diff line
@@ -229,7 +229,7 @@ static inline void parse_ib(struct kgsl_device *device,
static size_t snapshot_rb(struct kgsl_device *device, u8 *buf,
	size_t remain, void *priv)
{
	struct kgsl_snapshot_rb *header = (struct kgsl_snapshot_rb *)buf;
	struct kgsl_snapshot_rb_v2 *header = (struct kgsl_snapshot_rb_v2 *)buf;
	unsigned int *data = (unsigned int *)(buf + sizeof(*header));
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_ringbuffer *rb = ADRENO_CURRENT_RINGBUFFER(adreno_dev);
@@ -326,7 +326,10 @@ static size_t snapshot_rb(struct kgsl_device *device, u8 *buf,
	header->wptr = rb->wptr;
	header->rptr = rptr;
	header->rbsize = KGSL_RB_DWORDS;
	header->gpuaddr = rb->buffer_desc.gpuaddr;
	header->count = KGSL_RB_DWORDS;
	header->id = rb->id;

	adreno_rb_readtimestamp(device, rb, KGSL_TIMESTAMP_QUEUED,
					&header->timestamp_queued);
	adreno_rb_readtimestamp(device, rb, KGSL_TIMESTAMP_RETIRED,
@@ -354,7 +357,7 @@ static size_t snapshot_rb(struct kgsl_device *device, u8 *buf,

		if (parse_ibs && adreno_cmd_is_ib(adreno_dev, rbptr[index])) {
			uint64_t ibaddr;
			unsigned int ibsize;
			uint64_t ibsize;

			if (ADRENO_LEGACY_PM4(adreno_dev)) {
				ibaddr = rbptr[index + 1];
@@ -394,25 +397,29 @@ static int _count_mem_entries(int id, void *ptr, void *data)
	return 0;
}

struct mem_entry {
	uint64_t gpuaddr;
	uint64_t size;
	unsigned int type;
} __packed;

static int _save_mem_entries(int id, void *ptr, void *data)
{
	struct kgsl_mem_entry *entry = ptr;
	unsigned int **p = data;
	unsigned int *local = *p;
	struct mem_entry *m = (struct mem_entry *) data;

	*local++ = (unsigned int) entry->memdesc.gpuaddr;
	*local++ = (unsigned int) entry->memdesc.size;
	*local++ = kgsl_memdesc_get_memtype(&entry->memdesc);
	m->gpuaddr = entry->memdesc.gpuaddr;
	m->size = entry->memdesc.size;
	m->type = kgsl_memdesc_get_memtype(&entry->memdesc);

	*p = local;
	return 0;
}

static size_t snapshot_capture_mem_list(struct kgsl_device *device,
		u8 *buf, size_t remain, void *priv)
{
	struct kgsl_snapshot_replay_mem_list *header =
		(struct kgsl_snapshot_replay_mem_list *)buf;
	struct kgsl_snapshot_mem_list_v2 *header =
		(struct kgsl_snapshot_mem_list_v2 *)buf;
	int num_mem = 0;
	int ret = 0;
	unsigned int *data = (unsigned int *)(buf + sizeof(*header));
@@ -438,13 +445,13 @@ static size_t snapshot_capture_mem_list(struct kgsl_device *device,

	header->num_entries = num_mem;
	header->ptbase =
	 (__u32)kgsl_mmu_pagetable_get_ptbase(process->pagetable);
		kgsl_mmu_pagetable_get_ptbase(process->pagetable);
	/*
	 * Walk throught the memory list and store the
	 * tuples(gpuaddr, size, memtype) in snapshot
	 */

	idr_for_each(&process->mem_idr, _save_mem_entries, &data);
	idr_for_each(&process->mem_idr, _save_mem_entries, data);

	ret = sizeof(*header) + (num_mem * 3 * sizeof(unsigned int));
out:
@@ -455,17 +462,17 @@ out:
struct snapshot_ib_meta {
	struct kgsl_snapshot *snapshot;
	struct kgsl_snapshot_object *obj;
	unsigned int ib1base;
	unsigned int ib1size;
	unsigned int ib2base;
	unsigned int ib2size;
	uint64_t ib1base;
	uint64_t ib1size;
	uint64_t ib2base;
	uint64_t ib2size;
};

/* Snapshot the memory for an indirect buffer */
static size_t snapshot_ib(struct kgsl_device *device, u8 *buf,
	size_t remain, void *priv)
{
	struct kgsl_snapshot_ib *header = (struct kgsl_snapshot_ib *)buf;
	struct kgsl_snapshot_ib_v2 *header = (struct kgsl_snapshot_ib_v2 *)buf;
	struct snapshot_ib_meta *meta = priv;
	unsigned int *src;
	unsigned int *dst = (unsigned int *)(buf + sizeof(*header));
@@ -480,12 +487,6 @@ static size_t snapshot_ib(struct kgsl_device *device, u8 *buf,
	snapshot = meta->snapshot;
	obj = meta->obj;

	if (obj->size > SIZE_MAX) {
		KGSL_CORE_ERR("snapshot: GPU memory object 0x%016llX is too large to snapshot\n",
			obj->gpuaddr);
		return 0;
	}

	if (remain < (obj->size + sizeof(*header))) {
		KGSL_CORE_ERR("snapshot: Not enough memory for the ib\n");
		return 0;
@@ -521,13 +522,9 @@ static size_t snapshot_ib(struct kgsl_device *device, u8 *buf,
	}

	/* Write the sub-header for the section */
	header->gpuaddr = (unsigned int) obj->gpuaddr;
	/*
	 * This loses address bits, but we can't do better until the snapshot
	 * binary format is updated.
	 */
	header->gpuaddr = obj->gpuaddr;
	header->ptbase =
	 (__u32)kgsl_mmu_pagetable_get_ptbase(obj->entry->priv->pagetable);
		kgsl_mmu_pagetable_get_ptbase(obj->entry->priv->pagetable);
	header->size = obj->size >> 2;

	/* Write the contents of the ib */
@@ -540,8 +537,8 @@ static size_t snapshot_ib(struct kgsl_device *device, u8 *buf,
/* Dump another item on the current pending list */
static void dump_object(struct kgsl_device *device, int obj,
		struct kgsl_snapshot *snapshot,
		unsigned int ib1base, unsigned int ib1size,
		unsigned int ib2base, unsigned int ib2size)
		uint64_t ib1base, uint64_t ib1size,
		uint64_t ib2base, uint64_t ib2size)
{
	struct snapshot_ib_meta meta;

@@ -554,7 +551,7 @@ static void dump_object(struct kgsl_device *device, int obj,
		meta.ib2base = ib2base;
		meta.ib2size = ib2size;

		kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_IB,
		kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_IB_V2,
			snapshot, snapshot_ib, &meta);
		if (objbuf[obj].entry) {
			kgsl_memdesc_unmap(&(objbuf[obj].entry->memdesc));
@@ -627,8 +624,8 @@ static size_t snapshot_global(struct kgsl_device *device, u8 *buf,
{
	struct kgsl_memdesc *memdesc = priv;

	struct kgsl_snapshot_gpu_object *header =
		(struct kgsl_snapshot_gpu_object *)buf;
	struct kgsl_snapshot_gpu_object_v2 *header =
		(struct kgsl_snapshot_gpu_object_v2 *)buf;

	u8 *ptr = buf + sizeof(*header);

@@ -649,7 +646,7 @@ static size_t snapshot_global(struct kgsl_device *device, u8 *buf,
	header->size = memdesc->size >> 2;
	header->gpuaddr = memdesc->gpuaddr;
	header->ptbase =
	 (__u32)kgsl_mmu_pagetable_get_ptbase(device->mmu.defaultpagetable);
		kgsl_mmu_pagetable_get_ptbase(device->mmu.defaultpagetable);
	header->type = SNAPSHOT_GPU_OBJECT_GLOBAL;

	memcpy(ptr, memdesc->hostptr, memdesc->size);
@@ -669,8 +666,8 @@ void adreno_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot,
			struct kgsl_context *context)
{
	unsigned int i;
	uint32_t ib1base, ib1size;
	uint32_t ib2base, ib2size;
	uint64_t ib1base, ib2base;
	unsigned int ib1size, ib2size;
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);

@@ -684,26 +681,29 @@ void adreno_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot,
			context ? context->proc_priv : NULL);

	/* Dump the ringbuffer */
	kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_RB, snapshot,
	kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_RB_V2, snapshot,
			snapshot_rb, snapshot);

	adreno_readreg(adreno_dev, ADRENO_REG_CP_IB1_BASE, &ib1base);
	adreno_readreg64(adreno_dev, ADRENO_REG_CP_IB1_BASE,
			ADRENO_REG_CP_IB1_BASE_HI, &ib1base);
	adreno_readreg(adreno_dev, ADRENO_REG_CP_IB1_BUFSZ, &ib1size);
	adreno_readreg(adreno_dev, ADRENO_REG_CP_IB2_BASE, &ib2base);
	adreno_readreg64(adreno_dev, ADRENO_REG_CP_IB2_BASE,
			ADRENO_REG_CP_IB2_BASE_HI, &ib2base);
	adreno_readreg(adreno_dev, ADRENO_REG_CP_IB2_BUFSZ, &ib2size);

	/* Add GPU specific sections - registers mainly, but other stuff too */
	if (gpudev->snapshot)
		gpudev->snapshot(adreno_dev, snapshot);

	/* Dump selected global buffers */
	kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_GPU_OBJECT,
	kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_GPU_OBJECT_V2,
			snapshot, snapshot_global, &adreno_dev->dev.memstore);

	kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_GPU_OBJECT,
	kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_GPU_OBJECT_V2,
			snapshot, snapshot_global,
			&adreno_dev->dev.mmu.setstate_memory);

	kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_GPU_OBJECT,
	kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_GPU_OBJECT_V2,
			snapshot, snapshot_global,
			&adreno_dev->pwron_fixup);

@@ -711,7 +711,7 @@ void adreno_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot,
	 * Add a section that lists (gpuaddr, size, memtype) tuples of the
	 * hanging process
	 */
	kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_MEMLIST,
	kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_MEMLIST_V2,
			snapshot, snapshot_capture_mem_list, snapshot->process);
	/*
	 * Make sure that the last IB1 that was being executed is dumped.
@@ -725,10 +725,10 @@ void adreno_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot,
	 * figure how often this really happens.
	 */

	if (!find_object(SNAPSHOT_OBJ_TYPE_IB, (uint64_t) ib1base,
	if (!find_object(SNAPSHOT_OBJ_TYPE_IB, ib1base,
			snapshot->process) && ib1size) {
		push_object(SNAPSHOT_OBJ_TYPE_IB, snapshot->process,
			(uint64_t) ib1base, ib1size);
			ib1base, ib1size);
		KGSL_CORE_ERR(
		"CP_IB1_BASE not found in the ringbuffer.Dumping %x dwords of the buffer.\n",
		ib1size);
@@ -742,10 +742,10 @@ void adreno_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot,
	 * correct size.
	 */

	if (!find_object(SNAPSHOT_OBJ_TYPE_IB, (uint64_t) ib2base,
	if (!find_object(SNAPSHOT_OBJ_TYPE_IB, ib2base,
		snapshot->process) && ib2size) {
		push_object(SNAPSHOT_OBJ_TYPE_IB, snapshot->process,
			(uint64_t) ib2base, ib2size);
			ib2base, ib2size);
	}

	/*
+2 −2
Original line number Diff line number Diff line
@@ -336,7 +336,7 @@ static inline int kgsl_gpuaddr_in_memdesc(const struct kgsl_memdesc *memdesc,
		size = 1;

	/* don't overflow */
	if (size > UINT_MAX - gpuaddr)
	if (size > U64_MAX - gpuaddr)
		return 0;

	if (gpuaddr >= memdesc->gpuaddr &&
@@ -417,7 +417,7 @@ kgsl_mem_entry_put(struct kgsl_mem_entry *entry)
static inline bool kgsl_addr_range_overlap(uint64_t gpuaddr1,
		uint64_t size1, uint64_t gpuaddr2, uint64_t size2)
{
	if ((size1 > (UINT_MAX - gpuaddr1)) || (size2 > (UINT_MAX - gpuaddr2)))
	if ((size1 > (U64_MAX - gpuaddr1)) || (size2 > (U64_MAX - gpuaddr2)))
		return false;
	return !(((gpuaddr1 + size1) <= gpuaddr2) ||
		(gpuaddr1 >= (gpuaddr2 + size2)));
+0 −10
Original line number Diff line number Diff line
@@ -871,16 +871,6 @@ void kgsl_snapshot_add_section(struct kgsl_device *device, u16 id,
	size_t (*func)(struct kgsl_device *, u8 *, size_t, void *),
	void *priv);

/**
 * kgsl_device_max_memsize() - Return the maximum GPU address allowable on this
 * device
 * @device: Pointer to a kgsl_device struct
 */
static inline uint64_t kgsl_device_max_gpuaddr(struct kgsl_device *device)
{
	return (uint64_t) UINT_MAX;
}

/**
 * struct kgsl_pwr_limit - limit structure for each client
 * @node: Local list node for the limits list
+10 −29
Original line number Diff line number Diff line
@@ -283,7 +283,7 @@ int kgsl_snapshot_get_object(struct kgsl_snapshot *snapshot,
{
	struct kgsl_mem_entry *entry;
	struct kgsl_snapshot_object *obj;
	int offset;
	uint64_t offset;
	int ret = -EINVAL;
	unsigned int mem_type;

@@ -327,7 +327,7 @@ int kgsl_snapshot_get_object(struct kgsl_snapshot *snapshot,
		/* Adjust the gpuaddr to the start of the object */
		gpuaddr = entry->memdesc.gpuaddr;
	} else {
		offset = (size_t) (gpuaddr - entry->memdesc.gpuaddr);
		offset = gpuaddr - entry->memdesc.gpuaddr;
	}

	if (size + offset > entry->memdesc.size) {
@@ -336,11 +336,6 @@ int kgsl_snapshot_get_object(struct kgsl_snapshot *snapshot,
		goto err_put;
	}

	if (size > SIZE_MAX) {
		KGSL_CORE_ERR("GPU memory object is bigger than SIZE_MAX\n");
		goto err_put;
	}

	/* If the buffer is already on the list, skip it */
	list_for_each_entry(obj, &snapshot->obj_list, node) {
		/* combine the range with existing object if they overlap */
@@ -1050,22 +1045,12 @@ static size_t _mempool_add_object(u8 *data, struct kgsl_snapshot_object *obj)
{
	struct kgsl_snapshot_section_header *section =
		(struct kgsl_snapshot_section_header *)data;
	struct kgsl_snapshot_gpu_object *header =
		(struct kgsl_snapshot_gpu_object *)(data + sizeof(*section));
	struct kgsl_snapshot_gpu_object_v2 *header =
		(struct kgsl_snapshot_gpu_object_v2 *)(data + sizeof(*section));
	u8 *dest = data + sizeof(*section) + sizeof(*header);
	unsigned int size;
	uint64_t size;

	if (obj->size > UINT_MAX) {
		KGSL_CORE_ERR("snapshot: GPU memory object is bigger than UINT_MAX\n");
		return 0;
	}

	if (obj->gpuaddr > UINT_MAX) {
		KGSL_CORE_ERR("snapshot: GPU memory object address is bigger than UINT_MAX\n");
		return 0;
	}

	size = (unsigned int) obj->size;
	size = obj->size;

	if (!kgsl_memdesc_map(&obj->entry->memdesc)) {
		KGSL_CORE_ERR("snapshot: failed to map GPU object\n");
@@ -1073,13 +1058,13 @@ static size_t _mempool_add_object(u8 *data, struct kgsl_snapshot_object *obj)
	}

	section->magic = SNAPSHOT_SECTION_MAGIC;
	section->id = KGSL_SNAPSHOT_SECTION_GPU_OBJECT;
	section->id = KGSL_SNAPSHOT_SECTION_GPU_OBJECT_V2;
	section->size = size + sizeof(*header) + sizeof(*section);

	header->size = (int) size >> 2;
	header->gpuaddr = (__u32) obj->gpuaddr;
	header->size = size >> 2;
	header->gpuaddr = obj->gpuaddr;
	header->ptbase =
	 (__u32)kgsl_mmu_pagetable_get_ptbase(obj->entry->priv->pagetable);
		kgsl_mmu_pagetable_get_ptbase(obj->entry->priv->pagetable);
	header->type = obj->type;

	memcpy(dest, obj->entry->memdesc.hostptr + obj->offset, size);
@@ -1107,10 +1092,6 @@ void kgsl_snapshot_save_frozen_objs(struct work_struct *work)
	list_for_each_entry(obj, &snapshot->obj_list, node) {
		obj->size = ALIGN(obj->size, 4);

		/* Skip over objects that are too big */
		if (obj->size > UINT_MAX)
			continue;

		size += ((size_t) obj->size +
			sizeof(struct kgsl_snapshot_gpu_object) +
			sizeof(struct kgsl_snapshot_section_header));
+45 −0
Original line number Diff line number Diff line
@@ -46,13 +46,17 @@ struct kgsl_snapshot_section_header {
#define KGSL_SNAPSHOT_SECTION_OS           0x0101
#define KGSL_SNAPSHOT_SECTION_REGS         0x0201
#define KGSL_SNAPSHOT_SECTION_RB           0x0301
#define KGSL_SNAPSHOT_SECTION_RB_V2        0x0302
#define KGSL_SNAPSHOT_SECTION_IB           0x0401
#define KGSL_SNAPSHOT_SECTION_IB_V2        0x0402
#define KGSL_SNAPSHOT_SECTION_INDEXED_REGS 0x0501
#define KGSL_SNAPSHOT_SECTION_ISTORE       0x0801
#define KGSL_SNAPSHOT_SECTION_DEBUG        0x0901
#define KGSL_SNAPSHOT_SECTION_DEBUGBUS     0x0A01
#define KGSL_SNAPSHOT_SECTION_GPU_OBJECT   0x0B01
#define KGSL_SNAPSHOT_SECTION_GPU_OBJECT_V2 0x0B02
#define KGSL_SNAPSHOT_SECTION_MEMLIST      0x0E01
#define KGSL_SNAPSHOT_SECTION_MEMLIST_V2   0x0E02
#define KGSL_SNAPSHOT_SECTION_SHADER       0x1201

#define KGSL_SNAPSHOT_SECTION_END          0xFFFF
@@ -107,6 +111,20 @@ struct kgsl_snapshot_rb {
	__u32 timestamp_retired; /* The last timestamp retired by HW */
} __packed;

struct kgsl_snapshot_rb_v2 {
	int start;  /* dword at the start of the dump */
	int end;    /* dword at the end of the dump */
	int rbsize; /* Size (in dwords) of the ringbuffer */
	int wptr;   /* Current index of the CPU write pointer */
	int rptr;   /* Current index of the GPU read pointer */
	int count;  /* Number of dwords in the dump */
	__u32 timestamp_queued; /* The last queued timestamp */
	__u32 timestamp_retired; /* The last timestamp retired by HW */
	__u64 gpuaddr; /* The GPU address of the ringbuffer */
	__u32 id; /* Ringbuffer identifier */
} __packed;


/* Replay or Memory list section, both sections have same header */
struct kgsl_snapshot_replay_mem_list {
	/*
@@ -118,6 +136,18 @@ struct kgsl_snapshot_replay_mem_list {
	__u32 ptbase;
} __packed;

/* Replay or Memory list section, both sections have same header */
struct kgsl_snapshot_mem_list_v2 {
	/*
	 * Number of IBs to replay for replay section or
	 * number of memory list entries for mem list section
	 */
	int num_entries;
	/* Pagetable base to which the replay IBs or memory entries belong */
	__u64 ptbase;
} __packed;


/* Indirect buffer sub-section header */
struct kgsl_snapshot_ib {
	__u32 gpuaddr; /* GPU address of the the IB */
@@ -125,6 +155,14 @@ struct kgsl_snapshot_ib {
	int size;    /* Size of the IB */
} __packed;

/* Indirect buffer sub-section header (v2) */
struct kgsl_snapshot_ib_v2 {
	__u64 gpuaddr; /* GPU address of the the IB */
	__u64 ptbase;  /* Base for the pagetable the GPU address is valid in */
	__u64 size;    /* Size of the IB */
} __packed;


/* Register sub-section header */
struct kgsl_snapshot_regs {
	__u32 count; /* Number of register pairs in the section */
@@ -190,4 +228,11 @@ struct kgsl_snapshot_gpu_object {
	int size;    /* Size of the object (in dwords) */
};

struct kgsl_snapshot_gpu_object_v2 {
	int type;      /* Type of GPU object */
	__u64 gpuaddr; /* GPU address of the the object */
	__u64 ptbase;  /* Base for the pagetable the GPU address is valid in */
	__u64 size;    /* Size of the object (in dwords) */
} __packed;

#endif