diff options
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/serial/amba-pl011.c | 157 |
1 files changed, 66 insertions, 91 deletions
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index cb45136f686..faa16ee6b02 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c | |||
@@ -144,6 +144,62 @@ struct uart_amba_port { | |||
144 | }; | 144 | }; |
145 | 145 | ||
146 | /* | 146 | /* |
147 | * Reads up to 256 characters from the FIFO or until it's empty and | ||
148 | * inserts them into the TTY layer. Returns the number of characters | ||
149 | * read from the FIFO. | ||
150 | */ | ||
151 | static int pl011_fifo_to_tty(struct uart_amba_port *uap) | ||
152 | { | ||
153 | u16 status, ch; | ||
154 | unsigned int flag, max_count = 256; | ||
155 | int fifotaken = 0; | ||
156 | |||
157 | while (max_count--) { | ||
158 | status = readw(uap->port.membase + UART01x_FR); | ||
159 | if (status & UART01x_FR_RXFE) | ||
160 | break; | ||
161 | |||
162 | /* Take chars from the FIFO and update status */ | ||
163 | ch = readw(uap->port.membase + UART01x_DR) | | ||
164 | UART_DUMMY_DR_RX; | ||
165 | flag = TTY_NORMAL; | ||
166 | uap->port.icount.rx++; | ||
167 | fifotaken++; | ||
168 | |||
169 | if (unlikely(ch & UART_DR_ERROR)) { | ||
170 | if (ch & UART011_DR_BE) { | ||
171 | ch &= ~(UART011_DR_FE | UART011_DR_PE); | ||
172 | uap->port.icount.brk++; | ||
173 | if (uart_handle_break(&uap->port)) | ||
174 | continue; | ||
175 | } else if (ch & UART011_DR_PE) | ||
176 | uap->port.icount.parity++; | ||
177 | else if (ch & UART011_DR_FE) | ||
178 | uap->port.icount.frame++; | ||
179 | if (ch & UART011_DR_OE) | ||
180 | uap->port.icount.overrun++; | ||
181 | |||
182 | ch &= uap->port.read_status_mask; | ||
183 | |||
184 | if (ch & UART011_DR_BE) | ||
185 | flag = TTY_BREAK; | ||
186 | else if (ch & UART011_DR_PE) | ||
187 | flag = TTY_PARITY; | ||
188 | else if (ch & UART011_DR_FE) | ||
189 | flag = TTY_FRAME; | ||
190 | } | ||
191 | |||
192 | if (uart_handle_sysrq_char(&uap->port, ch & 255)) | ||
193 | continue; | ||
194 | |||
195 | uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag); | ||
196 | } | ||
197 | |||
198 | return fifotaken; | ||
199 | } | ||
200 | |||
201 | |||
202 | /* | ||
147 | * All the DMA operation mode stuff goes inside this ifdef. | 203 | * All the DMA operation mode stuff goes inside this ifdef. |
148 | * This assumes that you have a generic DMA device interface, | 204 | * This assumes that you have a generic DMA device interface, |
149 | * no custom DMA interfaces are supported. | 205 | * no custom DMA interfaces are supported. |
@@ -634,7 +690,6 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap, | |||
634 | struct pl011_sgbuf *sgbuf = use_buf_b ? | 690 | struct pl011_sgbuf *sgbuf = use_buf_b ? |
635 | &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a; | 691 | &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a; |
636 | struct device *dev = uap->dmarx.chan->device->dev; | 692 | struct device *dev = uap->dmarx.chan->device->dev; |
637 | unsigned int status, ch, flag; | ||
638 | int dma_count = 0; | 693 | int dma_count = 0; |
639 | u32 fifotaken = 0; /* only used for vdbg() */ | 694 | u32 fifotaken = 0; /* only used for vdbg() */ |
640 | 695 | ||
@@ -671,56 +726,16 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap, | |||
671 | 726 | ||
672 | /* | 727 | /* |
673 | * If we read all the DMA'd characters, and we had an | 728 | * If we read all the DMA'd characters, and we had an |
674 | * incomplete buffer, that could be due to an rx error, | 729 | * incomplete buffer, that could be due to an rx error, or |
675 | * or maybe we just timed out. Read any pending chars | 730 | * maybe we just timed out. Read any pending chars and check |
676 | * and check the error status. | 731 | * the error status. |
732 | * | ||
733 | * Error conditions will only occur in the FIFO, these will | ||
734 | * trigger an immediate interrupt and stop the DMA job, so we | ||
735 | * will always find the error in the FIFO, never in the DMA | ||
736 | * buffer. | ||
677 | */ | 737 | */ |
678 | while (1) { | 738 | fifotaken = pl011_fifo_to_tty(uap); |
679 | status = readw(uap->port.membase + UART01x_FR); | ||
680 | if (status & UART01x_FR_RXFE) | ||
681 | break; | ||
682 | |||
683 | /* Take chars from the FIFO and update status */ | ||
684 | ch = readw(uap->port.membase + UART01x_DR) | | ||
685 | UART_DUMMY_DR_RX; | ||
686 | flag = TTY_NORMAL; | ||
687 | uap->port.icount.rx++; | ||
688 | fifotaken++; | ||
689 | |||
690 | /* | ||
691 | * Error conditions will only occur in the FIFO, | ||
692 | * these will trigger an immediate interrupt and | ||
693 | * stop the DMA job, so we will always find the | ||
694 | * error in the FIFO, never in the DMA buffer. | ||
695 | */ | ||
696 | if (unlikely(ch & UART_DR_ERROR)) { | ||
697 | if (ch & UART011_DR_BE) { | ||
698 | ch &= ~(UART011_DR_FE | UART011_DR_PE); | ||
699 | uap->port.icount.brk++; | ||
700 | if (uart_handle_break(&uap->port)) | ||
701 | continue; | ||
702 | } else if (ch & UART011_DR_PE) | ||
703 | uap->port.icount.parity++; | ||
704 | else if (ch & UART011_DR_FE) | ||
705 | uap->port.icount.frame++; | ||
706 | if (ch & UART011_DR_OE) | ||
707 | uap->port.icount.overrun++; | ||
708 | |||
709 | ch &= uap->port.read_status_mask; | ||
710 | |||
711 | if (ch & UART011_DR_BE) | ||
712 | flag = TTY_BREAK; | ||
713 | else if (ch & UART011_DR_PE) | ||
714 | flag = TTY_PARITY; | ||
715 | else if (ch & UART011_DR_FE) | ||
716 | flag = TTY_FRAME; | ||
717 | } | ||
718 | |||
719 | if (uart_handle_sysrq_char(&uap->port, ch & 255)) | ||
720 | continue; | ||
721 | |||
722 | uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag); | ||
723 | } | ||
724 | } | 739 | } |
725 | 740 | ||
726 | spin_unlock(&uap->port.lock); | 741 | spin_unlock(&uap->port.lock); |
@@ -1036,49 +1051,9 @@ static void pl011_enable_ms(struct uart_port *port) | |||
1036 | static void pl011_rx_chars(struct uart_amba_port *uap) | 1051 | static void pl011_rx_chars(struct uart_amba_port *uap) |
1037 | { | 1052 | { |
1038 | struct tty_struct *tty = uap->port.state->port.tty; | 1053 | struct tty_struct *tty = uap->port.state->port.tty; |
1039 | unsigned int status, ch, flag, max_count = 256; | ||
1040 | 1054 | ||
1041 | status = readw(uap->port.membase + UART01x_FR); | 1055 | pl011_fifo_to_tty(uap); |
1042 | while ((status & UART01x_FR_RXFE) == 0 && max_count--) { | ||
1043 | ch = readw(uap->port.membase + UART01x_DR) | UART_DUMMY_DR_RX; | ||
1044 | flag = TTY_NORMAL; | ||
1045 | uap->port.icount.rx++; | ||
1046 | 1056 | ||
1047 | /* | ||
1048 | * Note that the error handling code is | ||
1049 | * out of the main execution path | ||
1050 | */ | ||
1051 | if (unlikely(ch & UART_DR_ERROR)) { | ||
1052 | if (ch & UART011_DR_BE) { | ||
1053 | ch &= ~(UART011_DR_FE | UART011_DR_PE); | ||
1054 | uap->port.icount.brk++; | ||
1055 | if (uart_handle_break(&uap->port)) | ||
1056 | goto ignore_char; | ||
1057 | } else if (ch & UART011_DR_PE) | ||
1058 | uap->port.icount.parity++; | ||
1059 | else if (ch & UART011_DR_FE) | ||
1060 | uap->port.icount.frame++; | ||
1061 | if (ch & UART011_DR_OE) | ||
1062 | uap->port.icount.overrun++; | ||
1063 | |||
1064 | ch &= uap->port.read_status_mask; | ||
1065 | |||
1066 | if (ch & UART011_DR_BE) | ||
1067 | flag = TTY_BREAK; | ||
1068 | else if (ch & UART011_DR_PE) | ||
1069 | flag = TTY_PARITY; | ||
1070 | else if (ch & UART011_DR_FE) | ||
1071 | flag = TTY_FRAME; | ||
1072 | } | ||
1073 | |||
1074 | if (uart_handle_sysrq_char(&uap->port, ch & 255)) | ||
1075 | goto ignore_char; | ||
1076 | |||
1077 | uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag); | ||
1078 | |||
1079 | ignore_char: | ||
1080 | status = readw(uap->port.membase + UART01x_FR); | ||
1081 | } | ||
1082 | spin_unlock(&uap->port.lock); | 1057 | spin_unlock(&uap->port.lock); |
1083 | tty_flip_buffer_push(tty); | 1058 | tty_flip_buffer_push(tty); |
1084 | /* | 1059 | /* |