diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index de9577449593..1571a3f978a5 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2012,2017-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012,2017-2019,2021, The Linux Foundation. All rights reserved. * * Description: CoreSight Trace Memory Controller driver */ @@ -23,10 +23,13 @@ #include #include #include +#include #include "coresight-priv.h" #include "coresight-tmc.h" +#define TMC_REG_DUMP_MAGIC 0x42445953 + void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata) { /* Ensure formatter, unformatter and hardware fifo are empty */ @@ -56,10 +59,84 @@ void tmc_flush_and_stop(struct tmc_drvdata *drvdata) tmc_wait_for_tmcready(drvdata); } +static void __tmc_reg_dump(struct tmc_drvdata *drvdata) +{ + struct dump_vaddr_entry *dump_entry; + struct msm_dump_data *dump_data; + uint32_t *reg_buf; + + if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) { + dump_entry = get_msm_dump_ptr(MSM_DUMP_DATA_TMC_ETR_REG); + dev_dbg(drvdata->dev, "%s: TMC ETR dump entry ptr is %pK\n", + __func__, dump_entry); + } else if (drvdata->config_type == TMC_CONFIG_TYPE_ETB || + drvdata->config_type == TMC_CONFIG_TYPE_ETF) { + dump_entry = get_msm_dump_ptr(MSM_DUMP_DATA_TMC_ETF_REG); + dev_dbg(drvdata->dev, "%s: TMC ETF dump entry ptr is %pK\n", + __func__, dump_entry); + } else + return; + + if (dump_entry == NULL) + return; + + reg_buf = (uint32_t *)(dump_entry->dump_vaddr); + dump_data = dump_entry->dump_data_vaddr; + + if (reg_buf == NULL || dump_data == NULL) + return; + + dev_dbg(drvdata->dev, "%s: TMC dump reg ptr is %pK, dump_data is %pK\n", + __func__, reg_buf, dump_data); + + reg_buf[1] = readl_relaxed(drvdata->base + TMC_RSZ); + reg_buf[3] = readl_relaxed(drvdata->base + TMC_STS); + reg_buf[5] = readl_relaxed(drvdata->base + TMC_RRP); + reg_buf[6] = readl_relaxed(drvdata->base + TMC_RWP); + reg_buf[7] = readl_relaxed(drvdata->base + TMC_TRG); + reg_buf[8] = readl_relaxed(drvdata->base + TMC_CTL); + reg_buf[10] = readl_relaxed(drvdata->base + TMC_MODE); + reg_buf[11] = readl_relaxed(drvdata->base + TMC_LBUFLEVEL); + reg_buf[12] = readl_relaxed(drvdata->base + TMC_CBUFLEVEL); + reg_buf[13] = readl_relaxed(drvdata->base + TMC_BUFWM); + if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) { + reg_buf[14] = readl_relaxed(drvdata->base + TMC_RRPHI); + reg_buf[15] = readl_relaxed(drvdata->base + TMC_RWPHI); + reg_buf[68] = readl_relaxed(drvdata->base + TMC_AXICTL); + reg_buf[70] = readl_relaxed(drvdata->base + TMC_DBALO); + reg_buf[71] = readl_relaxed(drvdata->base + TMC_DBAHI); + } + reg_buf[192] = readl_relaxed(drvdata->base + TMC_FFSR); + reg_buf[193] = readl_relaxed(drvdata->base + TMC_FFCR); + reg_buf[194] = readl_relaxed(drvdata->base + TMC_PSCR); + reg_buf[1000] = readl_relaxed(drvdata->base + CORESIGHT_CLAIMSET); + reg_buf[1001] = readl_relaxed(drvdata->base + CORESIGHT_CLAIMCLR); + reg_buf[1005] = readl_relaxed(drvdata->base + CORESIGHT_LSR); + reg_buf[1006] = readl_relaxed(drvdata->base + CORESIGHT_AUTHSTATUS); + reg_buf[1010] = readl_relaxed(drvdata->base + CORESIGHT_DEVID); + reg_buf[1011] = readl_relaxed(drvdata->base + CORESIGHT_DEVTYPE); + reg_buf[1012] = readl_relaxed(drvdata->base + CORESIGHT_PERIPHIDR4); + reg_buf[1013] = readl_relaxed(drvdata->base + CORESIGHT_PERIPHIDR5); + reg_buf[1014] = readl_relaxed(drvdata->base + CORESIGHT_PERIPHIDR6); + reg_buf[1015] = readl_relaxed(drvdata->base + CORESIGHT_PERIPHIDR7); + reg_buf[1016] = readl_relaxed(drvdata->base + CORESIGHT_PERIPHIDR0); + reg_buf[1017] = readl_relaxed(drvdata->base + CORESIGHT_PERIPHIDR1); + reg_buf[1018] = readl_relaxed(drvdata->base + CORESIGHT_PERIPHIDR2); + reg_buf[1019] = readl_relaxed(drvdata->base + CORESIGHT_PERIPHIDR3); + reg_buf[1020] = readl_relaxed(drvdata->base + CORESIGHT_COMPIDR0); + reg_buf[1021] = readl_relaxed(drvdata->base + CORESIGHT_COMPIDR1); + reg_buf[1022] = readl_relaxed(drvdata->base + CORESIGHT_COMPIDR2); + reg_buf[1023] = readl_relaxed(drvdata->base + CORESIGHT_COMPIDR3); + + dump_data->magic = TMC_REG_DUMP_MAGIC; +} + void tmc_enable_hw(struct tmc_drvdata *drvdata) { drvdata->enable = true; writel_relaxed(TMC_CTL_CAPT_EN, drvdata->base + TMC_CTL); + if (drvdata->force_reg_dump) + __tmc_reg_dump(drvdata); } void tmc_disable_hw(struct tmc_drvdata *drvdata) @@ -650,6 +727,8 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) return -EPROBE_DEFER; } } + if (of_property_read_bool(drvdata->dev->of_node, "qcom,force-reg-dump")) + drvdata->force_reg_dump = true; desc.pdata = pdata; desc.dev = dev; diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 1ca22dd77b50..9583a8bf8cad 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -268,6 +268,7 @@ struct tmc_drvdata { struct idr idr; struct mutex idr_mutex; struct etr_buf *perf_buf; + bool force_reg_dump; }; struct etr_buf_operations { diff --git a/drivers/soc/qcom/memory_dump_v2.c b/drivers/soc/qcom/memory_dump_v2.c index 9ebced6d0113..7db2816e9434 100644 --- a/drivers/soc/qcom/memory_dump_v2.c +++ b/drivers/soc/qcom/memory_dump_v2.c @@ -82,6 +82,7 @@ struct msm_memory_dump { }; static struct msm_memory_dump memdump; +static struct msm_mem_dump_vaddr_tbl vaddr_tbl; /** * update_reg_dump_table - update the register dump table @@ -699,6 +700,28 @@ int msm_dump_data_register_nominidump(enum msm_dump_table_ids id, } EXPORT_SYMBOL(msm_dump_data_register_nominidump); +struct dump_vaddr_entry *get_msm_dump_ptr(enum msm_dump_data_ids id) +{ + int i; + + if (!vaddr_tbl.entries) + return NULL; + + if (id > MSM_DUMP_DATA_MAX) + return NULL; + + for (i = 0; i < vaddr_tbl.num_node; i++) { + if (vaddr_tbl.entries[i].id == id) + break; + } + + if (i == vaddr_tbl.num_node) + return NULL; + + return &vaddr_tbl.entries[i]; +} +EXPORT_SYMBOL(get_msm_dump_ptr); + #define MSM_DUMP_TOTAL_SIZE_OFFSET 0x724 static int init_memory_dump(void *dump_vaddr, phys_addr_t phys_addr, size_t size) @@ -787,6 +810,14 @@ static int mem_dump_alloc(struct platform_device *pdev) uint32_t ns_vmids[] = {VMID_HLOS}; uint32_t ns_vm_perms[] = {PERM_READ | PERM_WRITE}; u64 shm_bridge_handle; + int i = 0; + + vaddr_tbl.num_node = of_get_child_count(node); + vaddr_tbl.entries = devm_kcalloc(&pdev->dev, vaddr_tbl.num_node, + sizeof(struct dump_vaddr_entry), + GFP_KERNEL); + if (!vaddr_tbl.entries) + dev_err(&pdev->dev, "Unable to allocate mem for ptr addr\n"); total_size = size = ret = no_of_nodes = 0; /* For dump table registration with IMEM */ @@ -862,9 +893,16 @@ static int mem_dump_alloc(struct platform_device *pdev) dump_entry.addr = phys_addr; ret = msm_dump_data_register_nominidump(MSM_DUMP_TABLE_APPS, &dump_entry); - if (ret) + if (ret) { dev_err(&pdev->dev, "Data dump setup failed, id = %d\n", id); + } else if (vaddr_tbl.entries) { + vaddr_tbl.entries[i].id = id; + vaddr_tbl.entries[i].dump_vaddr = + dump_vaddr + MSM_DUMP_DATA_SIZE; + vaddr_tbl.entries[i].dump_data_vaddr = dump_data; + i++; + } md_entry.phys_addr = dump_data->addr; md_entry.virt_addr = (uintptr_t)dump_vaddr + MSM_DUMP_DATA_SIZE; diff --git a/include/soc/qcom/memory_dump.h b/include/soc/qcom/memory_dump.h index bc84bc8d8ef8..d3f514add392 100644 --- a/include/soc/qcom/memory_dump.h +++ b/include/soc/qcom/memory_dump.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2012, 2014-2017, 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2012, 2014-2017, 2019, 2021, The Linux Foundation. All rights reserved. */ #ifndef __MSM_MEMORY_DUMP_H @@ -79,6 +79,8 @@ enum msm_dump_data_ids { MSM_DUMP_DATA_TMC_ETF = 0xF0, MSM_DUMP_DATA_TMC_ETF_SWAO = 0xF1, MSM_DUMP_DATA_TMC_REG = 0x100, + MSM_DUMP_DATA_TMC_ETR_REG = 0x100, + MSM_DUMP_DATA_TMC_ETF_REG = 0x101, MSM_DUMP_DATA_TMC_ETF_SWAO_REG = 0x102, MSM_DUMP_DATA_LOG_BUF = 0x110, MSM_DUMP_DATA_LOG_BUF_FIRST_IDX = 0x111, @@ -113,11 +115,23 @@ struct msm_dump_entry { uint64_t addr; }; +struct dump_vaddr_entry { + uint32_t id; + void *dump_vaddr; + struct msm_dump_data *dump_data_vaddr; +}; + +struct msm_mem_dump_vaddr_tbl { + uint8_t num_node; + struct dump_vaddr_entry *entries; +}; + #ifdef CONFIG_QCOM_MEMORY_DUMP_V2 extern int msm_dump_data_register(enum msm_dump_table_ids id, struct msm_dump_entry *entry); extern int msm_dump_data_register_nominidump(enum msm_dump_table_ids id, struct msm_dump_entry *entry); +extern struct dump_vaddr_entry *get_msm_dump_ptr(enum msm_dump_data_ids id); #else static inline int msm_dump_data_register(enum msm_dump_table_ids id, struct msm_dump_entry *entry)