blob: fd1fc2b21abc88d2e447cefea29d8e4d472a0215 [file] [log] [blame]
Pratik Patel74929432011-12-26 12:03:41 -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#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/types.h>
17#include <linux/device.h>
18#include <linux/platform_device.h>
19#include <linux/io.h>
20#include <linux/err.h>
Pratik Patelbf3e77442012-03-18 18:30:43 -070021#include <linux/export.h>
Pratik Patel74929432011-12-26 12:03:41 -080022#include <mach/rpm.h>
23
24#include "rpm_resources.h"
Pratik Patelb27a9352012-03-17 22:37:21 -070025#include "qdss-priv.h"
Pratik Patel74929432011-12-26 12:03:41 -080026
Pratik Patel1403f2a2012-03-21 10:10:00 -070027#define MAX_STR_LEN (65535)
28
Pratik Patel74929432011-12-26 12:03:41 -080029enum {
30 QDSS_CLK_OFF,
31 QDSS_CLK_ON_DBG,
32 QDSS_CLK_ON_HSDBG,
33};
34
Pratik Patel1403f2a2012-03-21 10:10:00 -070035/*
36 * Exclusion rules for structure fields.
37 *
38 * S: qdss.sources_mutex protected.
39 * I: qdss.sink_mutex protected.
40 * C: qdss.clk_mutex protected.
41 */
Pratik Patel6630ebe2012-03-06 16:44:22 -080042struct qdss_ctx {
Pratik Patel1403f2a2012-03-21 10:10:00 -070043 struct kobject *modulekobj;
44 struct msm_qdss_platform_data *pdata;
45 struct list_head sources; /* S: sources list */
46 struct mutex sources_mutex;
47 uint8_t sink_count; /* I: sink count */
48 struct mutex sink_mutex;
49 uint8_t max_clk;
50 uint8_t clk_count; /* C: clk count */
51 struct mutex clk_mutex;
Pratik Patel6630ebe2012-03-06 16:44:22 -080052};
53
54static struct qdss_ctx qdss;
55
Pratik Patel1403f2a2012-03-21 10:10:00 -070056/**
57 * qdss_get - get the qdss source handle
58 * @name: name of the qdss source
59 *
60 * Searches the sources list to get the qdss source handle for this source.
61 *
62 * CONTEXT:
63 * Typically called from init or probe functions
64 *
65 * RETURNS:
66 * pointer to struct qdss_source on success, %NULL on failure
67 */
68struct qdss_source *qdss_get(const char *name)
Pratik Patel6630ebe2012-03-06 16:44:22 -080069{
Pratik Patel1403f2a2012-03-21 10:10:00 -070070 struct qdss_source *src, *source = NULL;
71
72 mutex_lock(&qdss.sources_mutex);
73 list_for_each_entry(src, &qdss.sources, link) {
74 if (src->name) {
75 if (strncmp(src->name, name, MAX_STR_LEN))
76 continue;
77 source = src;
78 break;
79 }
80 }
81 mutex_unlock(&qdss.sources_mutex);
82
83 return source ? source : ERR_PTR(-ENOENT);
Pratik Patel6630ebe2012-03-06 16:44:22 -080084}
Pratik Patel1403f2a2012-03-21 10:10:00 -070085EXPORT_SYMBOL(qdss_get);
86
87/**
88 * qdss_put - release the qdss source handle
89 * @name: name of the qdss source
90 *
91 * CONTEXT:
92 * Typically called from driver remove or exit functions
93 */
94void qdss_put(struct qdss_source *src)
95{
96}
97EXPORT_SYMBOL(qdss_put);
98
99/**
100 * qdss_enable - enable qdss for the source
101 * @src: handle for the source making the call
102 *
103 * Enables qdss block (relevant funnel ports and sink) if not already
104 * enabled, otherwise increments the reference count
105 *
106 * CONTEXT:
107 * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
108 *
109 * RETURNS:
110 * 0 on success, non-zero on failure
111 */
112int qdss_enable(struct qdss_source *src)
113{
114 int ret;
115
116 if (!src)
117 return -EINVAL;
118
119 ret = qdss_clk_enable();
120 if (ret)
121 goto err;
122
123 if ((qdss.pdata)->afamily) {
124 mutex_lock(&qdss.sink_mutex);
125 if (qdss.sink_count == 0) {
126 etb_disable();
127 tpiu_disable();
128 /* enable ETB first to avoid losing any trace data */
129 etb_enable();
130 }
131 qdss.sink_count++;
132 mutex_unlock(&qdss.sink_mutex);
133 }
134
135 funnel_enable(0x0, src->fport_mask);
136 return 0;
137err:
138 return ret;
139}
140EXPORT_SYMBOL(qdss_enable);
141
142/**
143 * qdss_disable - disable qdss for the source
144 * @src: handle for the source making the call
145 *
146 * Disables qdss block (relevant funnel ports and sink) if the reference count
147 * is one, otherwise decrements the reference count
148 *
149 * CONTEXT:
150 * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
151 */
152void qdss_disable(struct qdss_source *src)
153{
154 if (!src)
155 return;
156
157 if ((qdss.pdata)->afamily) {
158 mutex_lock(&qdss.sink_mutex);
159 if (WARN(qdss.sink_count == 0, "qdss is unbalanced\n"))
160 goto out;
161 if (qdss.sink_count == 1) {
162 etb_dump();
163 etb_disable();
164 }
165 qdss.sink_count--;
166 mutex_unlock(&qdss.sink_mutex);
167 }
168
169 funnel_disable(0x0, src->fport_mask);
170 qdss_clk_disable();
171 return;
172out:
173 mutex_unlock(&qdss.sink_mutex);
174}
175EXPORT_SYMBOL(qdss_disable);
Pratik Patel74929432011-12-26 12:03:41 -0800176
Pratik Patelbf3e77442012-03-18 18:30:43 -0700177/**
Pratik Patelf3adf032012-05-03 12:50:21 -0700178 * qdss_disable_sink - force disable the current qdss sink(s)
179 *
180 * Force disable the current qdss sink(s) to stop the sink from accepting any
181 * trace generated subsequent to this call. This function should only be used
182 * as a way to stop the sink from getting polluted with trace data that is
183 * uninteresting after an event of interest has occured.
184 *
185 * CONTEXT:
186 * Can be called from atomic or non-atomic context.
187 */
188void qdss_disable_sink(void)
189{
190 if ((qdss.pdata)->afamily) {
191 etb_dump();
192 etb_disable();
193 }
194}
195EXPORT_SYMBOL(qdss_disable_sink);
196
197/**
Pratik Patelbf3e77442012-03-18 18:30:43 -0700198 * qdss_clk_enable - enable qdss clocks
199 *
200 * Enables qdss clocks via RPM if they aren't already enabled, otherwise
201 * increments the reference count.
202 *
203 * CONTEXT:
204 * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
205 *
206 * RETURNS:
207 * 0 on success, non-zero on failure
208 */
Pratik Patel74929432011-12-26 12:03:41 -0800209int qdss_clk_enable(void)
210{
211 int ret;
Pratik Patel74929432011-12-26 12:03:41 -0800212 struct msm_rpm_iv_pair iv;
Pratik Patel74929432011-12-26 12:03:41 -0800213
Pratik Patelbf3e77442012-03-18 18:30:43 -0700214 mutex_lock(&qdss.clk_mutex);
215 if (qdss.clk_count == 0) {
216 iv.id = MSM_RPM_ID_QDSS_CLK;
217 if (qdss.max_clk)
218 iv.value = QDSS_CLK_ON_HSDBG;
219 else
220 iv.value = QDSS_CLK_ON_DBG;
221 ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, &iv, 1);
222 if (WARN(ret, "qdss clks not enabled (%d)\n", ret))
223 goto err_clk;
224 }
225 qdss.clk_count++;
226 mutex_unlock(&qdss.clk_mutex);
Pratik Patel74929432011-12-26 12:03:41 -0800227 return 0;
Pratik Patel74929432011-12-26 12:03:41 -0800228err_clk:
Pratik Patelbf3e77442012-03-18 18:30:43 -0700229 mutex_unlock(&qdss.clk_mutex);
Pratik Patel74929432011-12-26 12:03:41 -0800230 return ret;
231}
Pratik Patelbf3e77442012-03-18 18:30:43 -0700232EXPORT_SYMBOL(qdss_clk_enable);
Pratik Patel74929432011-12-26 12:03:41 -0800233
Pratik Patelbf3e77442012-03-18 18:30:43 -0700234/**
235 * qdss_clk_disable - disable qdss clocks
236 *
237 * Disables qdss clocks via RPM if the reference count is one, otherwise
238 * decrements the reference count.
239 *
240 * CONTEXT:
241 * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
242 */
Pratik Patel74929432011-12-26 12:03:41 -0800243void qdss_clk_disable(void)
244{
245 int ret;
246 struct msm_rpm_iv_pair iv;
247
Pratik Patelbf3e77442012-03-18 18:30:43 -0700248 mutex_lock(&qdss.clk_mutex);
249 if (WARN(qdss.clk_count == 0, "qdss clks are unbalanced\n"))
250 goto out;
251 if (qdss.clk_count == 1) {
252 iv.id = MSM_RPM_ID_QDSS_CLK;
253 iv.value = QDSS_CLK_OFF;
254 ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, &iv, 1);
255 WARN(ret, "qdss clks not disabled (%d)\n", ret);
256 }
257 qdss.clk_count--;
258out:
259 mutex_unlock(&qdss.clk_mutex);
Pratik Patel74929432011-12-26 12:03:41 -0800260}
Pratik Patelbf3e77442012-03-18 18:30:43 -0700261EXPORT_SYMBOL(qdss_clk_disable);
Pratik Patel59e29942011-12-27 10:31:33 -0800262
Pratik Patel1403f2a2012-03-21 10:10:00 -0700263struct kobject *qdss_get_modulekobj(void)
264{
265 return qdss.modulekobj;
266}
267
Pratik Patel6630ebe2012-03-06 16:44:22 -0800268#define QDSS_ATTR(name) \
269static struct kobj_attribute name##_attr = \
270 __ATTR(name, S_IRUGO | S_IWUSR, name##_show, name##_store)
271
272static ssize_t max_clk_store(struct kobject *kobj,
273 struct kobj_attribute *attr,
274 const char *buf, size_t n)
275{
276 unsigned long val;
277
278 if (sscanf(buf, "%lx", &val) != 1)
279 return -EINVAL;
280
281 qdss.max_clk = val;
282 return n;
283}
284static ssize_t max_clk_show(struct kobject *kobj,
285 struct kobj_attribute *attr,
286 char *buf)
287{
288 unsigned long val = qdss.max_clk;
289 return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
290}
291QDSS_ATTR(max_clk);
292
Stephen Boyda9510502012-04-24 16:23:34 -0700293static void __devinit qdss_add_sources(struct qdss_source *srcs, size_t num)
Pratik Patel1403f2a2012-03-21 10:10:00 -0700294{
295 mutex_lock(&qdss.sources_mutex);
296 while (num--) {
297 list_add_tail(&srcs->link, &qdss.sources);
298 srcs++;
299 }
300 mutex_unlock(&qdss.sources_mutex);
301}
302
Pratik Patel6630ebe2012-03-06 16:44:22 -0800303static int __init qdss_sysfs_init(void)
304{
305 int ret;
306
307 qdss.modulekobj = kset_find_obj(module_kset, KBUILD_MODNAME);
308 if (!qdss.modulekobj) {
309 pr_err("failed to find QDSS sysfs module kobject\n");
310 ret = -ENOENT;
311 goto err;
312 }
313
314 ret = sysfs_create_file(qdss.modulekobj, &max_clk_attr.attr);
315 if (ret) {
316 pr_err("failed to create QDSS sysfs max_clk attribute\n");
317 goto err;
318 }
319
320 return 0;
321err:
322 return ret;
323}
324
Stephen Boyda9510502012-04-24 16:23:34 -0700325static void __devexit qdss_sysfs_exit(void)
Pratik Patel6630ebe2012-03-06 16:44:22 -0800326{
327 sysfs_remove_file(qdss.modulekobj, &max_clk_attr.attr);
328}
329
Pratik Patel1403f2a2012-03-21 10:10:00 -0700330static int __devinit qdss_probe(struct platform_device *pdev)
Pratik Patel59e29942011-12-27 10:31:33 -0800331{
332 int ret;
Pratik Patel1403f2a2012-03-21 10:10:00 -0700333 struct qdss_source *src_table;
334 size_t num_srcs;
Pratik Patel59e29942011-12-27 10:31:33 -0800335
Pratik Patel1403f2a2012-03-21 10:10:00 -0700336 mutex_init(&qdss.sources_mutex);
Pratik Patelbf3e77442012-03-18 18:30:43 -0700337 mutex_init(&qdss.clk_mutex);
Pratik Patel1403f2a2012-03-21 10:10:00 -0700338 mutex_init(&qdss.sink_mutex);
339
340 if (pdev->dev.platform_data == NULL) {
341 pr_err("%s: platform data is NULL\n", __func__);
342 ret = -ENODEV;
343 goto err_pdata;
344 }
345 qdss.pdata = pdev->dev.platform_data;
346
347 INIT_LIST_HEAD(&qdss.sources);
348 src_table = (qdss.pdata)->src_table;
349 num_srcs = (qdss.pdata)->size;
350 qdss_add_sources(src_table, num_srcs);
351
352 pr_info("QDSS arch initialized\n");
353 return 0;
354err_pdata:
355 mutex_destroy(&qdss.sink_mutex);
356 mutex_destroy(&qdss.clk_mutex);
357 mutex_destroy(&qdss.sources_mutex);
358 pr_err("QDSS init failed\n");
359 return ret;
360}
361
362static int __devexit qdss_remove(struct platform_device *pdev)
363{
364 qdss_sysfs_exit();
365 mutex_destroy(&qdss.sink_mutex);
366 mutex_destroy(&qdss.clk_mutex);
367 mutex_destroy(&qdss.sources_mutex);
368
369 return 0;
370}
371
372static struct platform_driver qdss_driver = {
373 .probe = qdss_probe,
374 .remove = __devexit_p(qdss_remove),
375 .driver = {
376 .name = "msm_qdss",
377 },
378};
379
380static int __init qdss_init(void)
381{
382 return platform_driver_register(&qdss_driver);
383}
384arch_initcall(qdss_init);
385
386static int __init qdss_module_init(void)
387{
388 int ret;
Pratik Patelbf3e77442012-03-18 18:30:43 -0700389
Pratik Patel6630ebe2012-03-06 16:44:22 -0800390 ret = qdss_sysfs_init();
391 if (ret)
392 goto err_sysfs;
Pratik Patel59e29942011-12-27 10:31:33 -0800393
Pratik Patel1403f2a2012-03-21 10:10:00 -0700394 pr_info("QDSS module initialized\n");
Pratik Patel59e29942011-12-27 10:31:33 -0800395 return 0;
Pratik Patel6630ebe2012-03-06 16:44:22 -0800396err_sysfs:
Pratik Patel59e29942011-12-27 10:31:33 -0800397 return ret;
398}
Pratik Patel1403f2a2012-03-21 10:10:00 -0700399module_init(qdss_module_init);
Pratik Patel59e29942011-12-27 10:31:33 -0800400
401static void __exit qdss_exit(void)
402{
Pratik Patel1403f2a2012-03-21 10:10:00 -0700403 platform_driver_unregister(&qdss_driver);
Pratik Patel59e29942011-12-27 10:31:33 -0800404}
405module_exit(qdss_exit);
406
407MODULE_LICENSE("GPL v2");
408MODULE_DESCRIPTION("Qualcomm Debug SubSystem Driver");