static void *a3xx_snapshot_debugbus(struct kgsl_device *device, void *snapshot, int *remain) { int i; for (i = 0; i < ARRAY_SIZE(debugbus_blocks); i++) { snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUGBUS, snapshot, remain, a3xx_snapshot_debugbus_block, (void *) debugbus_blocks[i]); } return snapshot; }
static void *a2xx_snapshot_indexed_registers(struct kgsl_device *device, void *snapshot, int *remain, unsigned int index, unsigned int data, unsigned int start, unsigned int count) { struct kgsl_snapshot_indexed_registers iregs; iregs.index = index; iregs.data = data; iregs.start = start; iregs.count = count; return kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_INDEXED_REGS, snapshot, remain, kgsl_snapshot_dump_indexed_regs, &iregs); }
void *a3xx_snapshot(struct adreno_device *adreno_dev, void *snapshot, int *remain, int hang) { struct kgsl_device *device = &adreno_dev->dev; struct kgsl_snapshot_registers regs; regs.regs = (unsigned int *) a3xx_registers; regs.count = a3xx_registers_count; /* Master set of (non debug) registers */ snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS, snapshot, remain, kgsl_snapshot_dump_regs, ®s); /* CP_STATE_DEBUG indexed registers */ snapshot = kgsl_snapshot_indexed_registers(device, snapshot, remain, REG_CP_STATE_DEBUG_INDEX, REG_CP_STATE_DEBUG_DATA, 0x0, 0x14); /* CP_ME indexed registers */ snapshot = kgsl_snapshot_indexed_registers(device, snapshot, remain, REG_CP_ME_CNTL, REG_CP_ME_STATUS, 64, 44); /* VPC memory */ snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a3xx_snapshot_vpc_memory, NULL); /* CP MEQ */ snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a3xx_snapshot_cp_meq, NULL); /* CP PFP and PM4 */ /* Reading these will hang the GPU if it isn't already hung */ if (hang) { snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a3xx_snapshot_cp_pfp_ram, NULL); snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a3xx_snapshot_cp_pm4_ram, NULL); } /* CP ROQ */ snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a3xx_snapshot_cp_roq, NULL); snapshot = a3xx_snapshot_debugbus(device, snapshot, remain); return snapshot; }
/* Dump another item on the current pending list */ static void *dump_object(struct kgsl_device *device, int obj, void *snapshot, int *remain) { switch (objbuf[obj].type) { case SNAPSHOT_OBJ_TYPE_IB: snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_IB, snapshot, remain, snapshot_ib, &objbuf[obj]); break; default: KGSL_DRV_ERR(device, "snapshot: Invalid snapshot object type: %d\n", objbuf[obj].type); break; } return snapshot; }
void *a2xx_snapshot(struct adreno_device *adreno_dev, void *snapshot, int *remain, int hang) { struct kgsl_device *device = &adreno_dev->dev; struct kgsl_snapshot_registers regs; unsigned int pmoverride; /* Choose the register set to dump */ if (adreno_is_a20x(adreno_dev)) { regs.regs = (unsigned int *) a200_registers; regs.count = a200_registers_count; } else { regs.regs = (unsigned int *) a220_registers; regs.count = a220_registers_count; } /* Master set of (non debug) registers */ snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS, snapshot, remain, kgsl_snapshot_dump_regs, ®s); /* CP_STATE_DEBUG indexed registers */ snapshot = a2xx_snapshot_indexed_registers(device, snapshot, remain, REG_CP_STATE_DEBUG_INDEX, REG_CP_STATE_DEBUG_DATA, 0x0, 0x14); /* CP_ME indexed registers */ snapshot = a2xx_snapshot_indexed_registers(device, snapshot, remain, REG_CP_ME_CNTL, REG_CP_ME_STATUS, 64, 44); /* * Need to temporarily turn off clock gating for the debug bus to * work */ adreno_regread(device, REG_RBBM_PM_OVERRIDE2, &pmoverride); adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0xFF); /* SX debug registers */ snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a2xx_snapshot_sxdebug, NULL); /* SU debug indexed registers (only for < 470) */ if (!adreno_is_a22x(adreno_dev)) snapshot = a2xx_snapshot_indexed_registers(device, snapshot, remain, REG_PA_SU_DEBUG_CNTL, REG_PA_SU_DEBUG_DATA, 0, 0x1B); /* CP debug registers */ snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a2xx_snapshot_cpdebug, NULL); /* MH debug indexed registers */ snapshot = a2xx_snapshot_indexed_registers(device, snapshot, remain, MH_DEBUG_CTRL, MH_DEBUG_DATA, 0x0, 0x40); /* Leia only register sets */ if (adreno_is_a22x(adreno_dev)) { /* RB DEBUG indexed regisers */ snapshot = a2xx_snapshot_indexed_registers(device, snapshot, remain, REG_RB_DEBUG_CNTL, REG_RB_DEBUG_DATA, 0, 8); /* RB DEBUG indexed registers bank 2 */ snapshot = a2xx_snapshot_indexed_registers(device, snapshot, remain, REG_RB_DEBUG_CNTL, REG_RB_DEBUG_DATA + 0x1000, 0, 8); /* PC_DEBUG indexed registers */ snapshot = a2xx_snapshot_indexed_registers(device, snapshot, remain, REG_PC_DEBUG_CNTL, REG_PC_DEBUG_DATA, 0, 8); /* GRAS_DEBUG indexed registers */ snapshot = a2xx_snapshot_indexed_registers(device, snapshot, remain, REG_GRAS_DEBUG_CNTL, REG_GRAS_DEBUG_DATA, 0, 4); /* MIU debug registers */ snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a2xx_snapshot_miudebug, NULL); /* SQ DEBUG debug registers */ snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a2xx_snapshot_sqdebug, NULL); /* * Reading SQ THREAD causes bad things to happen on a running * system, so only read it if the GPU is already hung */ if (hang) { /* SQ THREAD debug registers */ snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a2xx_snapshot_sqthreaddebug, NULL); } } /* Reset the clock gating */ adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, pmoverride); return snapshot; }
/* * kgsl_snapshot - construct a device snapshot * @device - device to snapshot * @hang - set to 1 if the snapshot was triggered following a hnag * Given a device, construct a binary snapshot dump of the current device state * and store it in the device snapshot memory. */ int kgsl_device_snapshot(struct kgsl_device *device, int hang) { struct kgsl_snapshot_header *header = device->snapshot; int remain = device->snapshot_maxsize - sizeof(*header); void *snapshot; struct platform_device *pdev = container_of(device->parentdev, struct platform_device, dev); struct kgsl_device_platform_data *pdata = pdev->dev.platform_data; /* * The first hang is always the one we are interested in. To * avoid a subsequent hang blowing away the first, the snapshot * is frozen until it is dumped via sysfs. * * Note that triggered snapshots are always taken regardless * of the state and never frozen. */ if (hang && device->snapshot_frozen == 1) return 0; if (device->snapshot == NULL) { KGSL_DRV_ERR(device, "snapshot: No snapshot memory available\n"); return -ENOMEM; } if (remain < sizeof(*header)) { KGSL_DRV_ERR(device, "snapshot: Not enough memory for the header\n"); return -ENOMEM; } header->magic = SNAPSHOT_MAGIC; header->gpuid = kgsl_gpuid(device); /* Get a pointer to the first section (right after the header) */ snapshot = ((void *) device->snapshot) + sizeof(*header); /* Build the Linux specific header */ snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_OS, snapshot, &remain, snapshot_os, (void *) hang); /* Get the device specific sections */ if (device->ftbl->snapshot) snapshot = device->ftbl->snapshot(device, snapshot, &remain, hang); /* Add the empty end section to let the parser know we are done */ snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_END, snapshot, &remain, NULL, NULL); device->snapshot_timestamp = get_seconds(); device->snapshot_size = (int) (snapshot - device->snapshot); /* Freeze the snapshot on a hang until it gets read */ device->snapshot_frozen = (hang) ? 1 : 0; /* log buffer info to aid in ramdump recovery */ KGSL_DRV_ERR(device,"snapshot created at va %p pa %x size %d\n", device->snapshot, pdata->snapshot_address, device->snapshot_size); if (hang) sysfs_notify(&device->snapshot_kobj, NULL, "timestamp"); return 0; }
void *a3xx_snapshot(struct adreno_device *adreno_dev, void *snapshot, int *remain, int hang) { struct kgsl_device *device = &adreno_dev->dev; struct kgsl_snapshot_registers_list list; struct kgsl_snapshot_registers regs[5]; list.registers = regs; list.count = 0; adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL, 0x00); _snapshot_a3xx_regs(regs, &list); _snapshot_hlsq_regs(regs, &list, adreno_dev); if (adreno_is_a330(adreno_dev)) _snapshot_a330_regs(regs, &list); snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS, snapshot, remain, kgsl_snapshot_dump_regs, &list); snapshot = kgsl_snapshot_indexed_registers(device, snapshot, remain, REG_CP_STATE_DEBUG_INDEX, REG_CP_STATE_DEBUG_DATA, 0x0, 0x14); snapshot = kgsl_snapshot_indexed_registers(device, snapshot, remain, REG_CP_ME_CNTL, REG_CP_ME_STATUS, 64, 44); snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a3xx_snapshot_vpc_memory, NULL); snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a3xx_snapshot_cp_meq, NULL); snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a3xx_snapshot_shader_memory, NULL); if (hang) { snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a3xx_snapshot_cp_pfp_ram, NULL); snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a3xx_snapshot_cp_pm4_ram, NULL); } snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a3xx_snapshot_cp_roq, NULL); if (adreno_is_a330(adreno_dev)) { snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a330_snapshot_cp_merciu, NULL); } snapshot = a3xx_snapshot_debugbus(device, snapshot, remain); adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL, A3XX_RBBM_CLOCK_CTL_DEFAULT); return snapshot; }
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; }
void *a3xx_snapshot(struct adreno_device *adreno_dev, void *snapshot, int *remain, int hang) { struct kgsl_device *device = &adreno_dev->dev; struct kgsl_snapshot_registers_list list; struct kgsl_snapshot_registers regs[2]; regs[0].regs = (unsigned int *) a3xx_registers; regs[0].count = a3xx_registers_count; list.registers = regs; list.count = 1; /* For A330, append the additional list of new registers to grab */ if (adreno_is_a330(adreno_dev)) { regs[1].regs = (unsigned int *) a330_registers; regs[1].count = a330_registers_count; list.count++; } /* Master set of (non debug) registers */ snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS, snapshot, remain, kgsl_snapshot_dump_regs, &list); /* CP_STATE_DEBUG indexed registers */ snapshot = kgsl_snapshot_indexed_registers(device, snapshot, remain, REG_CP_STATE_DEBUG_INDEX, REG_CP_STATE_DEBUG_DATA, 0x0, 0x14); /* CP_ME indexed registers */ snapshot = kgsl_snapshot_indexed_registers(device, snapshot, remain, REG_CP_ME_CNTL, REG_CP_ME_STATUS, 64, 44); /* Disable Clock gating temporarily for the debug bus to work */ adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL, 0x00); /* VPC memory */ snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a3xx_snapshot_vpc_memory, NULL); /* CP MEQ */ snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a3xx_snapshot_cp_meq, NULL); /* Shader working/shadow memory */ snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a3xx_snapshot_shader_memory, NULL); /* CP PFP and PM4 */ /* Reading these will hang the GPU if it isn't already hung */ if (hang) { snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a3xx_snapshot_cp_pfp_ram, NULL); snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a3xx_snapshot_cp_pm4_ram, NULL); } /* CP ROQ */ snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a3xx_snapshot_cp_roq, NULL); if (adreno_is_a330(adreno_dev)) { snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain, a330_snapshot_cp_merciu, NULL); } snapshot = a3xx_snapshot_debugbus(device, snapshot, remain); /* Enable Clock gating */ adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL, A3XX_RBBM_CLOCK_CTL_DEFAULT); return snapshot; }