Linux-MIPS Archive on lore.kernel.org
 help / Atom feed
* [PATCH] serial: lantiq: Do not swap register read/writes
@ 2019-01-06 18:50 Hauke Mehrtens
  2019-01-06 20:38 ` John Crispin
  0 siblings, 1 reply; 2+ messages in thread
From: Hauke Mehrtens @ 2019-01-06 18:50 UTC (permalink / raw)
  To: gregkh
  Cc: john, linux-mips, linux-mips, jslaby, linux-serial, songjun.wu,
	Hauke Mehrtens

The ltq_r32() and ltq_w32() macros use the __raw_readl() and
__raw_writel() functions which do not swap the value to little endian.
On the big endian vrx200 SoC the UART is operated in big endian IO mode,
the readl() and write() functions convert the value to little endian
first and then the driver does not work any more on this SoC.
Currently the vrx200 SoC selects the CONFIG_SWAP_IO_SPACE option,
without this option the serial driver would work, but PCI devices do not
work any more.

This patch makes the driver use the __raw_readl() and __raw_writel()
functions which do not swap the endianness. On big endian system it is
assumed that the device should be access in big endian IO mode and on a
little endian system it would be access in little endian mode.

Fixes: 89b8bd2082bb ("serial: lantiq: Use readl/writel instead of ltq_r32/ltq_w32")
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/tty/serial/lantiq.c | 36 +++++++++++++++++++-----------------
 1 file changed, 19 insertions(+), 17 deletions(-)

diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index e052b69ceb98..9de9f0f239a1 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -114,9 +114,9 @@ struct ltq_uart_port {
 
 static inline void asc_update_bits(u32 clear, u32 set, void __iomem *reg)
 {
-	u32 tmp = readl(reg);
+	u32 tmp = __raw_readl(reg);
 
-	writel((tmp & ~clear) | set, reg);
+	__raw_writel((tmp & ~clear) | set, reg);
 }
 
 static inline struct
@@ -144,7 +144,7 @@ lqasc_start_tx(struct uart_port *port)
 static void
 lqasc_stop_rx(struct uart_port *port)
 {
-	writel(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE);
+	__raw_writel(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE);
 }
 
 static int
@@ -153,11 +153,12 @@ lqasc_rx_chars(struct uart_port *port)
 	struct tty_port *tport = &port->state->port;
 	unsigned int ch = 0, rsr = 0, fifocnt;
 
-	fifocnt = readl(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
+	fifocnt = __raw_readl(port->membase + LTQ_ASC_FSTAT) &
+		  ASCFSTAT_RXFFLMASK;
 	while (fifocnt--) {
 		u8 flag = TTY_NORMAL;
 		ch = readb(port->membase + LTQ_ASC_RBUF);
-		rsr = (readl(port->membase + LTQ_ASC_STATE)
+		rsr = (__raw_readl(port->membase + LTQ_ASC_STATE)
 			& ASCSTATE_ANY) | UART_DUMMY_UER_RX;
 		tty_flip_buffer_push(tport);
 		port->icount.rx++;
@@ -217,7 +218,7 @@ lqasc_tx_chars(struct uart_port *port)
 		return;
 	}
 
-	while (((readl(port->membase + LTQ_ASC_FSTAT) &
+	while (((__raw_readl(port->membase + LTQ_ASC_FSTAT) &
 		ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) {
 		if (port->x_char) {
 			writeb(port->x_char, port->membase + LTQ_ASC_TBUF);
@@ -245,7 +246,7 @@ lqasc_tx_int(int irq, void *_port)
 	unsigned long flags;
 	struct uart_port *port = (struct uart_port *)_port;
 	spin_lock_irqsave(&ltq_asc_lock, flags);
-	writel(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR);
+	__raw_writel(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR);
 	spin_unlock_irqrestore(&ltq_asc_lock, flags);
 	lqasc_start_tx(port);
 	return IRQ_HANDLED;
@@ -270,7 +271,7 @@ lqasc_rx_int(int irq, void *_port)
 	unsigned long flags;
 	struct uart_port *port = (struct uart_port *)_port;
 	spin_lock_irqsave(&ltq_asc_lock, flags);
-	writel(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR);
+	__raw_writel(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR);
 	lqasc_rx_chars(port);
 	spin_unlock_irqrestore(&ltq_asc_lock, flags);
 	return IRQ_HANDLED;
@@ -280,7 +281,8 @@ static unsigned int
 lqasc_tx_empty(struct uart_port *port)
 {
 	int status;
-	status = readl(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFFLMASK;
+	status = __raw_readl(port->membase + LTQ_ASC_FSTAT) &
+		 ASCFSTAT_TXFFLMASK;
 	return status ? 0 : TIOCSER_TEMT;
 }
 
@@ -313,12 +315,12 @@ lqasc_startup(struct uart_port *port)
 	asc_update_bits(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET),
 		port->membase + LTQ_ASC_CLC);
 
-	writel(0, port->membase + LTQ_ASC_PISEL);
-	writel(
+	__raw_writel(0, port->membase + LTQ_ASC_PISEL);
+	__raw_writel(
 		((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) |
 		ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU,
 		port->membase + LTQ_ASC_TXFCON);
-	writel(
+	__raw_writel(
 		((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK)
 		| ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU,
 		port->membase + LTQ_ASC_RXFCON);
@@ -350,7 +352,7 @@ lqasc_startup(struct uart_port *port)
 		goto err2;
 	}
 
-	writel(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX,
+	__raw_writel(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX,
 		port->membase + LTQ_ASC_IRNREN);
 	return 0;
 
@@ -369,7 +371,7 @@ lqasc_shutdown(struct uart_port *port)
 	free_irq(ltq_port->rx_irq, port);
 	free_irq(ltq_port->err_irq, port);
 
-	writel(0, port->membase + LTQ_ASC_CON);
+	__raw_writel(0, port->membase + LTQ_ASC_CON);
 	asc_update_bits(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU,
 		port->membase + LTQ_ASC_RXFCON);
 	asc_update_bits(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU,
@@ -461,13 +463,13 @@ lqasc_set_termios(struct uart_port *port,
 	asc_update_bits(ASCCON_BRS, 0, port->membase + LTQ_ASC_CON);
 
 	/* now we can write the new baudrate into the register */
-	writel(divisor, port->membase + LTQ_ASC_BG);
+	__raw_writel(divisor, port->membase + LTQ_ASC_BG);
 
 	/* turn the baudrate generator back on */
 	asc_update_bits(0, ASCCON_R, port->membase + LTQ_ASC_CON);
 
 	/* enable rx */
-	writel(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE);
+	__raw_writel(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE);
 
 	spin_unlock_irqrestore(&ltq_asc_lock, flags);
 
@@ -578,7 +580,7 @@ lqasc_console_putchar(struct uart_port *port, int ch)
 		return;
 
 	do {
-		fifofree = (readl(port->membase + LTQ_ASC_FSTAT)
+		fifofree = (__raw_readl(port->membase + LTQ_ASC_FSTAT)
 			& ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF;
 	} while (fifofree == 0);
 	writeb(ch, port->membase + LTQ_ASC_TBUF);
-- 
2.20.1


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] serial: lantiq: Do not swap register read/writes
  2019-01-06 18:50 [PATCH] serial: lantiq: Do not swap register read/writes Hauke Mehrtens
@ 2019-01-06 20:38 ` John Crispin
  0 siblings, 0 replies; 2+ messages in thread
From: John Crispin @ 2019-01-06 20:38 UTC (permalink / raw)
  To: Hauke Mehrtens, gregkh
  Cc: linux-mips, linux-mips, jslaby, linux-serial, songjun.wu


On 06/01/2019 19:50, Hauke Mehrtens wrote:
> The ltq_r32() and ltq_w32() macros use the __raw_readl() and
> __raw_writel() functions which do not swap the value to little endian.
> On the big endian vrx200 SoC the UART is operated in big endian IO mode,
> the readl() and write() functions convert the value to little endian
> first and then the driver does not work any more on this SoC.
> Currently the vrx200 SoC selects the CONFIG_SWAP_IO_SPACE option,
> without this option the serial driver would work, but PCI devices do not
> work any more.
>
> This patch makes the driver use the __raw_readl() and __raw_writel()
> functions which do not swap the endianness. On big endian system it is
> assumed that the device should be access in big endian IO mode and on a
> little endian system it would be access in little endian mode.
>
> Fixes: 89b8bd2082bb ("serial: lantiq: Use readl/writel instead of ltq_r32/ltq_w32")
> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Acked-by: John Crispin <john@phrozen.org>
> ---
>   drivers/tty/serial/lantiq.c | 36 +++++++++++++++++++-----------------
>   1 file changed, 19 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
> index e052b69ceb98..9de9f0f239a1 100644
> --- a/drivers/tty/serial/lantiq.c
> +++ b/drivers/tty/serial/lantiq.c
> @@ -114,9 +114,9 @@ struct ltq_uart_port {
>   
>   static inline void asc_update_bits(u32 clear, u32 set, void __iomem *reg)
>   {
> -	u32 tmp = readl(reg);
> +	u32 tmp = __raw_readl(reg);
>   
> -	writel((tmp & ~clear) | set, reg);
> +	__raw_writel((tmp & ~clear) | set, reg);
>   }
>   
>   static inline struct
> @@ -144,7 +144,7 @@ lqasc_start_tx(struct uart_port *port)
>   static void
>   lqasc_stop_rx(struct uart_port *port)
>   {
> -	writel(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE);
> +	__raw_writel(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE);
>   }
>   
>   static int
> @@ -153,11 +153,12 @@ lqasc_rx_chars(struct uart_port *port)
>   	struct tty_port *tport = &port->state->port;
>   	unsigned int ch = 0, rsr = 0, fifocnt;
>   
> -	fifocnt = readl(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
> +	fifocnt = __raw_readl(port->membase + LTQ_ASC_FSTAT) &
> +		  ASCFSTAT_RXFFLMASK;
>   	while (fifocnt--) {
>   		u8 flag = TTY_NORMAL;
>   		ch = readb(port->membase + LTQ_ASC_RBUF);
> -		rsr = (readl(port->membase + LTQ_ASC_STATE)
> +		rsr = (__raw_readl(port->membase + LTQ_ASC_STATE)
>   			& ASCSTATE_ANY) | UART_DUMMY_UER_RX;
>   		tty_flip_buffer_push(tport);
>   		port->icount.rx++;
> @@ -217,7 +218,7 @@ lqasc_tx_chars(struct uart_port *port)
>   		return;
>   	}
>   
> -	while (((readl(port->membase + LTQ_ASC_FSTAT) &
> +	while (((__raw_readl(port->membase + LTQ_ASC_FSTAT) &
>   		ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) {
>   		if (port->x_char) {
>   			writeb(port->x_char, port->membase + LTQ_ASC_TBUF);
> @@ -245,7 +246,7 @@ lqasc_tx_int(int irq, void *_port)
>   	unsigned long flags;
>   	struct uart_port *port = (struct uart_port *)_port;
>   	spin_lock_irqsave(&ltq_asc_lock, flags);
> -	writel(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR);
> +	__raw_writel(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR);
>   	spin_unlock_irqrestore(&ltq_asc_lock, flags);
>   	lqasc_start_tx(port);
>   	return IRQ_HANDLED;
> @@ -270,7 +271,7 @@ lqasc_rx_int(int irq, void *_port)
>   	unsigned long flags;
>   	struct uart_port *port = (struct uart_port *)_port;
>   	spin_lock_irqsave(&ltq_asc_lock, flags);
> -	writel(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR);
> +	__raw_writel(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR);
>   	lqasc_rx_chars(port);
>   	spin_unlock_irqrestore(&ltq_asc_lock, flags);
>   	return IRQ_HANDLED;
> @@ -280,7 +281,8 @@ static unsigned int
>   lqasc_tx_empty(struct uart_port *port)
>   {
>   	int status;
> -	status = readl(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFFLMASK;
> +	status = __raw_readl(port->membase + LTQ_ASC_FSTAT) &
> +		 ASCFSTAT_TXFFLMASK;
>   	return status ? 0 : TIOCSER_TEMT;
>   }
>   
> @@ -313,12 +315,12 @@ lqasc_startup(struct uart_port *port)
>   	asc_update_bits(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET),
>   		port->membase + LTQ_ASC_CLC);
>   
> -	writel(0, port->membase + LTQ_ASC_PISEL);
> -	writel(
> +	__raw_writel(0, port->membase + LTQ_ASC_PISEL);
> +	__raw_writel(
>   		((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) |
>   		ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU,
>   		port->membase + LTQ_ASC_TXFCON);
> -	writel(
> +	__raw_writel(
>   		((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK)
>   		| ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU,
>   		port->membase + LTQ_ASC_RXFCON);
> @@ -350,7 +352,7 @@ lqasc_startup(struct uart_port *port)
>   		goto err2;
>   	}
>   
> -	writel(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX,
> +	__raw_writel(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX,
>   		port->membase + LTQ_ASC_IRNREN);
>   	return 0;
>   
> @@ -369,7 +371,7 @@ lqasc_shutdown(struct uart_port *port)
>   	free_irq(ltq_port->rx_irq, port);
>   	free_irq(ltq_port->err_irq, port);
>   
> -	writel(0, port->membase + LTQ_ASC_CON);
> +	__raw_writel(0, port->membase + LTQ_ASC_CON);
>   	asc_update_bits(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU,
>   		port->membase + LTQ_ASC_RXFCON);
>   	asc_update_bits(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU,
> @@ -461,13 +463,13 @@ lqasc_set_termios(struct uart_port *port,
>   	asc_update_bits(ASCCON_BRS, 0, port->membase + LTQ_ASC_CON);
>   
>   	/* now we can write the new baudrate into the register */
> -	writel(divisor, port->membase + LTQ_ASC_BG);
> +	__raw_writel(divisor, port->membase + LTQ_ASC_BG);
>   
>   	/* turn the baudrate generator back on */
>   	asc_update_bits(0, ASCCON_R, port->membase + LTQ_ASC_CON);
>   
>   	/* enable rx */
> -	writel(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE);
> +	__raw_writel(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE);
>   
>   	spin_unlock_irqrestore(&ltq_asc_lock, flags);
>   
> @@ -578,7 +580,7 @@ lqasc_console_putchar(struct uart_port *port, int ch)
>   		return;
>   
>   	do {
> -		fifofree = (readl(port->membase + LTQ_ASC_FSTAT)
> +		fifofree = (__raw_readl(port->membase + LTQ_ASC_FSTAT)
>   			& ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF;
>   	} while (fifofree == 0);
>   	writeb(ch, port->membase + LTQ_ASC_TBUF);

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, back to index

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-06 18:50 [PATCH] serial: lantiq: Do not swap register read/writes Hauke Mehrtens
2019-01-06 20:38 ` John Crispin

Linux-MIPS Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-mips/0 linux-mips/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-mips linux-mips/ https://lore.kernel.org/linux-mips \
		linux-mips@vger.kernel.org linux-mips@archiver.kernel.org
	public-inbox-index linux-mips


Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-mips


AGPL code for this site: git clone https://public-inbox.org/ public-inbox