soc: qcom: Add snapshot of the cpuss driver

This snapshot is taken as of msm-3.18 commit dacccc6.

CRs-Fixed: 1011333
Change-Id: I4ed06b5602220ed4e30bd37a0633ccb3454f7d43
Signed-off-by: Runmin Wang <runminw@codeaurora.org>
This commit is contained in:
Runmin Wang 2016-05-03 16:31:23 -07:00 committed by Jeevan Shriram
parent a0c23c20d1
commit 9669bbda4d
4 changed files with 162 additions and 0 deletions

View file

@ -0,0 +1,27 @@
CPU Subsystem Dump Driver
The CPU Subsystem dump driver is used to dump various hardware entities
like the instruction and data tlbs or the unified tlbs etc. to an
allocated buffer. This allows the data to be analysed in case of corruption.
Required Properties for the cpuss_dump node:
-compatible = "qcom,cpuss-dump";
All child nodes of cpuss_dump node are interpreted as the various hardware
entities which need to be dumped.
Required properties of the dump nodes
- qcom,dump-node: phandle to the acutal cpuss hardware entity present
in the cpu map
- qcom,dump-id: The ID within the data dump table where this entry needs to
be added.
Example:
msm_cpuss_dump {
compatible = "qcom,cpuss-dump";
qcom,itlb_dump100 {
qcom,dump-node = <&L1_itlb_100>;
qcom,dump-id = <34>;
};
};

View file

@ -460,6 +460,15 @@ config MSM_BOOT_STATS
This figures are reported in mpm sleep clock cycles and have a This figures are reported in mpm sleep clock cycles and have a
resolution of 31 bits as 1 bit is used as an overflow check. resolution of 31 bits as 1 bit is used as an overflow check.
config QCOM_CPUSS_DUMP
bool "CPU Subsystem Dumping support"
help
Add support to dump various hardware entities such as the instruction
and data tlb's as well as the unified tlb, which are a part of the
cpu subsystem to an allocated buffer. This allows for analysis of the
the entities if corruption is suspected.
If unsure, say N
config MSM_QDSP6_APRV2 config MSM_QDSP6_APRV2
bool "Audio QDSP6 APRv2 support" bool "Audio QDSP6 APRv2 support"
depends on MSM_SMD depends on MSM_SMD

View file

@ -50,6 +50,7 @@ endif
obj-$(CONFIG_QPNP_HAPTIC) += qpnp-haptic.o obj-$(CONFIG_QPNP_HAPTIC) += qpnp-haptic.o
obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o
obj-$(CONFIG_QCOM_CPUSS_DUMP) += cpuss_dump.o
obj-$(CONFIG_QCOM_PM) += spm.o obj-$(CONFIG_QCOM_PM) += spm.o
obj-$(CONFIG_QCOM_SMD) += smd.o obj-$(CONFIG_QCOM_SMD) += smd.o
obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o

View file

@ -0,0 +1,125 @@
/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <soc/qcom/memory_dump.h>
static int cpuss_dump_probe(struct platform_device *pdev)
{
struct device_node *child_node, *dump_node;
const struct device_node *node = pdev->dev.of_node;
static dma_addr_t dump_addr;
static void *dump_vaddr;
struct msm_dump_data *dump_data;
struct msm_dump_entry dump_entry;
int ret;
u32 size, id;
for_each_available_child_of_node(node, child_node) {
dump_node = of_parse_phandle(child_node, "qcom,dump-node", 0);
if (!dump_node) {
dev_err(&pdev->dev, "Unable to find node for %s\n",
child_node->name);
continue;
}
ret = of_property_read_u32(dump_node, "qcom,dump-size", &size);
if (ret) {
dev_err(&pdev->dev, "Unable to find size for %s\n",
dump_node->name);
continue;
}
ret = of_property_read_u32(child_node, "qcom,dump-id", &id);
if (ret) {
dev_err(&pdev->dev, "Unable to find id for %s\n",
child_node->name);
continue;
}
dump_vaddr = (void *) dma_alloc_coherent(&pdev->dev, size,
&dump_addr, GFP_KERNEL);
if (!dump_vaddr) {
dev_err(&pdev->dev, "Couldn't get memory for dumping\n");
continue;
}
memset(dump_vaddr, 0x0, size);
dump_data = devm_kzalloc(&pdev->dev,
sizeof(struct msm_dump_data), GFP_KERNEL);
if (!dump_data) {
dev_err(&pdev->dev, "Dump data allocation failed\n");
dma_free_coherent(&pdev->dev, size, dump_vaddr,
dump_addr);
continue;
}
dump_data->addr = dump_addr;
dump_data->len = size;
dump_entry.id = id;
dump_entry.addr = virt_to_phys(dump_data);
ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
if (ret) {
dev_err(&pdev->dev, "Data dump setup failed, id = %d\n",
id);
dma_free_coherent(&pdev->dev, size, dump_vaddr,
dump_addr);
devm_kfree(&pdev->dev, dump_data);
}
}
return 0;
}
static int cpuss_dump_remove(struct platform_device *pdev)
{
return 0;
}
static const struct of_device_id cpuss_dump_match_table[] = {
{ .compatible = "qcom,cpuss-dump", },
{}
};
static struct platform_driver cpuss_dump_driver = {
.probe = cpuss_dump_probe,
.remove = cpuss_dump_remove,
.driver = {
.name = "msm_cpuss_dump",
.owner = THIS_MODULE,
.of_match_table = cpuss_dump_match_table,
},
};
static int __init cpuss_dump_init(void)
{
return platform_driver_register(&cpuss_dump_driver);
}
static void __exit cpuss_dump_exit(void)
{
platform_driver_unregister(&cpuss_dump_driver);
}
subsys_initcall(cpuss_dump_init);
module_exit(cpuss_dump_exit)