blob: 6e79dfe70dd1b221cc3d0783ea61f1c9bd42f5a0 [file] [log] [blame]
Laura Abbottad340ff2012-01-04 14:23:48 -08001/*
2 * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/atomic.h>
15#include <linux/export.h>
16#include <linux/kernel.h>
17#include <linux/memory_alloc.h>
18#include <linux/module.h>
Laura Abbottf8c03b92012-02-16 14:57:58 -080019#include <linux/platform_device.h>
Laura Abbottad340ff2012-01-04 14:23:48 -080020#include <linux/sched.h>
21#include <linux/slab.h>
22#include <linux/string.h>
23#include <asm/io.h>
24#include <asm-generic/sizes.h>
25#include <mach/memory.h>
26#include <mach/msm_rtb.h>
27#include <mach/system.h>
28
29#define SENTINEL_BYTE_1 0xFF
30#define SENTINEL_BYTE_2 0xAA
31#define SENTINEL_BYTE_3 0xFF
32
33/* Write
34 * 1) 3 bytes sentinel
35 * 2) 1 bytes of log type
36 * 3) 4 bytes of where the caller came from
37 * 4) 4 bytes index
38 * 4) 4 bytes extra data from the caller
39 *
40 * Total = 16 bytes.
41 */
42struct msm_rtb_layout {
43 unsigned char sentinel[3];
44 unsigned char log_type;
45 void *caller;
46 unsigned long idx;
47 void *data;
48} __attribute__ ((__packed__));
49
50
51struct msm_rtb_state {
52 struct msm_rtb_layout *rtb;
53 unsigned long phys;
54 int nentries;
55 int size;
56 int enabled;
57 uint32_t filter;
58 int step_size;
59};
60
61#if defined(CONFIG_MSM_RTB_SEPARATE_CPUS)
62DEFINE_PER_CPU(atomic_t, msm_rtb_idx_cpu);
63#else
64static atomic_t msm_rtb_idx;
65#endif
66
67struct msm_rtb_state msm_rtb = {
Laura Abbottaa9b60b2012-01-23 13:06:20 -080068 .filter = 1 << LOGK_LOGBUF,
Laura Abbottad340ff2012-01-04 14:23:48 -080069};
70
71module_param_named(filter, msm_rtb.filter, uint, 0644);
72module_param_named(enable, msm_rtb.enabled, int, 0644);
73
74int msm_rtb_event_should_log(enum logk_event_type log_type)
75{
76 return msm_rtb.enabled &&
77 ((1 << log_type) & msm_rtb.filter);
78}
79EXPORT_SYMBOL(msm_rtb_event_should_log);
80
81static void msm_rtb_emit_sentinel(struct msm_rtb_layout *start)
82{
83 start->sentinel[0] = SENTINEL_BYTE_1;
84 start->sentinel[1] = SENTINEL_BYTE_2;
85 start->sentinel[2] = SENTINEL_BYTE_3;
86}
87
88static void msm_rtb_write_type(enum logk_event_type log_type,
89 struct msm_rtb_layout *start)
90{
91 start->log_type = (char)log_type;
92}
93
94static void msm_rtb_write_caller(void *caller, struct msm_rtb_layout *start)
95{
96 start->caller = caller;
97}
98
99static void msm_rtb_write_idx(unsigned long idx,
100 struct msm_rtb_layout *start)
101{
102 start->idx = idx;
103}
104
105static void msm_rtb_write_data(void *data, struct msm_rtb_layout *start)
106{
107 start->data = data;
108}
109
Laura Abbottad340ff2012-01-04 14:23:48 -0800110#if defined(CONFIG_MSM_RTB_SEPARATE_CPUS)
111static int msm_rtb_get_idx(void)
112{
113 int cpu, i;
114 atomic_t *index;
115
116 /*
117 * ideally we would use get_cpu but this is a close enough
118 * approximation for our purposes.
119 */
120 cpu = raw_smp_processor_id();
121
122 index = &per_cpu(msm_rtb_idx_cpu, cpu);
123
124 i = atomic_add_return(msm_rtb.step_size, index);
125 i -= msm_rtb.step_size;
126
127 return i;
128}
129#else
130static int msm_rtb_get_idx(void)
131{
132 int i;
133
134 i = atomic_inc_return(&msm_rtb_idx);
135 i--;
136
137 return i;
138}
139#endif
140
141int uncached_logk_pc(enum logk_event_type log_type, void *caller,
142 void *data)
143{
144 int i;
145 struct msm_rtb_layout *start;
146
147 if (!msm_rtb_event_should_log(log_type))
148 return 0;
149
150 i = msm_rtb_get_idx();
151
152 start = &msm_rtb.rtb[i & (msm_rtb.nentries - 1)];
153
154 msm_rtb_emit_sentinel(start);
155 msm_rtb_write_type(log_type, start);
156 msm_rtb_write_caller(caller, start);
157 msm_rtb_write_idx(i, start);
158 msm_rtb_write_data(data, start);
159 mb();
160
161 return 1;
162}
163EXPORT_SYMBOL(uncached_logk_pc);
164
165noinline int uncached_logk(enum logk_event_type log_type, void *data)
166{
167 return uncached_logk_pc(log_type, __builtin_return_address(0), data);
168}
169EXPORT_SYMBOL(uncached_logk);
170
Laura Abbottf8c03b92012-02-16 14:57:58 -0800171int msm_rtb_probe(struct platform_device *pdev)
Laura Abbottad340ff2012-01-04 14:23:48 -0800172{
Laura Abbottf8c03b92012-02-16 14:57:58 -0800173 struct msm_rtb_platform_data *d = pdev->dev.platform_data;
Laura Abbottad340ff2012-01-04 14:23:48 -0800174#if defined(CONFIG_MSM_RTB_SEPARATE_CPUS)
175 unsigned int cpu;
176#endif
177
Laura Abbottf8c03b92012-02-16 14:57:58 -0800178 msm_rtb.size = d->size;
179
Laura Abbottad340ff2012-01-04 14:23:48 -0800180 if (msm_rtb.size <= 0 || msm_rtb.size > SZ_1M)
181 return -EINVAL;
182
183 /*
184 * The ioremap call is made separately to store the physical
185 * address of the buffer. This is necessary for cases where
186 * the only way to access the buffer is a physical address.
187 */
188 msm_rtb.phys = allocate_contiguous_ebi_nomap(msm_rtb.size, SZ_4K);
189
190 if (!msm_rtb.phys)
191 return -ENOMEM;
192
193 msm_rtb.rtb = ioremap(msm_rtb.phys, msm_rtb.size);
194
195 if (!msm_rtb.rtb) {
196 free_contiguous_memory_by_paddr(msm_rtb.phys);
197 return -ENOMEM;
198 }
199
200 msm_rtb.nentries = msm_rtb.size / sizeof(struct msm_rtb_layout);
201
202 /* Round this down to a power of 2 */
203 msm_rtb.nentries = __rounddown_pow_of_two(msm_rtb.nentries);
204
205 memset(msm_rtb.rtb, 0, msm_rtb.size);
206
207
208#if defined(CONFIG_MSM_RTB_SEPARATE_CPUS)
209 for_each_possible_cpu(cpu) {
210 atomic_t *a = &per_cpu(msm_rtb_idx_cpu, cpu);
211 atomic_set(a, cpu);
212 }
213 msm_rtb.step_size = num_possible_cpus();
214#else
215 atomic_set(&msm_rtb_idx, 0);
216 msm_rtb.step_size = 1;
217#endif
218
219
220 msm_rtb.enabled = 1;
221 return 0;
222}
Laura Abbottf8c03b92012-02-16 14:57:58 -0800223
224static struct platform_driver msm_rtb_driver = {
225 .driver = {
226 .name = "msm_rtb",
227 .owner = THIS_MODULE
228 },
229};
230
231static int __init msm_rtb_init(void)
232{
233 return platform_driver_probe(&msm_rtb_driver, msm_rtb_probe);
234}
235
236static void __exit msm_rtb_exit(void)
237{
238 platform_driver_unregister(&msm_rtb_driver);
239}
Laura Abbottad340ff2012-01-04 14:23:48 -0800240module_init(msm_rtb_init)
Laura Abbottf8c03b92012-02-16 14:57:58 -0800241module_exit(msm_rtb_exit)