diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-07 01:14:23 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-07 01:14:23 -0400 |
commit | b334b77351890a137f31a38f1ca2f1de0886a453 (patch) | |
tree | 3b7ed7948b63388ed8474388ef5711a4dc7d5b27 | |
parent | e900f2c0973b0e9eb549230be55bacef9eea6f65 (diff) | |
parent | 72586c6061ab8c23ffd9f301ed19782a44ff5f04 (diff) |
Merge tag 'tty-4.1-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial driver fixes from Greg KH:
"Here are a few TTY and Serial driver fixes for reported regressions
and crashes.
All of these have been in linux-next with no reported problems"
* tag 'tty-4.1-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
n_tty: Fix auditing support for cannonical mode
serial: 8250_omap: provide complete custom startup & shutdown callbacks
n_tty: Fix calculation of size in canon_copy_from_read_buf
serial: imx: Fix DMA handling for IDLE condition aborts
serial/amba-pl011: Unconditionally poll for FIFO space before each TX char
-rw-r--r-- | drivers/tty/n_tty.c | 21 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_omap.c | 82 | ||||
-rw-r--r-- | drivers/tty/serial/amba-pl011.c | 16 | ||||
-rw-r--r-- | drivers/tty/serial/imx.c | 8 |
4 files changed, 105 insertions, 22 deletions
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index cc57a3a6b02b..396344cb011f 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c | |||
@@ -162,6 +162,17 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x, | |||
162 | return put_user(x, ptr); | 162 | return put_user(x, ptr); |
163 | } | 163 | } |
164 | 164 | ||
165 | static inline int tty_copy_to_user(struct tty_struct *tty, | ||
166 | void __user *to, | ||
167 | const void *from, | ||
168 | unsigned long n) | ||
169 | { | ||
170 | struct n_tty_data *ldata = tty->disc_data; | ||
171 | |||
172 | tty_audit_add_data(tty, to, n, ldata->icanon); | ||
173 | return copy_to_user(to, from, n); | ||
174 | } | ||
175 | |||
165 | /** | 176 | /** |
166 | * n_tty_kick_worker - start input worker (if required) | 177 | * n_tty_kick_worker - start input worker (if required) |
167 | * @tty: terminal | 178 | * @tty: terminal |
@@ -2070,8 +2081,8 @@ static int canon_copy_from_read_buf(struct tty_struct *tty, | |||
2070 | 2081 | ||
2071 | size = N_TTY_BUF_SIZE - tail; | 2082 | size = N_TTY_BUF_SIZE - tail; |
2072 | n = eol - tail; | 2083 | n = eol - tail; |
2073 | if (n > 4096) | 2084 | if (n > N_TTY_BUF_SIZE) |
2074 | n += 4096; | 2085 | n += N_TTY_BUF_SIZE; |
2075 | n += found; | 2086 | n += found; |
2076 | c = n; | 2087 | c = n; |
2077 | 2088 | ||
@@ -2084,12 +2095,12 @@ static int canon_copy_from_read_buf(struct tty_struct *tty, | |||
2084 | __func__, eol, found, n, c, size, more); | 2095 | __func__, eol, found, n, c, size, more); |
2085 | 2096 | ||
2086 | if (n > size) { | 2097 | if (n > size) { |
2087 | ret = copy_to_user(*b, read_buf_addr(ldata, tail), size); | 2098 | ret = tty_copy_to_user(tty, *b, read_buf_addr(ldata, tail), size); |
2088 | if (ret) | 2099 | if (ret) |
2089 | return -EFAULT; | 2100 | return -EFAULT; |
2090 | ret = copy_to_user(*b + size, ldata->read_buf, n - size); | 2101 | ret = tty_copy_to_user(tty, *b + size, ldata->read_buf, n - size); |
2091 | } else | 2102 | } else |
2092 | ret = copy_to_user(*b, read_buf_addr(ldata, tail), n); | 2103 | ret = tty_copy_to_user(tty, *b, read_buf_addr(ldata, tail), n); |
2093 | 2104 | ||
2094 | if (ret) | 2105 | if (ret) |
2095 | return -EFAULT; | 2106 | return -EFAULT; |
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 9289999cb7c6..dce1a23706e8 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c | |||
@@ -562,12 +562,36 @@ static irqreturn_t omap_wake_irq(int irq, void *dev_id) | |||
562 | return IRQ_NONE; | 562 | return IRQ_NONE; |
563 | } | 563 | } |
564 | 564 | ||
565 | #ifdef CONFIG_SERIAL_8250_DMA | ||
566 | static int omap_8250_dma_handle_irq(struct uart_port *port); | ||
567 | #endif | ||
568 | |||
569 | static irqreturn_t omap8250_irq(int irq, void *dev_id) | ||
570 | { | ||
571 | struct uart_port *port = dev_id; | ||
572 | struct uart_8250_port *up = up_to_u8250p(port); | ||
573 | unsigned int iir; | ||
574 | int ret; | ||
575 | |||
576 | #ifdef CONFIG_SERIAL_8250_DMA | ||
577 | if (up->dma) { | ||
578 | ret = omap_8250_dma_handle_irq(port); | ||
579 | return IRQ_RETVAL(ret); | ||
580 | } | ||
581 | #endif | ||
582 | |||
583 | serial8250_rpm_get(up); | ||
584 | iir = serial_port_in(port, UART_IIR); | ||
585 | ret = serial8250_handle_irq(port, iir); | ||
586 | serial8250_rpm_put(up); | ||
587 | |||
588 | return IRQ_RETVAL(ret); | ||
589 | } | ||
590 | |||
565 | static int omap_8250_startup(struct uart_port *port) | 591 | static int omap_8250_startup(struct uart_port *port) |
566 | { | 592 | { |
567 | struct uart_8250_port *up = | 593 | struct uart_8250_port *up = up_to_u8250p(port); |
568 | container_of(port, struct uart_8250_port, port); | ||
569 | struct omap8250_priv *priv = port->private_data; | 594 | struct omap8250_priv *priv = port->private_data; |
570 | |||
571 | int ret; | 595 | int ret; |
572 | 596 | ||
573 | if (priv->wakeirq) { | 597 | if (priv->wakeirq) { |
@@ -580,10 +604,31 @@ static int omap_8250_startup(struct uart_port *port) | |||
580 | 604 | ||
581 | pm_runtime_get_sync(port->dev); | 605 | pm_runtime_get_sync(port->dev); |
582 | 606 | ||
583 | ret = serial8250_do_startup(port); | 607 | up->mcr = 0; |
584 | if (ret) | 608 | serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); |
609 | |||
610 | serial_out(up, UART_LCR, UART_LCR_WLEN8); | ||
611 | |||
612 | up->lsr_saved_flags = 0; | ||
613 | up->msr_saved_flags = 0; | ||
614 | |||
615 | if (up->dma) { | ||
616 | ret = serial8250_request_dma(up); | ||
617 | if (ret) { | ||
618 | dev_warn_ratelimited(port->dev, | ||
619 | "failed to request DMA\n"); | ||
620 | up->dma = NULL; | ||
621 | } | ||
622 | } | ||
623 | |||
624 | ret = request_irq(port->irq, omap8250_irq, IRQF_SHARED, | ||
625 | dev_name(port->dev), port); | ||
626 | if (ret < 0) | ||
585 | goto err; | 627 | goto err; |
586 | 628 | ||
629 | up->ier = UART_IER_RLSI | UART_IER_RDI; | ||
630 | serial_out(up, UART_IER, up->ier); | ||
631 | |||
587 | #ifdef CONFIG_PM | 632 | #ifdef CONFIG_PM |
588 | up->capabilities |= UART_CAP_RPM; | 633 | up->capabilities |= UART_CAP_RPM; |
589 | #endif | 634 | #endif |
@@ -610,8 +655,7 @@ err: | |||
610 | 655 | ||
611 | static void omap_8250_shutdown(struct uart_port *port) | 656 | static void omap_8250_shutdown(struct uart_port *port) |
612 | { | 657 | { |
613 | struct uart_8250_port *up = | 658 | struct uart_8250_port *up = up_to_u8250p(port); |
614 | container_of(port, struct uart_8250_port, port); | ||
615 | struct omap8250_priv *priv = port->private_data; | 659 | struct omap8250_priv *priv = port->private_data; |
616 | 660 | ||
617 | flush_work(&priv->qos_work); | 661 | flush_work(&priv->qos_work); |
@@ -621,11 +665,24 @@ static void omap_8250_shutdown(struct uart_port *port) | |||
621 | pm_runtime_get_sync(port->dev); | 665 | pm_runtime_get_sync(port->dev); |
622 | 666 | ||
623 | serial_out(up, UART_OMAP_WER, 0); | 667 | serial_out(up, UART_OMAP_WER, 0); |
624 | serial8250_do_shutdown(port); | 668 | |
669 | up->ier = 0; | ||
670 | serial_out(up, UART_IER, 0); | ||
671 | |||
672 | if (up->dma) | ||
673 | serial8250_release_dma(up); | ||
674 | |||
675 | /* | ||
676 | * Disable break condition and FIFOs | ||
677 | */ | ||
678 | if (up->lcr & UART_LCR_SBC) | ||
679 | serial_out(up, UART_LCR, up->lcr & ~UART_LCR_SBC); | ||
680 | serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); | ||
625 | 681 | ||
626 | pm_runtime_mark_last_busy(port->dev); | 682 | pm_runtime_mark_last_busy(port->dev); |
627 | pm_runtime_put_autosuspend(port->dev); | 683 | pm_runtime_put_autosuspend(port->dev); |
628 | 684 | ||
685 | free_irq(port->irq, port); | ||
629 | if (priv->wakeirq) | 686 | if (priv->wakeirq) |
630 | free_irq(priv->wakeirq, port); | 687 | free_irq(priv->wakeirq, port); |
631 | } | 688 | } |
@@ -974,6 +1031,13 @@ static inline int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) | |||
974 | } | 1031 | } |
975 | #endif | 1032 | #endif |
976 | 1033 | ||
1034 | static int omap8250_no_handle_irq(struct uart_port *port) | ||
1035 | { | ||
1036 | /* IRQ has not been requested but handling irq? */ | ||
1037 | WARN_ONCE(1, "Unexpected irq handling before port startup\n"); | ||
1038 | return 0; | ||
1039 | } | ||
1040 | |||
977 | static int omap8250_probe(struct platform_device *pdev) | 1041 | static int omap8250_probe(struct platform_device *pdev) |
978 | { | 1042 | { |
979 | struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1043 | struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
@@ -1075,6 +1139,7 @@ static int omap8250_probe(struct platform_device *pdev) | |||
1075 | pm_runtime_get_sync(&pdev->dev); | 1139 | pm_runtime_get_sync(&pdev->dev); |
1076 | 1140 | ||
1077 | omap_serial_fill_features_erratas(&up, priv); | 1141 | omap_serial_fill_features_erratas(&up, priv); |
1142 | up.port.handle_irq = omap8250_no_handle_irq; | ||
1078 | #ifdef CONFIG_SERIAL_8250_DMA | 1143 | #ifdef CONFIG_SERIAL_8250_DMA |
1079 | if (pdev->dev.of_node) { | 1144 | if (pdev->dev.of_node) { |
1080 | /* | 1145 | /* |
@@ -1088,7 +1153,6 @@ static int omap8250_probe(struct platform_device *pdev) | |||
1088 | ret = of_property_count_strings(pdev->dev.of_node, "dma-names"); | 1153 | ret = of_property_count_strings(pdev->dev.of_node, "dma-names"); |
1089 | if (ret == 2) { | 1154 | if (ret == 2) { |
1090 | up.dma = &priv->omap8250_dma; | 1155 | up.dma = &priv->omap8250_dma; |
1091 | up.port.handle_irq = omap_8250_dma_handle_irq; | ||
1092 | priv->omap8250_dma.fn = the_no_dma_filter_fn; | 1156 | priv->omap8250_dma.fn = the_no_dma_filter_fn; |
1093 | priv->omap8250_dma.tx_dma = omap_8250_tx_dma; | 1157 | priv->omap8250_dma.tx_dma = omap_8250_tx_dma; |
1094 | priv->omap8250_dma.rx_dma = omap_8250_rx_dma; | 1158 | priv->omap8250_dma.rx_dma = omap_8250_rx_dma; |
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 6f5a0720a8c8..763eb20fe321 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c | |||
@@ -1249,20 +1249,19 @@ __acquires(&uap->port.lock) | |||
1249 | 1249 | ||
1250 | /* | 1250 | /* |
1251 | * Transmit a character | 1251 | * Transmit a character |
1252 | * There must be at least one free entry in the TX FIFO to accept the char. | ||
1253 | * | 1252 | * |
1254 | * Returns true if the FIFO might have space in it afterwards; | 1253 | * Returns true if the character was successfully queued to the FIFO. |
1255 | * returns false if the FIFO definitely became full. | 1254 | * Returns false otherwise. |
1256 | */ | 1255 | */ |
1257 | static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c) | 1256 | static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c) |
1258 | { | 1257 | { |
1258 | if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) | ||
1259 | return false; /* unable to transmit character */ | ||
1260 | |||
1259 | writew(c, uap->port.membase + UART01x_DR); | 1261 | writew(c, uap->port.membase + UART01x_DR); |
1260 | uap->port.icount.tx++; | 1262 | uap->port.icount.tx++; |
1261 | 1263 | ||
1262 | if (likely(uap->tx_irq_seen > 1)) | 1264 | return true; |
1263 | return true; | ||
1264 | |||
1265 | return !(readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF); | ||
1266 | } | 1265 | } |
1267 | 1266 | ||
1268 | static bool pl011_tx_chars(struct uart_amba_port *uap) | 1267 | static bool pl011_tx_chars(struct uart_amba_port *uap) |
@@ -1296,7 +1295,8 @@ static bool pl011_tx_chars(struct uart_amba_port *uap) | |||
1296 | return false; | 1295 | return false; |
1297 | 1296 | ||
1298 | if (uap->port.x_char) { | 1297 | if (uap->port.x_char) { |
1299 | pl011_tx_char(uap, uap->port.x_char); | 1298 | if (!pl011_tx_char(uap, uap->port.x_char)) |
1299 | goto done; | ||
1300 | uap->port.x_char = 0; | 1300 | uap->port.x_char = 0; |
1301 | --count; | 1301 | --count; |
1302 | } | 1302 | } |
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index c8cfa0637128..88250395b0ce 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c | |||
@@ -911,6 +911,14 @@ static void dma_rx_callback(void *data) | |||
911 | 911 | ||
912 | status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state); | 912 | status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state); |
913 | count = RX_BUF_SIZE - state.residue; | 913 | count = RX_BUF_SIZE - state.residue; |
914 | |||
915 | if (readl(sport->port.membase + USR2) & USR2_IDLE) { | ||
916 | /* In condition [3] the SDMA counted up too early */ | ||
917 | count--; | ||
918 | |||
919 | writel(USR2_IDLE, sport->port.membase + USR2); | ||
920 | } | ||
921 | |||
914 | dev_dbg(sport->port.dev, "We get %d bytes.\n", count); | 922 | dev_dbg(sport->port.dev, "We get %d bytes.\n", count); |
915 | 923 | ||
916 | if (count) { | 924 | if (count) { |