static void z180_dump_ib(struct kgsl_device *device)
{
	unsigned int rb_size;
	unsigned int *rb_hostptr;
	unsigned int rb_words;
	unsigned int rb_gpuaddr;
	unsigned int ib_gpuptr = 0;
	unsigned int ib_size = 0;
	void *ib_hostptr = NULL;
	int rb_slot_num = -1;
	struct z180_device *z180_dev = Z180_DEVICE(device);
	struct kgsl_mem_entry *entry = NULL;
	phys_addr_t pt_base;
	unsigned int i;
	unsigned int j;
	char linebuf[CHARS_PER_LINE];
	unsigned int current_ib_slot;
	unsigned int len;
	unsigned int rowsize;
	KGSL_LOG_DUMP(device, "Z180 IB dump\n");

	rb_hostptr = (unsigned int *) z180_dev->ringbuffer.cmdbufdesc.hostptr;

	rb_size = Z180_RB_SIZE;
	rb_gpuaddr = z180_dev->ringbuffer.cmdbufdesc.gpuaddr;

	rb_words = rb_size/sizeof(unsigned int);

	KGSL_LOG_DUMP(device, "Ringbuffer size (bytes): %u\n", rb_size);

	KGSL_LOG_DUMP(device, "rb_words: %d\n", rb_words);

	pt_base = kgsl_mmu_get_current_ptbase(&device->mmu);

	
	for (i = 0; i < rb_words; i++) {
		if (rb_hostptr[i] == Z180_STREAM_PACKET_CALL) {

			rb_slot_num++;
			current_ib_slot =
				z180_dev->current_timestamp % Z180_PACKET_COUNT;
			if (rb_slot_num != current_ib_slot)
				continue;

			ib_gpuptr = rb_hostptr[i+1];

			entry = kgsl_get_mem_entry(device, pt_base, ib_gpuptr,
							1);

			if (entry == NULL) {
				KGSL_LOG_DUMP(device,
				"IB mem entry not found for ringbuffer slot#: %d\n",
				rb_slot_num);
				continue;
			}

			ib_hostptr = kgsl_memdesc_map(&entry->memdesc);

			if (ib_hostptr == NULL) {
				KGSL_LOG_DUMP(device,
				"Could not map IB to kernel memory, Ringbuffer Slot: %d\n",
				rb_slot_num);
				kgsl_mem_entry_put(entry);
				continue;
			}

			ib_size = entry->memdesc.size;
			KGSL_LOG_DUMP(device,
				"IB size: %dbytes, IB size in words: %d\n",
				ib_size,
				ib_size/sizeof(unsigned int));

			for (j = 0; j < ib_size; j += WORDS_PER_LINE) {
				len = ib_size - j*sizeof(unsigned int);
				rowsize = WORDS_PER_LINE*sizeof(unsigned int);
				hex_dump_to_buffer(ib_hostptr+j, len, rowsize,
						sizeof(unsigned int), linebuf,
						sizeof(linebuf), false);
				KGSL_LOG_DUMP(device, "IB%d: %04X: %s\n",
						rb_slot_num,
						(rb_gpuaddr +
						j*sizeof(unsigned int)),
						linebuf);
			}
			KGSL_LOG_DUMP(device, "IB Dump Finished\n");
			kgsl_mem_entry_put(entry);
		}
	}
}
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;
}
Пример #3
0
/* Snapshot the Linux specific information */
static int snapshot_os(struct kgsl_device *device,
	void *snapshot, int remain, void *priv)
{
	struct kgsl_snapshot_linux *header = snapshot;
	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
	struct task_struct *task;
	pid_t pid;
	int hang = (int) priv;
	int ctxtcount = 0;
	int size = sizeof(*header);

	/* Figure out how many active contexts there are - these will
	 * be appended on the end of the structure */

	idr_for_each(&device->context_idr, snapshot_context_count, &ctxtcount);

	size += ctxtcount * sizeof(struct kgsl_snapshot_linux_context);

	/* Make sure there is enough room for the data */
	if (remain < size) {
		SNAPSHOT_ERR_NOMEM(device, "OS");
		return 0;
	}

	memset(header, 0, sizeof(*header));

	header->osid = KGSL_SNAPSHOT_OS_LINUX;

	header->state = hang ? SNAPSHOT_STATE_HUNG : SNAPSHOT_STATE_RUNNING;

	/* Get the kernel build information */
	strlcpy(header->release, utsname()->release, sizeof(header->release));
	strlcpy(header->version, utsname()->version, sizeof(header->version));

	/* Get the Unix time for the timestamp */
	header->seconds = get_seconds();

	/* Remember the power information */
	header->power_flags = pwr->power_flags;
	header->power_level = pwr->active_pwrlevel;
	header->power_interval_timeout = pwr->interval_timeout;
	header->grpclk = kgsl_get_clkrate(pwr->grp_clks[0]);
	header->busclk = kgsl_get_clkrate(pwr->ebi1_clk);

	/* Future proof for per-context timestamps */
	header->current_context = -1;

	/* Get the current PT base */
	header->ptbase = kgsl_mmu_get_current_ptbase(device);
	/* And the PID for the task leader */
	pid = header->pid = kgsl_mmu_get_ptname_from_ptbase(header->ptbase);

	task = find_task_by_vpid(pid);

	if (task)
		get_task_comm(header->comm, task);

	header->ctxtcount = ctxtcount;

	/* append information for each context */
	_ctxtptr = snapshot + sizeof(*header);
	idr_for_each(&device->context_idr, snapshot_context_info, NULL);

	/* Return the size of the data segment */
	return size;
}
/* 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);
}