TTY/Serial driver fixes for 4.1-rc7

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.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iEYEABECAAYFAlVzhBsACgkQMUfUDdst+yk3vACgok97fBbPTarm5Xw7yZAbu3tD
 6twAmwQC2GwyyAoZz3HTjK0NQnfBIm8N
 =j8nR
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Linus Torvalds 2015-06-06 22:14:23 -07:00
commit b334b77351
4 changed files with 105 additions and 22 deletions

View File

@ -162,6 +162,17 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
return put_user(x, ptr);
}
static inline int tty_copy_to_user(struct tty_struct *tty,
void __user *to,
const void *from,
unsigned long n)
{
struct n_tty_data *ldata = tty->disc_data;
tty_audit_add_data(tty, to, n, ldata->icanon);
return copy_to_user(to, from, n);
}
/**
* n_tty_kick_worker - start input worker (if required)
* @tty: terminal
@ -2070,8 +2081,8 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
size = N_TTY_BUF_SIZE - tail;
n = eol - tail;
if (n > 4096)
n += 4096;
if (n > N_TTY_BUF_SIZE)
n += N_TTY_BUF_SIZE;
n += found;
c = n;
@ -2084,12 +2095,12 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
__func__, eol, found, n, c, size, more);
if (n > size) {
ret = copy_to_user(*b, read_buf_addr(ldata, tail), size);
ret = tty_copy_to_user(tty, *b, read_buf_addr(ldata, tail), size);
if (ret)
return -EFAULT;
ret = copy_to_user(*b + size, ldata->read_buf, n - size);
ret = tty_copy_to_user(tty, *b + size, ldata->read_buf, n - size);
} else
ret = copy_to_user(*b, read_buf_addr(ldata, tail), n);
ret = tty_copy_to_user(tty, *b, read_buf_addr(ldata, tail), n);
if (ret)
return -EFAULT;

View File

@ -562,12 +562,36 @@ static irqreturn_t omap_wake_irq(int irq, void *dev_id)
return IRQ_NONE;
}
#ifdef CONFIG_SERIAL_8250_DMA
static int omap_8250_dma_handle_irq(struct uart_port *port);
#endif
static irqreturn_t omap8250_irq(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
struct uart_8250_port *up = up_to_u8250p(port);
unsigned int iir;
int ret;
#ifdef CONFIG_SERIAL_8250_DMA
if (up->dma) {
ret = omap_8250_dma_handle_irq(port);
return IRQ_RETVAL(ret);
}
#endif
serial8250_rpm_get(up);
iir = serial_port_in(port, UART_IIR);
ret = serial8250_handle_irq(port, iir);
serial8250_rpm_put(up);
return IRQ_RETVAL(ret);
}
static int omap_8250_startup(struct uart_port *port)
{
struct uart_8250_port *up =
container_of(port, struct uart_8250_port, port);
struct uart_8250_port *up = up_to_u8250p(port);
struct omap8250_priv *priv = port->private_data;
int ret;
if (priv->wakeirq) {
@ -580,10 +604,31 @@ static int omap_8250_startup(struct uart_port *port)
pm_runtime_get_sync(port->dev);
ret = serial8250_do_startup(port);
if (ret)
up->mcr = 0;
serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
serial_out(up, UART_LCR, UART_LCR_WLEN8);
up->lsr_saved_flags = 0;
up->msr_saved_flags = 0;
if (up->dma) {
ret = serial8250_request_dma(up);
if (ret) {
dev_warn_ratelimited(port->dev,
"failed to request DMA\n");
up->dma = NULL;
}
}
ret = request_irq(port->irq, omap8250_irq, IRQF_SHARED,
dev_name(port->dev), port);
if (ret < 0)
goto err;
up->ier = UART_IER_RLSI | UART_IER_RDI;
serial_out(up, UART_IER, up->ier);
#ifdef CONFIG_PM
up->capabilities |= UART_CAP_RPM;
#endif
@ -610,8 +655,7 @@ static int omap_8250_startup(struct uart_port *port)
static void omap_8250_shutdown(struct uart_port *port)
{
struct uart_8250_port *up =
container_of(port, struct uart_8250_port, port);
struct uart_8250_port *up = up_to_u8250p(port);
struct omap8250_priv *priv = port->private_data;
flush_work(&priv->qos_work);
@ -621,11 +665,24 @@ static void omap_8250_shutdown(struct uart_port *port)
pm_runtime_get_sync(port->dev);
serial_out(up, UART_OMAP_WER, 0);
serial8250_do_shutdown(port);
up->ier = 0;
serial_out(up, UART_IER, 0);
if (up->dma)
serial8250_release_dma(up);
/*
* Disable break condition and FIFOs
*/
if (up->lcr & UART_LCR_SBC)
serial_out(up, UART_LCR, up->lcr & ~UART_LCR_SBC);
serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
pm_runtime_mark_last_busy(port->dev);
pm_runtime_put_autosuspend(port->dev);
free_irq(port->irq, port);
if (priv->wakeirq)
free_irq(priv->wakeirq, port);
}
@ -974,6 +1031,13 @@ static inline int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
}
#endif
static int omap8250_no_handle_irq(struct uart_port *port)
{
/* IRQ has not been requested but handling irq? */
WARN_ONCE(1, "Unexpected irq handling before port startup\n");
return 0;
}
static int omap8250_probe(struct platform_device *pdev)
{
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@ -1075,6 +1139,7 @@ static int omap8250_probe(struct platform_device *pdev)
pm_runtime_get_sync(&pdev->dev);
omap_serial_fill_features_erratas(&up, priv);
up.port.handle_irq = omap8250_no_handle_irq;
#ifdef CONFIG_SERIAL_8250_DMA
if (pdev->dev.of_node) {
/*
@ -1088,7 +1153,6 @@ static int omap8250_probe(struct platform_device *pdev)
ret = of_property_count_strings(pdev->dev.of_node, "dma-names");
if (ret == 2) {
up.dma = &priv->omap8250_dma;
up.port.handle_irq = omap_8250_dma_handle_irq;
priv->omap8250_dma.fn = the_no_dma_filter_fn;
priv->omap8250_dma.tx_dma = omap_8250_tx_dma;
priv->omap8250_dma.rx_dma = omap_8250_rx_dma;

View File

@ -1249,20 +1249,19 @@ __acquires(&uap->port.lock)
/*
* Transmit a character
* There must be at least one free entry in the TX FIFO to accept the char.
*
* Returns true if the FIFO might have space in it afterwards;
* returns false if the FIFO definitely became full.
* Returns true if the character was successfully queued to the FIFO.
* Returns false otherwise.
*/
static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c)
{
if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
return false; /* unable to transmit character */
writew(c, uap->port.membase + UART01x_DR);
uap->port.icount.tx++;
if (likely(uap->tx_irq_seen > 1))
return true;
return !(readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF);
return true;
}
static bool pl011_tx_chars(struct uart_amba_port *uap)
@ -1296,7 +1295,8 @@ static bool pl011_tx_chars(struct uart_amba_port *uap)
return false;
if (uap->port.x_char) {
pl011_tx_char(uap, uap->port.x_char);
if (!pl011_tx_char(uap, uap->port.x_char))
goto done;
uap->port.x_char = 0;
--count;
}

View File

@ -911,6 +911,14 @@ static void dma_rx_callback(void *data)
status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state);
count = RX_BUF_SIZE - state.residue;
if (readl(sport->port.membase + USR2) & USR2_IDLE) {
/* In condition [3] the SDMA counted up too early */
count--;
writel(USR2_IDLE, sport->port.membase + USR2);
}
dev_dbg(sport->port.dev, "We get %d bytes.\n", count);
if (count) {