debuggers.hg

view xen/drivers/char/ns16550.c @ 20420:5a224e101cb3

Miscellaneous data placement adjustments

Make various data items const or __read_mostly where
possible/reasonable.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Oct 28 10:54:50 2009 +0000 (2009-10-28)
parents cf95641ba1d0
children 12fc55dffb6b
line source
1 /******************************************************************************
2 * ns16550.c
3 *
4 * Driver for 16550-series UARTs. This driver is to be kept within Xen as
5 * it permits debugging of seriously-toasted machines (e.g., in situations
6 * where a device driver within a guest OS would be inaccessible).
7 *
8 * Copyright (c) 2003-2005, K A Fraser
9 */
11 #include <xen/config.h>
12 #include <xen/console.h>
13 #include <xen/init.h>
14 #include <xen/irq.h>
15 #include <xen/sched.h>
16 #include <xen/serial.h>
17 #include <xen/iocap.h>
18 #include <asm/io.h>
20 /*
21 * Configure serial port with a string:
22 * <baud>[/<clock_hz>][,DPS[,<io-base>[,<irq>]]].
23 * The tail of the string can be omitted if platform defaults are sufficient.
24 * If the baud rate is pre-configured, perhaps by a bootloader, then 'auto'
25 * can be specified in place of a numeric baud rate. Polled mode is specified
26 * by requesting irq 0.
27 */
28 static char __initdata opt_com1[30] = "";
29 static char __initdata opt_com2[30] = "";
30 string_param("com1", opt_com1);
31 string_param("com2", opt_com2);
33 static struct ns16550 {
34 int baud, clock_hz, data_bits, parity, stop_bits, irq;
35 unsigned long io_base; /* I/O port or memory-mapped I/O address. */
36 char *remapped_io_base; /* Remapped virtual address of mmap I/O. */
37 /* UART with IRQ line: interrupt-driven I/O. */
38 struct irqaction irqaction;
39 /* UART with no IRQ line: periodically-polled I/O. */
40 struct timer timer;
41 unsigned int timeout_ms;
42 } ns16550_com[2] = { { 0 } };
44 /* Register offsets */
45 #define RBR 0x00 /* receive buffer */
46 #define THR 0x00 /* transmit holding */
47 #define IER 0x01 /* interrupt enable */
48 #define IIR 0x02 /* interrupt identity */
49 #define FCR 0x02 /* FIFO control */
50 #define LCR 0x03 /* line control */
51 #define MCR 0x04 /* Modem control */
52 #define LSR 0x05 /* line status */
53 #define MSR 0x06 /* Modem status */
54 #define DLL 0x00 /* divisor latch (ls) (DLAB=1) */
55 #define DLM 0x01 /* divisor latch (ms) (DLAB=1) */
57 /* Interrupt Enable Register */
58 #define IER_ERDAI 0x01 /* rx data recv'd */
59 #define IER_ETHREI 0x02 /* tx reg. empty */
60 #define IER_ELSI 0x04 /* rx line status */
61 #define IER_EMSI 0x08 /* MODEM status */
63 /* Interrupt Identification Register */
64 #define IIR_NOINT 0x01 /* no interrupt pending */
65 #define IIR_IMASK 0x06 /* interrupt identity: */
66 #define IIR_LSI 0x06 /* - rx line status */
67 #define IIR_RDAI 0x04 /* - rx data recv'd */
68 #define IIR_THREI 0x02 /* - tx reg. empty */
69 #define IIR_MSI 0x00 /* - MODEM status */
71 /* FIFO Control Register */
72 #define FCR_ENABLE 0x01 /* enable FIFO */
73 #define FCR_CLRX 0x02 /* clear Rx FIFO */
74 #define FCR_CLTX 0x04 /* clear Tx FIFO */
75 #define FCR_DMA 0x10 /* enter DMA mode */
76 #define FCR_TRG1 0x00 /* Rx FIFO trig lev 1 */
77 #define FCR_TRG4 0x40 /* Rx FIFO trig lev 4 */
78 #define FCR_TRG8 0x80 /* Rx FIFO trig lev 8 */
79 #define FCR_TRG14 0xc0 /* Rx FIFO trig lev 14 */
81 /* Line Control Register */
82 #define LCR_DLAB 0x80 /* Divisor Latch Access */
84 /* Modem Control Register */
85 #define MCR_DTR 0x01 /* Data Terminal Ready */
86 #define MCR_RTS 0x02 /* Request to Send */
87 #define MCR_OUT2 0x08 /* OUT2: interrupt mask */
88 #define MCR_LOOP 0x10 /* Enable loopback test mode */
90 /* Line Status Register */
91 #define LSR_DR 0x01 /* Data ready */
92 #define LSR_OE 0x02 /* Overrun */
93 #define LSR_PE 0x04 /* Parity error */
94 #define LSR_FE 0x08 /* Framing error */
95 #define LSR_BI 0x10 /* Break */
96 #define LSR_THRE 0x20 /* Xmit hold reg empty */
97 #define LSR_TEMT 0x40 /* Xmitter empty */
98 #define LSR_ERR 0x80 /* Error */
100 /* These parity settings can be ORed directly into the LCR. */
101 #define PARITY_NONE (0<<3)
102 #define PARITY_ODD (1<<3)
103 #define PARITY_EVEN (3<<3)
104 #define PARITY_MARK (5<<3)
105 #define PARITY_SPACE (7<<3)
107 /* Frequency of external clock source. This definition assumes PC platform. */
108 #define UART_CLOCK_HZ 1843200
110 static char ns_read_reg(struct ns16550 *uart, int reg)
111 {
112 if ( uart->remapped_io_base == NULL )
113 return inb(uart->io_base + reg);
114 return readb(uart->remapped_io_base + reg);
115 }
117 static void ns_write_reg(struct ns16550 *uart, int reg, char c)
118 {
119 if ( uart->remapped_io_base == NULL )
120 return outb(c, uart->io_base + reg);
121 writeb(c, uart->remapped_io_base + reg);
122 }
124 static void ns16550_interrupt(
125 int irq, void *dev_id, struct cpu_user_regs *regs)
126 {
127 struct serial_port *port = dev_id;
128 struct ns16550 *uart = port->uart;
130 while ( !(ns_read_reg(uart, IIR) & IIR_NOINT) )
131 {
132 char lsr = ns_read_reg(uart, LSR);
133 if ( lsr & LSR_THRE )
134 serial_tx_interrupt(port, regs);
135 if ( lsr & LSR_DR )
136 serial_rx_interrupt(port, regs);
137 }
138 }
140 static void ns16550_poll(void *data)
141 {
142 struct serial_port *port = data;
143 struct ns16550 *uart = port->uart;
144 struct cpu_user_regs *regs = guest_cpu_user_regs();
146 while ( ns_read_reg(uart, LSR) & LSR_DR )
147 serial_rx_interrupt(port, regs);
149 if ( ns_read_reg(uart, LSR) & LSR_THRE )
150 serial_tx_interrupt(port, regs);
152 set_timer(&uart->timer, NOW() + MILLISECS(uart->timeout_ms));
153 }
155 static int ns16550_tx_empty(struct serial_port *port)
156 {
157 struct ns16550 *uart = port->uart;
158 return !!(ns_read_reg(uart, LSR) & LSR_THRE);
159 }
161 static void ns16550_putc(struct serial_port *port, char c)
162 {
163 struct ns16550 *uart = port->uart;
164 ns_write_reg(uart, THR, c);
165 }
167 static int ns16550_getc(struct serial_port *port, char *pc)
168 {
169 struct ns16550 *uart = port->uart;
171 if ( !(ns_read_reg(uart, LSR) & LSR_DR) )
172 return 0;
174 *pc = ns_read_reg(uart, RBR);
175 return 1;
176 }
178 static void __devinit ns16550_init_preirq(struct serial_port *port)
179 {
180 struct ns16550 *uart = port->uart;
181 unsigned char lcr;
182 unsigned int divisor;
184 /* I/O ports are distinguished by their size (16 bits). */
185 if ( uart->io_base >= 0x10000 )
186 uart->remapped_io_base = (char *)ioremap(uart->io_base, 8);
188 lcr = (uart->data_bits - 5) | ((uart->stop_bits - 1) << 2) | uart->parity;
190 /* No interrupts. */
191 ns_write_reg(uart, IER, 0);
193 /* Line control and baud-rate generator. */
194 ns_write_reg(uart, LCR, lcr | LCR_DLAB);
195 if ( uart->baud != BAUD_AUTO )
196 {
197 /* Baud rate specified: program it into the divisor latch. */
198 divisor = uart->clock_hz / (uart->baud << 4);
199 ns_write_reg(uart, DLL, (char)divisor);
200 ns_write_reg(uart, DLM, (char)(divisor >> 8));
201 }
202 else
203 {
204 /* Baud rate already set: read it out from the divisor latch. */
205 divisor = ns_read_reg(uart, DLL);
206 divisor |= ns_read_reg(uart, DLM) << 8;
207 uart->baud = uart->clock_hz / (divisor << 4);
208 }
209 ns_write_reg(uart, LCR, lcr);
211 /* No flow ctrl: DTR and RTS are both wedged high to keep remote happy. */
212 ns_write_reg(uart, MCR, MCR_DTR | MCR_RTS);
214 /* Enable and clear the FIFOs. Set a large trigger threshold. */
215 ns_write_reg(uart, FCR, FCR_ENABLE | FCR_CLRX | FCR_CLTX | FCR_TRG14);
217 /* Check this really is a 16550+. Otherwise we have no FIFOs. */
218 if ( ((ns_read_reg(uart, IIR) & 0xc0) == 0xc0) &&
219 ((ns_read_reg(uart, FCR) & FCR_TRG14) == FCR_TRG14) )
220 port->tx_fifo_size = 16;
221 }
223 static void __devinit ns16550_init_postirq(struct serial_port *port)
224 {
225 struct ns16550 *uart = port->uart;
226 int rc, bits;
228 if ( uart->irq < 0 )
229 return;
231 serial_async_transmit(port);
233 if ( uart->irq == 0 )
234 {
235 /* Polled mode. Calculate time to fill RX FIFO and/or empty TX FIFO. */
236 bits = uart->data_bits + uart->stop_bits + !!uart->parity;
237 uart->timeout_ms = max_t(
238 unsigned int, 1, (bits * port->tx_fifo_size * 1000) / uart->baud);
239 init_timer(&uart->timer, ns16550_poll, port, 0);
240 set_timer(&uart->timer, NOW() + MILLISECS(uart->timeout_ms));
241 }
242 else
243 {
244 uart->irqaction.handler = ns16550_interrupt;
245 uart->irqaction.name = "ns16550";
246 uart->irqaction.dev_id = port;
247 if ( (rc = setup_irq(uart->irq, &uart->irqaction)) != 0 )
248 printk("ERROR: Failed to allocate ns16550 IRQ %d\n", uart->irq);
250 /* Master interrupt enable; also keep DTR/RTS asserted. */
251 ns_write_reg(uart, MCR, MCR_OUT2 | MCR_DTR | MCR_RTS);
253 /* Enable receive and transmit interrupts. */
254 ns_write_reg(uart, IER, IER_ERDAI | IER_ETHREI);
255 }
256 }
258 #ifdef CONFIG_X86
259 static void __init ns16550_endboot(struct serial_port *port)
260 {
261 struct ns16550 *uart = port->uart;
262 if ( ioports_deny_access(dom0, uart->io_base, uart->io_base + 7) != 0 )
263 BUG();
264 }
265 #else
266 #define ns16550_endboot NULL
267 #endif
269 static int ns16550_irq(struct serial_port *port)
270 {
271 struct ns16550 *uart = port->uart;
272 return ((uart->irq > 0) ? uart->irq : -1);
273 }
275 static struct uart_driver __read_mostly ns16550_driver = {
276 .init_preirq = ns16550_init_preirq,
277 .init_postirq = ns16550_init_postirq,
278 .endboot = ns16550_endboot,
279 .tx_empty = ns16550_tx_empty,
280 .putc = ns16550_putc,
281 .getc = ns16550_getc,
282 .irq = ns16550_irq
283 };
285 static int __init parse_parity_char(int c)
286 {
287 switch ( c )
288 {
289 case 'n':
290 return PARITY_NONE;
291 case 'o':
292 return PARITY_ODD;
293 case 'e':
294 return PARITY_EVEN;
295 case 'm':
296 return PARITY_MARK;
297 case 's':
298 return PARITY_SPACE;
299 }
300 return 0;
301 }
303 static int __init check_existence(struct ns16550 *uart)
304 {
305 unsigned char status, scratch, scratch2, scratch3;
307 /*
308 * We can't poke MMIO UARTs until they get I/O remapped later. Assume that
309 * if we're getting MMIO UARTs, the arch code knows what it's doing.
310 */
311 if ( uart->io_base >= 0x10000 )
312 return 1;
314 /*
315 * Do a simple existence test first; if we fail this,
316 * there's no point trying anything else.
317 */
318 scratch = ns_read_reg(uart, IER);
319 ns_write_reg(uart, IER, 0);
321 /*
322 * Mask out IER[7:4] bits for test as some UARTs (e.g. TL
323 * 16C754B) allow only to modify them if an EFR bit is set.
324 */
325 scratch2 = ns_read_reg(uart, IER) & 0x0f;
326 ns_write_reg(uart, IER, 0x0F);
327 scratch3 = ns_read_reg(uart, IER) & 0x0f;
328 ns_write_reg(uart, IER, scratch);
329 if ( (scratch2 != 0) || (scratch3 != 0x0F) )
330 return 0;
332 /*
333 * Check to see if a UART is really there.
334 * Use loopback test mode.
335 */
336 ns_write_reg(uart, MCR, MCR_LOOP | 0x0A);
337 status = ns_read_reg(uart, MSR) & 0xF0;
338 return (status == 0x90);
339 }
341 #define PARSE_ERR(_f, _a...) \
342 do { \
343 printk( "ERROR: " _f "\n" , ## _a ); \
344 return; \
345 } while ( 0 )
347 static void __init ns16550_parse_port_config(
348 struct ns16550 *uart, const char *conf)
349 {
350 int baud;
352 /* No user-specified configuration? */
353 if ( (conf == NULL) || (*conf == '\0') )
354 {
355 /* Some platforms may automatically probe the UART configuartion. */
356 if ( uart->baud != 0 )
357 goto config_parsed;
358 return;
359 }
361 if ( strncmp(conf, "auto", 4) == 0 )
362 {
363 uart->baud = BAUD_AUTO;
364 conf += 4;
365 }
366 else if ( (baud = simple_strtoul(conf, &conf, 10)) != 0 )
367 uart->baud = baud;
369 if ( *conf == '/')
370 {
371 conf++;
372 uart->clock_hz = simple_strtoul(conf, &conf, 0) << 4;
373 }
375 if ( *conf != ',' )
376 goto config_parsed;
377 conf++;
379 uart->data_bits = simple_strtoul(conf, &conf, 10);
381 uart->parity = parse_parity_char(*conf);
382 conf++;
384 uart->stop_bits = simple_strtoul(conf, &conf, 10);
386 if ( *conf == ',' )
387 {
388 conf++;
389 uart->io_base = simple_strtoul(conf, &conf, 0);
391 if ( *conf == ',' )
392 {
393 conf++;
394 uart->irq = simple_strtoul(conf, &conf, 10);
395 }
396 }
398 config_parsed:
399 /* Sanity checks. */
400 if ( (uart->baud != BAUD_AUTO) &&
401 ((uart->baud < 1200) || (uart->baud > 115200)) )
402 PARSE_ERR("Baud rate %d outside supported range.", uart->baud);
403 if ( (uart->data_bits < 5) || (uart->data_bits > 8) )
404 PARSE_ERR("%d data bits are unsupported.", uart->data_bits);
405 if ( (uart->stop_bits < 1) || (uart->stop_bits > 2) )
406 PARSE_ERR("%d stop bits are unsupported.", uart->stop_bits);
407 if ( uart->io_base == 0 )
408 PARSE_ERR("I/O base address must be specified.");
409 if ( !check_existence(uart) )
410 PARSE_ERR("16550-compatible serial UART not present");
412 /* Register with generic serial driver. */
413 serial_register_uart(uart - ns16550_com, &ns16550_driver, uart);
414 }
416 void __init ns16550_init(int index, struct ns16550_defaults *defaults)
417 {
418 struct ns16550 *uart;
420 if ( (index < 0) || (index > 1) )
421 return;
423 uart = &ns16550_com[index];
425 uart->baud = (defaults->baud ? :
426 console_has((index == 0) ? "com1" : "com2")
427 ? BAUD_AUTO : 0);
428 uart->clock_hz = UART_CLOCK_HZ;
429 uart->data_bits = defaults->data_bits;
430 uart->parity = parse_parity_char(defaults->parity);
431 uart->stop_bits = defaults->stop_bits;
432 uart->irq = defaults->irq;
433 uart->io_base = defaults->io_base;
435 ns16550_parse_port_config(uart, (index == 0) ? opt_com1 : opt_com2);
436 }
438 /*
439 * Local variables:
440 * mode: C
441 * c-set-style: "BSD"
442 * c-basic-offset: 4
443 * tab-width: 4
444 * indent-tabs-mode: nil
445 * End:
446 */