Пример #1
0
int kgsl_snapshot_dump_indexed_regs(struct kgsl_device *device,
	void *snapshot, int remain, void *priv)
{
	struct kgsl_snapshot_indexed_registers *iregs = priv;
	struct kgsl_snapshot_indexed_regs *header = snapshot;
	unsigned int *data = snapshot + sizeof(*header);
	int i;

	if (remain < (iregs->count * 4) + sizeof(*header)) {
		SNAPSHOT_ERR_NOMEM(device, "INDEXED REGS");
		return 0;
	}

	header->index_reg = iregs->index;
	header->data_reg = iregs->data;
	header->count = iregs->count;
	header->start = iregs->start;

	for (i = 0; i < iregs->count; i++) {
		kgsl_regwrite(device, iregs->index, iregs->start + i);
		kgsl_regread(device, iregs->data, &data[i]);
	}

	return (iregs->count * 4) + sizeof(*header);
}
static void kgsl_mh_reg_read_fill(struct kgsl_device *device, int i,
	unsigned int *vals, int linec)
{
	int j;

	for (j = 0; j < linec; ++j) {
		kgsl_regwrite(device, MH_DEBUG_CTRL, i+j);
		kgsl_regread(device, MH_DEBUG_DATA, vals+j);
	}
}
static void kgsl_sx_reg_read_fill(struct kgsl_device *device, int i,
	unsigned int *vals, int linec)
{
	int j;

	for (j = 0; j < linec; ++j) {
		kgsl_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1B00 | i);
		kgsl_regread(device, REG_RBBM_DEBUG_OUT, vals+j);
	}
}
static ssize_t coresight_read_reg(struct kgsl_device *device,
		unsigned int offset, char *buf)
{
	unsigned int regval = 0;

	mutex_lock(&device->mutex);
	if (!kgsl_active_count_get(device)) {
		kgsl_regread(device, offset, &regval);
		kgsl_active_count_put(device);
	}
	mutex_unlock(&device->mutex);
	return snprintf(buf, PAGE_SIZE, "0x%X", regval);
}
Пример #5
0
/**
 * z180_dump_regs - Dumps all of Z180 external registers. Prints the word offset
 * of the register in each output line.
 * @device: kgsl_device pointer to the Z180 core
 */
static void z180_dump_regs(struct kgsl_device *device)
{
	unsigned int i;
	unsigned int reg_val;

	KGSL_LOG_DUMP(device, "Z180 Register Dump\n");
	for (i = 0; i < ARRAY_SIZE(regs_to_dump); i++) {
		kgsl_regread(device,
				regs_to_dump[i]/sizeof(unsigned int), &reg_val);
		KGSL_LOG_DUMP(device, "REG: %04X: %08X\n",
				regs_to_dump[i]/sizeof(unsigned int), reg_val);
	}
}
Пример #6
0
ssize_t adreno_coresight_show_register(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	unsigned int val = 0;
	struct kgsl_device *device = dev_get_drvdata(dev->parent);
	struct adreno_device *adreno_dev;
	struct adreno_coresight_attr *cattr = TO_ADRENO_CORESIGHT_ATTR(attr);

	if (device == NULL)
		return -EINVAL;

	adreno_dev = ADRENO_DEVICE(device);

	if (cattr->reg == NULL)
		return -EINVAL;

	/*
	 * Return the current value of the register if coresight is enabled,
	 * otherwise report 0
	 */

	mutex_lock(&device->mutex);
	if (test_bit(ADRENO_DEVICE_CORESIGHT, &adreno_dev->priv)) {

		/*
		 * If the device isn't power collapsed read the actual value
		 * from the hardware - otherwise return the cached value
		 */

		if (device->state == KGSL_STATE_ACTIVE ||
			device->state == KGSL_STATE_NAP) {
			if (!kgsl_active_count_get(device)) {
				kgsl_regread(device, cattr->reg->offset,
					&cattr->reg->value);
				kgsl_active_count_put(device);
			}
		}

		val = cattr->reg->value;
	}
	mutex_unlock(&device->mutex);

	return snprintf(buf, PAGE_SIZE, "0x%X", val);
}
Пример #7
0
/*
 * kgsl_snapshot_dump_regs - helper function to dump device registers
 * @device - the device to dump registers from
 * @snapshot - pointer to the start of the region of memory for the snapshot
 * @remain - a pointer to the number of bytes remaining in the snapshot
 * @priv - A pointer to the kgsl_snapshot_registers data
 *
 * Given an array of register ranges pairs (start,end [inclusive]), dump the
 * registers into a snapshot register section.  The snapshot region stores a
 * part of dwords for each register - the word address of the register, and
 * the value.
 */
int kgsl_snapshot_dump_regs(struct kgsl_device *device, void *snapshot,
	int remain, void *priv)
{
	struct kgsl_snapshot_regs *header = snapshot;
	struct kgsl_snapshot_registers *regs = priv;
	unsigned int *data = snapshot + sizeof(*header);
	int count = 0, i, j;

	/* Figure out how many registers we are going to dump */

	for (i = 0; i < regs->count; i++) {
		int start = regs->regs[i * 2];
		int end = regs->regs[i * 2 + 1];

		count += (end - start + 1);
	}

	if (remain < (count * 8) + sizeof(*header)) {
		SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
		return 0;
	}

	for (i = 0; i < regs->count; i++) {
		unsigned int start = regs->regs[i * 2];
		unsigned int end = regs->regs[i * 2 + 1];

		for (j = start; j <= end; j++) {
			unsigned int val;

			kgsl_regread(device, j, &val);
			*data++ = j;
			*data++ = val;
		}
	}

	header->count = count;

	/* Return the size of the section */
	return (count * 8) + sizeof(*header);
}
/* Snapshot the istore memory */
static int snapshot_istore(struct kgsl_device *device, void *snapshot,
	int remain, void *priv)
{
	struct kgsl_snapshot_istore *header = snapshot;
	unsigned int *data = snapshot + sizeof(*header);
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	int count, i;

	count = adreno_dev->istore_size * ADRENO_ISTORE_WORDS;

	if (remain < (count * 4) + sizeof(*header)) {
		KGSL_DRV_ERR(device,
			"snapshot: Not enough memory for the istore section");
		return 0;
	}

	header->count = adreno_dev->istore_size;

	for (i = 0; i < count; i++)
		kgsl_regread(device, ADRENO_ISTORE_START + i, &data[i]);

	return (count * 4) + sizeof(*header);
}
Пример #9
0
/**
 * _adreno_coresight_get_and_clear(): Save the current value of coresight
 * registers and clear the registers subsequently. Clearing registers
 * has the effect of disabling coresight.
 * @adreno_dev: Pointer to adreno device struct
 */
static int _adreno_coresight_get_and_clear(struct adreno_device *adreno_dev)
{
	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
	struct kgsl_device *device = &adreno_dev->dev;
	struct adreno_coresight *coresight = gpudev->coresight;
	int i;

	if (coresight == NULL)
		return -ENODEV;

	kgsl_pre_hwaccess(device);
	/*
	 * Save the current value of each coresight register
	 * and then clear each register
	 */
	for (i = 0; i < coresight->count; i++) {
		kgsl_regread(device, coresight->registers[i].offset,
			&coresight->registers[i].value);
		kgsl_regwrite(device, coresight->registers[i].offset,
			0);
	}

	return 0;
}
Пример #10
0
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, ib_memsize;
	uint8_t *base_addr;
	char linebuf[80];

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

	kgsl_regread(device, REG_MH_MMU_PT_BASE, &pt_base);
	base_addr = kgsl_sharedmem_convertaddr(device, pt_base, kgsl_ib_base,
		&ib_memsize);

	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, memsize=%d\n", kgsl_ib_base,
		(uint32_t)base_addr, kgsl_ib_size, ib_memsize);
	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;
}
void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain,
		int hang)
{
	int i;
	uint32_t ptbase, ibbase, ibsize;
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);

	/* Reset the list of objects */
	objbufptr = 0;

	/* Get the physical address of the MMU pagetable */
	ptbase = kgsl_mmu_get_current_ptbase(device);

	/* Dump the ringbuffer */
	snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_RB,
		snapshot, remain, snapshot_rb, NULL);

	/*
	 * Make sure that the last IB1 that was being executed is dumped.
	 * Since this was the last IB1 that was processed, we should have
	 * already added it to the list during the ringbuffer parse but we
	 * want to be double plus sure.
	 */

	kgsl_regread(device, REG_CP_IB1_BASE, &ibbase);
	kgsl_regread(device, REG_CP_IB1_BUFSZ, &ibsize);

	/*
	 * The problem is that IB size from the register is the unprocessed size
	 * of the buffer not the original size, so if we didn't catch this
	 * buffer being directly used in the RB, then we might not be able to
	 * dump the whle thing. Print a warning message so we can try to
	 * figure how often this really happens.
	 */

	if (!find_object(SNAPSHOT_OBJ_TYPE_IB, ibbase, ptbase) && ibsize) {
		push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
			ibbase, ibsize);
		KGSL_DRV_ERR(device, "CP_IB1_BASE not found in the ringbuffer. "
			"Dumping %x dwords of the buffer.\n", ibsize);
	}

	kgsl_regread(device, REG_CP_IB2_BASE, &ibbase);
	kgsl_regread(device, REG_CP_IB2_BUFSZ, &ibsize);

	/*
	 * Add the last parsed IB2 to the list. The IB2 should be found as we
	 * parse the objects below, but we try to add it to the list first, so
	 * it too can be parsed.  Don't print an error message in this case - if
	 * the IB2 is found during parsing, the list will be updated with the
	 * correct size.
	 */

	if (!find_object(SNAPSHOT_OBJ_TYPE_IB, ibbase, ptbase) && ibsize) {
		push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
			ibbase, ibsize);
	}

	/*
	 * Go through the list of found objects and dump each one.  As the IBs
	 * are parsed, more objects might be found, and objbufptr will increase
	 */
	for (i = 0; i < objbufptr; i++)
		snapshot = dump_object(device, i, snapshot, remain);

	/*
	 * Only dump the istore on a hang - reading it on a running system
	 * has a non 0 chance of hanging the GPU
	 */

	if (hang) {
		snapshot = kgsl_snapshot_add_section(device,
			KGSL_SNAPSHOT_SECTION_ISTORE, snapshot, remain,
			snapshot_istore, NULL);
	}

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

	return snapshot;
}
/* Snapshot the ringbuffer memory */
static int snapshot_rb(struct kgsl_device *device, void *snapshot,
	int remain, void *priv)
{
	struct kgsl_snapshot_rb *header = snapshot;
	unsigned int *data = snapshot + sizeof(*header);
	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
	unsigned int rbbase, ptbase, rptr, *rbptr;
	int start, stop, index;
	int numitems, size;
	int parse_ibs = 0, ib_parse_start;

	/* Get the GPU address of the ringbuffer */
	kgsl_regread(device, REG_CP_RB_BASE, &rbbase);

	/* Get the physical address of the MMU pagetable */
	ptbase = kgsl_mmu_get_current_ptbase(device);

	/* Get the current read pointers for the RB */
	kgsl_regread(device, REG_CP_RB_RPTR, &rptr);

	/* start the dump at the rptr minus some history */
	start = (int) rptr - NUM_DWORDS_OF_RINGBUFFER_HISTORY;
	if (start < 0)
		start += rb->sizedwords;

	/*
	 * Stop the dump at the point where the software last wrote.  Don't use
	 * the hardware value here on the chance that it didn't get properly
	 * updated
	 */

	stop = (int) rb->wptr + 16;
	if (stop > rb->sizedwords)
		stop -= rb->sizedwords;

	/* Set up the header for the section */

	numitems = (stop > start) ? stop - start :
		(rb->sizedwords - start) + stop;

	size = (numitems << 2);

	if (remain < size + sizeof(*header)) {
		KGSL_DRV_ERR(device,
			"snapshot: Not enough memory for the rb section");
		return 0;
	}

	/* Write the sub-header for the section */
	header->start = start;
	header->end = stop;
	header->wptr = rb->wptr;
	header->rbsize = rb->sizedwords;
	header->count = numitems;

	/*
	 * We can only reliably dump IBs from the beginning of the context,
	 * and it turns out that for the vast majority of the time we really
	 * only care about the current context when it comes to diagnosing
	 * a hang. So, with an eye to limiting the buffer dumping to what is
	 * really useful find the beginning of the context and only dump
	 * IBs from that point
	 */

	index = rptr;
	ib_parse_start = start;
	rbptr = rb->buffer_desc.hostptr;

	while (index != start) {
		index--;

		if (index < 0) {
			/*
			 * The marker we are looking for is 2 dwords long, so
			 * when wrapping, go back 2 from the end so we don't
			 * access out of range in the if statement below
			 */
			index = rb->sizedwords - 2;

			/*
			 * Account for the possibility that start might be at
			 * rb->sizedwords - 1
			 */

			if (start == rb->sizedwords - 1)
				break;
		}

		/*
		 * Look for a NOP packet with the context switch identifier in
		 * the second dword
		 */

		if (rbptr[index] == cp_nop_packet(1) &&
			rbptr[index + 1] == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
				ib_parse_start = index;
				break;
		}
	}

	index = start;

	/*
	 * Loop through the RB, copying the data and looking for indirect
	 * buffers and MMU pagetable changes
	 */

	while (index != rb->wptr) {
		*data = rbptr[index];

		/* Only parse IBs between the context start and the rptr */

		if (index == ib_parse_start)
			parse_ibs = 1;

		if (index == rptr)
			parse_ibs = 0;

		if (parse_ibs && adreno_cmd_is_ib(rbptr[index]))
			push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
				rbptr[index + 1], rbptr[index + 2]);

		index = index + 1;

		if (index == rb->sizedwords)
			index = 0;

		data++;
	}

	/* Dump 16 dwords past the wptr, but don't  bother interpeting it */

	while (index != stop) {
		*data = rbptr[index];
		index = index + 1;

		if (index == rb->sizedwords)
			index = 0;

		data++;
	}

	/* Return the size of the section */
	return size + sizeof(*header);
}