Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b8360c97 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "soc: qcom: memory_dump_v2: add client support for memory dump v2"

parents c07cc526 689346a4
Loading
Loading
Loading
Loading
+100 −13
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <soc/qcom/scm.h>
#include <asm/cacheflush.h>
#include <mach/msm_cache_dump.h>
@@ -65,13 +66,17 @@ static int msm_cache_dump_probe(struct platform_device *pdev)
{
	struct msm_cache_dump_platform_data *d = pdev->dev.platform_data;
	struct msm_client_dump l1_dump_entry, l2_dump_entry;
	int ret;
	struct msm_dump_entry dump_entry;
	struct msm_dump_data *l1_inst_data, *l1_data_data, *l2_data;
	int ret, cpu;
	struct {
		unsigned long buf;
		unsigned long size;
	} l1_cache_data;
	u32 l1_size, l2_size;
	unsigned long total_size;
	u32 l1_inst_size, l1_data_size;
	phys_addr_t l1_inst_start, l1_data_start, l2_start;

	if (pdev->dev.of_node) {
		ret = of_property_read_u32(pdev->dev.of_node,
@@ -130,6 +135,7 @@ static int msm_cache_dump_probe(struct platform_device *pdev)
			__func__, ret);
#endif

	if (MSM_DUMP_MAJOR(msm_dump_table_version()) == 1) {
		l1_dump_entry.id = MSM_L1_CACHE;
		l1_dump_entry.start_addr = msm_cache_dump_addr;
		l1_dump_entry.end_addr = l1_dump_entry.start_addr + l1_size - 1;
@@ -145,10 +151,91 @@ static int msm_cache_dump_probe(struct platform_device *pdev)
		ret = msm_dump_tbl_register(&l2_dump_entry);
		if (ret)
			pr_err("Could not register L2 dump area: %d\n", ret);
	} else {
		l1_inst_data = kzalloc(sizeof(struct msm_dump_data) *
				       num_present_cpus(), GFP_KERNEL);
		if (!l1_inst_data) {
			pr_err("l1 inst data structure allocation failed\n");
			ret = -ENOMEM;
			goto err0;
		}

		l1_data_data = kzalloc(sizeof(struct msm_dump_data) *
				       num_present_cpus(), GFP_KERNEL);
		if (!l1_data_data) {
			pr_err("l1 data data structure allocation failed\n");
			ret = -ENOMEM;
			goto err1;
		}

		l1_inst_start = msm_cache_dump_addr;
		l1_data_start = msm_cache_dump_addr + (l1_size / 2);
		l1_inst_size = l1_size / (num_present_cpus() * 2);
		l1_data_size = l1_inst_size;

		for_each_cpu(cpu, cpu_present_mask) {
			l1_inst_data[cpu].addr = l1_inst_start +
							cpu * l1_inst_size;
			l1_inst_data[cpu].len = l1_inst_size;
			dump_entry.id = MSM_DUMP_DATA_L1_INST_CACHE + cpu;
			dump_entry.addr = virt_to_phys(&l1_inst_data[cpu]);
			ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS,
						     &dump_entry);
			/*
			 * Don't free the buffers in case of error since
			 * registration may have succeeded for some cpus.
			 */
			if (ret)
				pr_err("cpu %d l1 inst dump setup failed\n",
					cpu);

			l1_data_data[cpu].addr = l1_data_start +
							cpu * l1_data_size;
			l1_data_data[cpu].len = l1_data_size;
			dump_entry.id = MSM_DUMP_DATA_L1_DATA_CACHE + cpu;
			dump_entry.addr = virt_to_phys(&l1_data_data[cpu]);
			ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS,
						     &dump_entry);
			/*
			 * Don't free the buffers in case of error since
			 * registration may have succeeded for some cpus.
			 */
			if (ret)
				pr_err("cpu %d l1 data dump setup failed\n",
					cpu);
		}

		l2_data = kzalloc(sizeof(struct msm_dump_data) *
				  num_present_cpus(), GFP_KERNEL);
		if (!l2_data) {
			pr_err("l2 data structure allocation failed\n");
			ret = -ENOMEM;
			goto err2;
		}

		l2_start = msm_cache_dump_addr + l1_size;

		l2_data->addr = l2_start;
		l2_data->len = l2_size;
		dump_entry.id = MSM_DUMP_DATA_L2_CACHE;
		dump_entry.addr = virt_to_phys(l2_data);
		ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS,
					     &dump_entry);
		if (ret)
			pr_err("l2 dump setup failed\n");
	}

	atomic_notifier_chain_register(&panic_notifier_list,
						&msm_cache_dump_blk);
	return 0;
err2:
	kfree(l1_data_data);
err1:
	kfree(l1_inst_data);
err0:
	dma_free_coherent(&pdev->dev, total_size, msm_cache_dump_vaddr,
			  msm_cache_dump_addr);
	return ret;
}

static int msm_cache_dump_remove(struct platform_device *pdev)
+30 −11
Original line number Diff line number Diff line
@@ -261,6 +261,7 @@ struct etm_drvdata {
	bool				pcsave_sticky_enable;
	bool				pcsave_boot_enable;
	bool				round_robin;
	struct msm_dump_data		reg_data;
};

static struct etm_drvdata *etmdrvdata[NR_CPUS];
@@ -2111,6 +2112,7 @@ static int etm_probe(struct platform_device *pdev)
	static int count;
	void *baddr;
	struct msm_client_dump dump;
	struct msm_dump_entry dump_entry;
	struct coresight_desc *desc;

	if (coresight_fuse_access_disabled() ||
@@ -2194,20 +2196,37 @@ static int etm_probe(struct platform_device *pdev)
		drvdata->round_robin = of_property_read_bool(pdev->dev.of_node,
							"qcom,round-robin");

	if (MSM_DUMP_MAJOR(msm_dump_table_version()) == 1) {
		baddr = devm_kzalloc(dev, PAGE_SIZE + reg_size, GFP_KERNEL);
		if (baddr) {
		*(uint32_t *)(baddr + ETM_REG_DUMP_VER_OFF) = ETM_REG_DUMP_VER;
			dump.id = MSM_ETM0_REG + drvdata->cpu;
			dump.start_addr = virt_to_phys(baddr);
			dump.end_addr = dump.start_addr + PAGE_SIZE + reg_size;
			ret = msm_dump_tbl_register(&dump);
			if (ret) {
				devm_kfree(dev, baddr);
			dev_err(dev, "ETM REG dump setup failed/unsupported\n");
				dev_err(dev, "ETM REG dump setup failed\n");
			}
		} else {
			dev_err(dev, "ETM REG dump space allocation failed\n");
		}
	} else {
		baddr = devm_kzalloc(dev, reg_size, GFP_KERNEL);
		if (baddr) {
			drvdata->reg_data.addr = virt_to_phys(baddr);
			drvdata->reg_data.len = reg_size;
			dump_entry.id = MSM_DUMP_DATA_ETM_REG + drvdata->cpu;
			dump_entry.addr = virt_to_phys(&drvdata->reg_data);
			ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS,
						     &dump_entry);
			if (ret) {
				devm_kfree(dev, baddr);
				dev_err(dev, "ETM REG dump setup failed\n");
			}
		} else {
			dev_err(dev, "ETM REG dump space allocation failed\n");
		}
	}

	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
	if (!desc) {
+101 −37
Original line number Diff line number Diff line
@@ -152,7 +152,9 @@ struct tmc_drvdata {
	bool			reading;
	bool			aborting;
	char			*reg_buf;
	struct msm_dump_data	reg_data;
	char			*buf;
	struct msm_dump_data	buf_data;
	dma_addr_t		paddr;
	void __iomem		*vaddr;
	uint32_t		size;
@@ -647,6 +649,12 @@ static void __tmc_reg_dump(struct tmc_drvdata *drvdata)
		return;

	reg_hdr = drvdata->reg_buf - PAGE_SIZE;
	if (MSM_DUMP_MAJOR(msm_dump_table_version()) == 1)
		*(uint32_t *)(reg_hdr + TMC_REG_DUMP_VER_OFF) =
							TMC_REG_DUMP_VER;
	else
		drvdata->reg_data.version = TMC_REG_DUMP_VER;

	reg_buf = (uint32_t *)drvdata->reg_buf;

	reg_buf[1] = tmc_readl(drvdata, TMC_RSZ);
@@ -688,7 +696,11 @@ static void __tmc_reg_dump(struct tmc_drvdata *drvdata)
	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;
	if (MSM_DUMP_MAJOR(msm_dump_table_version()) == 1)
		*(uint32_t *)(reg_hdr + TMC_REG_DUMP_MAGIC_OFF) =
							TMC_REG_DUMP_MAGIC;
	else
		drvdata->reg_data.magic = TMC_REG_DUMP_MAGIC;
}

static void __tmc_etb_dump(struct tmc_drvdata *drvdata)
@@ -700,6 +712,13 @@ static void __tmc_etb_dump(struct tmc_drvdata *drvdata)
	uint32_t read_data;
	int i;

	hdr = drvdata->buf - PAGE_SIZE;
	if (MSM_DUMP_MAJOR(msm_dump_table_version()) == 1)
		*(uint32_t *)(hdr + TMC_ETFETB_DUMP_VER_OFF) =
							TMC_ETFETB_DUMP_VER;
	else
		drvdata->buf_data.version = TMC_ETFETB_DUMP_VER;

	memwidth = BMVAL(tmc_readl(drvdata, CORESIGHT_DEVID), 8, 10);
	if (memwidth == TMC_MEM_INTF_WIDTH_32BITS)
		memwords = 1;
@@ -723,9 +742,11 @@ static void __tmc_etb_dump(struct tmc_drvdata *drvdata)

out:
	if (drvdata->aborting) {
		hdr = drvdata->buf - PAGE_SIZE;
		if (MSM_DUMP_MAJOR(msm_dump_table_version()) == 1)
			*(uint32_t *)(hdr + TMC_ETFETB_DUMP_MAGIC_OFF) =
							TMC_ETFETB_DUMP_MAGIC;
		else
			drvdata->buf_data.magic = TMC_ETFETB_DUMP_MAGIC;
	}
}

@@ -1636,6 +1657,7 @@ static int tmc_probe(struct platform_device *pdev)
	static int count;
	void *baddr;
	struct msm_client_dump dump;
	struct msm_dump_entry dump_entry;
	struct coresight_cti_data *ctidata;
	struct coresight_desc *desc;

@@ -1716,44 +1738,86 @@ static int tmc_probe(struct platform_device *pdev)
		if (ret)
			goto err1;
	} else {
		if (MSM_DUMP_MAJOR(msm_dump_table_version()) == 1) {
			baddr = devm_kzalloc(dev, PAGE_SIZE + drvdata->size,
					     GFP_KERNEL);
			if (!baddr)
				return -ENOMEM;
			drvdata->buf = baddr + PAGE_SIZE;
		*(uint32_t *)(baddr + TMC_ETFETB_DUMP_VER_OFF) =
							TMC_ETFETB_DUMP_VER;

			dump.id = MSM_TMC_ETFETB + etfetb_count;
			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_tbl_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 or
		 * as part of abort.
			 * 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)
			dev_info(dev, "TMC ETF-ETB dump setup failed\n");
				dev_err(dev, "TMC ETF-ETB dump setup failed\n");
		} else {
			drvdata->buf = devm_kzalloc(dev, drvdata->size,
						    GFP_KERNEL);
			if (!drvdata->buf)
				return -ENOMEM;

			drvdata->buf_data.addr = virt_to_phys(drvdata->buf);
			drvdata->buf_data.len = drvdata->size;
			dump_entry.id = MSM_DUMP_DATA_TMC_ETF + etfetb_count;
			dump_entry.addr = virt_to_phys(&drvdata->buf_data);
			ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS,
						     &dump_entry);
			/*
			 * 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)
				dev_err(dev, "TMC ETF-ETB dump setup failed\n");
		}
		etfetb_count++;
	}

	if (MSM_DUMP_MAJOR(msm_dump_table_version()) == 1) {
		baddr = devm_kzalloc(dev, PAGE_SIZE + reg_size, GFP_KERNEL);
		if (baddr) {
			drvdata->reg_buf = baddr + PAGE_SIZE;
		*(uint32_t *)(baddr + TMC_REG_DUMP_VER_OFF) = TMC_REG_DUMP_VER;

			dump.id = MSM_TMC0_REG + count;
			dump.start_addr = virt_to_phys(baddr);
			dump.end_addr = dump.start_addr + PAGE_SIZE + reg_size;
			ret = msm_dump_tbl_register(&dump);
			/*
		 * 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.
			 * 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_err(dev, "TMC REG dump setup failed\n");
		} else {
		dev_info(dev, "TMC REG dump space allocation failed\n");
			dev_err(dev, "TMC REG dump allocation failed\n");
		}
	} else {
		drvdata->reg_buf = devm_kzalloc(dev, reg_size, GFP_KERNEL);
		if (drvdata->reg_buf) {
			drvdata->reg_data.addr = virt_to_phys(drvdata->reg_buf);
			drvdata->reg_data.len = reg_size;
			dump_entry.id = MSM_DUMP_DATA_TMC_REG + count;
			dump_entry.addr = virt_to_phys(&drvdata->reg_data);
			ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS,
						     &dump_entry);
			/*
			 * 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_err(dev, "TMC REG dump setup failed\n");
		} else {
			dev_err(dev, "TMC REG dump allocation failed\n");
		}
	}
	count++;

+65 −21
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@
#define MASK_SIZE		32
#define SCM_SET_REGSAVE_CMD	0x2
#define SCM_SVC_SEC_WDOG_DIS	0x7
#define MAX_CPU_CTX_SIZE	512

static struct workqueue_struct *wdog_wq;

@@ -359,12 +360,17 @@ static irqreturn_t wdog_ppi_bark(int irq, void *dev_id)
static void configure_bark_dump(struct msm_watchdog_data *wdog_dd)
{
	int ret;
	struct msm_client_dump dump_entry;
	struct msm_client_dump cpu_dump_entry;
	struct msm_dump_entry dump_entry;
	struct msm_dump_data *cpu_data;
	int cpu;
	void *cpu_buf;
	struct {
		unsigned addr;
		int len;
	} cmd_buf;

	if (MSM_DUMP_MAJOR(msm_dump_table_version()) == 1) {
		wdog_dd->scm_regsave = (void *)__get_free_page(GFP_KERNEL);
		if (wdog_dd->scm_regsave) {
			cmd_buf.addr = virt_to_phys(wdog_dd->scm_regsave);
@@ -375,10 +381,12 @@ static void configure_bark_dump(struct msm_watchdog_data *wdog_dd)
				pr_err("Setting register save address failed.\n"
				       "Registers won't be dumped on a dog "
				       "bite\n");
		dump_entry.id = MSM_CPU_CTXT;
		dump_entry.start_addr = virt_to_phys(wdog_dd->scm_regsave);
		dump_entry.end_addr = dump_entry.start_addr + PAGE_SIZE;
		ret = msm_dump_tbl_register(&dump_entry);
			cpu_dump_entry.id = MSM_CPU_CTXT;
			cpu_dump_entry.start_addr =
					virt_to_phys(wdog_dd->scm_regsave);
			cpu_dump_entry.end_addr = cpu_dump_entry.start_addr +
						  PAGE_SIZE;
			ret = msm_dump_tbl_register(&cpu_dump_entry);
			if (ret)
				pr_err("Setting cpu dump region failed\n"
				"Registers wont be dumped during cpu hang\n");
@@ -391,6 +399,42 @@ static void configure_bark_dump(struct msm_watchdog_data *wdog_dd)
			 * without saving registers.
			 */
		}
	} else {
		cpu_data = kzalloc(sizeof(struct msm_dump_data) *
				   num_present_cpus(), GFP_KERNEL);
		if (!cpu_data) {
			pr_err("cpu dump data structure allocation failed\n");
			goto out0;
		}
		cpu_buf = kzalloc(MAX_CPU_CTX_SIZE * num_present_cpus(),
				  GFP_KERNEL);
		if (!cpu_buf) {
			pr_err("cpu reg context space allocation failed\n");
			goto out1;
		}

		for_each_cpu(cpu, cpu_present_mask) {
			cpu_data[cpu].addr = virt_to_phys(cpu_buf +
							cpu * MAX_CPU_CTX_SIZE);
			cpu_data[cpu].len = MAX_CPU_CTX_SIZE;
			dump_entry.id = MSM_DUMP_DATA_CPU_CTX + cpu;
			dump_entry.addr = virt_to_phys(&cpu_data[cpu]);
			ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS,
						     &dump_entry);
			/*
			 * Don't free the buffers in case of error since
			 * registration may have succeeded for some cpus.
			 */
			if (ret)
				pr_err("cpu %d reg dump setup failed\n", cpu);
		}
	}

	return;
out1:
	kfree(cpu_data);
out0:
	return;
}