blob: 8b4978f2dff6844d3ddd209b0628e386f780bf65 [file] [log] [blame]
Laura Abbott306bcc22012-03-08 11:24:53 -08001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/io.h>
18#include <linux/delay.h>
19#include <linux/workqueue.h>
20#include <linux/platform_device.h>
21#include <linux/pm.h>
22#include <linux/memory_alloc.h>
Laura Abbott7b637362012-03-29 16:43:49 -070023#include <linux/notifier.h>
Stepan Moskovchenko872c75f2012-09-12 18:49:59 -070024#include <linux/of.h>
25#include <linux/of_device.h>
Laura Abbott306bcc22012-03-08 11:24:53 -080026#include <mach/scm.h>
27#include <mach/msm_cache_dump.h>
28#include <mach/memory.h>
29#include <mach/msm_iomap.h>
Stepan Moskovchenko872c75f2012-09-12 18:49:59 -070030#include <mach/msm_memory_dump.h>
Laura Abbott306bcc22012-03-08 11:24:53 -080031
Laura Abbott520cdce2012-05-10 16:22:33 -070032#define L2_DUMP_OFFSET 0x14
Laura Abbott306bcc22012-03-08 11:24:53 -080033
34static unsigned long msm_cache_dump_addr;
35
36/*
Laura Abbottbeeca592012-05-25 14:50:08 -070037 * These should not actually be dereferenced. There's no
38 * need for a virtual mapping, but the physical address is
39 * necessary.
Laura Abbott306bcc22012-03-08 11:24:53 -080040 */
Laura Abbottbeeca592012-05-25 14:50:08 -070041static struct l1_cache_dump *l1_dump;
42static struct l2_cache_dump *l2_dump;
Stepan Moskovchenko872c75f2012-09-12 18:49:59 -070043static int use_imem_dump_offset;
Laura Abbott306bcc22012-03-08 11:24:53 -080044
Laura Abbott7b637362012-03-29 16:43:49 -070045static int msm_cache_dump_panic(struct notifier_block *this,
46 unsigned long event, void *ptr)
47{
48#ifdef CONFIG_MSM_CACHE_DUMP_ON_PANIC
Laura Abbott0f3bd612012-05-10 16:27:31 -070049 /*
50 * Clear the bootloader magic so the dumps aren't overwritten
51 */
Stepan Moskovchenko872c75f2012-09-12 18:49:59 -070052 if (use_imem_dump_offset)
53 __raw_writel(0, MSM_IMEM_BASE + L2_DUMP_OFFSET);
Laura Abbott0f3bd612012-05-10 16:27:31 -070054
Laura Abbott7b637362012-03-29 16:43:49 -070055 scm_call_atomic1(L1C_SERVICE_ID, CACHE_BUFFER_DUMP_COMMAND_ID, 2);
56 scm_call_atomic1(L1C_SERVICE_ID, CACHE_BUFFER_DUMP_COMMAND_ID, 1);
57#endif
58 return 0;
59}
60
61static struct notifier_block msm_cache_dump_blk = {
62 .notifier_call = msm_cache_dump_panic,
63 /*
64 * higher priority to ensure this runs before another panic handler
65 * flushes the caches.
66 */
67 .priority = 1,
68};
69
Laura Abbott306bcc22012-03-08 11:24:53 -080070static int msm_cache_dump_probe(struct platform_device *pdev)
71{
72 struct msm_cache_dump_platform_data *d = pdev->dev.platform_data;
Stepan Moskovchenko872c75f2012-09-12 18:49:59 -070073 struct msm_client_dump l1_dump_entry, l2_dump_entry;
Laura Abbott306bcc22012-03-08 11:24:53 -080074 int ret;
75 struct {
76 unsigned long buf;
77 unsigned long size;
78 } l1_cache_data;
Laura Abbott306bcc22012-03-08 11:24:53 -080079 void *temp;
Stepan Moskovchenko872c75f2012-09-12 18:49:59 -070080 u32 l1_size, l2_size;
81 unsigned long total_size;
Laura Abbott306bcc22012-03-08 11:24:53 -080082
Stepan Moskovchenko872c75f2012-09-12 18:49:59 -070083 if (pdev->dev.of_node) {
84 ret = of_property_read_u32(pdev->dev.of_node,
85 "qcom,l1-dump-size", &l1_size);
86 if (ret)
87 return ret;
88
89 ret = of_property_read_u32(pdev->dev.of_node,
90 "qcom,l2-dump-size", &l2_size);
91 if (ret)
92 return ret;
93
94 use_imem_dump_offset = of_property_read_bool(pdev->dev.of_node,
95 "qcom,use-imem-dump-offset");
96 } else {
97 l1_size = d->l1_size;
98 l2_size = d->l2_size;
99
100 /* Non-DT targets assume the IMEM dump offset shall be used */
101 use_imem_dump_offset = 1;
102 };
103
104 total_size = l1_size + l2_size;
Laura Abbott306bcc22012-03-08 11:24:53 -0800105 msm_cache_dump_addr = allocate_contiguous_ebi_nomap(total_size, SZ_4K);
106
107 if (!msm_cache_dump_addr) {
108 pr_err("%s: Could not get memory for cache dumping\n",
109 __func__);
110 return -ENOMEM;
111 }
112
113 temp = ioremap(msm_cache_dump_addr, total_size);
114 memset(temp, 0xFF, total_size);
115 iounmap(temp);
116
117 l1_cache_data.buf = msm_cache_dump_addr;
Stepan Moskovchenko872c75f2012-09-12 18:49:59 -0700118 l1_cache_data.size = l1_size;
Laura Abbott306bcc22012-03-08 11:24:53 -0800119
120 ret = scm_call(L1C_SERVICE_ID, L1C_BUFFER_SET_COMMAND_ID,
121 &l1_cache_data, sizeof(l1_cache_data), NULL, 0);
122
123 if (ret)
124 pr_err("%s: could not register L1 buffer ret = %d.\n",
125 __func__, ret);
126
Laura Abbottbeeca592012-05-25 14:50:08 -0700127 l1_dump = (struct l1_cache_dump *)msm_cache_dump_addr;
Stepan Moskovchenko872c75f2012-09-12 18:49:59 -0700128 l2_dump = (struct l2_cache_dump *)(msm_cache_dump_addr + l1_size);
Laura Abbottbeeca592012-05-25 14:50:08 -0700129
Laura Abbott7b637362012-03-29 16:43:49 -0700130#if defined(CONFIG_MSM_CACHE_DUMP_ON_PANIC)
Stepan Moskovchenko872c75f2012-09-12 18:49:59 -0700131 l1_cache_data.buf = msm_cache_dump_addr + l1_size;
132 l1_cache_data.size = l2_size;
Laura Abbott7b637362012-03-29 16:43:49 -0700133
134 ret = scm_call(L1C_SERVICE_ID, L2C_BUFFER_SET_COMMAND_ID,
135 &l1_cache_data, sizeof(l1_cache_data), NULL, 0);
136
137 if (ret)
138 pr_err("%s: could not register L2 buffer ret = %d.\n",
139 __func__, ret);
Laura Abbott0f3bd612012-05-10 16:27:31 -0700140#endif
Stepan Moskovchenko872c75f2012-09-12 18:49:59 -0700141
142 if (use_imem_dump_offset)
143 __raw_writel(msm_cache_dump_addr + l1_size,
Laura Abbott520cdce2012-05-10 16:22:33 -0700144 MSM_IMEM_BASE + L2_DUMP_OFFSET);
Stepan Moskovchenko872c75f2012-09-12 18:49:59 -0700145 else {
146 l1_dump_entry.id = MSM_L1_CACHE;
147 l1_dump_entry.start_addr = msm_cache_dump_addr;
148 l1_dump_entry.end_addr = l1_dump_entry.start_addr + l1_size - 1;
Laura Abbott306bcc22012-03-08 11:24:53 -0800149
Stepan Moskovchenko872c75f2012-09-12 18:49:59 -0700150 l2_dump_entry.id = MSM_L2_CACHE;
151 l2_dump_entry.start_addr = msm_cache_dump_addr + l1_size;
152 l2_dump_entry.end_addr = l2_dump_entry.start_addr + l2_size - 1;
Laura Abbottbeeca592012-05-25 14:50:08 -0700153
Stepan Moskovchenko872c75f2012-09-12 18:49:59 -0700154 ret = msm_dump_table_register(&l1_dump_entry);
155 if (ret)
156 pr_err("Could not register L1 dump area: %d\n", ret);
157
158 ret = msm_dump_table_register(&l2_dump_entry);
159 if (ret)
160 pr_err("Could not register L2 dump area: %d\n", ret);
161 }
Laura Abbottbeeca592012-05-25 14:50:08 -0700162
Laura Abbott7b637362012-03-29 16:43:49 -0700163 atomic_notifier_chain_register(&panic_notifier_list,
164 &msm_cache_dump_blk);
165 return 0;
166}
167
168static int msm_cache_dump_remove(struct platform_device *pdev)
169{
170 atomic_notifier_chain_unregister(&panic_notifier_list,
171 &msm_cache_dump_blk);
Laura Abbott306bcc22012-03-08 11:24:53 -0800172 return 0;
173}
174
Stepan Moskovchenko872c75f2012-09-12 18:49:59 -0700175static struct of_device_id cache_dump_match_table[] = {
176 { .compatible = "qcom,cache_dump", },
177 {}
178};
179EXPORT_COMPAT("qcom,cache_dump");
180
Laura Abbott306bcc22012-03-08 11:24:53 -0800181static struct platform_driver msm_cache_dump_driver = {
Laura Abbott7b637362012-03-29 16:43:49 -0700182 .remove = __devexit_p(msm_cache_dump_remove),
Laura Abbott306bcc22012-03-08 11:24:53 -0800183 .driver = {
184 .name = "msm_cache_dump",
Stepan Moskovchenko872c75f2012-09-12 18:49:59 -0700185 .owner = THIS_MODULE,
186 .of_match_table = cache_dump_match_table,
Laura Abbott306bcc22012-03-08 11:24:53 -0800187 },
188};
189
190static int __init msm_cache_dump_init(void)
191{
192 return platform_driver_probe(&msm_cache_dump_driver,
193 msm_cache_dump_probe);
194}
195
196static void __exit msm_cache_dump_exit(void)
197{
198 platform_driver_unregister(&msm_cache_dump_driver);
199}
200late_initcall(msm_cache_dump_init);
201module_exit(msm_cache_dump_exit)