1 /******************************************************************************
2 * serial.c
3 *
4 * Framework for serial device drivers.
5 *
6 * Copyright (c) 2003-2008, K A Fraser
7 */
8
9 #include <xen/delay.h>
10 #include <xen/init.h>
11 #include <xen/mm.h>
12 #include <xen/param.h>
13 #include <xen/serial.h>
14 #include <xen/cache.h>
15
16 #include <asm/processor.h>
17
18 /* Never drop characters, even if the async transmit buffer fills. */
19 /* #define SERIAL_NEVER_DROP_CHARS 1 */
20
21 unsigned int __ro_after_init serial_txbufsz = CONFIG_SERIAL_TX_BUFSIZE;
22 size_param("serial_tx_buffer", serial_txbufsz);
23
24 #define mask_serial_rxbuf_idx(_i) ((_i)&(serial_rxbufsz-1))
25 #define mask_serial_txbuf_idx(_i) ((_i)&(serial_txbufsz-1))
26
27 static struct serial_port com[SERHND_IDX + 1] = {
28 [0 ... SERHND_IDX] = {
29 .rx_lock = SPIN_LOCK_UNLOCKED,
30 .tx_lock = SPIN_LOCK_UNLOCKED
31 }
32 };
33
34 static bool __read_mostly post_irq;
35
serial_start_tx(struct serial_port * port)36 static inline void serial_start_tx(struct serial_port *port)
37 {
38 if ( port->driver->start_tx != NULL )
39 port->driver->start_tx(port);
40 }
41
serial_stop_tx(struct serial_port * port)42 static inline void serial_stop_tx(struct serial_port *port)
43 {
44 if ( port->driver->stop_tx != NULL )
45 port->driver->stop_tx(port);
46 }
47
serial_rx_interrupt(struct serial_port * port)48 void serial_rx_interrupt(struct serial_port *port)
49 {
50 char c;
51 serial_rx_fn fn = NULL;
52 unsigned long flags;
53
54 spin_lock_irqsave(&port->rx_lock, flags);
55
56 if ( port->driver->getc(port, &c) )
57 {
58 if ( port->rx != NULL )
59 fn = port->rx;
60 else if ( (c & 0x80) && (port->rx_hi != NULL) )
61 fn = port->rx_hi;
62 else if ( !(c & 0x80) && (port->rx_lo != NULL) )
63 fn = port->rx_lo;
64 else if ( (port->rxbufp - port->rxbufc) != serial_rxbufsz )
65 port->rxbuf[mask_serial_rxbuf_idx(port->rxbufp++)] = c;
66 }
67
68 spin_unlock_irqrestore(&port->rx_lock, flags);
69
70 if ( fn != NULL )
71 fn(c & 0x7f);
72 }
73
serial_tx_interrupt(struct serial_port * port)74 void serial_tx_interrupt(struct serial_port *port)
75 {
76 int i, n;
77 unsigned long flags;
78
79 local_irq_save(flags);
80
81 /*
82 * Avoid spinning for a long time: if there is a long-term lock holder
83 * then we know that they'll be stuffing bytes into the transmitter which
84 * will therefore not be empty for long.
85 */
86 while ( !spin_trylock(&port->tx_lock) )
87 {
88 if ( port->driver->tx_ready(port) <= 0 )
89 goto out;
90 cpu_relax();
91 }
92
93 if ( port->txbufc == port->txbufp )
94 {
95 /* Disable TX. nothing to send */
96 serial_stop_tx(port);
97 spin_unlock(&port->tx_lock);
98 goto out;
99 }
100 else
101 {
102 if ( port->driver->tx_ready(port) )
103 serial_start_tx(port);
104 }
105 for ( i = 0, n = port->driver->tx_ready(port); i < n; i++ )
106 {
107 if ( port->txbufc == port->txbufp )
108 break;
109 port->driver->putc(
110 port, port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]);
111 }
112 if ( i && port->driver->flush )
113 port->driver->flush(port);
114
115 spin_unlock(&port->tx_lock);
116
117 out:
118 local_irq_restore(flags);
119 }
120
__serial_putc(struct serial_port * port,char c)121 static void __serial_putc(struct serial_port *port, char c)
122 {
123 if ( (port->txbuf != NULL) && !port->sync )
124 {
125 /* Interrupt-driven (asynchronous) transmitter. */
126
127 if ( port->tx_quench )
128 {
129 /* Buffer filled and we are dropping characters. */
130 if ( (port->txbufp - port->txbufc) > (serial_txbufsz / 2) )
131 return;
132 port->tx_quench = 0;
133 }
134
135 if ( (port->txbufp - port->txbufc) == serial_txbufsz )
136 {
137 if ( port->tx_log_everything )
138 {
139 /* Buffer is full: we spin waiting for space to appear. */
140 int n;
141
142 while ( (n = port->driver->tx_ready(port)) == 0 )
143 cpu_relax();
144 if ( n > 0 )
145 {
146 /* Enable TX before sending chars */
147 serial_start_tx(port);
148 while ( n-- )
149 port->driver->putc(
150 port,
151 port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]);
152 port->txbuf[mask_serial_txbuf_idx(port->txbufp++)] = c;
153 }
154 }
155 else
156 {
157 /* Buffer is full: drop chars until buffer is half empty. */
158 port->tx_quench = 1;
159 }
160 return;
161 }
162
163 if ( ((port->txbufp - port->txbufc) == 0) &&
164 port->driver->tx_ready(port) > 0 )
165 {
166 /* Enable TX before sending chars */
167 serial_start_tx(port);
168 /* Buffer and UART FIFO are both empty, and port is available. */
169 port->driver->putc(port, c);
170 }
171 else
172 {
173 /* Normal case: buffer the character. */
174 port->txbuf[mask_serial_txbuf_idx(port->txbufp++)] = c;
175 }
176 }
177 else if ( port->driver->tx_ready )
178 {
179 int n;
180
181 /* Synchronous finite-capacity transmitter. */
182 while ( !(n = port->driver->tx_ready(port)) )
183 cpu_relax();
184 if ( n > 0 )
185 {
186 /* Enable TX before sending chars */
187 serial_start_tx(port);
188 port->driver->putc(port, c);
189 }
190 }
191 else
192 {
193 /* Simple synchronous transmitter. */
194 serial_start_tx(port);
195 port->driver->putc(port, c);
196 }
197 }
198
serial_puts(int handle,const char * s,size_t nr)199 void serial_puts(int handle, const char *s, size_t nr)
200 {
201 struct serial_port *port;
202 unsigned long flags;
203
204 if ( handle == -1 )
205 return;
206
207 port = &com[handle & SERHND_IDX];
208 if ( !port->driver || !port->driver->putc )
209 return;
210
211 spin_lock_irqsave(&port->tx_lock, flags);
212
213 for ( ; nr > 0; nr--, s++ )
214 {
215 char c = *s;
216
217 if ( (c == '\n') && (handle & SERHND_COOKED) )
218 __serial_putc(port, '\r' | ((handle & SERHND_HI) ? 0x80 : 0x00));
219
220 if ( handle & SERHND_HI )
221 c |= 0x80;
222 else if ( handle & SERHND_LO )
223 c &= 0x7f;
224
225 __serial_putc(port, c);
226 }
227
228 if ( port->driver->flush )
229 port->driver->flush(port);
230
231 spin_unlock_irqrestore(&port->tx_lock, flags);
232 }
233
serial_parse_handle(const char * conf)234 int __init serial_parse_handle(const char *conf)
235 {
236 int handle, flags = 0;
237
238 if ( !strncmp(conf, "dbgp", 4) && (!conf[4] || conf[4] == ',') )
239 {
240 handle = SERHND_DBGP;
241 goto common;
242 }
243
244 if ( !strncmp(conf, "ehci", 4) && (!conf[4] || conf[4] == ',') )
245 {
246 handle = SERHND_DBGP;
247 goto common;
248 }
249
250 if ( !strncmp(conf, "xhci", 4) && (!conf[4] || conf[4] == ',') )
251 {
252 handle = SERHND_XHCI;
253 goto common;
254 }
255
256 if ( !strncmp(conf, "dtuart", 6) )
257 {
258 handle = SERHND_DTUART;
259 goto common;
260 }
261
262 if ( strncmp(conf, "com", 3) )
263 goto fail;
264
265 switch ( conf[3] )
266 {
267 case '1':
268 handle = SERHND_COM1;
269 break;
270 case '2':
271 handle = SERHND_COM2;
272 break;
273 default:
274 goto fail;
275 }
276
277 if ( conf[4] == 'H' )
278 flags |= SERHND_HI;
279 else if ( conf[4] == 'L' )
280 flags |= SERHND_LO;
281
282 common:
283 if ( !com[handle].driver )
284 goto fail;
285
286 if ( !post_irq )
287 com[handle].state = serial_parsed;
288 else if ( com[handle].state != serial_initialized )
289 {
290 if ( com[handle].driver->init_postirq )
291 com[handle].driver->init_postirq(&com[handle]);
292 com[handle].state = serial_initialized;
293 }
294
295 return handle | flags | SERHND_COOKED;
296
297 fail:
298 return -1;
299 }
300
serial_set_rx_handler(int handle,serial_rx_fn fn)301 void __init serial_set_rx_handler(int handle, serial_rx_fn fn)
302 {
303 struct serial_port *port;
304 unsigned long flags;
305
306 if ( handle == -1 )
307 return;
308
309 port = &com[handle & SERHND_IDX];
310
311 spin_lock_irqsave(&port->rx_lock, flags);
312
313 if ( port->rx != NULL )
314 goto fail;
315
316 if ( handle & SERHND_LO )
317 {
318 if ( port->rx_lo != NULL )
319 goto fail;
320 port->rx_lo = fn;
321 }
322 else if ( handle & SERHND_HI )
323 {
324 if ( port->rx_hi != NULL )
325 goto fail;
326 port->rx_hi = fn;
327 }
328 else
329 {
330 if ( (port->rx_hi != NULL) || (port->rx_lo != NULL) )
331 goto fail;
332 port->rx = fn;
333 }
334
335 spin_unlock_irqrestore(&port->rx_lock, flags);
336 return;
337
338 fail:
339 spin_unlock_irqrestore(&port->rx_lock, flags);
340 printk("ERROR: Conflicting receive handlers for COM%d\n",
341 handle & SERHND_IDX);
342 }
343
serial_force_unlock(int handle)344 void serial_force_unlock(int handle)
345 {
346 struct serial_port *port;
347
348 if ( handle == -1 )
349 return;
350
351 port = &com[handle & SERHND_IDX];
352
353 spin_lock_init(&port->rx_lock);
354 spin_lock_init(&port->tx_lock);
355
356 serial_start_sync(handle);
357 }
358
serial_start_sync(int handle)359 void serial_start_sync(int handle)
360 {
361 struct serial_port *port;
362 unsigned long flags;
363
364 if ( handle == -1 )
365 return;
366
367 port = &com[handle & SERHND_IDX];
368
369 spin_lock_irqsave(&port->tx_lock, flags);
370
371 if ( port->sync++ == 0 )
372 {
373 while ( (port->txbufp - port->txbufc) != 0 )
374 {
375 int n;
376
377 while ( !(n = port->driver->tx_ready(port)) )
378 cpu_relax();
379 if ( n < 0 )
380 /* port is unavailable and might not come up until reenabled by
381 dom0, we can't really do proper sync */
382 break;
383 serial_start_tx(port);
384 port->driver->putc(
385 port, port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]);
386 }
387 if ( port->driver->flush )
388 port->driver->flush(port);
389 }
390
391 spin_unlock_irqrestore(&port->tx_lock, flags);
392 }
393
serial_end_sync(int handle)394 void serial_end_sync(int handle)
395 {
396 struct serial_port *port;
397 unsigned long flags;
398
399 if ( handle == -1 )
400 return;
401
402 port = &com[handle & SERHND_IDX];
403
404 spin_lock_irqsave(&port->tx_lock, flags);
405
406 port->sync--;
407
408 spin_unlock_irqrestore(&port->tx_lock, flags);
409 }
410
serial_start_log_everything(int handle)411 void serial_start_log_everything(int handle)
412 {
413 struct serial_port *port;
414 unsigned long flags;
415
416 if ( handle == -1 )
417 return;
418
419 port = &com[handle & SERHND_IDX];
420
421 spin_lock_irqsave(&port->tx_lock, flags);
422 port->tx_log_everything++;
423 port->tx_quench = 0;
424 spin_unlock_irqrestore(&port->tx_lock, flags);
425 }
426
serial_end_log_everything(int handle)427 void serial_end_log_everything(int handle)
428 {
429 struct serial_port *port;
430 unsigned long flags;
431
432 if ( handle == -1 )
433 return;
434
435 port = &com[handle & SERHND_IDX];
436
437 spin_lock_irqsave(&port->tx_lock, flags);
438 port->tx_log_everything--;
439 spin_unlock_irqrestore(&port->tx_lock, flags);
440 }
441
serial_init_preirq(void)442 void __init serial_init_preirq(void)
443 {
444 int i;
445 for ( i = 0; i < ARRAY_SIZE(com); i++ )
446 if ( com[i].driver && com[i].driver->init_preirq )
447 com[i].driver->init_preirq(&com[i]);
448 }
449
serial_init_irq(void)450 void __init serial_init_irq(void)
451 {
452 unsigned int i;
453
454 for ( i = 0; i < ARRAY_SIZE(com); i++ )
455 if ( com[i].driver && com[i].driver->init_irq )
456 com[i].driver->init_irq(&com[i]);
457 }
458
serial_init_postirq(void)459 void __init serial_init_postirq(void)
460 {
461 int i;
462 for ( i = 0; i < ARRAY_SIZE(com); i++ )
463 if ( com[i].state == serial_parsed )
464 {
465 if ( com[i].driver->init_postirq )
466 com[i].driver->init_postirq(&com[i]);
467 com[i].state = serial_initialized;
468 }
469 post_irq = 1;
470 }
471
serial_endboot(void)472 void __init serial_endboot(void)
473 {
474 int i;
475 for ( i = 0; i < ARRAY_SIZE(com); i++ )
476 if ( com[i].driver && com[i].driver->endboot )
477 com[i].driver->endboot(&com[i]);
478 }
479
serial_irq(int idx)480 int __init serial_irq(int idx)
481 {
482 if ( (idx >= 0) && (idx < ARRAY_SIZE(com)) &&
483 com[idx].driver && com[idx].driver->irq )
484 return com[idx].driver->irq(&com[idx]);
485
486 return -1;
487 }
488
serial_vuart_info(int idx)489 const struct vuart_info *serial_vuart_info(int idx)
490 {
491 if ( (idx >= 0) && (idx < ARRAY_SIZE(com)) &&
492 com[idx].driver && com[idx].driver->vuart_info )
493 return com[idx].driver->vuart_info(&com[idx]);
494
495 return NULL;
496 }
497
serial_suspend(void)498 void serial_suspend(void)
499 {
500 int i;
501 for ( i = 0; i < ARRAY_SIZE(com); i++ )
502 if ( com[i].state == serial_initialized && com[i].driver->suspend )
503 com[i].driver->suspend(&com[i]);
504 }
505
serial_resume(void)506 void serial_resume(void)
507 {
508 int i;
509 for ( i = 0; i < ARRAY_SIZE(com); i++ )
510 if ( com[i].state == serial_initialized && com[i].driver->resume )
511 com[i].driver->resume(&com[i]);
512 }
513
serial_register_uart(int idx,struct uart_driver * driver,void * uart)514 void __init serial_register_uart(int idx, struct uart_driver *driver,
515 void *uart)
516 {
517 /* Store UART-specific info. */
518 com[idx].driver = driver;
519 com[idx].uart = uart;
520 }
521
serial_async_transmit(struct serial_port * port)522 void __init serial_async_transmit(struct serial_port *port)
523 {
524 BUG_ON(!port->driver->tx_ready);
525 if ( port->txbuf != NULL )
526 return;
527 if ( serial_txbufsz < PAGE_SIZE )
528 serial_txbufsz = PAGE_SIZE;
529 while ( serial_txbufsz & (serial_txbufsz - 1) )
530 serial_txbufsz &= serial_txbufsz - 1;
531 port->txbuf = alloc_xenheap_pages(
532 get_order_from_bytes(serial_txbufsz), 0);
533 }
534
535 /*
536 * Local variables:
537 * mode: C
538 * c-file-style: "BSD"
539 * c-basic-offset: 4
540 * tab-width: 4
541 * indent-tabs-mode: nil
542 * End:
543 */
544