diff options
author | Fabio Estevam <fabio.estevam@nxp.com> | 2017-07-11 07:03:43 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-07-17 08:14:24 -0400 |
commit | 3ee5447e8cd9a65d08fbb49fa9767cbf7fef6d91 (patch) | |
tree | bb96b6c9eec940fd0ecc86e14fc92f6b6a099943 | |
parent | 514ab34dbad6c6fa824a1f56984c196e59082346 (diff) |
tty: serial: lpuart: Fix the logic for detecting the 32-bit type UART
Commit 0d6fce904452 ("tty: serial: lpuart: introduce lpuart_soc_data to
represent SoC property") introduced a buggy logic for detecting the 32-bit
type UART since the condition: "if (sport->port.iotype & UPIO_MEM32BE)"
is always true.
Performing such bitfield AND operation is not correct, because in the
case of Vybrid UART iotype is UPIO_MEM (2), so:
UPIO_MEM & UPIO_MEM32BE = 010 & 110 = 010, which is true.
Such logic tells the driver to always treat the UART operations as 32-bit,
leading to the driver misbehavior on Vybrid.
Fix the 32-bit type detection logic to avoid UART breakage on Vybrid.
While at it, introduce a lpuart_is_32() function to help readability.
Fixes: 0d6fce904452 ("tty: serial: lpuart: introduce lpuart_soc_data to represent SoC property")
Reported-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Signed-off-by: Fabio Estevam <fabio.estevam@nxp.com>
Reviewed-by: Dong Aisheng <aisheng.dong@nxp.com>
Tested-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/tty/serial/fsl_lpuart.c | 24 |
1 files changed, 15 insertions, 9 deletions
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 343de8c384b0..898dcb091a27 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c | |||
@@ -619,6 +619,12 @@ static unsigned int lpuart32_tx_empty(struct uart_port *port) | |||
619 | TIOCSER_TEMT : 0; | 619 | TIOCSER_TEMT : 0; |
620 | } | 620 | } |
621 | 621 | ||
622 | static bool lpuart_is_32(struct lpuart_port *sport) | ||
623 | { | ||
624 | return sport->port.iotype == UPIO_MEM32 || | ||
625 | sport->port.iotype == UPIO_MEM32BE; | ||
626 | } | ||
627 | |||
622 | static irqreturn_t lpuart_txint(int irq, void *dev_id) | 628 | static irqreturn_t lpuart_txint(int irq, void *dev_id) |
623 | { | 629 | { |
624 | struct lpuart_port *sport = dev_id; | 630 | struct lpuart_port *sport = dev_id; |
@@ -627,7 +633,7 @@ static irqreturn_t lpuart_txint(int irq, void *dev_id) | |||
627 | 633 | ||
628 | spin_lock_irqsave(&sport->port.lock, flags); | 634 | spin_lock_irqsave(&sport->port.lock, flags); |
629 | if (sport->port.x_char) { | 635 | if (sport->port.x_char) { |
630 | if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE)) | 636 | if (lpuart_is_32(sport)) |
631 | lpuart32_write(&sport->port, sport->port.x_char, UARTDATA); | 637 | lpuart32_write(&sport->port, sport->port.x_char, UARTDATA); |
632 | else | 638 | else |
633 | writeb(sport->port.x_char, sport->port.membase + UARTDR); | 639 | writeb(sport->port.x_char, sport->port.membase + UARTDR); |
@@ -635,14 +641,14 @@ static irqreturn_t lpuart_txint(int irq, void *dev_id) | |||
635 | } | 641 | } |
636 | 642 | ||
637 | if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { | 643 | if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { |
638 | if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE)) | 644 | if (lpuart_is_32(sport)) |
639 | lpuart32_stop_tx(&sport->port); | 645 | lpuart32_stop_tx(&sport->port); |
640 | else | 646 | else |
641 | lpuart_stop_tx(&sport->port); | 647 | lpuart_stop_tx(&sport->port); |
642 | goto out; | 648 | goto out; |
643 | } | 649 | } |
644 | 650 | ||
645 | if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE)) | 651 | if (lpuart_is_32(sport)) |
646 | lpuart32_transmit_buffer(sport); | 652 | lpuart32_transmit_buffer(sport); |
647 | else | 653 | else |
648 | lpuart_transmit_buffer(sport); | 654 | lpuart_transmit_buffer(sport); |
@@ -1978,12 +1984,12 @@ static int __init lpuart_console_setup(struct console *co, char *options) | |||
1978 | if (options) | 1984 | if (options) |
1979 | uart_parse_options(options, &baud, &parity, &bits, &flow); | 1985 | uart_parse_options(options, &baud, &parity, &bits, &flow); |
1980 | else | 1986 | else |
1981 | if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE)) | 1987 | if (lpuart_is_32(sport)) |
1982 | lpuart32_console_get_options(sport, &baud, &parity, &bits); | 1988 | lpuart32_console_get_options(sport, &baud, &parity, &bits); |
1983 | else | 1989 | else |
1984 | lpuart_console_get_options(sport, &baud, &parity, &bits); | 1990 | lpuart_console_get_options(sport, &baud, &parity, &bits); |
1985 | 1991 | ||
1986 | if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE)) | 1992 | if (lpuart_is_32(sport)) |
1987 | lpuart32_setup_watermark(sport); | 1993 | lpuart32_setup_watermark(sport); |
1988 | else | 1994 | else |
1989 | lpuart_setup_watermark(sport); | 1995 | lpuart_setup_watermark(sport); |
@@ -2118,7 +2124,7 @@ static int lpuart_probe(struct platform_device *pdev) | |||
2118 | } | 2124 | } |
2119 | sport->port.irq = ret; | 2125 | sport->port.irq = ret; |
2120 | sport->port.iotype = sdata->iotype; | 2126 | sport->port.iotype = sdata->iotype; |
2121 | if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE)) | 2127 | if (lpuart_is_32(sport)) |
2122 | sport->port.ops = &lpuart32_pops; | 2128 | sport->port.ops = &lpuart32_pops; |
2123 | else | 2129 | else |
2124 | sport->port.ops = &lpuart_pops; | 2130 | sport->port.ops = &lpuart_pops; |
@@ -2145,7 +2151,7 @@ static int lpuart_probe(struct platform_device *pdev) | |||
2145 | 2151 | ||
2146 | platform_set_drvdata(pdev, &sport->port); | 2152 | platform_set_drvdata(pdev, &sport->port); |
2147 | 2153 | ||
2148 | if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE)) | 2154 | if (lpuart_is_32(sport)) |
2149 | lpuart_reg.cons = LPUART32_CONSOLE; | 2155 | lpuart_reg.cons = LPUART32_CONSOLE; |
2150 | else | 2156 | else |
2151 | lpuart_reg.cons = LPUART_CONSOLE; | 2157 | lpuart_reg.cons = LPUART_CONSOLE; |
@@ -2198,7 +2204,7 @@ static int lpuart_suspend(struct device *dev) | |||
2198 | struct lpuart_port *sport = dev_get_drvdata(dev); | 2204 | struct lpuart_port *sport = dev_get_drvdata(dev); |
2199 | unsigned long temp; | 2205 | unsigned long temp; |
2200 | 2206 | ||
2201 | if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE)) { | 2207 | if (lpuart_is_32(sport)) { |
2202 | /* disable Rx/Tx and interrupts */ | 2208 | /* disable Rx/Tx and interrupts */ |
2203 | temp = lpuart32_read(&sport->port, UARTCTRL); | 2209 | temp = lpuart32_read(&sport->port, UARTCTRL); |
2204 | temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE); | 2210 | temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE); |
@@ -2249,7 +2255,7 @@ static int lpuart_resume(struct device *dev) | |||
2249 | if (sport->port.suspended && !sport->port.irq_wake) | 2255 | if (sport->port.suspended && !sport->port.irq_wake) |
2250 | clk_prepare_enable(sport->clk); | 2256 | clk_prepare_enable(sport->clk); |
2251 | 2257 | ||
2252 | if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE)) { | 2258 | if (lpuart_is_32(sport)) { |
2253 | lpuart32_setup_watermark(sport); | 2259 | lpuart32_setup_watermark(sport); |
2254 | temp = lpuart32_read(&sport->port, UARTCTRL); | 2260 | temp = lpuart32_read(&sport->port, UARTCTRL); |
2255 | temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE | | 2261 | temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE | |