Mainline commit "serial: Test for no tx data on tx restart" not correct for i.MX6?
Subsystems (2)
Hi,
this is a question regarding the i.MX6 part (drivers/tty/serial/imx.c) of the commit
serial: Test for no tx data on tx restart
Talking with some i.MX6 experts about this, I've got the comment
-- cut --
The imx serial driver part of this commit isn't correct as imx.c sends x_char in irq handler, not in imx_start_tx(), -- cut --
What do you think?
Best regards
Dirk
P.S.: I don't have the initial post in my inbox, so sorry for the new thread.
Hi Dirk,
Quoted 8 lines · Dirk Behme
Hi,
this is a question regarding the i.MX6 part (
drivers/tty/serial/imx.c) of the commitserial: Test for no tx data on tx restart
Quoted 8 lines
Talking with some i.MX6 experts about this, I've got the comment
-- cut --
The imx serial driver part of this commit isn't correct asimx.csendsx_charin irq handler, not inimx_start_tx(), -- cut --What do you think?
Thanks for the comment.
Yeah, I missed that the imx driver handled x_char _at all_, because how the imx driver is handling x_char looks broken.
For example, if data is already in the tx ring buffer, imx_start_tx() will send that data before the x_char, and if all the tx ring buffer data is sent successfully, the tx interrupt is switched back off, so the x_char won't be sent.
Also, the imx driver doesn't send x_char in dma mode?
Regards,
Peter Hurley
Hi Peter
Quoted 21 lines · Peter Hurley
Hi Dirk,
Quoted 8 lines · Dirk Behme
Hi,
this is a question regarding the i.MX6 part (
drivers/tty/serial/imx.c) of the commitserial: Test for no tx data on tx restart
Quoted 8 lines
Talking with some i.MX6 experts about this, I've got the comment
-- cut --
The imx serial driver part of this commit isn't correct asimx.csendsx_charin irq handler, not inimx_start_tx(), -- cut --What do you think?
Thanks for the comment.
Quoted 7 lines
Yeah, I missed that the imx driver handled
x_char_atall_, because how the imx driver is handlingx_charlooks broken.For example, if data is already in the tx ring buffer,
imx_start_tx()will send that data before thex_char, and if all the tx ring buffer data is sent successfully, the tx interrupt is switched back off, so thex_charwon't be sent.
imx_start_tx() doesn't do any actual data transfer, it only switches tx interrupt on, and tx interrupt does the actual data transfer, so if x_char is pending, it will always be sent before the data in ring buffer.
Quoted 1 line
Also, the imx driver doesn't send
x_charin dma mode?
Yes, I think so.
Thanks,
Jiada
Quoted 3 lines
Regards,
Peter Hurley
Hi Jiada,
Quoted 27 lines · jiwang
Hi Peter
Quoted 24 lines · Peter Hurley
Hi Dirk,
Quoted 8 lines · Dirk Behme
Hi,
this is a question regarding the i.MX6 part (
drivers/tty/serial/imx.c) of the commitserial: Test for no tx data on tx restart
Quoted 8 lines
Talking with some i.MX6 experts about this, I've got the comment
-- cut --
The imx serial driver part of this commit isn't correct asimx.csendsx_charin irq handler, not inimx_start_tx(), -- cut --What do you think?
Thanks for the comment.
Yeah, I missed that the imx driver handled
x_char_atall_, because how the imx driver is handlingx_charlooks broken.
Quoted 6 lines
Quoted 4 lines
For example, if data is already in the tx ring buffer,
imx_start_tx()will send that data before thex_char, and if all the tx ring buffer data is sent successfully, the tx interrupt is switched back off, so thex_charwon't be sent.
imx_start_tx()doesn't do any actual data transfer
???
565 static void imx_start_tx(struct uart_port *port)
566 {
...
610
611 if (readl(sport->port.membase + uts_reg(sport)) & UTS_TXEMPTY)
612 imx_transmit_buffer(sport);
613 }
463 static inline void imx_transmit_buffer(struct imx_port *sport)
464 {
465 struct circ_buf *xmit = &sport->port.state->xmit;
466
467 while (!uart_circ_empty(xmit) &&
468 !(readl(sport->port.membase + uts_reg(sport))
469 & UTS_TXFULL)) {
470 /* send xmit->buf[xmit->tail]
471 * out the port here */
472 writel(xmit->buf[xmit->tail], sport->port.membase + URTX0);
473 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
474 sport->port.icount.tx++;
475 }
476
477 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
478 uart_write_wakeup(&sport->port);
479
480 if (uart_circ_empty(xmit))
481 imx_stop_tx(&sport->port);
482 }Regards,
Peter Hurley
Hi Peter
Quoted 58 lines · Peter Hurley
Hi Jiada,
Quoted 24 lines · jiwang
Hi Peter
Quoted 21 lines · Peter Hurley
Hi Dirk,
Quoted 8 lines · Dirk Behme
Hi,
this is a question regarding the i.MX6 part (
drivers/tty/serial/imx.c) of the commitserial: Test for no tx data on tx restart
Quoted 8 lines
Talking with some i.MX6 experts about this, I've got the comment
-- cut --
The imx serial driver part of this commit isn't correct asimx.csendsx_charin irq handler, not inimx_start_tx(), -- cut --What do you think?
Thanks for the comment.
Quoted 8 lines
Quoted 7 lines
Yeah, I missed that the imx driver handled
x_char_atall_, because how the imx driver is handlingx_charlooks broken.For example, if data is already in the tx ring buffer,
imx_start_tx()will send that data before thex_char, and if all the tx ring buffer data is sent successfully, the tx interrupt is switched back off, so thex_charwon't be sent.
imx_start_tx()doesn't do any actual data transfer???
565 static void imx_start_tx(struct uart_port *port) 566 { ... 610 611 if (readl(sport->port.membase + uts_reg(sport)) & UTS_TXEMPTY) 612 imx_transmit_buffer(sport); 613 } 463 static inline void imx_transmit_buffer(struct imx_port *sport) 464 { 465 struct circ_buf *xmit = &sport->port.state->xmit; 466 467 while (!uart_circ_empty(xmit) && 468 !(readl(sport->port.membase + uts_reg(sport)) 469 & UTS_TXFULL)) { 470 /* send xmit->buf[xmit->tail] 471 * out the port here */ 472 writel(xmit->buf[xmit->tail], sport->port.membase + URTX0); 473 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 474 sport->port.icount.tx++;
Quoted 8 lines
475 }
476
477 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
478 uart_write_wakeup(&sport->port);
479
480 if (uart_circ_empty(xmit))
481 imx_stop_tx(&sport->port);
482 }sorry, our imx driver has been modified differently,
yes, you are right, mainline imx driver's handling of x_char looks broken
@Shijie,
do you have any comment?
Thanks,
Jiada
Quoted 2 lines
Regards,
Peter Hurley
Quoted 23 lines · jiwang
Quoted 22 lines · Peter Hurley
Quoted 21 lines · jiwang
Quoted 20 lines · Peter Hurley
Quoted 8 lines · Dirk Behme
Hi,
this is a question regarding the i.MX6 part (
drivers/tty/serial/imx.c) of the commitserial: Test for no tx data on tx restart
Quoted 8 lines
Talking with some i.MX6 experts about this, I've got the comment
-- cut --
The imx serial driver part of this commit isn't correct asimx.csendsx_charin irq handler, not inimx_start_tx(), -- cut --What do you think?
Yeah, I missed that the imx driver handled
x_char_atall_, because how the imx driver is handlingx_charlooks broken.
[...]
Quoted 2 lines
sorry, our imx driver has been modified differently,
yes, you are right, mainline imx driver's handling ofx_charlooks broken
Jiada or Dirk or whomever,
Would someone please test the patch below on actual imx hardware?
You can download a standalone x_char unit test from
http://blog.hurleysoftware.com/uploads/tty_xchar.c
Instructions for building, setting up and testing are included in the file.
--- >% ---
Subject: [PATCH] serial: imx: Fix x_char handling and tx flow control
The serial core expects the UART driver to transmit x_char (START/STOP chars) even if tx is stopped and before data already in the tx ring buffer if possible. Also, sending x_char must not cause additional data in the tx ring buffer to transmit if tx is stopped.
Cause x_char to be transmitted before any other data is sent. Auto-stop tx if the tx ring buffer is empty or tx should be stopped. Only perform one write wakeup if tx ring buffer space is below threshold.
x_char handling in DMA mode is still broken; add FIXME.
--- drivers/tty/serial/imx.c | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-)
drivers/tty/serial/imx.c +16 -23
@@ -460,9 +460,19 @@ static inline void imx_transmit_buffer(struct imx_port *sport) {struct circ_buf *xmit = &sport->port.state->xmit; +if (sport->port.x_char) { +/* Send next char */ +writel (sport->port.x_char, sport->port.membase +URTX0 ); +return ; + } + +if (uart_circ_empty (xmit) ||uart_tx_stopped (&sport->port)) { +imx_stop_tx (&sport->port); +return ; + } +while (!uart_circ_empty (xmit) && - !(readl (sport->port.membase +uts_reg (sport)) - &UTS_TXFULL )) { + !(readl (sport->port.membase +uts_reg (sport)) &UTS_TXFULL )) {/* send xmit->buf[xmit->tail] * out the port here */ writel (xmit->buf[xmit->tail], sport->port.membase +URTX0 );
@@ -563,9 +573,6 @@ static void imx_start_tx(struct uart_port *port)struct imx_port *sport = (struct imx_port *)port;unsigned long temp; -if (uart_circ_empty (&port->state->xmit)) -return ; -if (USE_IRDA (sport)) {/* half duplex in IrDA mode; have to disable receive mode */ temp =readl (sport->port.membase +UCR4 );
@@ -600,7 +607,10 @@ static void imx_start_tx(struct uart_port *port) }if (sport->dma_is_enabled) { -imx_dma_tx (sport); +/* FIXME: port->x_char must be transmitted if != 0 */ +if (!uart_circ_empty (&port->state->xmit) && + !uart_tx_stopped (port)) +imx_dma_tx (sport);return ; }
@@ -628,27 +638,10 @@ static irqreturn_t imx_rtsint(int irq, void *dev_id)static irqreturn_t imx_txint (int irq,void *dev_id) {struct imx_port *sport = dev_id; -struct circ_buf *xmit = &sport->port.state->xmit;unsigned long flags;spin_lock_irqsave (&sport->port.lock, flags); -if (sport->port.x_char) { -/* Send next char */ -writel (sport->port.x_char, sport->port.membase +URTX0 ); - goto out; - } - -if (uart_circ_empty (xmit) ||uart_tx_stopped (&sport->port)) { -imx_stop_tx (&sport->port); - goto out; - } -imx_transmit_buffer (sport); - -if (uart_circ_chars_pending (xmit) <WAKEUP_CHARS ) -uart_write_wakeup (&sport->port); - -out:spin_unlock_irqrestore (&sport->port.lock, flags);return IRQ_HANDLED ; }
Signature · 1 line
2.0.4