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