ia64/xen-unstable

view xen/drivers/char/serial.c @ 17864:d4dcd4d39952

Bring back console_start_log_everything() as a milder alternative to
console_start_sync(). Revert keyhandler logic to use it. The
difference now is that serial logic is updated to not drop characters
if inb a log_everything region. Still this is milder than a sync
region since the async buffer must be filled before we start to
busy-wait on each character.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 13 14:15:00 2008 +0100 (2008-06-13)
parents 7eab5d8788a6
children 982e6fce0e47
line source
1 /******************************************************************************
2 * serial.c
3 *
4 * Framework for serial device drivers.
5 *
6 * Copyright (c) 2003-2008, K A Fraser
7 */
9 #include <xen/config.h>
10 #include <xen/delay.h>
11 #include <xen/init.h>
12 #include <xen/irq.h>
13 #include <xen/keyhandler.h>
14 #include <xen/sched.h>
15 #include <xen/mm.h>
16 #include <xen/serial.h>
18 /* Never drop characters, even if the async transmit buffer fills. */
19 /* #define SERIAL_NEVER_DROP_CHARS 1 */
21 unsigned int serial_txbufsz = 16384;
22 static void __init parse_serial_tx_buffer(const char *s)
23 {
24 serial_txbufsz = max((unsigned int)parse_size_and_unit(s, NULL), 512u);
25 }
26 custom_param("serial_tx_buffer", parse_serial_tx_buffer);
28 #define mask_serial_rxbuf_idx(_i) ((_i)&(serial_rxbufsz-1))
29 #define mask_serial_txbuf_idx(_i) ((_i)&(serial_txbufsz-1))
31 static struct serial_port com[2] = {
32 { .rx_lock = SPIN_LOCK_UNLOCKED, .tx_lock = SPIN_LOCK_UNLOCKED },
33 { .rx_lock = SPIN_LOCK_UNLOCKED, .tx_lock = SPIN_LOCK_UNLOCKED }
34 };
36 void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
37 {
38 char c;
39 serial_rx_fn fn = NULL;
40 unsigned long flags;
42 spin_lock_irqsave(&port->rx_lock, flags);
44 if ( port->driver->getc(port, &c) )
45 {
46 if ( port->rx != NULL )
47 fn = port->rx;
48 else if ( (c & 0x80) && (port->rx_hi != NULL) )
49 fn = port->rx_hi;
50 else if ( !(c & 0x80) && (port->rx_lo != NULL) )
51 fn = port->rx_lo;
52 else if ( (port->rxbufp - port->rxbufc) != serial_rxbufsz )
53 port->rxbuf[mask_serial_rxbuf_idx(port->rxbufp++)] = c;
54 }
56 spin_unlock_irqrestore(&port->rx_lock, flags);
58 if ( fn != NULL )
59 (*fn)(c & 0x7f, regs);
60 }
62 void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
63 {
64 int i;
65 unsigned long flags;
67 local_irq_save(flags);
69 /*
70 * Avoid spinning for a long time: if there is a long-term lock holder
71 * then we know that they'll be stuffing bytes into the transmitter which
72 * will therefore not be empty for long.
73 */
74 while ( !spin_trylock(&port->tx_lock) )
75 {
76 if ( !port->driver->tx_empty(port) )
77 return;
78 cpu_relax();
79 }
81 if ( port->driver->tx_empty(port) )
82 {
83 for ( i = 0; i < port->tx_fifo_size; i++ )
84 {
85 if ( port->txbufc == port->txbufp )
86 break;
87 port->driver->putc(
88 port, port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]);
89 }
90 }
92 spin_unlock_irqrestore(&port->tx_lock, flags);
93 }
95 static void __serial_putc(struct serial_port *port, char c)
96 {
97 if ( (port->txbuf != NULL) && !port->sync )
98 {
99 /* Interrupt-driven (asynchronous) transmitter. */
101 if ( port->tx_quench )
102 {
103 /* Buffer filled and we are dropping characters. */
104 if ( (port->txbufp - port->txbufc) > (serial_txbufsz / 2) )
105 return;
106 port->tx_quench = 0;
107 }
109 if ( (port->txbufp - port->txbufc) == serial_txbufsz )
110 {
111 if ( port->tx_log_everything )
112 {
113 /* Buffer is full: we spin waiting for space to appear. */
114 int i;
115 while ( !port->driver->tx_empty(port) )
116 cpu_relax();
117 for ( i = 0; i < port->tx_fifo_size; i++ )
118 port->driver->putc(
119 port,
120 port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]);
121 port->txbuf[mask_serial_txbuf_idx(port->txbufp++)] = c;
122 }
123 else
124 {
125 /* Buffer is full: drop chars until buffer is half empty. */
126 port->tx_quench = 1;
127 }
128 return;
129 }
131 if ( ((port->txbufp - port->txbufc) == 0) &&
132 port->driver->tx_empty(port) )
133 {
134 /* Buffer and UART FIFO are both empty. */
135 port->driver->putc(port, c);
136 }
137 else
138 {
139 /* Normal case: buffer the character. */
140 port->txbuf[mask_serial_txbuf_idx(port->txbufp++)] = c;
141 }
142 }
143 else if ( port->driver->tx_empty )
144 {
145 /* Synchronous finite-capacity transmitter. */
146 while ( !port->driver->tx_empty(port) )
147 cpu_relax();
148 port->driver->putc(port, c);
149 }
150 else
151 {
152 /* Simple synchronous transmitter. */
153 port->driver->putc(port, c);
154 }
155 }
157 void serial_putc(int handle, char c)
158 {
159 struct serial_port *port;
160 unsigned long flags;
162 if ( handle == -1 )
163 return;
165 port = &com[handle & SERHND_IDX];
166 if ( !port->driver || !port->driver->putc )
167 return;
169 spin_lock_irqsave(&port->tx_lock, flags);
171 if ( (c == '\n') && (handle & SERHND_COOKED) )
172 __serial_putc(port, '\r' | ((handle & SERHND_HI) ? 0x80 : 0x00));
174 if ( handle & SERHND_HI )
175 c |= 0x80;
176 else if ( handle & SERHND_LO )
177 c &= 0x7f;
179 __serial_putc(port, c);
181 spin_unlock_irqrestore(&port->tx_lock, flags);
182 }
184 void serial_puts(int handle, const char *s)
185 {
186 struct serial_port *port;
187 unsigned long flags;
188 char c;
190 if ( handle == -1 )
191 return;
193 port = &com[handle & SERHND_IDX];
194 if ( !port->driver || !port->driver->putc )
195 return;
197 spin_lock_irqsave(&port->tx_lock, flags);
199 while ( (c = *s++) != '\0' )
200 {
201 if ( (c == '\n') && (handle & SERHND_COOKED) )
202 __serial_putc(port, '\r' | ((handle & SERHND_HI) ? 0x80 : 0x00));
204 if ( handle & SERHND_HI )
205 c |= 0x80;
206 else if ( handle & SERHND_LO )
207 c &= 0x7f;
209 __serial_putc(port, c);
210 }
212 spin_unlock_irqrestore(&port->tx_lock, flags);
213 }
215 char serial_getc(int handle)
216 {
217 struct serial_port *port;
218 char c;
219 unsigned long flags;
221 if ( handle == -1 )
222 return '\0';
224 port = &com[handle & SERHND_IDX];
225 if ( !port->driver || !port->driver->getc )
226 return '\0';
228 do {
229 for ( ; ; )
230 {
231 spin_lock_irqsave(&port->rx_lock, flags);
233 if ( port->rxbufp != port->rxbufc )
234 {
235 c = port->rxbuf[mask_serial_rxbuf_idx(port->rxbufc++)];
236 spin_unlock_irqrestore(&port->rx_lock, flags);
237 break;
238 }
240 if ( port->driver->getc(port, &c) )
241 {
242 spin_unlock_irqrestore(&port->rx_lock, flags);
243 break;
244 }
246 spin_unlock_irqrestore(&port->rx_lock, flags);
248 cpu_relax();
249 udelay(100);
250 }
251 } while ( ((handle & SERHND_LO) && (c & 0x80)) ||
252 ((handle & SERHND_HI) && !(c & 0x80)) );
254 return c & 0x7f;
255 }
257 int serial_parse_handle(char *conf)
258 {
259 int handle;
261 /* Silently fail if user has explicitly requested no serial I/O. */
262 if ( strcmp(conf, "none") == 0 )
263 return -1;
265 if ( strncmp(conf, "com", 3) != 0 )
266 goto fail;
268 switch ( conf[3] )
269 {
270 case '1':
271 handle = 0;
272 break;
273 case '2':
274 handle = 1;
275 break;
276 default:
277 goto fail;
278 }
280 if ( conf[4] == 'H' )
281 handle |= SERHND_HI;
282 else if ( conf[4] == 'L' )
283 handle |= SERHND_LO;
285 handle |= SERHND_COOKED;
287 return handle;
289 fail:
290 printk("ERROR: bad serial-interface specification '%s'\n", conf);
291 return -1;
292 }
294 void serial_set_rx_handler(int handle, serial_rx_fn fn)
295 {
296 struct serial_port *port;
297 unsigned long flags;
299 if ( handle == -1 )
300 return;
302 port = &com[handle & SERHND_IDX];
304 spin_lock_irqsave(&port->rx_lock, flags);
306 if ( port->rx != NULL )
307 goto fail;
309 if ( handle & SERHND_LO )
310 {
311 if ( port->rx_lo != NULL )
312 goto fail;
313 port->rx_lo = fn;
314 }
315 else if ( handle & SERHND_HI )
316 {
317 if ( port->rx_hi != NULL )
318 goto fail;
319 port->rx_hi = fn;
320 }
321 else
322 {
323 if ( (port->rx_hi != NULL) || (port->rx_lo != NULL) )
324 goto fail;
325 port->rx = fn;
326 }
328 spin_unlock_irqrestore(&port->rx_lock, flags);
329 return;
331 fail:
332 spin_unlock_irqrestore(&port->rx_lock, flags);
333 printk("ERROR: Conflicting receive handlers for COM%d\n",
334 handle & SERHND_IDX);
335 }
337 void serial_force_unlock(int handle)
338 {
339 struct serial_port *port;
341 if ( handle == -1 )
342 return;
344 port = &com[handle & SERHND_IDX];
346 spin_lock_init(&port->rx_lock);
347 spin_lock_init(&port->tx_lock);
349 serial_start_sync(handle);
350 }
352 void serial_start_sync(int handle)
353 {
354 struct serial_port *port;
355 unsigned long flags;
357 if ( handle == -1 )
358 return;
360 port = &com[handle & SERHND_IDX];
362 spin_lock_irqsave(&port->tx_lock, flags);
364 if ( port->sync++ == 0 )
365 {
366 while ( (port->txbufp - port->txbufc) != 0 )
367 {
368 while ( !port->driver->tx_empty(port) )
369 cpu_relax();
370 port->driver->putc(
371 port, port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]);
372 }
373 }
375 spin_unlock_irqrestore(&port->tx_lock, flags);
376 }
378 void serial_end_sync(int handle)
379 {
380 struct serial_port *port;
381 unsigned long flags;
383 if ( handle == -1 )
384 return;
386 port = &com[handle & SERHND_IDX];
388 spin_lock_irqsave(&port->tx_lock, flags);
390 port->sync--;
392 spin_unlock_irqrestore(&port->tx_lock, flags);
393 }
395 void serial_start_log_everything(int handle)
396 {
397 struct serial_port *port;
398 unsigned long flags;
400 if ( handle == -1 )
401 return;
403 port = &com[handle & SERHND_IDX];
405 spin_lock_irqsave(&port->tx_lock, flags);
406 port->tx_log_everything++;
407 port->tx_quench = 0;
408 spin_unlock_irqrestore(&port->tx_lock, flags);
409 }
411 void serial_end_log_everything(int handle)
412 {
413 struct serial_port *port;
414 unsigned long flags;
416 if ( handle == -1 )
417 return;
419 port = &com[handle & SERHND_IDX];
421 spin_lock_irqsave(&port->tx_lock, flags);
422 port->tx_log_everything--;
423 spin_unlock_irqrestore(&port->tx_lock, flags);
424 }
426 int serial_tx_space(int handle)
427 {
428 struct serial_port *port;
429 if ( handle == -1 )
430 return serial_txbufsz;
431 port = &com[handle & SERHND_IDX];
432 return serial_txbufsz - (port->txbufp - port->txbufc);
433 }
435 void __devinit serial_init_preirq(void)
436 {
437 int i;
438 for ( i = 0; i < ARRAY_SIZE(com); i++ )
439 if ( com[i].driver && com[i].driver->init_preirq )
440 com[i].driver->init_preirq(&com[i]);
441 }
443 void __devinit serial_init_postirq(void)
444 {
445 int i;
446 for ( i = 0; i < ARRAY_SIZE(com); i++ )
447 if ( com[i].driver && com[i].driver->init_postirq )
448 com[i].driver->init_postirq(&com[i]);
449 }
451 void __init serial_endboot(void)
452 {
453 int i;
454 for ( i = 0; i < ARRAY_SIZE(com); i++ )
455 if ( com[i].driver && com[i].driver->endboot )
456 com[i].driver->endboot(&com[i]);
457 }
459 int serial_irq(int idx)
460 {
461 if ( (idx >= 0) && (idx < ARRAY_SIZE(com)) &&
462 com[idx].driver && com[idx].driver->irq )
463 return com[idx].driver->irq(&com[idx]);
465 return -1;
466 }
468 void serial_suspend(void)
469 {
470 int i, irq;
471 for ( i = 0; i < ARRAY_SIZE(com); i++ )
472 if ( (irq = serial_irq(i)) >= 0 )
473 free_irq(irq);
474 }
476 void serial_resume(void)
477 {
478 serial_init_preirq();
479 serial_init_postirq();
480 }
482 void serial_register_uart(int idx, struct uart_driver *driver, void *uart)
483 {
484 /* Store UART-specific info. */
485 com[idx].driver = driver;
486 com[idx].uart = uart;
488 /* Default is no transmit FIFO. */
489 com[idx].tx_fifo_size = 1;
490 }
492 void serial_async_transmit(struct serial_port *port)
493 {
494 BUG_ON(!port->driver->tx_empty);
495 if ( port->txbuf == NULL )
496 port->txbuf = alloc_xenheap_pages(
497 get_order_from_bytes(serial_txbufsz));
498 }
500 /*
501 * Local variables:
502 * mode: C
503 * c-set-style: "BSD"
504 * c-basic-offset: 4
505 * tab-width: 4
506 * indent-tabs-mode: nil
507 * End:
508 */