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 int a3xx_snapshot_vpc_memory(struct kgsl_device *device, void *snapshot, int remain, void *priv) { struct kgsl_snapshot_debug *header = snapshot; unsigned int *data = snapshot + sizeof(*header); int size = VPC_MEMORY_BANKS * VPC_MEMORY_SIZE; int bank, addr, i = 0; if (remain < DEBUG_SECTION_SZ(size)) { SNAPSHOT_ERR_NOMEM(device, "VPC MEMORY"); return 0; } header->type = SNAPSHOT_DEBUG_VPC_MEMORY; header->size = size; for (bank = 0; bank < VPC_MEMORY_BANKS; bank++) { for (addr = 0; addr < VPC_MEMORY_SIZE; addr++) { unsigned int val = bank | (addr << 4); adreno_regwrite(device, A3XX_VPC_VPC_DEBUG_RAM_SEL, val); adreno_regread(device, A3XX_VPC_VPC_DEBUG_RAM_READ, &data[i++]); } } return DEBUG_SECTION_SZ(size); }
static int a3xx_snapshot_debugbus_block(struct kgsl_device *device, void *snapshot, int remain, void *priv) { struct kgsl_snapshot_debugbus *header = snapshot; unsigned int id = (unsigned int) priv; unsigned int val; int i; unsigned int *data = snapshot + sizeof(*header); int size = (DEBUGFS_BLOCK_SIZE * sizeof(unsigned int)) + sizeof(*header); if (remain < size) { SNAPSHOT_ERR_NOMEM(device, "DEBUGBUS"); return 0; } val = (id << 8) | (1 << 16); header->id = id; header->count = DEBUGFS_BLOCK_SIZE; for (i = 0; i < DEBUGFS_BLOCK_SIZE; i++) { adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, val | i); adreno_regread(device, A3XX_RBBM_DEBUG_BUS_DATA_STATUS, &data[i]); } return size; }
static int a330_snapshot_cp_merciu(struct kgsl_device *device, void *snapshot, int remain, void *priv) { struct kgsl_snapshot_debug *header = snapshot; unsigned int *data = snapshot + sizeof(*header); int i, size; size = A330_CP_MERCIU_QUEUE_SIZE << 1; if (remain < DEBUG_SECTION_SZ(size)) { SNAPSHOT_ERR_NOMEM(device, "CP MERCIU DEBUG"); return 0; } header->type = SNAPSHOT_DEBUG_CP_MERCIU; header->size = size; adreno_regwrite(device, A3XX_CP_MERCIU_ADDR, 0x0); for (i = 0; i < A330_CP_MERCIU_QUEUE_SIZE; i++) { adreno_regread(device, A3XX_CP_MERCIU_DATA, &data[(i * 2)]); adreno_regread(device, A3XX_CP_MERCIU_DATA2, &data[(i * 2) + 1]); } return DEBUG_SECTION_SZ(size); }
static int a3xx_snapshot_cp_roq(struct kgsl_device *device, void *snapshot, int remain, void *priv) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct kgsl_snapshot_debug *header = snapshot; unsigned int *data = snapshot + sizeof(*header); int i, size; size = adreno_is_a330(adreno_dev) ? A330_CP_ROQ_SIZE : A320_CP_ROQ_SIZE; if (remain < DEBUG_SECTION_SZ(size)) { SNAPSHOT_ERR_NOMEM(device, "CP ROQ DEBUG"); return 0; } header->type = SNAPSHOT_DEBUG_CP_ROQ; header->size = size; adreno_regwrite(device, A3XX_CP_ROQ_ADDR, 0x0); for (i = 0; i < size; i++) adreno_regread(device, A3XX_CP_ROQ_DATA, &data[i]); return DEBUG_SECTION_SZ(size); }
static int a3xx_snapshot_cp_pm4_ram(struct kgsl_device *device, void *snapshot, int remain, void *priv) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct kgsl_snapshot_debug *header = snapshot; unsigned int *data = snapshot + sizeof(*header); int i, size = adreno_dev->pm4_fw_size - 1; if (remain < DEBUG_SECTION_SZ(size)) { SNAPSHOT_ERR_NOMEM(device, "CP PM4 RAM DEBUG"); return 0; } header->type = SNAPSHOT_DEBUG_CP_PM4_RAM; header->size = size; /* * Read the firmware from the GPU rather than use our cache in order to * try to catch mis-programming or corruption in the hardware. We do * use the cached version of the size, however, instead of trying to * maintain always changing hardcoded constants */ adreno_regwrite(device, REG_CP_ME_RAM_RADDR, 0x0); for (i = 0; i < size; i++) adreno_regread(device, REG_CP_ME_RAM_DATA, &data[i]); return DEBUG_SECTION_SZ(size); }
static int a3xx_snapshot_debugbus_block(struct kgsl_device *device, void *snapshot, int remain, void *priv) { struct kgsl_snapshot_debugbus *header = snapshot; unsigned int id = (unsigned int) priv; unsigned int val; int i; unsigned int *data = snapshot + sizeof(*header); int size = (DEBUGFS_BLOCK_SIZE * sizeof(unsigned int)) + sizeof(*header); if (remain < size) { SNAPSHOT_ERR_NOMEM(device, "DEBUGBUS"); return 0; } val = (id << 8) | (1 << 16); header->id = id; header->count = DEBUGFS_BLOCK_SIZE; for (i = 0; i < DEBUGFS_BLOCK_SIZE; i++) _rbbm_debug_bus_read(device, id, i, &data[i]); return size; }
static int a3xx_snapshot_shader_memory(struct kgsl_device *device, void *snapshot, int remain, void *priv) { struct kgsl_snapshot_debug *header = snapshot; unsigned int *data = snapshot + sizeof(*header); int i; if (remain < DEBUG_SECTION_SZ(SHADER_MEMORY_SIZE)) { SNAPSHOT_ERR_NOMEM(device, "SHADER MEMORY"); return 0; } header->type = SNAPSHOT_DEBUG_SHADER_MEMORY; header->size = SHADER_MEMORY_SIZE; for (i = 0; i < SHADER_MEMORY_SIZE; i++) adreno_regread(device, 0x4000 + i, &data[i]); return DEBUG_SECTION_SZ(SHADER_MEMORY_SIZE); }
static int a3xx_snapshot_cp_meq(struct kgsl_device *device, void *snapshot, int remain, void *priv) { struct kgsl_snapshot_debug *header = snapshot; unsigned int *data = snapshot + sizeof(*header); int i; if (remain < DEBUG_SECTION_SZ(CP_MEQ_SIZE)) { SNAPSHOT_ERR_NOMEM(device, "CP MEQ DEBUG"); return 0; } header->type = SNAPSHOT_DEBUG_CP_MEQ; header->size = CP_MEQ_SIZE; adreno_regwrite(device, A3XX_CP_MEQ_ADDR, 0x0); for (i = 0; i < CP_MEQ_SIZE; i++) adreno_regread(device, A3XX_CP_MEQ_DATA, &data[i]); return DEBUG_SECTION_SZ(CP_MEQ_SIZE); }
/* * 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); }
static int a3xx_snapshot_cp_pfp_ram(struct kgsl_device *device, void *snapshot, int remain, void *priv) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct kgsl_snapshot_debug *header = snapshot; unsigned int *data = snapshot + sizeof(*header); int i, size = adreno_dev->pfp_fw_size - 1; if (remain < DEBUG_SECTION_SZ(size)) { SNAPSHOT_ERR_NOMEM(device, "CP PFP RAM DEBUG"); return 0; } header->type = SNAPSHOT_DEBUG_CP_PFP_RAM; header->size = size; kgsl_regwrite(device, A3XX_CP_PFP_UCODE_ADDR, 0x0); for (i = 0; i < size; i++) adreno_regread(device, A3XX_CP_PFP_UCODE_DATA, &data[i]); return DEBUG_SECTION_SZ(size); }
static int a2xx_snapshot_sqthreaddebug(struct kgsl_device *device, void *snapshot, int remain, void *priv) { struct kgsl_snapshot_debug *header = snapshot; unsigned int *data = snapshot + sizeof(*header); int i, offset = 0; int size = SQ_DEBUG_THREAD_SIZE * 2 * 16; if (remain < DEBUG_SECTION_SZ(size)) { SNAPSHOT_ERR_NOMEM(device, "SQ THREAD DEBUG"); return 0; } header->type = SNAPSHOT_DEBUG_SQTHREAD; header->size = size; for (i = 0; i < 16; i++) { adreno_regwrite(device, REG_SQ_DEBUG_TB_STATUS_SEL, i | (6<<4) | (i<<7) | (1<<11) | (1<<12) | (i<<16) | (6<<20) | (i<<23)); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_STATE_MEM, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_STATUS_REG, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATE_MEM, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATUS_REG_0, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATUS_REG_1, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATUS_REG_2, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATUS_REG_3, data, offset); } return DEBUG_SECTION_SZ(size); }
static int a2xx_snapshot_cpdebug(struct kgsl_device *device, void *snapshot, int remain, void *priv) { struct kgsl_snapshot_debug *header = snapshot; unsigned int *data = snapshot + sizeof(*header); int i; if (remain < DEBUG_SECTION_SZ(CPDEBUG_COUNT)) { SNAPSHOT_ERR_NOMEM(device, "CP DEBUG"); return 0; } header->type = SNAPSHOT_DEBUG_CP; header->size = CPDEBUG_COUNT; for (i = 0; i < CPDEBUG_COUNT; i++) { adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1628); adreno_regread(device, REG_RBBM_DEBUG_OUT, &data[i]); } adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0); return DEBUG_SECTION_SZ(CPDEBUG_COUNT); }
static int a2xx_snapshot_sqdebug(struct kgsl_device *device, void *snapshot, int remain, void *priv) { struct kgsl_snapshot_debug *header = snapshot; unsigned int *data = snapshot + sizeof(*header); int i, offset = 0; int size = SQ_DEBUG_BANK_SIZE * 2 * 2; if (remain < DEBUG_SECTION_SZ(size)) { SNAPSHOT_ERR_NOMEM(device, "SQ Debug"); return 0; } header->type = SNAPSHOT_DEBUG_SQ; header->size = size; for (i = 0; i < 2; i++) { SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_CONST_MGR_FSM+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_EXP_ALLOC+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_FSM_ALU_0+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_FSM_ALU_1+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_GPR_PIX+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_GPR_VTX+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_INPUT_FSM+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_MISC+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_MISC_0+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_MISC_1+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_0+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATE_MEM+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATUS_REG_0+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATUS_REG_1+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATUS_REG_2+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATUS_REG_3+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PTR_BUFF+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_TB_STATUS_SEL+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_TP_FSM+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_0+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_1+i*0x1000, data, offset); SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_STATE_MEM+i*0x1000, data, offset); } return DEBUG_SECTION_SZ(size); }
/* 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; }