mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
coresight: support dumping tmc-etf and tmc-etr on kernel panic
Dump TMC ETF and TMC ETR registers on abort to allow post crash parsing. Also ensure magic value is written for TMC ETF buffer dump. Change-Id: I8f21c456bcc79ed3e2831bd6bd1e6a6dbfdb93d0 Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
This commit is contained in:
parent
6e99801d1b
commit
8efed79331
1 changed files with 116 additions and 39 deletions
|
@ -50,41 +50,45 @@ do { \
|
||||||
mb(); \
|
mb(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define TMC_RSZ (0x004)
|
#define TMC_RSZ (0x004)
|
||||||
#define TMC_STS (0x00C)
|
#define TMC_STS (0x00C)
|
||||||
#define TMC_RRD (0x010)
|
#define TMC_RRD (0x010)
|
||||||
#define TMC_RRP (0x014)
|
#define TMC_RRP (0x014)
|
||||||
#define TMC_RWP (0x018)
|
#define TMC_RWP (0x018)
|
||||||
#define TMC_TRG (0x01C)
|
#define TMC_TRG (0x01C)
|
||||||
#define TMC_CTL (0x020)
|
#define TMC_CTL (0x020)
|
||||||
#define TMC_RWD (0x024)
|
#define TMC_RWD (0x024)
|
||||||
#define TMC_MODE (0x028)
|
#define TMC_MODE (0x028)
|
||||||
#define TMC_LBUFLEVEL (0x02C)
|
#define TMC_LBUFLEVEL (0x02C)
|
||||||
#define TMC_CBUFLEVEL (0x030)
|
#define TMC_CBUFLEVEL (0x030)
|
||||||
#define TMC_BUFWM (0x034)
|
#define TMC_BUFWM (0x034)
|
||||||
#define TMC_RRPHI (0x038)
|
#define TMC_RRPHI (0x038)
|
||||||
#define TMC_RWPHI (0x03C)
|
#define TMC_RWPHI (0x03C)
|
||||||
#define TMC_AXICTL (0x110)
|
#define TMC_AXICTL (0x110)
|
||||||
#define TMC_DBALO (0x118)
|
#define TMC_DBALO (0x118)
|
||||||
#define TMC_DBAHI (0x11C)
|
#define TMC_DBAHI (0x11C)
|
||||||
#define TMC_FFSR (0x300)
|
#define TMC_FFSR (0x300)
|
||||||
#define TMC_FFCR (0x304)
|
#define TMC_FFCR (0x304)
|
||||||
#define TMC_PSCR (0x308)
|
#define TMC_PSCR (0x308)
|
||||||
#define TMC_ITMISCOP0 (0xEE0)
|
#define TMC_ITMISCOP0 (0xEE0)
|
||||||
#define TMC_ITTRFLIN (0xEE8)
|
#define TMC_ITTRFLIN (0xEE8)
|
||||||
#define TMC_ITATBDATA0 (0xEEC)
|
#define TMC_ITATBDATA0 (0xEEC)
|
||||||
#define TMC_ITATBCTR2 (0xEF0)
|
#define TMC_ITATBCTR2 (0xEF0)
|
||||||
#define TMC_ITATBCTR1 (0xEF4)
|
#define TMC_ITATBCTR1 (0xEF4)
|
||||||
#define TMC_ITATBCTR0 (0xEF8)
|
#define TMC_ITATBCTR0 (0xEF8)
|
||||||
|
|
||||||
#define BYTES_PER_WORD 4
|
#define BYTES_PER_WORD 4
|
||||||
#define TMC_ETR_BAM_PIPE_INDEX 0
|
#define TMC_ETR_BAM_PIPE_INDEX 0
|
||||||
#define TMC_ETR_BAM_NR_PIPES 2
|
#define TMC_ETR_BAM_NR_PIPES 2
|
||||||
|
|
||||||
#define TMC_ETFETB_DUMP_VER_OFF (4)
|
#define TMC_ETFETB_DUMP_MAGIC_OFF (0)
|
||||||
#define TMC_ETFETB_DUMP_VER (1)
|
#define TMC_ETFETB_DUMP_MAGIC (0x5D1DB1BF)
|
||||||
#define TMC_REG_DUMP_VER_OFF (4)
|
#define TMC_ETFETB_DUMP_VER_OFF (4)
|
||||||
#define TMC_REG_DUMP_VER (1)
|
#define TMC_ETFETB_DUMP_VER (1)
|
||||||
|
#define TMC_REG_DUMP_MAGIC_OFF (0)
|
||||||
|
#define TMC_REG_DUMP_MAGIC (0x5D1DB1BF)
|
||||||
|
#define TMC_REG_DUMP_VER_OFF (4)
|
||||||
|
#define TMC_REG_DUMP_VER (1)
|
||||||
|
|
||||||
enum tmc_config_type {
|
enum tmc_config_type {
|
||||||
TMC_CONFIG_TYPE_ETB,
|
TMC_CONFIG_TYPE_ETB,
|
||||||
|
@ -134,6 +138,8 @@ struct tmc_drvdata {
|
||||||
struct mutex read_lock;
|
struct mutex read_lock;
|
||||||
int read_count;
|
int read_count;
|
||||||
bool reading;
|
bool reading;
|
||||||
|
bool aborting;
|
||||||
|
char *reg_buf;
|
||||||
char *buf;
|
char *buf;
|
||||||
unsigned long paddr;
|
unsigned long paddr;
|
||||||
void __iomem *vaddr;
|
void __iomem *vaddr;
|
||||||
|
@ -462,10 +468,64 @@ static int tmc_enable_link(struct coresight_device *csdev, int inport,
|
||||||
return tmc_enable(drvdata, TMC_MODE_HARDWARE_FIFO);
|
return tmc_enable(drvdata, TMC_MODE_HARDWARE_FIFO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __tmc_reg_dump(struct tmc_drvdata *drvdata)
|
||||||
|
{
|
||||||
|
char *reg_hdr;
|
||||||
|
uint32_t *reg_buf;
|
||||||
|
|
||||||
|
if (!drvdata->reg_buf || !drvdata->aborting)
|
||||||
|
return;
|
||||||
|
|
||||||
|
reg_hdr = drvdata->reg_buf - PAGE_SIZE;
|
||||||
|
reg_buf = (uint32_t *)drvdata->reg_buf;
|
||||||
|
|
||||||
|
reg_buf[1] = tmc_readl(drvdata, TMC_RSZ);
|
||||||
|
reg_buf[3] = tmc_readl(drvdata, TMC_STS);
|
||||||
|
reg_buf[5] = tmc_readl(drvdata, TMC_RRP);
|
||||||
|
reg_buf[6] = tmc_readl(drvdata, TMC_RWP);
|
||||||
|
reg_buf[7] = tmc_readl(drvdata, TMC_TRG);
|
||||||
|
reg_buf[8] = tmc_readl(drvdata, TMC_CTL);
|
||||||
|
reg_buf[10] = tmc_readl(drvdata, TMC_MODE);
|
||||||
|
reg_buf[11] = tmc_readl(drvdata, TMC_LBUFLEVEL);
|
||||||
|
reg_buf[12] = tmc_readl(drvdata, TMC_CBUFLEVEL);
|
||||||
|
reg_buf[13] = tmc_readl(drvdata, TMC_BUFWM);
|
||||||
|
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
|
||||||
|
reg_buf[14] = tmc_readl(drvdata, TMC_RRPHI);
|
||||||
|
reg_buf[15] = tmc_readl(drvdata, TMC_RWPHI);
|
||||||
|
reg_buf[68] = tmc_readl(drvdata, TMC_AXICTL);
|
||||||
|
reg_buf[70] = tmc_readl(drvdata, TMC_DBALO);
|
||||||
|
reg_buf[71] = tmc_readl(drvdata, TMC_DBAHI);
|
||||||
|
}
|
||||||
|
reg_buf[192] = tmc_readl(drvdata, TMC_FFSR);
|
||||||
|
reg_buf[193] = tmc_readl(drvdata, TMC_FFCR);
|
||||||
|
reg_buf[194] = tmc_readl(drvdata, TMC_PSCR);
|
||||||
|
reg_buf[1000] = tmc_readl(drvdata, CORESIGHT_CLAIMSET);
|
||||||
|
reg_buf[1001] = tmc_readl(drvdata, CORESIGHT_CLAIMCLR);
|
||||||
|
reg_buf[1005] = tmc_readl(drvdata, CORESIGHT_LSR);
|
||||||
|
reg_buf[1006] = tmc_readl(drvdata, CORESIGHT_AUTHSTATUS);
|
||||||
|
reg_buf[1010] = tmc_readl(drvdata, CORESIGHT_DEVID);
|
||||||
|
reg_buf[1011] = tmc_readl(drvdata, CORESIGHT_DEVTYPE);
|
||||||
|
reg_buf[1012] = tmc_readl(drvdata, CORESIGHT_PERIPHIDR4);
|
||||||
|
reg_buf[1013] = tmc_readl(drvdata, CORESIGHT_PERIPHIDR5);
|
||||||
|
reg_buf[1014] = tmc_readl(drvdata, CORESIGHT_PERIPHIDR6);
|
||||||
|
reg_buf[1015] = tmc_readl(drvdata, CORESIGHT_PERIPHIDR7);
|
||||||
|
reg_buf[1016] = tmc_readl(drvdata, CORESIGHT_PERIPHIDR0);
|
||||||
|
reg_buf[1017] = tmc_readl(drvdata, CORESIGHT_PERIPHIDR1);
|
||||||
|
reg_buf[1018] = tmc_readl(drvdata, CORESIGHT_PERIPHIDR2);
|
||||||
|
reg_buf[1019] = tmc_readl(drvdata, CORESIGHT_PERIPHIDR3);
|
||||||
|
reg_buf[1020] = tmc_readl(drvdata, CORESIGHT_COMPIDR0);
|
||||||
|
reg_buf[1021] = tmc_readl(drvdata, CORESIGHT_COMPIDR1);
|
||||||
|
reg_buf[1022] = tmc_readl(drvdata, CORESIGHT_COMPIDR2);
|
||||||
|
reg_buf[1023] = tmc_readl(drvdata, CORESIGHT_COMPIDR3);
|
||||||
|
|
||||||
|
*(uint32_t *)(reg_hdr + TMC_REG_DUMP_MAGIC_OFF) = TMC_REG_DUMP_MAGIC;
|
||||||
|
}
|
||||||
|
|
||||||
static void __tmc_etb_dump(struct tmc_drvdata *drvdata)
|
static void __tmc_etb_dump(struct tmc_drvdata *drvdata)
|
||||||
{
|
{
|
||||||
enum tmc_mem_intf_width memwidth;
|
enum tmc_mem_intf_width memwidth;
|
||||||
uint8_t memwords;
|
uint8_t memwords;
|
||||||
|
char *hdr;
|
||||||
char *bufp;
|
char *bufp;
|
||||||
uint32_t read_data;
|
uint32_t read_data;
|
||||||
int i;
|
int i;
|
||||||
|
@ -485,11 +545,18 @@ static void __tmc_etb_dump(struct tmc_drvdata *drvdata)
|
||||||
for (i = 0; i < memwords; i++) {
|
for (i = 0; i < memwords; i++) {
|
||||||
read_data = tmc_readl(drvdata, TMC_RRD);
|
read_data = tmc_readl(drvdata, TMC_RRD);
|
||||||
if (read_data == 0xFFFFFFFF)
|
if (read_data == 0xFFFFFFFF)
|
||||||
return;
|
goto out;
|
||||||
memcpy(bufp, &read_data, BYTES_PER_WORD);
|
memcpy(bufp, &read_data, BYTES_PER_WORD);
|
||||||
bufp += BYTES_PER_WORD;
|
bufp += BYTES_PER_WORD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (drvdata->aborting) {
|
||||||
|
hdr = drvdata->buf - PAGE_SIZE;
|
||||||
|
*(uint32_t *)(hdr + TMC_ETFETB_DUMP_MAGIC_OFF) =
|
||||||
|
TMC_ETFETB_DUMP_MAGIC;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __tmc_etb_disable(struct tmc_drvdata *drvdata)
|
static void __tmc_etb_disable(struct tmc_drvdata *drvdata)
|
||||||
|
@ -498,6 +565,7 @@ static void __tmc_etb_disable(struct tmc_drvdata *drvdata)
|
||||||
|
|
||||||
tmc_flush_and_stop(drvdata);
|
tmc_flush_and_stop(drvdata);
|
||||||
__tmc_etb_dump(drvdata);
|
__tmc_etb_dump(drvdata);
|
||||||
|
__tmc_reg_dump(drvdata);
|
||||||
__tmc_disable(drvdata);
|
__tmc_disable(drvdata);
|
||||||
|
|
||||||
TMC_LOCK(drvdata);
|
TMC_LOCK(drvdata);
|
||||||
|
@ -522,6 +590,7 @@ static void __tmc_etr_disable_to_mem(struct tmc_drvdata *drvdata)
|
||||||
|
|
||||||
tmc_flush_and_stop(drvdata);
|
tmc_flush_and_stop(drvdata);
|
||||||
__tmc_etr_dump(drvdata);
|
__tmc_etr_dump(drvdata);
|
||||||
|
__tmc_reg_dump(drvdata);
|
||||||
__tmc_disable(drvdata);
|
__tmc_disable(drvdata);
|
||||||
|
|
||||||
TMC_LOCK(drvdata);
|
TMC_LOCK(drvdata);
|
||||||
|
@ -604,6 +673,8 @@ static void tmc_abort(struct coresight_device *csdev)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
enum tmc_mode mode;
|
enum tmc_mode mode;
|
||||||
|
|
||||||
|
drvdata->aborting = true;
|
||||||
|
|
||||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||||
if (drvdata->reading)
|
if (drvdata->reading)
|
||||||
goto out0;
|
goto out0;
|
||||||
|
@ -1077,8 +1148,10 @@ static int __devinit tmc_probe(struct platform_device *pdev)
|
||||||
dump.start_addr = virt_to_phys(baddr);
|
dump.start_addr = virt_to_phys(baddr);
|
||||||
dump.end_addr = dump.start_addr + PAGE_SIZE + drvdata->size;
|
dump.end_addr = dump.start_addr + PAGE_SIZE + drvdata->size;
|
||||||
ret = msm_dump_table_register(&dump);
|
ret = msm_dump_table_register(&dump);
|
||||||
/* Don't free the buffer in case of error since it can still
|
/*
|
||||||
* be used to provide dump collection via the device node
|
* Don't free the buffer in case of error since it can still
|
||||||
|
* be used to provide dump collection via the device node or
|
||||||
|
* as part of abort.
|
||||||
*/
|
*/
|
||||||
if (ret)
|
if (ret)
|
||||||
dev_info(dev, "TMC ETF-ETB dump setup failed\n");
|
dev_info(dev, "TMC ETF-ETB dump setup failed\n");
|
||||||
|
@ -1087,15 +1160,19 @@ static int __devinit tmc_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
baddr = devm_kzalloc(dev, PAGE_SIZE + reg_size, GFP_KERNEL);
|
baddr = devm_kzalloc(dev, PAGE_SIZE + reg_size, GFP_KERNEL);
|
||||||
if (baddr) {
|
if (baddr) {
|
||||||
|
drvdata->reg_buf = baddr + PAGE_SIZE;
|
||||||
*(uint32_t *)(baddr + TMC_REG_DUMP_VER_OFF) = TMC_REG_DUMP_VER;
|
*(uint32_t *)(baddr + TMC_REG_DUMP_VER_OFF) = TMC_REG_DUMP_VER;
|
||||||
dump.id = MSM_TMC0_REG + count;
|
dump.id = MSM_TMC0_REG + count;
|
||||||
dump.start_addr = virt_to_phys(baddr);
|
dump.start_addr = virt_to_phys(baddr);
|
||||||
dump.end_addr = dump.start_addr + PAGE_SIZE + reg_size;
|
dump.end_addr = dump.start_addr + PAGE_SIZE + reg_size;
|
||||||
ret = msm_dump_table_register(&dump);
|
ret = msm_dump_table_register(&dump);
|
||||||
if (ret) {
|
/*
|
||||||
devm_kfree(dev, baddr);
|
* Don't free the buffer in case of error since it can still
|
||||||
|
* be used to dump registers as part of abort to aid post crash
|
||||||
|
* parsing.
|
||||||
|
*/
|
||||||
|
if (ret)
|
||||||
dev_info(dev, "TMC REG dump setup failed\n");
|
dev_info(dev, "TMC REG dump setup failed\n");
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
dev_info(dev, "TMC REG dump space allocation failed\n");
|
dev_info(dev, "TMC REG dump space allocation failed\n");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue