/* Push a new buffer object onto the list */
static void push_object(struct kgsl_device *device, int type,
	phys_addr_t ptbase,
	uint32_t gpuaddr, int dwords)
{
	int index;
	void *ptr;
	struct kgsl_mem_entry *entry = NULL;

	/*
	 * Sometimes IBs can be reused in the same dump.  Because we parse from
	 * oldest to newest, if we come across an IB that has already been used,
	 * assume that it has been reused and update the list with the newest
	 * size.
	 */

	for (index = 0; index < objbufptr; index++) {
		if (objbuf[index].gpuaddr == gpuaddr &&
			objbuf[index].ptbase == ptbase) {
				objbuf[index].dwords = dwords;
				return;
			}
	}

	if (objbufptr == SNAPSHOT_OBJ_BUFSIZE) {
		KGSL_DRV_ERR(device, "snapshot: too many snapshot objects\n");
		return;
	}

	/*
	 * adreno_convertaddr verifies that the IB size is valid - at least in
	 * the context of it being smaller then the allocated memory space
	 */
	ptr = adreno_convertaddr(device, ptbase, gpuaddr, dwords << 2, &entry);

	if (ptr == NULL) {
		KGSL_DRV_ERR(device,
			"snapshot: Can't find GPU address for %x\n", gpuaddr);
		return;
	}

	/* Put it on the list of things to parse */
	objbuf[objbufptr].type = type;
	objbuf[objbufptr].gpuaddr = gpuaddr;
	objbuf[objbufptr].ptbase = ptbase;
	objbuf[objbufptr].dwords = dwords;
	objbuf[objbufptr].entry = entry;
	objbuf[objbufptr++].ptr = ptr;
}
static ssize_t kgsl_ib_dump_read(
	struct file *file,
	char __user *buff,
	size_t buff_count,
	loff_t *ppos)
{
	int i, count = kgsl_ib_size, remaining, pos = 0, tot = 0, ss;
	struct kgsl_device *device = file->private_data;
	const int rowc = 32;
	unsigned int pt_base;
	uint8_t *base_addr;
	char linebuf[80];

	if (!ppos || !device || !kgsl_ib_base)
		return 0;

	kgsl_regread(device, MH_MMU_PT_BASE, &pt_base);
	base_addr = adreno_convertaddr(device, pt_base, kgsl_ib_base,
                kgsl_ib_size*sizeof(uint32_t));

	if (!base_addr)
		return 0;

	pr_info("%s ppos=%ld, buff_count=%d, count=%d\n", __func__, (long)*ppos,
		buff_count, count);
	ss = snprintf(linebuf, sizeof(linebuf), "IB: base=%08x(%08x"
		"), size=%d\n", kgsl_ib_base,
		(uint32_t)base_addr, kgsl_ib_size);
	if (*ppos == 0) {
		if (copy_to_user(buff, linebuf, ss+1))
			return -EFAULT;
		tot += ss;
		buff += ss;
		*ppos += ss;
	}
	pos += ss;
	remaining = count;
	for (i = 0; i < count; i += rowc) {
		int linec = min(remaining, rowc);

		remaining -= rowc;
		ss = kgsl_hex_dump("IB: %05x: ", i, base_addr, rowc, linec,
			buff);
		if (ss < 0)
			return ss;

		if (pos >= *ppos) {
			if (tot+ss >= buff_count) {
				ss = copy_to_user(buff, "", 1);
				return tot;
			}
			tot += ss;
			buff += ss;
			*ppos += ss;
		}
		pos += ss;
		base_addr += linec;
	}

	return tot;
}