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