Merge tag 'mfd-3.14-1' of git://git.linaro.org/people/ljones/mfd
[cascardo/linux.git] / drivers / staging / dgap / dgap_trace.c
1 /*
2  * Copyright 2003 Digi International (www.digi.com)
3  *      Scott H Kilau <Scott_Kilau at digi dot com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
12  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13  * PURPOSE.  See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  *
20  *      NOTE TO LINUX KERNEL HACKERS:  DO NOT REFORMAT THIS CODE!
21  *
22  *      This is shared code between Digi's CVS archive and the
23  *      Linux Kernel sources.
24  *      Changing the source just for reformatting needlessly breaks
25  *      our CVS diff history.
26  *
27  *      Send any bug fixes/changes to:  Eng.Linux at digi dot com.
28  *      Thank you.
29  *
30  */
31
32 /* $Id: dgap_trace.c,v 1.1 2009/10/23 14:01:57 markh Exp $ */
33
34 #include <linux/kernel.h>
35 #include <linux/sched.h>        /* For jiffies, task states */
36 #include <linux/interrupt.h>    /* For tasklet and interrupt structs/defines */
37 #include <linux/vmalloc.h>
38
39 #include "dgap_driver.h"
40 #include "dgap_trace.h"
41
42 #define TRC_TO_CONSOLE 1
43
44 /* file level globals */
45 static char *dgap_trcbuf;               /* the ringbuffer */
46
47 #if defined(TRC_TO_KMEM)
48 static int dgap_trcbufi = 0;            /* index of the tilde at the end of */
49 #endif
50
51 extern int dgap_trcbuf_size;            /* size of the ringbuffer */
52
53 #if defined(TRC_TO_KMEM)
54 static DEFINE_SPINLOCK(dgap_tracef_lock);
55 #endif
56
57 #if 0
58
59 #if !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE)
60 void dgap_tracef(const char *fmt, ...)
61 {
62         return;
63 }
64
65 #else /* !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE) */
66
67 void dgap_tracef(const char *fmt, ...)
68 {
69         va_list          ap;
70         char             buf[TRC_MAXMSG+1];
71         size_t           lenbuf;
72         int              i;
73         static int       failed = FALSE;
74 # if defined(TRC_TO_KMEM)
75         unsigned long    flags;
76 #endif
77
78         if(failed)
79                 return;
80 # if defined(TRC_TO_KMEM)
81         DGAP_LOCK(dgap_tracef_lock, flags);
82 #endif
83
84         /* Format buf using fmt and arguments contained in ap. */
85         va_start(ap, fmt);
86         i = vsprintf(buf, fmt,  ap);
87         va_end(ap);
88         lenbuf = strlen(buf);
89
90 # if defined(TRC_TO_KMEM)
91         {
92                 static int       initd=0;
93
94                 /*
95                  * Now, in addition to (or instead of) printing this stuff out
96                  * (which is a buffered operation), also tuck it away into a
97                  * corner of memory which can be examined post-crash in kdb.
98                  */
99                 if (!initd) {
100                         dgap_trcbuf = (char *) vmalloc(dgap_trcbuf_size);
101                         if(!dgap_trcbuf) {
102                                 failed = TRUE;
103                                 printk("dgap: tracing init failed!\n");
104                                 return;
105                         }
106
107                         memset(dgap_trcbuf, '\0',  dgap_trcbuf_size);
108                         dgap_trcbufi = 0;
109                         initd++;
110
111                         printk("dgap: tracing enabled - " TRC_DTRC
112                                 " 0x%lx 0x%x\n",
113                                 (unsigned long)dgap_trcbuf,
114                                 dgap_trcbuf_size);
115                 }
116
117 #  if defined(TRC_ON_OVERFLOW_WRAP_AROUND)
118                 /*
119                  * This is the less CPU-intensive way to do things.  We simply
120                  * wrap around before we fall off the end of the buffer.  A
121                  * tilde (~) demarcates the current end of the trace.
122                  *
123                  * This method should be used if you are concerned about race
124                  * conditions as it is less likely to affect the timing of
125                  * things.
126                  */
127
128                 if (dgap_trcbufi + lenbuf >= dgap_trcbuf_size) {
129                         /* We are wrapping, so wipe out the last tilde. */
130                         dgap_trcbuf[dgap_trcbufi] = '\0';
131                         /* put the new string at the beginning of the buffer */
132                         dgap_trcbufi = 0;
133                 }
134
135                 strcpy(&dgap_trcbuf[dgap_trcbufi], buf);
136                 dgap_trcbufi += lenbuf;
137                 dgap_trcbuf[dgap_trcbufi] = '~';
138
139 #  elif defined(TRC_ON_OVERFLOW_SHIFT_BUFFER)
140                 /*
141                  * This is the more CPU-intensive way to do things.  If we
142                  * venture into the last 1/8 of the buffer, we shift the
143                  * last 7/8 of the buffer forward, wiping out the first 1/8.
144                  * Advantage: No wrap-around, only truncation from the
145                  * beginning.
146                  *
147                  * This method should not be used if you are concerned about
148                  * timing changes affecting the behaviour of the driver (ie,
149                  * race conditions).
150                  */
151                 strcpy(&dgap_trcbuf[dgap_trcbufi], buf);
152                 dgap_trcbufi += lenbuf;
153                 dgap_trcbuf[dgap_trcbufi] = '~';
154                 dgap_trcbuf[dgap_trcbufi+1] = '\0';
155
156                 /* If we're near the end of the trace buffer... */
157                 if (dgap_trcbufi > (dgap_trcbuf_size/8)*7) {
158                         /* Wipe out the first eighth to make some more room. */
159                         strcpy(dgap_trcbuf, &dgap_trcbuf[dgap_trcbuf_size/8]);
160                         dgap_trcbufi = strlen(dgap_trcbuf)-1;
161                         /* Plop overflow message at the top of the buffer. */
162                         bcopy(TRC_OVERFLOW, dgap_trcbuf, strlen(TRC_OVERFLOW));
163                 }
164 #  else
165 #   error "TRC_ON_OVERFLOW_WRAP_AROUND or TRC_ON_OVERFLOW_SHIFT_BUFFER?"
166 #  endif
167         }
168         DGAP_UNLOCK(dgap_tracef_lock, flags);
169
170 # endif /* defined(TRC_TO_KMEM) */
171 }
172
173 #endif /* !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE) */
174
175 #endif
176
177 /*
178  * dgap_tracer_free()
179  *
180  *
181  */
182 void dgap_tracer_free(void)
183 {
184         if(dgap_trcbuf)
185                 vfree(dgap_trcbuf);
186 }