From: John Ogness <john.ogness@linutronix.de>
To: Peter Hurley <peter@hurleysoftware.com>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Tony Lindgren <tony@atomide.com>,
nsekhar@ti.com, linux-kernel@vger.kernel.org,
linux-serial@vger.kernel.org, linux-omap@vger.kernel.org
Subject: [PATCH] tty: serial: 8250_omap: do not defer termios changes
Date: Thu, 31 Mar 2016 10:41:56 +0200 [thread overview]
Message-ID: <8737r7ght7.fsf@linutronix.de> (raw)
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
It has been observed that the TX-DMA can stall if termios changes
occur while a TX-DMA operation is in progress. Previously this was
handled by allowing set_termios to return immediately and deferring
the change until the operation is completed. Now set_termios will
block until the operation is completed, proceed with the changes,
then schedule any pending next operation.
Commit message and forward port by John Ogness.
Tested-by: John Ogness <john.ogness@linutronix.de>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
Patch against next-20160331.
drivers/tty/serial/8250/8250_omap.c | 57 ++++++++++++++++----------
1 file changed, 37 insertions(+), 20 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 6f76051..9459b4d 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -100,9 +100,9 @@ struct omap8250_priv {
u8 wer;
u8 xon;
u8 xoff;
- u8 delayed_restore;
u16 quot;
+ wait_queue_head_t termios_wait;
bool is_suspending;
int wakeirq;
int wakeups_enabled;
@@ -257,18 +257,6 @@ static void omap8250_update_mdr1(struct uart_8250_port *up,
static void omap8250_restore_regs(struct uart_8250_port *up)
{
struct omap8250_priv *priv = up->port.private_data;
- struct uart_8250_dma *dma = up->dma;
-
- if (dma && dma->tx_running) {
- /*
- * TCSANOW requests the change to occur immediately however if
- * we have a TX-DMA operation in progress then it has been
- * observed that it might stall and never complete. Therefore we
- * delay DMA completes to prevent this hang from happen.
- */
- priv->delayed_restore = 1;
- return;
- }
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_EFR, UART_EFR_ECB);
@@ -310,6 +298,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
up->port.ops->set_mctrl(&up->port, up->port.mctrl);
}
+static void omap_8250_dma_tx_complete(void *param);
/*
* OMAP can use "CLK / (16 or 13) / div" for baud rate. And then we have have
* some differences in how we want to handle flow control.
@@ -320,6 +309,8 @@ static void omap_8250_set_termios(struct uart_port *port,
{
struct uart_8250_port *up = up_to_u8250p(port);
struct omap8250_priv *priv = up->port.private_data;
+ struct uart_8250_dma *dma = up->dma;
+ unsigned int complete_dma = 0;
unsigned char cval = 0;
unsigned int baud;
@@ -430,7 +421,7 @@ static void omap_8250_set_termios(struct uart_port *port,
priv->scr = OMAP_UART_SCR_RX_TRIG_GRANU1_MASK | OMAP_UART_SCR_TX_EMPTY |
OMAP_UART_SCR_TX_TRIG_GRANU1_MASK;
- if (up->dma)
+ if (dma)
priv->scr |= OMAP_UART_SCR_DMAMODE_1 |
OMAP_UART_SCR_DMAMODE_CTL;
@@ -460,6 +451,24 @@ static void omap_8250_set_termios(struct uart_port *port,
priv->efr |= OMAP_UART_SW_TX;
}
}
+
+ if (dma && dma->tx_running) {
+ /*
+ * TCSANOW requests the change to occur immediately, however
+ * if we have a TX-DMA operation in progress then it has been
+ * observed that it might stall and never complete. Therefore
+ * we wait until DMA completes to prevent this hang from
+ * happening.
+ */
+
+ dma->tx_running = 2;
+
+ spin_unlock_irq(&up->port.lock);
+ wait_event_interruptible(priv->termios_wait,
+ dma->tx_running == 3);
+ spin_lock_irq(&up->port.lock);
+ complete_dma = 1;
+ }
omap8250_restore_regs(up);
spin_unlock_irq(&up->port.lock);
@@ -475,6 +484,8 @@ static void omap_8250_set_termios(struct uart_port *port,
/* Don't rewrite B0 */
if (tty_termios_baud_rate(termios))
tty_termios_encode_baud_rate(termios, baud, baud);
+ if (complete_dma)
+ omap_8250_dma_tx_complete(up);
}
/* same as 8250 except that we may have extra flow bits set in EFR */
@@ -893,17 +904,18 @@ static void omap_8250_dma_tx_complete(void *param)
spin_lock_irqsave(&p->port.lock, flags);
+ if (dma->tx_running == 2) {
+ dma->tx_running = 3;
+ wake_up(&priv->termios_wait);
+ goto out;
+ }
+
dma->tx_running = 0;
xmit->tail += dma->tx_size;
xmit->tail &= UART_XMIT_SIZE - 1;
p->port.icount.tx += dma->tx_size;
- if (priv->delayed_restore) {
- priv->delayed_restore = 0;
- omap8250_restore_regs(p);
- }
-
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&p->port);
@@ -923,7 +935,7 @@ static void omap_8250_dma_tx_complete(void *param)
p->ier |= UART_IER_THRI;
serial_port_out(&p->port, UART_IER, p->ier);
}
-
+out:
spin_unlock_irqrestore(&p->port.lock, flags);
}
@@ -1088,6 +1100,10 @@ static inline int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
{
return -EINVAL;
}
+
+static void omap_8250_dma_tx_complete(void *param)
+{
+}
#endif
static int omap8250_no_handle_irq(struct uart_port *port)
@@ -1241,6 +1257,7 @@ static int omap8250_probe(struct platform_device *pdev)
priv->omap8250_dma.rx_size = RX_TRIGGER;
priv->omap8250_dma.rxconf.src_maxburst = RX_TRIGGER;
priv->omap8250_dma.txconf.dst_maxburst = TX_TRIGGER;
+ init_waitqueue_head(&priv->termios_wait);
if (of_machine_is_compatible("ti,am33xx"))
priv->habit |= OMAP_DMA_TX_KICK;
--
1.7.10.4
WARNING: multiple messages have this Message-ID (diff)
From: John Ogness <john.ogness@linutronix.de>
To: Peter Hurley <peter@hurleysoftware.com>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Tony Lindgren <tony@atomide.com>
Cc: nsekhar@ti.com
Cc: linux-kernel@vger.kernel.org
Cc: linux-serial@vger.kernel.org
Cc: linux-omap@vger.kernel.org
Subject: [PATCH] tty: serial: 8250_omap: do not defer termios changes
Date: Thu, 31 Mar 2016 10:41:56 +0200 [thread overview]
Message-ID: <8737r7ght7.fsf@linutronix.de> (raw)
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
It has been observed that the TX-DMA can stall if termios changes
occur while a TX-DMA operation is in progress. Previously this was
handled by allowing set_termios to return immediately and deferring
the change until the operation is completed. Now set_termios will
block until the operation is completed, proceed with the changes,
then schedule any pending next operation.
Commit message and forward port by John Ogness.
Tested-by: John Ogness <john.ogness@linutronix.de>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
Patch against next-20160331.
drivers/tty/serial/8250/8250_omap.c | 57 ++++++++++++++++----------
1 file changed, 37 insertions(+), 20 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 6f76051..9459b4d 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -100,9 +100,9 @@ struct omap8250_priv {
u8 wer;
u8 xon;
u8 xoff;
- u8 delayed_restore;
u16 quot;
+ wait_queue_head_t termios_wait;
bool is_suspending;
int wakeirq;
int wakeups_enabled;
@@ -257,18 +257,6 @@ static void omap8250_update_mdr1(struct uart_8250_port *up,
static void omap8250_restore_regs(struct uart_8250_port *up)
{
struct omap8250_priv *priv = up->port.private_data;
- struct uart_8250_dma *dma = up->dma;
-
- if (dma && dma->tx_running) {
- /*
- * TCSANOW requests the change to occur immediately however if
- * we have a TX-DMA operation in progress then it has been
- * observed that it might stall and never complete. Therefore we
- * delay DMA completes to prevent this hang from happen.
- */
- priv->delayed_restore = 1;
- return;
- }
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_EFR, UART_EFR_ECB);
@@ -310,6 +298,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
up->port.ops->set_mctrl(&up->port, up->port.mctrl);
}
+static void omap_8250_dma_tx_complete(void *param);
/*
* OMAP can use "CLK / (16 or 13) / div" for baud rate. And then we have have
* some differences in how we want to handle flow control.
@@ -320,6 +309,8 @@ static void omap_8250_set_termios(struct uart_port *port,
{
struct uart_8250_port *up = up_to_u8250p(port);
struct omap8250_priv *priv = up->port.private_data;
+ struct uart_8250_dma *dma = up->dma;
+ unsigned int complete_dma = 0;
unsigned char cval = 0;
unsigned int baud;
@@ -430,7 +421,7 @@ static void omap_8250_set_termios(struct uart_port *port,
priv->scr = OMAP_UART_SCR_RX_TRIG_GRANU1_MASK | OMAP_UART_SCR_TX_EMPTY |
OMAP_UART_SCR_TX_TRIG_GRANU1_MASK;
- if (up->dma)
+ if (dma)
priv->scr |= OMAP_UART_SCR_DMAMODE_1 |
OMAP_UART_SCR_DMAMODE_CTL;
@@ -460,6 +451,24 @@ static void omap_8250_set_termios(struct uart_port *port,
priv->efr |= OMAP_UART_SW_TX;
}
}
+
+ if (dma && dma->tx_running) {
+ /*
+ * TCSANOW requests the change to occur immediately, however
+ * if we have a TX-DMA operation in progress then it has been
+ * observed that it might stall and never complete. Therefore
+ * we wait until DMA completes to prevent this hang from
+ * happening.
+ */
+
+ dma->tx_running = 2;
+
+ spin_unlock_irq(&up->port.lock);
+ wait_event_interruptible(priv->termios_wait,
+ dma->tx_running == 3);
+ spin_lock_irq(&up->port.lock);
+ complete_dma = 1;
+ }
omap8250_restore_regs(up);
spin_unlock_irq(&up->port.lock);
@@ -475,6 +484,8 @@ static void omap_8250_set_termios(struct uart_port *port,
/* Don't rewrite B0 */
if (tty_termios_baud_rate(termios))
tty_termios_encode_baud_rate(termios, baud, baud);
+ if (complete_dma)
+ omap_8250_dma_tx_complete(up);
}
/* same as 8250 except that we may have extra flow bits set in EFR */
@@ -893,17 +904,18 @@ static void omap_8250_dma_tx_complete(void *param)
spin_lock_irqsave(&p->port.lock, flags);
+ if (dma->tx_running == 2) {
+ dma->tx_running = 3;
+ wake_up(&priv->termios_wait);
+ goto out;
+ }
+
dma->tx_running = 0;
xmit->tail += dma->tx_size;
xmit->tail &= UART_XMIT_SIZE - 1;
p->port.icount.tx += dma->tx_size;
- if (priv->delayed_restore) {
- priv->delayed_restore = 0;
- omap8250_restore_regs(p);
- }
-
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&p->port);
@@ -923,7 +935,7 @@ static void omap_8250_dma_tx_complete(void *param)
p->ier |= UART_IER_THRI;
serial_port_out(&p->port, UART_IER, p->ier);
}
-
+out:
spin_unlock_irqrestore(&p->port.lock, flags);
}
@@ -1088,6 +1100,10 @@ static inline int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
{
return -EINVAL;
}
+
+static void omap_8250_dma_tx_complete(void *param)
+{
+}
#endif
static int omap8250_no_handle_irq(struct uart_port *port)
@@ -1241,6 +1257,7 @@ static int omap8250_probe(struct platform_device *pdev)
priv->omap8250_dma.rx_size = RX_TRIGGER;
priv->omap8250_dma.rxconf.src_maxburst = RX_TRIGGER;
priv->omap8250_dma.txconf.dst_maxburst = TX_TRIGGER;
+ init_waitqueue_head(&priv->termios_wait);
if (of_machine_is_compatible("ti,am33xx"))
priv->habit |= OMAP_DMA_TX_KICK;
--
1.7.10.4
next reply other threads:[~2016-03-31 8:41 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-03-31 8:41 John Ogness [this message]
2016-03-31 8:41 ` [PATCH] tty: serial: 8250_omap: do not defer termios changes John Ogness
2016-03-31 10:51 ` John Ogness
2016-03-31 14:33 ` One Thousand Gnomes
2016-04-05 4:07 ` Peter Hurley
2016-04-11 8:18 ` John Ogness
2016-04-11 17:53 ` Peter Hurley
2016-04-11 18:31 ` Sebastian Andrzej Siewior
2016-04-11 20:10 ` Peter Hurley
2016-04-12 17:03 ` Sebastian Andrzej Siewior
2016-04-12 18:42 ` Peter Hurley
2016-04-14 16:03 ` Peter Hurley
2016-04-12 23:20 ` 8250 dma issues ( was Re: [PATCH] tty: serial: 8250_omap: do not defer termios changes) Peter Hurley
2016-04-14 15:07 ` One Thousand Gnomes
2016-04-14 17:54 ` Peter Hurley
2016-04-13 0:00 ` omap uart + dma issues (Re: " Peter Hurley
2016-04-13 11:11 ` Sekhar Nori
2016-04-13 11:11 ` Sekhar Nori
2016-04-14 1:14 ` Peter Hurley
2016-05-03 12:00 ` [PATCH] tty: serial: 8250_omap: do not defer termios changes Vignesh R
2016-05-03 12:00 ` Vignesh R
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=8737r7ght7.fsf@linutronix.de \
--to=john.ogness@linutronix.de \
--cc=bigeasy@linutronix.de \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-omap@vger.kernel.org \
--cc=linux-serial@vger.kernel.org \
--cc=nsekhar@ti.com \
--cc=peter@hurleysoftware.com \
--cc=tony@atomide.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.