diff options
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/8250.c | 21 | ||||
-rw-r--r-- | drivers/serial/bfin_5xx.c | 125 | ||||
-rw-r--r-- | drivers/serial/icom.c | 55 | ||||
-rw-r--r-- | drivers/serial/sunhv.c | 276 |
4 files changed, 332 insertions, 145 deletions
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 48e259a0167d..c84dab083a85 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c | |||
@@ -894,7 +894,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) | |||
894 | quot = serial_dl_read(up); | 894 | quot = serial_dl_read(up); |
895 | quot <<= 3; | 895 | quot <<= 3; |
896 | 896 | ||
897 | status1 = serial_in(up, 0x04); /* EXCR1 */ | 897 | status1 = serial_in(up, 0x04); /* EXCR2 */ |
898 | status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ | 898 | status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ |
899 | status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ | 899 | status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ |
900 | serial_outp(up, 0x04, status1); | 900 | serial_outp(up, 0x04, status1); |
@@ -2617,7 +2617,22 @@ void serial8250_suspend_port(int line) | |||
2617 | */ | 2617 | */ |
2618 | void serial8250_resume_port(int line) | 2618 | void serial8250_resume_port(int line) |
2619 | { | 2619 | { |
2620 | uart_resume_port(&serial8250_reg, &serial8250_ports[line].port); | 2620 | struct uart_8250_port *up = &serial8250_ports[line]; |
2621 | |||
2622 | if (up->capabilities & UART_NATSEMI) { | ||
2623 | unsigned char tmp; | ||
2624 | |||
2625 | /* Ensure it's still in high speed mode */ | ||
2626 | serial_outp(up, UART_LCR, 0xE0); | ||
2627 | |||
2628 | tmp = serial_in(up, 0x04); /* EXCR2 */ | ||
2629 | tmp &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ | ||
2630 | tmp |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ | ||
2631 | serial_outp(up, 0x04, tmp); | ||
2632 | |||
2633 | serial_outp(up, UART_LCR, 0); | ||
2634 | } | ||
2635 | uart_resume_port(&serial8250_reg, &up->port); | ||
2621 | } | 2636 | } |
2622 | 2637 | ||
2623 | /* | 2638 | /* |
@@ -2694,7 +2709,7 @@ static int serial8250_resume(struct platform_device *dev) | |||
2694 | struct uart_8250_port *up = &serial8250_ports[i]; | 2709 | struct uart_8250_port *up = &serial8250_ports[i]; |
2695 | 2710 | ||
2696 | if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) | 2711 | if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) |
2697 | uart_resume_port(&serial8250_reg, &up->port); | 2712 | serial8250_resume_port(i); |
2698 | } | 2713 | } |
2699 | 2714 | ||
2700 | return 0; | 2715 | return 0; |
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 408390f93db9..787dc7168f3e 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c | |||
@@ -6,8 +6,6 @@ | |||
6 | * Created: | 6 | * Created: |
7 | * Description: Driver for blackfin 5xx serial ports | 7 | * Description: Driver for blackfin 5xx serial ports |
8 | * | 8 | * |
9 | * Rev: $Id: bfin_5xx.c,v 1.19 2006/09/24 02:33:53 aubrey Exp $ | ||
10 | * | ||
11 | * Modified: | 9 | * Modified: |
12 | * Copyright 2006 Analog Devices Inc. | 10 | * Copyright 2006 Analog Devices Inc. |
13 | * | 11 | * |
@@ -152,7 +150,7 @@ static void local_put_char(struct bfin_serial_port *uart, char ch) | |||
152 | 150 | ||
153 | static void bfin_serial_rx_chars(struct bfin_serial_port *uart) | 151 | static void bfin_serial_rx_chars(struct bfin_serial_port *uart) |
154 | { | 152 | { |
155 | struct tty_struct *tty = uart->port.info?uart->port.info->tty:0; | 153 | struct tty_struct *tty = uart->port.info->tty; |
156 | unsigned int status, ch, flg; | 154 | unsigned int status, ch, flg; |
157 | #ifdef BF533_FAMILY | 155 | #ifdef BF533_FAMILY |
158 | static int in_break = 0; | 156 | static int in_break = 0; |
@@ -173,8 +171,10 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) | |||
173 | if (ch != 0) { | 171 | if (ch != 0) { |
174 | in_break = 0; | 172 | in_break = 0; |
175 | ch = UART_GET_CHAR(uart); | 173 | ch = UART_GET_CHAR(uart); |
176 | } | 174 | if (bfin_revid() < 5) |
177 | return; | 175 | return; |
176 | } else | ||
177 | return; | ||
178 | } | 178 | } |
179 | #endif | 179 | #endif |
180 | 180 | ||
@@ -185,27 +185,32 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) | |||
185 | uart->port.icount.brk++; | 185 | uart->port.icount.brk++; |
186 | if (uart_handle_break(&uart->port)) | 186 | if (uart_handle_break(&uart->port)) |
187 | goto ignore_char; | 187 | goto ignore_char; |
188 | flg = TTY_BREAK; | 188 | } |
189 | } else if (status & PE) { | 189 | if (status & PE) |
190 | flg = TTY_PARITY; | ||
191 | uart->port.icount.parity++; | 190 | uart->port.icount.parity++; |
192 | } else if (status & OE) { | 191 | if (status & OE) |
193 | flg = TTY_OVERRUN; | ||
194 | uart->port.icount.overrun++; | 192 | uart->port.icount.overrun++; |
195 | } else if (status & FE) { | 193 | if (status & FE) |
196 | flg = TTY_FRAME; | ||
197 | uart->port.icount.frame++; | 194 | uart->port.icount.frame++; |
198 | } else | 195 | |
196 | status &= uart->port.read_status_mask; | ||
197 | |||
198 | if (status & BI) | ||
199 | flg = TTY_BREAK; | ||
200 | else if (status & PE) | ||
201 | flg = TTY_PARITY; | ||
202 | else if (status & FE) | ||
203 | flg = TTY_FRAME; | ||
204 | else | ||
199 | flg = TTY_NORMAL; | 205 | flg = TTY_NORMAL; |
200 | 206 | ||
201 | if (uart_handle_sysrq_char(&uart->port, ch)) | 207 | if (uart_handle_sysrq_char(&uart->port, ch)) |
202 | goto ignore_char; | 208 | goto ignore_char; |
203 | if (tty) | ||
204 | uart_insert_char(&uart->port, status, 2, ch, flg); | ||
205 | 209 | ||
206 | ignore_char: | 210 | uart_insert_char(&uart->port, status, OE, ch, flg); |
207 | if (tty) | 211 | |
208 | tty_flip_buffer_push(tty); | 212 | ignore_char: |
213 | tty_flip_buffer_push(tty); | ||
209 | } | 214 | } |
210 | 215 | ||
211 | static void bfin_serial_tx_chars(struct bfin_serial_port *uart) | 216 | static void bfin_serial_tx_chars(struct bfin_serial_port *uart) |
@@ -240,24 +245,29 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart) | |||
240 | bfin_serial_stop_tx(&uart->port); | 245 | bfin_serial_stop_tx(&uart->port); |
241 | } | 246 | } |
242 | 247 | ||
243 | static irqreturn_t bfin_serial_int(int irq, void *dev_id) | 248 | static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id) |
244 | { | 249 | { |
245 | struct bfin_serial_port *uart = dev_id; | 250 | struct bfin_serial_port *uart = dev_id; |
246 | unsigned short status; | ||
247 | 251 | ||
248 | spin_lock(&uart->port.lock); | 252 | spin_lock(&uart->port.lock); |
249 | status = UART_GET_IIR(uart); | 253 | while ((UART_GET_IIR(uart) & IIR_STATUS) == IIR_RX_READY) |
250 | do { | 254 | bfin_serial_rx_chars(uart); |
251 | if ((status & IIR_STATUS) == IIR_TX_READY) | ||
252 | bfin_serial_tx_chars(uart); | ||
253 | if ((status & IIR_STATUS) == IIR_RX_READY) | ||
254 | bfin_serial_rx_chars(uart); | ||
255 | status = UART_GET_IIR(uart); | ||
256 | } while (status & (IIR_TX_READY | IIR_RX_READY)); | ||
257 | spin_unlock(&uart->port.lock); | 255 | spin_unlock(&uart->port.lock); |
258 | return IRQ_HANDLED; | 256 | return IRQ_HANDLED; |
259 | } | 257 | } |
260 | 258 | ||
259 | static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id) | ||
260 | { | ||
261 | struct bfin_serial_port *uart = dev_id; | ||
262 | |||
263 | spin_lock(&uart->port.lock); | ||
264 | while ((UART_GET_IIR(uart) & IIR_STATUS) == IIR_TX_READY) | ||
265 | bfin_serial_tx_chars(uart); | ||
266 | spin_unlock(&uart->port.lock); | ||
267 | return IRQ_HANDLED; | ||
268 | } | ||
269 | |||
270 | |||
261 | static void bfin_serial_do_work(struct work_struct *work) | 271 | static void bfin_serial_do_work(struct work_struct *work) |
262 | { | 272 | { |
263 | struct bfin_serial_port *uart = container_of(work, struct bfin_serial_port, cts_workqueue); | 273 | struct bfin_serial_port *uart = container_of(work, struct bfin_serial_port, cts_workqueue); |
@@ -319,7 +329,7 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) | |||
319 | spin_unlock_irqrestore(&uart->port.lock, flags); | 329 | spin_unlock_irqrestore(&uart->port.lock, flags); |
320 | } | 330 | } |
321 | 331 | ||
322 | static void bfin_serial_dma_rx_chars(struct bfin_serial_port * uart) | 332 | static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart) |
323 | { | 333 | { |
324 | struct tty_struct *tty = uart->port.info->tty; | 334 | struct tty_struct *tty = uart->port.info->tty; |
325 | int i, flg, status; | 335 | int i, flg, status; |
@@ -331,25 +341,32 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port * uart) | |||
331 | uart->port.icount.brk++; | 341 | uart->port.icount.brk++; |
332 | if (uart_handle_break(&uart->port)) | 342 | if (uart_handle_break(&uart->port)) |
333 | goto dma_ignore_char; | 343 | goto dma_ignore_char; |
334 | flg = TTY_BREAK; | 344 | } |
335 | } else if (status & PE) { | 345 | if (status & PE) |
336 | flg = TTY_PARITY; | ||
337 | uart->port.icount.parity++; | 346 | uart->port.icount.parity++; |
338 | } else if (status & OE) { | 347 | if (status & OE) |
339 | flg = TTY_OVERRUN; | ||
340 | uart->port.icount.overrun++; | 348 | uart->port.icount.overrun++; |
341 | } else if (status & FE) { | 349 | if (status & FE) |
342 | flg = TTY_FRAME; | ||
343 | uart->port.icount.frame++; | 350 | uart->port.icount.frame++; |
344 | } else | 351 | |
352 | status &= uart->port.read_status_mask; | ||
353 | |||
354 | if (status & BI) | ||
355 | flg = TTY_BREAK; | ||
356 | else if (status & PE) | ||
357 | flg = TTY_PARITY; | ||
358 | else if (status & FE) | ||
359 | flg = TTY_FRAME; | ||
360 | else | ||
345 | flg = TTY_NORMAL; | 361 | flg = TTY_NORMAL; |
346 | 362 | ||
347 | for (i = uart->rx_dma_buf.head; i < uart->rx_dma_buf.tail; i++) { | 363 | for (i = uart->rx_dma_buf.head; i < uart->rx_dma_buf.tail; i++) { |
348 | if (uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i])) | 364 | if (uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i])) |
349 | goto dma_ignore_char; | 365 | goto dma_ignore_char; |
350 | uart_insert_char(&uart->port, status, 2, uart->rx_dma_buf.buf[i], flg); | 366 | uart_insert_char(&uart->port, status, OE, uart->rx_dma_buf.buf[i], flg); |
351 | } | 367 | } |
352 | dma_ignore_char: | 368 | |
369 | dma_ignore_char: | ||
353 | tty_flip_buffer_push(tty); | 370 | tty_flip_buffer_push(tty); |
354 | } | 371 | } |
355 | 372 | ||
@@ -545,14 +562,14 @@ static int bfin_serial_startup(struct uart_port *port) | |||
545 | add_timer(&(uart->rx_dma_timer)); | 562 | add_timer(&(uart->rx_dma_timer)); |
546 | #else | 563 | #else |
547 | if (request_irq | 564 | if (request_irq |
548 | (uart->port.irq, bfin_serial_int, IRQF_DISABLED, | 565 | (uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED, |
549 | "BFIN_UART_RX", uart)) { | 566 | "BFIN_UART_RX", uart)) { |
550 | printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n"); | 567 | printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n"); |
551 | return -EBUSY; | 568 | return -EBUSY; |
552 | } | 569 | } |
553 | 570 | ||
554 | if (request_irq | 571 | if (request_irq |
555 | (uart->port.irq+1, bfin_serial_int, IRQF_DISABLED, | 572 | (uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED, |
556 | "BFIN_UART_TX", uart)) { | 573 | "BFIN_UART_TX", uart)) { |
557 | printk(KERN_NOTICE "Unable to attach BlackFin UART TX interrupt\n"); | 574 | printk(KERN_NOTICE "Unable to attach BlackFin UART TX interrupt\n"); |
558 | free_irq(uart->port.irq, uart); | 575 | free_irq(uart->port.irq, uart); |
@@ -614,13 +631,27 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, | |||
614 | lcr |= EPS; | 631 | lcr |= EPS; |
615 | } | 632 | } |
616 | 633 | ||
617 | /* These controls are not implemented for this port */ | 634 | port->read_status_mask = OE; |
618 | termios->c_iflag |= INPCK | BRKINT | PARMRK; | 635 | if (termios->c_iflag & INPCK) |
619 | termios->c_iflag &= ~(IGNPAR | IGNBRK); | 636 | port->read_status_mask |= (FE | PE); |
637 | if (termios->c_iflag & (BRKINT | PARMRK)) | ||
638 | port->read_status_mask |= BI; | ||
620 | 639 | ||
621 | /* These controls are not implemented for this port */ | 640 | /* |
622 | termios->c_iflag |= INPCK | BRKINT | PARMRK; | 641 | * Characters to ignore |
623 | termios->c_iflag &= ~(IGNPAR | IGNBRK); | 642 | */ |
643 | port->ignore_status_mask = 0; | ||
644 | if (termios->c_iflag & IGNPAR) | ||
645 | port->ignore_status_mask |= FE | PE; | ||
646 | if (termios->c_iflag & IGNBRK) { | ||
647 | port->ignore_status_mask |= BI; | ||
648 | /* | ||
649 | * If we're ignoring parity and break indicators, | ||
650 | * ignore overruns too (for real raw support). | ||
651 | */ | ||
652 | if (termios->c_iflag & IGNPAR) | ||
653 | port->ignore_status_mask |= OE; | ||
654 | } | ||
624 | 655 | ||
625 | baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); | 656 | baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); |
626 | quot = uart_get_divisor(port, baud); | 657 | quot = uart_get_divisor(port, baud); |
diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c index 6202995e8211..9d3105b64a7a 100644 --- a/drivers/serial/icom.c +++ b/drivers/serial/icom.c | |||
@@ -69,33 +69,40 @@ | |||
69 | 69 | ||
70 | static const struct pci_device_id icom_pci_table[] = { | 70 | static const struct pci_device_id icom_pci_table[] = { |
71 | { | 71 | { |
72 | .vendor = PCI_VENDOR_ID_IBM, | 72 | .vendor = PCI_VENDOR_ID_IBM, |
73 | .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1, | 73 | .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1, |
74 | .subvendor = PCI_ANY_ID, | 74 | .subvendor = PCI_ANY_ID, |
75 | .subdevice = PCI_ANY_ID, | 75 | .subdevice = PCI_ANY_ID, |
76 | .driver_data = ADAPTER_V1, | 76 | .driver_data = ADAPTER_V1, |
77 | }, | 77 | }, |
78 | { | 78 | { |
79 | .vendor = PCI_VENDOR_ID_IBM, | 79 | .vendor = PCI_VENDOR_ID_IBM, |
80 | .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, | 80 | .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, |
81 | .subvendor = PCI_VENDOR_ID_IBM, | 81 | .subvendor = PCI_VENDOR_ID_IBM, |
82 | .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX, | 82 | .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX, |
83 | .driver_data = ADAPTER_V2, | 83 | .driver_data = ADAPTER_V2, |
84 | }, | 84 | }, |
85 | { | 85 | { |
86 | .vendor = PCI_VENDOR_ID_IBM, | 86 | .vendor = PCI_VENDOR_ID_IBM, |
87 | .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, | 87 | .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, |
88 | .subvendor = PCI_VENDOR_ID_IBM, | 88 | .subvendor = PCI_VENDOR_ID_IBM, |
89 | .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM, | 89 | .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM, |
90 | .driver_data = ADAPTER_V2, | 90 | .driver_data = ADAPTER_V2, |
91 | }, | 91 | }, |
92 | { | 92 | { |
93 | .vendor = PCI_VENDOR_ID_IBM, | 93 | .vendor = PCI_VENDOR_ID_IBM, |
94 | .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, | 94 | .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, |
95 | .subvendor = PCI_VENDOR_ID_IBM, | 95 | .subvendor = PCI_VENDOR_ID_IBM, |
96 | .subdevice = PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL, | 96 | .subdevice = PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL, |
97 | .driver_data = ADAPTER_V2, | 97 | .driver_data = ADAPTER_V2, |
98 | }, | 98 | }, |
99 | { | ||
100 | .vendor = PCI_VENDOR_ID_IBM, | ||
101 | .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, | ||
102 | .subvendor = PCI_VENDOR_ID_IBM, | ||
103 | .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM_PCIE, | ||
104 | .driver_data = ADAPTER_V2, | ||
105 | }, | ||
99 | {} | 106 | {} |
100 | }; | 107 | }; |
101 | 108 | ||
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index c3a6bd2e7950..96557e6dba60 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* sunhv.c: Serial driver for SUN4V hypervisor console. | 1 | /* sunhv.c: Serial driver for SUN4V hypervisor console. |
2 | * | 2 | * |
3 | * Copyright (C) 2006 David S. Miller (davem@davemloft.net) | 3 | * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net) |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <linux/module.h> | 6 | #include <linux/module.h> |
@@ -35,57 +35,51 @@ | |||
35 | #define CON_BREAK ((long)-1) | 35 | #define CON_BREAK ((long)-1) |
36 | #define CON_HUP ((long)-2) | 36 | #define CON_HUP ((long)-2) |
37 | 37 | ||
38 | static inline long hypervisor_con_getchar(long *status) | 38 | #define IGNORE_BREAK 0x1 |
39 | { | 39 | #define IGNORE_ALL 0x2 |
40 | register unsigned long func asm("%o5"); | ||
41 | register unsigned long arg0 asm("%o0"); | ||
42 | register unsigned long arg1 asm("%o1"); | ||
43 | |||
44 | func = HV_FAST_CONS_GETCHAR; | ||
45 | arg0 = 0; | ||
46 | arg1 = 0; | ||
47 | __asm__ __volatile__("ta %6" | ||
48 | : "=&r" (func), "=&r" (arg0), "=&r" (arg1) | ||
49 | : "0" (func), "1" (arg0), "2" (arg1), | ||
50 | "i" (HV_FAST_TRAP)); | ||
51 | 40 | ||
52 | *status = arg0; | 41 | static char *con_write_page; |
42 | static char *con_read_page; | ||
53 | 43 | ||
54 | return (long) arg1; | 44 | static int hung_up = 0; |
55 | } | ||
56 | 45 | ||
57 | static inline long hypervisor_con_putchar(long ch) | 46 | static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit) |
58 | { | 47 | { |
59 | register unsigned long func asm("%o5"); | 48 | while (!uart_circ_empty(xmit)) { |
60 | register unsigned long arg0 asm("%o0"); | 49 | long status = sun4v_con_putchar(xmit->buf[xmit->tail]); |
61 | 50 | ||
62 | func = HV_FAST_CONS_PUTCHAR; | 51 | if (status != HV_EOK) |
63 | arg0 = ch; | 52 | break; |
64 | __asm__ __volatile__("ta %4" | ||
65 | : "=&r" (func), "=&r" (arg0) | ||
66 | : "0" (func), "1" (arg0), "i" (HV_FAST_TRAP)); | ||
67 | 53 | ||
68 | return (long) arg0; | 54 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); |
55 | port->icount.tx++; | ||
56 | } | ||
69 | } | 57 | } |
70 | 58 | ||
71 | #define IGNORE_BREAK 0x1 | 59 | static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit) |
72 | #define IGNORE_ALL 0x2 | 60 | { |
61 | while (!uart_circ_empty(xmit)) { | ||
62 | unsigned long ra = __pa(xmit->buf + xmit->tail); | ||
63 | unsigned long len, status, sent; | ||
73 | 64 | ||
74 | static int hung_up = 0; | 65 | len = CIRC_CNT_TO_END(xmit->head, xmit->tail, |
66 | UART_XMIT_SIZE); | ||
67 | status = sun4v_con_write(ra, len, &sent); | ||
68 | if (status != HV_EOK) | ||
69 | break; | ||
70 | xmit->tail = (xmit->tail + sent) & (UART_XMIT_SIZE - 1); | ||
71 | port->icount.tx += sent; | ||
72 | } | ||
73 | } | ||
75 | 74 | ||
76 | static struct tty_struct *receive_chars(struct uart_port *port) | 75 | static int receive_chars_getchar(struct uart_port *port, struct tty_struct *tty) |
77 | { | 76 | { |
78 | struct tty_struct *tty = NULL; | ||
79 | int saw_console_brk = 0; | 77 | int saw_console_brk = 0; |
80 | int limit = 10000; | 78 | int limit = 10000; |
81 | 79 | ||
82 | if (port->info != NULL) /* Unopened serial console */ | ||
83 | tty = port->info->tty; | ||
84 | |||
85 | while (limit-- > 0) { | 80 | while (limit-- > 0) { |
86 | long status; | 81 | long status; |
87 | long c = hypervisor_con_getchar(&status); | 82 | long c = sun4v_con_getchar(&status); |
88 | unsigned char flag; | ||
89 | 83 | ||
90 | if (status == HV_EWOULDBLOCK) | 84 | if (status == HV_EWOULDBLOCK) |
91 | break; | 85 | break; |
@@ -110,27 +104,90 @@ static struct tty_struct *receive_chars(struct uart_port *port) | |||
110 | continue; | 104 | continue; |
111 | } | 105 | } |
112 | 106 | ||
113 | flag = TTY_NORMAL; | ||
114 | port->icount.rx++; | 107 | port->icount.rx++; |
115 | if (c == CON_BREAK) { | ||
116 | port->icount.brk++; | ||
117 | if (uart_handle_break(port)) | ||
118 | continue; | ||
119 | flag = TTY_BREAK; | ||
120 | } | ||
121 | 108 | ||
122 | if (uart_handle_sysrq_char(port, c)) | 109 | if (uart_handle_sysrq_char(port, c)) |
123 | continue; | 110 | continue; |
124 | 111 | ||
125 | if ((port->ignore_status_mask & IGNORE_ALL) || | 112 | tty_insert_flip_char(tty, c, TTY_NORMAL); |
126 | ((port->ignore_status_mask & IGNORE_BREAK) && | 113 | } |
127 | (c == CON_BREAK))) | 114 | |
115 | return saw_console_brk; | ||
116 | } | ||
117 | |||
118 | static int receive_chars_read(struct uart_port *port, struct tty_struct *tty) | ||
119 | { | ||
120 | int saw_console_brk = 0; | ||
121 | int limit = 10000; | ||
122 | |||
123 | while (limit-- > 0) { | ||
124 | unsigned long ra = __pa(con_read_page); | ||
125 | unsigned long bytes_read, i; | ||
126 | long stat = sun4v_con_read(ra, PAGE_SIZE, &bytes_read); | ||
127 | |||
128 | if (stat != HV_EOK) { | ||
129 | bytes_read = 0; | ||
130 | |||
131 | if (stat == CON_BREAK) { | ||
132 | if (uart_handle_break(port)) | ||
133 | continue; | ||
134 | saw_console_brk = 1; | ||
135 | *con_read_page = 0; | ||
136 | bytes_read = 1; | ||
137 | } else if (stat == CON_HUP) { | ||
138 | hung_up = 1; | ||
139 | uart_handle_dcd_change(port, 0); | ||
140 | continue; | ||
141 | } else { | ||
142 | /* HV_EWOULDBLOCK, etc. */ | ||
143 | break; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | if (hung_up) { | ||
148 | hung_up = 0; | ||
149 | uart_handle_dcd_change(port, 1); | ||
150 | } | ||
151 | |||
152 | for (i = 0; i < bytes_read; i++) | ||
153 | uart_handle_sysrq_char(port, con_read_page[i]); | ||
154 | |||
155 | if (tty == NULL) | ||
128 | continue; | 156 | continue; |
129 | 157 | ||
130 | tty_insert_flip_char(tty, c, flag); | 158 | port->icount.rx += bytes_read; |
159 | |||
160 | tty_insert_flip_string(tty, con_read_page, bytes_read); | ||
131 | } | 161 | } |
132 | 162 | ||
133 | if (saw_console_brk) | 163 | return saw_console_brk; |
164 | } | ||
165 | |||
166 | struct sunhv_ops { | ||
167 | void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit); | ||
168 | int (*receive_chars)(struct uart_port *port, struct tty_struct *tty); | ||
169 | }; | ||
170 | |||
171 | static struct sunhv_ops bychar_ops = { | ||
172 | .transmit_chars = transmit_chars_putchar, | ||
173 | .receive_chars = receive_chars_getchar, | ||
174 | }; | ||
175 | |||
176 | static struct sunhv_ops bywrite_ops = { | ||
177 | .transmit_chars = transmit_chars_write, | ||
178 | .receive_chars = receive_chars_read, | ||
179 | }; | ||
180 | |||
181 | static struct sunhv_ops *sunhv_ops = &bychar_ops; | ||
182 | |||
183 | static struct tty_struct *receive_chars(struct uart_port *port) | ||
184 | { | ||
185 | struct tty_struct *tty = NULL; | ||
186 | |||
187 | if (port->info != NULL) /* Unopened serial console */ | ||
188 | tty = port->info->tty; | ||
189 | |||
190 | if (sunhv_ops->receive_chars(port, tty)) | ||
134 | sun_do_break(); | 191 | sun_do_break(); |
135 | 192 | ||
136 | return tty; | 193 | return tty; |
@@ -147,15 +204,7 @@ static void transmit_chars(struct uart_port *port) | |||
147 | if (uart_circ_empty(xmit) || uart_tx_stopped(port)) | 204 | if (uart_circ_empty(xmit) || uart_tx_stopped(port)) |
148 | return; | 205 | return; |
149 | 206 | ||
150 | while (!uart_circ_empty(xmit)) { | 207 | sunhv_ops->transmit_chars(port, xmit); |
151 | long status = hypervisor_con_putchar(xmit->buf[xmit->tail]); | ||
152 | |||
153 | if (status != HV_EOK) | ||
154 | break; | ||
155 | |||
156 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | ||
157 | port->icount.tx++; | ||
158 | } | ||
159 | 208 | ||
160 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | 209 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) |
161 | uart_write_wakeup(port); | 210 | uart_write_wakeup(port); |
@@ -212,7 +261,7 @@ static void sunhv_start_tx(struct uart_port *port) | |||
212 | struct circ_buf *xmit = &port->info->xmit; | 261 | struct circ_buf *xmit = &port->info->xmit; |
213 | 262 | ||
214 | while (!uart_circ_empty(xmit)) { | 263 | while (!uart_circ_empty(xmit)) { |
215 | long status = hypervisor_con_putchar(xmit->buf[xmit->tail]); | 264 | long status = sun4v_con_putchar(xmit->buf[xmit->tail]); |
216 | 265 | ||
217 | if (status != HV_EOK) | 266 | if (status != HV_EOK) |
218 | break; | 267 | break; |
@@ -231,9 +280,10 @@ static void sunhv_send_xchar(struct uart_port *port, char ch) | |||
231 | spin_lock_irqsave(&port->lock, flags); | 280 | spin_lock_irqsave(&port->lock, flags); |
232 | 281 | ||
233 | while (limit-- > 0) { | 282 | while (limit-- > 0) { |
234 | long status = hypervisor_con_putchar(ch); | 283 | long status = sun4v_con_putchar(ch); |
235 | if (status == HV_EOK) | 284 | if (status == HV_EOK) |
236 | break; | 285 | break; |
286 | udelay(1); | ||
237 | } | 287 | } |
238 | 288 | ||
239 | spin_unlock_irqrestore(&port->lock, flags); | 289 | spin_unlock_irqrestore(&port->lock, flags); |
@@ -254,15 +304,15 @@ static void sunhv_break_ctl(struct uart_port *port, int break_state) | |||
254 | { | 304 | { |
255 | if (break_state) { | 305 | if (break_state) { |
256 | unsigned long flags; | 306 | unsigned long flags; |
257 | int limit = 1000000; | 307 | int limit = 10000; |
258 | 308 | ||
259 | spin_lock_irqsave(&port->lock, flags); | 309 | spin_lock_irqsave(&port->lock, flags); |
260 | 310 | ||
261 | while (limit-- > 0) { | 311 | while (limit-- > 0) { |
262 | long status = hypervisor_con_putchar(CON_BREAK); | 312 | long status = sun4v_con_putchar(CON_BREAK); |
263 | if (status == HV_EOK) | 313 | if (status == HV_EOK) |
264 | break; | 314 | break; |
265 | udelay(2); | 315 | udelay(1); |
266 | } | 316 | } |
267 | 317 | ||
268 | spin_unlock_irqrestore(&port->lock, flags); | 318 | spin_unlock_irqrestore(&port->lock, flags); |
@@ -359,38 +409,99 @@ static struct uart_driver sunhv_reg = { | |||
359 | 409 | ||
360 | static struct uart_port *sunhv_port; | 410 | static struct uart_port *sunhv_port; |
361 | 411 | ||
362 | static inline void sunhv_console_putchar(struct uart_port *port, char c) | 412 | /* Copy 's' into the con_write_page, decoding "\n" into |
413 | * "\r\n" along the way. We have to return two lengths | ||
414 | * because the caller needs to know how much to advance | ||
415 | * 's' and also how many bytes to output via con_write_page. | ||
416 | */ | ||
417 | static int fill_con_write_page(const char *s, unsigned int n, | ||
418 | unsigned long *page_bytes) | ||
419 | { | ||
420 | const char *orig_s = s; | ||
421 | char *p = con_write_page; | ||
422 | int left = PAGE_SIZE; | ||
423 | |||
424 | while (n--) { | ||
425 | if (*s == '\n') { | ||
426 | if (left < 2) | ||
427 | break; | ||
428 | *p++ = '\r'; | ||
429 | left--; | ||
430 | } else if (left < 1) | ||
431 | break; | ||
432 | *p++ = *s++; | ||
433 | left--; | ||
434 | } | ||
435 | *page_bytes = p - con_write_page; | ||
436 | return s - orig_s; | ||
437 | } | ||
438 | |||
439 | static void sunhv_console_write_paged(struct console *con, const char *s, unsigned n) | ||
363 | { | 440 | { |
441 | struct uart_port *port = sunhv_port; | ||
364 | unsigned long flags; | 442 | unsigned long flags; |
365 | int limit = 1000000; | ||
366 | 443 | ||
367 | spin_lock_irqsave(&port->lock, flags); | 444 | spin_lock_irqsave(&port->lock, flags); |
445 | while (n > 0) { | ||
446 | unsigned long ra = __pa(con_write_page); | ||
447 | unsigned long page_bytes; | ||
448 | unsigned int cpy = fill_con_write_page(s, n, | ||
449 | &page_bytes); | ||
450 | |||
451 | n -= cpy; | ||
452 | s += cpy; | ||
453 | while (page_bytes > 0) { | ||
454 | unsigned long written; | ||
455 | int limit = 1000000; | ||
456 | |||
457 | while (limit--) { | ||
458 | unsigned long stat; | ||
459 | |||
460 | stat = sun4v_con_write(ra, page_bytes, | ||
461 | &written); | ||
462 | if (stat == HV_EOK) | ||
463 | break; | ||
464 | udelay(1); | ||
465 | } | ||
466 | if (limit <= 0) | ||
467 | break; | ||
468 | page_bytes -= written; | ||
469 | ra += written; | ||
470 | } | ||
471 | } | ||
472 | spin_unlock_irqrestore(&port->lock, flags); | ||
473 | } | ||
474 | |||
475 | static inline void sunhv_console_putchar(struct uart_port *port, char c) | ||
476 | { | ||
477 | int limit = 1000000; | ||
368 | 478 | ||
369 | while (limit-- > 0) { | 479 | while (limit-- > 0) { |
370 | long status = hypervisor_con_putchar(c); | 480 | long status = sun4v_con_putchar(c); |
371 | if (status == HV_EOK) | 481 | if (status == HV_EOK) |
372 | break; | 482 | break; |
373 | udelay(2); | 483 | udelay(1); |
374 | } | 484 | } |
375 | |||
376 | spin_unlock_irqrestore(&port->lock, flags); | ||
377 | } | 485 | } |
378 | 486 | ||
379 | static void sunhv_console_write(struct console *con, const char *s, unsigned n) | 487 | static void sunhv_console_write_bychar(struct console *con, const char *s, unsigned n) |
380 | { | 488 | { |
381 | struct uart_port *port = sunhv_port; | 489 | struct uart_port *port = sunhv_port; |
490 | unsigned long flags; | ||
382 | int i; | 491 | int i; |
383 | 492 | ||
493 | spin_lock_irqsave(&port->lock, flags); | ||
384 | for (i = 0; i < n; i++) { | 494 | for (i = 0; i < n; i++) { |
385 | if (*s == '\n') | 495 | if (*s == '\n') |
386 | sunhv_console_putchar(port, '\r'); | 496 | sunhv_console_putchar(port, '\r'); |
387 | sunhv_console_putchar(port, *s++); | 497 | sunhv_console_putchar(port, *s++); |
388 | } | 498 | } |
499 | spin_unlock_irqrestore(&port->lock, flags); | ||
389 | } | 500 | } |
390 | 501 | ||
391 | static struct console sunhv_console = { | 502 | static struct console sunhv_console = { |
392 | .name = "ttyHV", | 503 | .name = "ttyHV", |
393 | .write = sunhv_console_write, | 504 | .write = sunhv_console_write_bychar, |
394 | .device = uart_console_device, | 505 | .device = uart_console_device, |
395 | .flags = CON_PRINTBUFFER, | 506 | .flags = CON_PRINTBUFFER, |
396 | .index = -1, | 507 | .index = -1, |
@@ -410,6 +521,7 @@ static inline struct console *SUNHV_CONSOLE(void) | |||
410 | static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match) | 521 | static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match) |
411 | { | 522 | { |
412 | struct uart_port *port; | 523 | struct uart_port *port; |
524 | unsigned long minor; | ||
413 | int err; | 525 | int err; |
414 | 526 | ||
415 | if (op->irqs[0] == 0xffffffff) | 527 | if (op->irqs[0] == 0xffffffff) |
@@ -419,6 +531,22 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m | |||
419 | if (unlikely(!port)) | 531 | if (unlikely(!port)) |
420 | return -ENOMEM; | 532 | return -ENOMEM; |
421 | 533 | ||
534 | minor = 1; | ||
535 | if (sun4v_hvapi_register(HV_GRP_CORE, 1, &minor) == 0 && | ||
536 | minor >= 1) { | ||
537 | err = -ENOMEM; | ||
538 | con_write_page = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
539 | if (!con_write_page) | ||
540 | goto out_free_port; | ||
541 | |||
542 | con_read_page = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
543 | if (!con_read_page) | ||
544 | goto out_free_con_write_page; | ||
545 | |||
546 | sunhv_console.write = sunhv_console_write_paged; | ||
547 | sunhv_ops = &bywrite_ops; | ||
548 | } | ||
549 | |||
422 | sunhv_port = port; | 550 | sunhv_port = port; |
423 | 551 | ||
424 | port->line = 0; | 552 | port->line = 0; |
@@ -437,7 +565,7 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m | |||
437 | 565 | ||
438 | err = uart_register_driver(&sunhv_reg); | 566 | err = uart_register_driver(&sunhv_reg); |
439 | if (err) | 567 | if (err) |
440 | goto out_free_port; | 568 | goto out_free_con_read_page; |
441 | 569 | ||
442 | sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64; | 570 | sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64; |
443 | sunserial_current_minor += 1; | 571 | sunserial_current_minor += 1; |
@@ -463,6 +591,12 @@ out_unregister_driver: | |||
463 | sunserial_current_minor -= 1; | 591 | sunserial_current_minor -= 1; |
464 | uart_unregister_driver(&sunhv_reg); | 592 | uart_unregister_driver(&sunhv_reg); |
465 | 593 | ||
594 | out_free_con_read_page: | ||
595 | kfree(con_read_page); | ||
596 | |||
597 | out_free_con_write_page: | ||
598 | kfree(con_write_page); | ||
599 | |||
466 | out_free_port: | 600 | out_free_port: |
467 | kfree(port); | 601 | kfree(port); |
468 | sunhv_port = NULL; | 602 | sunhv_port = NULL; |