Pull sim-fixes into release branch
[linux-2.6] / arch / ppc64 / kernel / udbg.c
1 /*
2  * polling mode stateless debugging stuff, originally for NS16550 Serial Ports
3  *
4  * c 2001 PPC 64 Team, IBM Corp
5  *
6  *      This program is free software; you can redistribute it and/or
7  *      modify it under the terms of the GNU General Public License
8  *      as published by the Free Software Foundation; either version
9  *      2 of the License, or (at your option) any later version.
10  */
11
12 #include <stdarg.h>
13 #define WANT_PPCDBG_TAB /* Only defined here */
14 #include <linux/config.h>
15 #include <linux/types.h>
16 #include <linux/sched.h>
17 #include <linux/console.h>
18 #include <asm/ppcdebug.h>
19 #include <asm/processor.h>
20
21 void (*udbg_putc)(unsigned char c);
22 unsigned char (*udbg_getc)(void);
23 int (*udbg_getc_poll)(void);
24
25 /* udbg library, used by xmon et al */
26 void udbg_puts(const char *s)
27 {
28         if (udbg_putc) {
29                 char c;
30
31                 if (s && *s != '\0') {
32                         while ((c = *s++) != '\0')
33                                 udbg_putc(c);
34                 }
35         }
36 #if 0
37         else {
38                 printk("%s", s);
39         }
40 #endif
41 }
42
43 int udbg_write(const char *s, int n)
44 {
45         int remain = n;
46         char c;
47
48         if (!udbg_putc)
49                 return 0;
50
51         if (s && *s != '\0') {
52                 while (((c = *s++) != '\0') && (remain-- > 0)) {
53                         udbg_putc(c);
54                 }
55         }
56
57         return n - remain;
58 }
59
60 int udbg_read(char *buf, int buflen)
61 {
62         char c, *p = buf;
63         int i;
64
65         if (!udbg_getc)
66                 return 0;
67
68         for (i = 0; i < buflen; ++i) {
69                 do {
70                         c = udbg_getc();
71                 } while (c == 0x11 || c == 0x13);
72                 if (c == 0)
73                         break;
74                 *p++ = c;
75         }
76
77         return i;
78 }
79
80 #define UDBG_BUFSIZE 256
81 void udbg_printf(const char *fmt, ...)
82 {
83         unsigned char buf[UDBG_BUFSIZE];
84         va_list args;
85
86         va_start(args, fmt);
87         vsnprintf(buf, UDBG_BUFSIZE, fmt, args);
88         udbg_puts(buf);
89         va_end(args);
90 }
91
92 /* PPCDBG stuff */
93
94 u64 ppc64_debug_switch;
95
96 /* Special print used by PPCDBG() macro */
97 void udbg_ppcdbg(unsigned long debug_flags, const char *fmt, ...)
98 {
99         unsigned long active_debugs = debug_flags & ppc64_debug_switch;
100
101         if (active_debugs) {
102                 va_list ap;
103                 unsigned char buf[UDBG_BUFSIZE];
104                 unsigned long i, len = 0;
105
106                 for (i=0; i < PPCDBG_NUM_FLAGS; i++) {
107                         if (((1U << i) & active_debugs) && 
108                             trace_names[i]) {
109                                 len += strlen(trace_names[i]); 
110                                 udbg_puts(trace_names[i]);
111                                 break;
112                         }
113                 }
114
115                 snprintf(buf, UDBG_BUFSIZE, " [%s]: ", current->comm);
116                 len += strlen(buf); 
117                 udbg_puts(buf);
118
119                 while (len < 18) {
120                         udbg_puts(" ");
121                         len++;
122                 }
123
124                 va_start(ap, fmt);
125                 vsnprintf(buf, UDBG_BUFSIZE, fmt, ap);
126                 udbg_puts(buf);
127                 va_end(ap);
128         }
129 }
130
131 unsigned long udbg_ifdebug(unsigned long flags)
132 {
133         return (flags & ppc64_debug_switch);
134 }
135
136 /*
137  * Initialize the PPCDBG state.  Called before relocation has been enabled.
138  */
139 void __init ppcdbg_initialize(void)
140 {
141         ppc64_debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | */
142         /* PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */;
143 }
144
145 /*
146  * Early boot console based on udbg
147  */
148 static void udbg_console_write(struct console *con, const char *s,
149                 unsigned int n)
150 {
151         udbg_write(s, n);
152 }
153
154 static struct console udbg_console = {
155         .name   = "udbg",
156         .write  = udbg_console_write,
157         .flags  = CON_PRINTBUFFER,
158         .index  = -1,
159 };
160
161 static int early_console_initialized;
162
163 void __init disable_early_printk(void)
164 {
165         if (!early_console_initialized)
166                 return;
167         unregister_console(&udbg_console);
168         early_console_initialized = 0;
169 }
170
171 /* called by setup_system */
172 void register_early_udbg_console(void)
173 {
174         early_console_initialized = 1;
175         register_console(&udbg_console);
176 }
177
178 #if 0   /* if you want to use this as a regular output console */
179 console_initcall(register_udbg_console);
180 #endif