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; }
/* 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); }