forked from luck/tmp_suning_uos_patched
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:
commit
b334b77351
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user