aboutsummaryrefslogtreecommitdiff
path: root/drivers/tty/serial/sh-sci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial/sh-sci.c')
-rw-r--r--drivers/tty/serial/sh-sci.c68
1 files changed, 37 insertions, 31 deletions
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index e512eaa57ed5..f738980a8b2c 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -585,7 +585,7 @@ static void sci_start_tx(struct uart_port *port)
sci_serial_out(port, SCSCR, new);
}
- if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
+ if (s->chan_tx && !kfifo_is_empty(&port->state->port.xmit_fifo) &&
dma_submit_error(s->cookie_tx)) {
if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE)
/* Switch irq from SCIF to DMA */
@@ -817,7 +817,7 @@ static int sci_rxfill(struct uart_port *port)
static void sci_transmit_chars(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
unsigned int stopped = uart_tx_stopped(port);
unsigned short status;
unsigned short ctrl;
@@ -826,7 +826,7 @@ static void sci_transmit_chars(struct uart_port *port)
status = sci_serial_in(port, SCxSR);
if (!(status & SCxSR_TDxE(port))) {
ctrl = sci_serial_in(port, SCSCR);
- if (uart_circ_empty(xmit))
+ if (kfifo_is_empty(&tport->xmit_fifo))
ctrl &= ~SCSCR_TIE;
else
ctrl |= SCSCR_TIE;
@@ -842,15 +842,14 @@ static void sci_transmit_chars(struct uart_port *port)
if (port->x_char) {
c = port->x_char;
port->x_char = 0;
- } else if (!uart_circ_empty(xmit) && !stopped) {
- c = xmit->buf[xmit->tail];
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- } else if (port->type == PORT_SCI && uart_circ_empty(xmit)) {
- ctrl = sci_serial_in(port, SCSCR);
- ctrl &= ~SCSCR_TE;
- sci_serial_out(port, SCSCR, ctrl);
- return;
- } else {
+ } else if (stopped || !kfifo_get(&tport->xmit_fifo, &c)) {
+ if (port->type == PORT_SCI &&
+ kfifo_is_empty(&tport->xmit_fifo)) {
+ ctrl = sci_serial_in(port, SCSCR);
+ ctrl &= ~SCSCR_TE;
+ sci_serial_out(port, SCSCR, ctrl);
+ return;
+ }
break;
}
@@ -861,9 +860,9 @@ static void sci_transmit_chars(struct uart_port *port)
sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port));
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (uart_circ_empty(xmit)) {
+ if (kfifo_is_empty(&tport->xmit_fifo)) {
if (port->type == PORT_SCI) {
ctrl = sci_serial_in(port, SCSCR);
ctrl &= ~SCSCR_TIE;
@@ -1199,7 +1198,7 @@ static void sci_dma_tx_complete(void *arg)
{
struct sci_port *s = arg;
struct uart_port *port = &s->port;
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
unsigned long flags;
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
@@ -1208,10 +1207,10 @@ static void sci_dma_tx_complete(void *arg)
uart_xmit_advance(port, s->tx_dma_len);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (!uart_circ_empty(xmit)) {
+ if (!kfifo_is_empty(&tport->xmit_fifo)) {
s->cookie_tx = 0;
schedule_work(&s->work_tx);
} else {
@@ -1258,6 +1257,7 @@ static int sci_dma_rx_find_active(struct sci_port *s)
return -1;
}
+/* Must only be called with uart_port_lock taken */
static void sci_dma_rx_chan_invalidate(struct sci_port *s)
{
unsigned int i;
@@ -1271,9 +1271,14 @@ static void sci_dma_rx_chan_invalidate(struct sci_port *s)
static void sci_dma_rx_release(struct sci_port *s)
{
struct dma_chan *chan = s->chan_rx_saved;
+ struct uart_port *port = &s->port;
+ unsigned long flags;
+ uart_port_lock_irqsave(port, &flags);
s->chan_rx_saved = NULL;
sci_dma_rx_chan_invalidate(s);
+ uart_port_unlock_irqrestore(port, flags);
+
dmaengine_terminate_sync(chan);
dma_free_coherent(chan->device->dev, s->buf_len_rx * 2, s->rx_buf[0],
sg_dma_address(&s->sg_rx[0]));
@@ -1319,14 +1324,14 @@ static void sci_dma_rx_complete(void *arg)
dev_dbg(port->dev, "%s(%d) active cookie %d\n", __func__, port->line,
s->active_rx);
+ hrtimer_cancel(&s->rx_timer);
+
uart_port_lock_irqsave(port, &flags);
active = sci_dma_rx_find_active(s);
if (active >= 0)
count = sci_dma_rx_push(s, s->rx_buf[active], s->buf_len_rx);
- start_hrtimer_us(&s->rx_timer, s->rx_timeout);
-
if (count)
tty_flip_buffer_push(&port->state->port);
@@ -1349,17 +1354,18 @@ static void sci_dma_rx_complete(void *arg)
uart_port_unlock_irqrestore(port, flags);
dev_dbg(port->dev, "%s: cookie %d #%d, new active cookie %d\n",
__func__, s->cookie_rx[active], active, s->active_rx);
+
+ start_hrtimer_us(&s->rx_timer, s->rx_timeout);
+
return;
fail:
- uart_port_unlock_irqrestore(port, flags);
- dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
/* Switch to PIO */
- uart_port_lock_irqsave(port, &flags);
dmaengine_terminate_async(chan);
sci_dma_rx_chan_invalidate(s);
sci_dma_rx_reenable_irq(s);
uart_port_unlock_irqrestore(port, flags);
+ dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
}
static void sci_dma_tx_release(struct sci_port *s)
@@ -1424,10 +1430,10 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
struct dma_async_tx_descriptor *desc;
struct dma_chan *chan = s->chan_tx;
struct uart_port *port = &s->port;
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
unsigned long flags;
+ unsigned int tail;
dma_addr_t buf;
- int head, tail;
/*
* DMA is idle now.
@@ -1437,10 +1443,9 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
* consistent xmit buffer state.
*/
uart_port_lock_irq(port);
- head = xmit->head;
- tail = xmit->tail;
+ s->tx_dma_len = kfifo_out_linear(&tport->xmit_fifo, &tail,
+ UART_XMIT_SIZE);
buf = s->tx_dma_addr + tail;
- s->tx_dma_len = CIRC_CNT_TO_END(head, tail, UART_XMIT_SIZE);
if (!s->tx_dma_len) {
/* Transmit buffer has been flushed */
uart_port_unlock_irq(port);
@@ -1469,8 +1474,8 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
}
uart_port_unlock_irq(port);
- dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n",
- __func__, xmit->buf, tail, head, s->cookie_tx);
+ dev_dbg(port->dev, "%s: %p: %u, cookie %d\n",
+ __func__, tport->xmit_buf, tail, s->cookie_tx);
dma_async_issue_pending(chan);
return;
@@ -1585,6 +1590,7 @@ static struct dma_chan *sci_request_dma_chan(struct uart_port *port,
static void sci_request_dma(struct uart_port *port)
{
struct sci_port *s = to_sci_port(port);
+ struct tty_port *tport = &port->state->port;
struct dma_chan *chan;
dev_dbg(port->dev, "%s: port %d\n", __func__, port->line);
@@ -1613,7 +1619,7 @@ static void sci_request_dma(struct uart_port *port)
if (chan) {
/* UART circular tx buffer is an aligned page. */
s->tx_dma_addr = dma_map_single(chan->device->dev,
- port->state->xmit.buf,
+ tport->xmit_buf,
UART_XMIT_SIZE,
DMA_TO_DEVICE);
if (dma_mapping_error(chan->device->dev, s->tx_dma_addr)) {
@@ -1622,7 +1628,7 @@ static void sci_request_dma(struct uart_port *port)
} else {
dev_dbg(port->dev, "%s: mapped %lu@%p to %pad\n",
__func__, UART_XMIT_SIZE,
- port->state->xmit.buf, &s->tx_dma_addr);
+ tport->xmit_buf, &s->tx_dma_addr);
INIT_WORK(&s->work_tx, sci_dma_tx_work_fn);
s->chan_tx_saved = s->chan_tx = chan;