aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/udbg_16550.c
diff options
context:
space:
mode:
authorAndrew Klossner <andrew@cesa.opbu.xerox.com>2009-03-09 03:52:41 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-03-11 02:11:34 -0400
commitaf9c7249071bf862781df06eb24456cab763dc7d (patch)
tree8ec042b89029db61ccdb493f46ab7f4cdd9306cb /arch/powerpc/kernel/udbg_16550.c
parenta77acda0b7f2e54009955512e577812433d7abc5 (diff)
powerpc/udbg: Fix lost byte during console handover; change LFCR to CRLF
When the console is on a serial port to be driven by serial8250, a character can be lost from the end of the first line in the two-line sequence serial8250.0: ttyS0 at MMIO 0xe0004500 (irq = 42) is a 16550A console handover: boot [udbg0] -> real [ttyS0] This happens because udbg_puts or udbg_write stuff the last byte of the line into the Tx FIFO and return, whereupon the serial8250 initialization code immediately empties that FIFO. The fix: udbg_puts and udbg_write now wait for the Tx FIFO to clear before returning. This delays the system by one additional serial frame time for each line written by udbg, but the effect is not noticeable, a cumulative 17 milliseconds for 200 lines of early printk output at 115200 baud. Also, the routines in udbg_16550.c now emit CRLF instead of LFCR. Linux makes a point of emitting CRLF because, when serial output is captured to a file, LFCR sequences can confuse text editors. See http://lkml.org/lkml/2006/2/4/50 for some history. Signed-off-by: Andrew Klossner <andrew@cesa.opbu.xerox.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/udbg_16550.c')
-rw-r--r--arch/powerpc/kernel/udbg_16550.c60
1 files changed, 50 insertions, 10 deletions
diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c
index 7b7da8cfd5e..0362a891e54 100644
--- a/arch/powerpc/kernel/udbg_16550.c
+++ b/arch/powerpc/kernel/udbg_16550.c
@@ -48,14 +48,21 @@ struct NS16550 {
48 48
49static struct NS16550 __iomem *udbg_comport; 49static struct NS16550 __iomem *udbg_comport;
50 50
51static void udbg_550_putc(char c) 51static void udbg_550_flush(void)
52{ 52{
53 if (udbg_comport) { 53 if (udbg_comport) {
54 while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0) 54 while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
55 /* wait for idle */; 55 /* wait for idle */;
56 out_8(&udbg_comport->thr, c); 56 }
57}
58
59static void udbg_550_putc(char c)
60{
61 if (udbg_comport) {
57 if (c == '\n') 62 if (c == '\n')
58 udbg_550_putc('\r'); 63 udbg_550_putc('\r');
64 udbg_550_flush();
65 out_8(&udbg_comport->thr, c);
59 } 66 }
60} 67}
61 68
@@ -108,6 +115,7 @@ void udbg_init_uart(void __iomem *comport, unsigned int speed,
108 /* Clear & enable FIFOs */ 115 /* Clear & enable FIFOs */
109 out_8(&udbg_comport->fcr ,0x07); 116 out_8(&udbg_comport->fcr ,0x07);
110 udbg_putc = udbg_550_putc; 117 udbg_putc = udbg_550_putc;
118 udbg_flush = udbg_550_flush;
111 udbg_getc = udbg_550_getc; 119 udbg_getc = udbg_550_getc;
112 udbg_getc_poll = udbg_550_getc_poll; 120 udbg_getc_poll = udbg_550_getc_poll;
113 } 121 }
@@ -149,14 +157,21 @@ unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock)
149} 157}
150 158
151#ifdef CONFIG_PPC_MAPLE 159#ifdef CONFIG_PPC_MAPLE
152void udbg_maple_real_putc(char c) 160void udbg_maple_real_flush(void)
153{ 161{
154 if (udbg_comport) { 162 if (udbg_comport) {
155 while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0) 163 while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
156 /* wait for idle */; 164 /* wait for idle */;
157 real_writeb(c, &udbg_comport->thr); eieio(); 165 }
166}
167
168void udbg_maple_real_putc(char c)
169{
170 if (udbg_comport) {
158 if (c == '\n') 171 if (c == '\n')
159 udbg_maple_real_putc('\r'); 172 udbg_maple_real_putc('\r');
173 udbg_maple_real_flush();
174 real_writeb(c, &udbg_comport->thr); eieio();
160 } 175 }
161} 176}
162 177
@@ -165,20 +180,28 @@ void __init udbg_init_maple_realmode(void)
165 udbg_comport = (struct NS16550 __iomem *)0xf40003f8; 180 udbg_comport = (struct NS16550 __iomem *)0xf40003f8;
166 181
167 udbg_putc = udbg_maple_real_putc; 182 udbg_putc = udbg_maple_real_putc;
183 udbg_flush = udbg_maple_real_flush;
168 udbg_getc = NULL; 184 udbg_getc = NULL;
169 udbg_getc_poll = NULL; 185 udbg_getc_poll = NULL;
170} 186}
171#endif /* CONFIG_PPC_MAPLE */ 187#endif /* CONFIG_PPC_MAPLE */
172 188
173#ifdef CONFIG_PPC_PASEMI 189#ifdef CONFIG_PPC_PASEMI
174void udbg_pas_real_putc(char c) 190void udbg_pas_real_flush(void)
175{ 191{
176 if (udbg_comport) { 192 if (udbg_comport) {
177 while ((real_205_readb(&udbg_comport->lsr) & LSR_THRE) == 0) 193 while ((real_205_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
178 /* wait for idle */; 194 /* wait for idle */;
179 real_205_writeb(c, &udbg_comport->thr); eieio(); 195 }
196}
197
198void udbg_pas_real_putc(char c)
199{
200 if (udbg_comport) {
180 if (c == '\n') 201 if (c == '\n')
181 udbg_pas_real_putc('\r'); 202 udbg_pas_real_putc('\r');
203 udbg_pas_real_flush();
204 real_205_writeb(c, &udbg_comport->thr); eieio();
182 } 205 }
183} 206}
184 207
@@ -187,6 +210,7 @@ void udbg_init_pas_realmode(void)
187 udbg_comport = (struct NS16550 __iomem *)0xfcff03f8UL; 210 udbg_comport = (struct NS16550 __iomem *)0xfcff03f8UL;
188 211
189 udbg_putc = udbg_pas_real_putc; 212 udbg_putc = udbg_pas_real_putc;
213 udbg_flush = udbg_pas_real_flush;
190 udbg_getc = NULL; 214 udbg_getc = NULL;
191 udbg_getc_poll = NULL; 215 udbg_getc_poll = NULL;
192} 216}
@@ -195,14 +219,21 @@ void udbg_init_pas_realmode(void)
195#ifdef CONFIG_PPC_EARLY_DEBUG_44x 219#ifdef CONFIG_PPC_EARLY_DEBUG_44x
196#include <platforms/44x/44x.h> 220#include <platforms/44x/44x.h>
197 221
198static void udbg_44x_as1_putc(char c) 222static int udbg_44x_as1_flush(void)
199{ 223{
200 if (udbg_comport) { 224 if (udbg_comport) {
201 while ((as1_readb(&udbg_comport->lsr) & LSR_THRE) == 0) 225 while ((as1_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
202 /* wait for idle */; 226 /* wait for idle */;
203 as1_writeb(c, &udbg_comport->thr); eieio(); 227 }
228}
229
230static void udbg_44x_as1_putc(char c)
231{
232 if (udbg_comport) {
204 if (c == '\n') 233 if (c == '\n')
205 udbg_44x_as1_putc('\r'); 234 udbg_44x_as1_putc('\r');
235 udbg_44x_as1_flush();
236 as1_writeb(c, &udbg_comport->thr); eieio();
206 } 237 }
207} 238}
208 239
@@ -222,19 +253,27 @@ void __init udbg_init_44x_as1(void)
222 (struct NS16550 __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR; 253 (struct NS16550 __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR;
223 254
224 udbg_putc = udbg_44x_as1_putc; 255 udbg_putc = udbg_44x_as1_putc;
256 udbg_flush = udbg_44x_as1_flush;
225 udbg_getc = udbg_44x_as1_getc; 257 udbg_getc = udbg_44x_as1_getc;
226} 258}
227#endif /* CONFIG_PPC_EARLY_DEBUG_44x */ 259#endif /* CONFIG_PPC_EARLY_DEBUG_44x */
228 260
229#ifdef CONFIG_PPC_EARLY_DEBUG_40x 261#ifdef CONFIG_PPC_EARLY_DEBUG_40x
230static void udbg_40x_real_putc(char c) 262static void udbg_40x_real_flush(void)
231{ 263{
232 if (udbg_comport) { 264 if (udbg_comport) {
233 while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0) 265 while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
234 /* wait for idle */; 266 /* wait for idle */;
235 real_writeb(c, &udbg_comport->thr); eieio(); 267 }
268}
269
270static void udbg_40x_real_putc(char c)
271{
272 if (udbg_comport) {
236 if (c == '\n') 273 if (c == '\n')
237 udbg_40x_real_putc('\r'); 274 udbg_40x_real_putc('\r');
275 udbg_40x_real_flush();
276 real_writeb(c, &udbg_comport->thr); eieio();
238 } 277 }
239} 278}
240 279
@@ -254,6 +293,7 @@ void __init udbg_init_40x_realmode(void)
254 CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR; 293 CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR;
255 294
256 udbg_putc = udbg_40x_real_putc; 295 udbg_putc = udbg_40x_real_putc;
296 udbg_flush = udbg_40x_real_flush;
257 udbg_getc = udbg_40x_real_getc; 297 udbg_getc = udbg_40x_real_getc;
258 udbg_getc_poll = NULL; 298 udbg_getc_poll = NULL;
259} 299}