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, ®val); kgsl_active_count_put(device); } mutex_unlock(&device->mutex); return snprintf(buf, PAGE_SIZE, "0x%X", regval); }
/** * 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), ®_val); KGSL_LOG_DUMP(device, "REG: %04X: %08X\n", regs_to_dump[i]/sizeof(unsigned int), reg_val); } }
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); }
/* * 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); }
/** * _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; }
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); }