diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index d8b73e791a55..7d8b2644e06d 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -123,11 +123,6 @@ struct sci_port { struct notifier_block freq_transition; }; -/* Function prototypes */ -static void sci_start_tx(struct uart_port *port); -static void sci_stop_tx(struct uart_port *port); -static void sci_start_rx(struct uart_port *port); - #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS static struct sci_port sci_ports[SCI_NPORTS]; @@ -489,6 +484,89 @@ static void sci_port_disable(struct sci_port *sci_port) pm_runtime_put_sync(sci_port->port.dev); } +static inline unsigned long port_rx_irq_mask(struct uart_port *port) +{ + /* + * Not all ports (such as SCIFA) will support REIE. Rather than + * special-casing the port type, we check the port initialization + * IRQ enable mask to see whether the IRQ is desired at all. If + * it's unset, it's logically inferred that there's no point in + * testing for it. + */ + return SCSCR_RIE | (to_sci_port(port)->cfg->scscr & SCSCR_REIE); +} + +static void sci_start_tx(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + unsigned short ctrl; + +#ifdef CONFIG_SERIAL_SH_SCI_DMA + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + u16 new, scr = serial_port_in(port, SCSCR); + if (s->chan_tx) + new = scr | SCSCR_TDRQE; + else + new = scr & ~SCSCR_TDRQE; + if (new != scr) + serial_port_out(port, SCSCR, new); + } + + if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) && + dma_submit_error(s->cookie_tx)) { + s->cookie_tx = 0; + schedule_work(&s->work_tx); + } +#endif + + if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */ + ctrl = serial_port_in(port, SCSCR); + serial_port_out(port, SCSCR, ctrl | SCSCR_TIE); + } +} + +static void sci_stop_tx(struct uart_port *port) +{ + unsigned short ctrl; + + /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ + ctrl = serial_port_in(port, SCSCR); + + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + ctrl &= ~SCSCR_TDRQE; + + ctrl &= ~SCSCR_TIE; + + serial_port_out(port, SCSCR, ctrl); +} + +static void sci_start_rx(struct uart_port *port) +{ + unsigned short ctrl; + + ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port); + + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + ctrl &= ~SCSCR_RDRQE; + + serial_port_out(port, SCSCR, ctrl); +} + +static void sci_stop_rx(struct uart_port *port) +{ + unsigned short ctrl; + + ctrl = serial_port_in(port, SCSCR); + + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + ctrl &= ~SCSCR_RDRQE; + + ctrl &= ~port_rx_irq_mask(port); + + serial_port_out(port, SCSCR, ctrl); +} + static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask) { if (port->type == PORT_SCI) { @@ -940,6 +1018,427 @@ static int sci_handle_breaks(struct uart_port *port) return copied; } +#ifdef CONFIG_SERIAL_SH_SCI_DMA +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; + unsigned long flags; + + dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + + spin_lock_irqsave(&port->lock, flags); + + xmit->tail += s->tx_dma_len; + xmit->tail &= UART_XMIT_SIZE - 1; + + port->icount.tx += s->tx_dma_len; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (!uart_circ_empty(xmit)) { + s->cookie_tx = 0; + schedule_work(&s->work_tx); + } else { + s->cookie_tx = -EINVAL; + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + u16 ctrl = serial_port_in(port, SCSCR); + serial_port_out(port, SCSCR, ctrl & ~SCSCR_TIE); + } + } + + spin_unlock_irqrestore(&port->lock, flags); +} + +/* Locking: called with port lock held */ +static int sci_dma_rx_push(struct sci_port *s, void *buf, size_t count) +{ + struct uart_port *port = &s->port; + struct tty_port *tport = &port->state->port; + int copied; + + copied = tty_insert_flip_string(tport, buf, count); + if (copied < count) { + dev_warn(port->dev, "Rx overrun: dropping %zu bytes\n", + count - copied); + port->icount.buf_overrun++; + } + + port->icount.rx += copied; + + return copied; +} + +static int sci_dma_rx_find_active(struct sci_port *s) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(s->cookie_rx); i++) + if (s->active_rx == s->cookie_rx[i]) + return i; + + dev_err(s->port.dev, "%s: Rx cookie %d not found!\n", __func__, + s->active_rx); + return -1; +} + +static void sci_rx_dma_release(struct sci_port *s, bool enable_pio) +{ + struct dma_chan *chan = s->chan_rx; + struct uart_port *port = &s->port; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + s->chan_rx = NULL; + s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL; + spin_unlock_irqrestore(&port->lock, flags); + dmaengine_terminate_all(chan); + dma_free_coherent(chan->device->dev, s->buf_len_rx * 2, s->rx_buf[0], + sg_dma_address(&s->sg_rx[0])); + dma_release_channel(chan); + if (enable_pio) + sci_start_rx(port); +} + +static void sci_dma_rx_complete(void *arg) +{ + struct sci_port *s = arg; + struct uart_port *port = &s->port; + unsigned long flags; + int active, count = 0; + + dev_dbg(port->dev, "%s(%d) active cookie %d\n", __func__, port->line, + s->active_rx); + + spin_lock_irqsave(&port->lock, 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); + + mod_timer(&s->rx_timer, jiffies + s->rx_timeout); + + spin_unlock_irqrestore(&port->lock, flags); + + if (count) + tty_flip_buffer_push(&port->state->port); + + schedule_work(&s->work_rx); +} + +static void sci_tx_dma_release(struct sci_port *s, bool enable_pio) +{ + struct dma_chan *chan = s->chan_tx; + struct uart_port *port = &s->port; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + s->chan_tx = NULL; + s->cookie_tx = -EINVAL; + spin_unlock_irqrestore(&port->lock, flags); + dmaengine_terminate_all(chan); + dma_unmap_single(chan->device->dev, s->tx_dma_addr, UART_XMIT_SIZE, + DMA_TO_DEVICE); + dma_release_channel(chan); + if (enable_pio) + sci_start_tx(port); +} + +static void sci_submit_rx(struct sci_port *s) +{ + struct dma_chan *chan = s->chan_rx; + int i; + + for (i = 0; i < 2; i++) { + struct scatterlist *sg = &s->sg_rx[i]; + struct dma_async_tx_descriptor *desc; + + desc = dmaengine_prep_slave_sg(chan, + sg, 1, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) + goto fail; + + desc->callback = sci_dma_rx_complete; + desc->callback_param = s; + s->cookie_rx[i] = dmaengine_submit(desc); + if (dma_submit_error(s->cookie_rx[i])) + goto fail; + + dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__, + s->cookie_rx[i], i); + } + + s->active_rx = s->cookie_rx[0]; + + dma_async_issue_pending(chan); + return; + +fail: + if (i) + dmaengine_terminate_all(chan); + for (i = 0; i < 2; i++) + s->cookie_rx[i] = -EINVAL; + s->active_rx = -EINVAL; + dev_warn(s->port.dev, "Failed to re-start Rx DMA, using PIO\n"); + sci_rx_dma_release(s, true); +} + +static void work_fn_rx(struct work_struct *work) +{ + struct sci_port *s = container_of(work, struct sci_port, work_rx); + struct uart_port *port = &s->port; + struct dma_async_tx_descriptor *desc; + struct dma_tx_state state; + enum dma_status status; + unsigned long flags; + int new; + + spin_lock_irqsave(&port->lock, flags); + new = sci_dma_rx_find_active(s); + if (new < 0) { + spin_unlock_irqrestore(&port->lock, flags); + return; + } + + status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state); + if (status != DMA_COMPLETE) { + /* Handle incomplete DMA receive */ + struct dma_chan *chan = s->chan_rx; + unsigned int read; + int count; + + dmaengine_terminate_all(chan); + read = sg_dma_len(&s->sg_rx[new]) - state.residue; + dev_dbg(port->dev, "Read %u bytes with cookie %d\n", read, + s->active_rx); + + if (read) { + count = sci_dma_rx_push(s, s->rx_buf[new], read); + if (count) + tty_flip_buffer_push(&port->state->port); + } + + spin_unlock_irqrestore(&port->lock, flags); + + sci_submit_rx(s); + return; + } + + desc = dmaengine_prep_slave_sg(s->chan_rx, &s->sg_rx[new], 1, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) + goto fail; + + desc->callback = sci_dma_rx_complete; + desc->callback_param = s; + s->cookie_rx[new] = dmaengine_submit(desc); + if (dma_submit_error(s->cookie_rx[new])) + goto fail; + + s->active_rx = s->cookie_rx[!new]; + + dev_dbg(port->dev, "%s: cookie %d #%d, new active cookie %d\n", + __func__, s->cookie_rx[new], new, s->active_rx); + spin_unlock_irqrestore(&port->lock, flags); + return; + +fail: + spin_unlock_irqrestore(&port->lock, flags); + dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n"); + sci_rx_dma_release(s, true); +} + +static void work_fn_tx(struct work_struct *work) +{ + struct sci_port *s = container_of(work, struct sci_port, work_tx); + 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; + dma_addr_t buf; + + /* + * DMA is idle now. + * Port xmit buffer is already mapped, and it is one page... Just adjust + * offsets and lengths. Since it is a circular buffer, we have to + * transmit till the end, and then the rest. Take the port lock to get a + * consistent xmit buffer state. + */ + spin_lock_irq(&port->lock); + buf = s->tx_dma_addr + (xmit->tail & (UART_XMIT_SIZE - 1)); + s->tx_dma_len = min_t(unsigned int, + CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE), + CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE)); + spin_unlock_irq(&port->lock); + + desc = dmaengine_prep_slave_single(chan, buf, s->tx_dma_len, + DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dev_warn(port->dev, "Failed preparing Tx DMA descriptor\n"); + /* switch to PIO */ + sci_tx_dma_release(s, true); + return; + } + + dma_sync_single_for_device(chan->device->dev, buf, s->tx_dma_len, + DMA_TO_DEVICE); + + spin_lock_irq(&port->lock); + desc->callback = sci_dma_tx_complete; + desc->callback_param = s; + spin_unlock_irq(&port->lock); + s->cookie_tx = dmaengine_submit(desc); + if (dma_submit_error(s->cookie_tx)) { + dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n"); + /* switch to PIO */ + sci_tx_dma_release(s, true); + return; + } + + dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", + __func__, xmit->buf, xmit->tail, xmit->head, s->cookie_tx); + + dma_async_issue_pending(chan); +} + +static bool filter(struct dma_chan *chan, void *slave) +{ + struct sh_dmae_slave *param = slave; + + dev_dbg(chan->device->dev, "%s: slave ID %d\n", + __func__, param->shdma_slave.slave_id); + + chan->private = ¶m->shdma_slave; + return true; +} + +static void rx_timer_fn(unsigned long arg) +{ + struct sci_port *s = (struct sci_port *)arg; + struct uart_port *port = &s->port; + u16 scr = serial_port_in(port, SCSCR); + + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + scr &= ~SCSCR_RDRQE; + enable_irq(s->irqs[SCIx_RXI_IRQ]); + } + serial_port_out(port, SCSCR, scr | SCSCR_RIE); + dev_dbg(port->dev, "DMA Rx timed out\n"); + schedule_work(&s->work_rx); +} + +static void sci_request_dma(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + struct sh_dmae_slave *param; + struct dma_chan *chan; + dma_cap_mask_t mask; + + dev_dbg(port->dev, "%s: port %d\n", __func__, port->line); + + if (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0) + return; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + param = &s->param_tx; + + /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */ + param->shdma_slave.slave_id = s->cfg->dma_slave_tx; + + s->cookie_tx = -EINVAL; + chan = dma_request_channel(mask, filter, param); + dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan); + if (chan) { + s->chan_tx = chan; + /* UART circular tx buffer is an aligned page. */ + s->tx_dma_addr = dma_map_single(chan->device->dev, + port->state->xmit.buf, + UART_XMIT_SIZE, + DMA_TO_DEVICE); + if (dma_mapping_error(chan->device->dev, s->tx_dma_addr)) { + dev_warn(port->dev, "Failed mapping Tx DMA descriptor\n"); + dma_release_channel(chan); + s->chan_tx = NULL; + } else { + dev_dbg(port->dev, "%s: mapped %lu@%p to %pad\n", + __func__, UART_XMIT_SIZE, + port->state->xmit.buf, &s->tx_dma_addr); + } + + INIT_WORK(&s->work_tx, work_fn_tx); + } + + param = &s->param_rx; + + /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */ + param->shdma_slave.slave_id = s->cfg->dma_slave_rx; + + chan = dma_request_channel(mask, filter, param); + dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan); + if (chan) { + unsigned int i; + dma_addr_t dma; + void *buf; + + s->chan_rx = chan; + + s->buf_len_rx = 2 * max_t(size_t, 16, port->fifosize); + buf = dma_alloc_coherent(chan->device->dev, s->buf_len_rx * 2, + &dma, GFP_KERNEL); + if (!buf) { + dev_warn(port->dev, + "Failed to allocate Rx dma buffer, using PIO\n"); + dma_release_channel(chan); + s->chan_rx = NULL; + sci_start_rx(port); + return; + } + + for (i = 0; i < 2; i++) { + struct scatterlist *sg = &s->sg_rx[i]; + + sg_init_table(sg, 1); + s->rx_buf[i] = buf; + sg_dma_address(sg) = dma; + sg->length = s->buf_len_rx; + + buf += s->buf_len_rx; + dma += s->buf_len_rx; + } + + INIT_WORK(&s->work_rx, work_fn_rx); + setup_timer(&s->rx_timer, rx_timer_fn, (unsigned long)s); + + sci_submit_rx(s); + } +} + +static void sci_free_dma(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + + if (s->chan_tx) + sci_tx_dma_release(s, false); + if (s->chan_rx) + sci_rx_dma_release(s, false); +} +#else +static inline void sci_request_dma(struct uart_port *port) +{ +} + +static inline void sci_free_dma(struct uart_port *port) +{ +} +#endif + static irqreturn_t sci_rx_interrupt(int irq, void *ptr) { #ifdef CONFIG_SERIAL_SH_SCI_DMA @@ -1028,18 +1527,6 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr) return IRQ_HANDLED; } -static inline unsigned long port_rx_irq_mask(struct uart_port *port) -{ - /* - * Not all ports (such as SCIFA) will support REIE. Rather than - * special-casing the port type, we check the port initialization - * IRQ enable mask to see whether the IRQ is desired at all. If - * it's unset, it's logically inferred that there's no point in - * testing for it. - */ - return SCSCR_RIE | (to_sci_port(port)->cfg->scscr & SCSCR_REIE); -} - static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) { unsigned short ssr_status, scr_status, err_enabled, orer_status = 0; @@ -1270,366 +1757,6 @@ static unsigned int sci_get_mctrl(struct uart_port *port) return TIOCM_DSR | TIOCM_CAR; } -#ifdef CONFIG_SERIAL_SH_SCI_DMA -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; - unsigned long flags; - - dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); - - spin_lock_irqsave(&port->lock, flags); - - xmit->tail += s->tx_dma_len; - xmit->tail &= UART_XMIT_SIZE - 1; - - port->icount.tx += s->tx_dma_len; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (!uart_circ_empty(xmit)) { - s->cookie_tx = 0; - schedule_work(&s->work_tx); - } else { - s->cookie_tx = -EINVAL; - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - u16 ctrl = serial_port_in(port, SCSCR); - serial_port_out(port, SCSCR, ctrl & ~SCSCR_TIE); - } - } - - spin_unlock_irqrestore(&port->lock, flags); -} - -/* Locking: called with port lock held */ -static int sci_dma_rx_push(struct sci_port *s, void *buf, size_t count) -{ - struct uart_port *port = &s->port; - struct tty_port *tport = &port->state->port; - int copied; - - copied = tty_insert_flip_string(tport, buf, count); - if (copied < count) { - dev_warn(port->dev, "Rx overrun: dropping %zu bytes\n", - count - copied); - port->icount.buf_overrun++; - } - - port->icount.rx += copied; - - return copied; -} - -static int sci_dma_rx_find_active(struct sci_port *s) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(s->cookie_rx); i++) - if (s->active_rx == s->cookie_rx[i]) - return i; - - dev_err(s->port.dev, "%s: Rx cookie %d not found!\n", __func__, - s->active_rx); - return -1; -} - -static void sci_dma_rx_complete(void *arg) -{ - struct sci_port *s = arg; - struct uart_port *port = &s->port; - unsigned long flags; - int active, count = 0; - - dev_dbg(port->dev, "%s(%d) active cookie %d\n", __func__, port->line, - s->active_rx); - - spin_lock_irqsave(&port->lock, 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); - - mod_timer(&s->rx_timer, jiffies + s->rx_timeout); - - spin_unlock_irqrestore(&port->lock, flags); - - if (count) - tty_flip_buffer_push(&port->state->port); - - schedule_work(&s->work_rx); -} - -static void sci_rx_dma_release(struct sci_port *s, bool enable_pio) -{ - struct dma_chan *chan = s->chan_rx; - struct uart_port *port = &s->port; - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - s->chan_rx = NULL; - s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL; - spin_unlock_irqrestore(&port->lock, flags); - dmaengine_terminate_all(chan); - dma_free_coherent(chan->device->dev, s->buf_len_rx * 2, s->rx_buf[0], - sg_dma_address(&s->sg_rx[0])); - dma_release_channel(chan); - if (enable_pio) - sci_start_rx(port); -} - -static void sci_tx_dma_release(struct sci_port *s, bool enable_pio) -{ - struct dma_chan *chan = s->chan_tx; - struct uart_port *port = &s->port; - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - s->chan_tx = NULL; - s->cookie_tx = -EINVAL; - spin_unlock_irqrestore(&port->lock, flags); - dmaengine_terminate_all(chan); - dma_unmap_single(chan->device->dev, s->tx_dma_addr, UART_XMIT_SIZE, - DMA_TO_DEVICE); - dma_release_channel(chan); - if (enable_pio) - sci_start_tx(port); -} - -static void sci_submit_rx(struct sci_port *s) -{ - struct dma_chan *chan = s->chan_rx; - int i; - - for (i = 0; i < 2; i++) { - struct scatterlist *sg = &s->sg_rx[i]; - struct dma_async_tx_descriptor *desc; - - desc = dmaengine_prep_slave_sg(chan, - sg, 1, DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) - goto fail; - - desc->callback = sci_dma_rx_complete; - desc->callback_param = s; - s->cookie_rx[i] = dmaengine_submit(desc); - if (dma_submit_error(s->cookie_rx[i])) - goto fail; - - dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__, - s->cookie_rx[i], i); - } - - s->active_rx = s->cookie_rx[0]; - - dma_async_issue_pending(chan); - return; - -fail: - if (i) - dmaengine_terminate_all(chan); - for (i = 0; i < 2; i++) - s->cookie_rx[i] = -EINVAL; - s->active_rx = -EINVAL; - dev_warn(s->port.dev, "Failed to re-start Rx DMA, using PIO\n"); - sci_rx_dma_release(s, true); -} - -static void work_fn_rx(struct work_struct *work) -{ - struct sci_port *s = container_of(work, struct sci_port, work_rx); - struct uart_port *port = &s->port; - struct dma_async_tx_descriptor *desc; - struct dma_tx_state state; - enum dma_status status; - unsigned long flags; - int new; - - spin_lock_irqsave(&port->lock, flags); - new = sci_dma_rx_find_active(s); - if (new < 0) { - spin_unlock_irqrestore(&port->lock, flags); - return; - } - - status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state); - if (status != DMA_COMPLETE) { - /* Handle incomplete DMA receive */ - struct dma_chan *chan = s->chan_rx; - unsigned int read; - int count; - - dmaengine_terminate_all(chan); - read = sg_dma_len(&s->sg_rx[new]) - state.residue; - dev_dbg(port->dev, "Read %u bytes with cookie %d\n", read, - s->active_rx); - - if (read) { - count = sci_dma_rx_push(s, s->rx_buf[new], read); - if (count) - tty_flip_buffer_push(&port->state->port); - } - - spin_unlock_irqrestore(&port->lock, flags); - - sci_submit_rx(s); - return; - } - - desc = dmaengine_prep_slave_sg(s->chan_rx, &s->sg_rx[new], 1, - DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) - goto fail; - - desc->callback = sci_dma_rx_complete; - desc->callback_param = s; - s->cookie_rx[new] = dmaengine_submit(desc); - if (dma_submit_error(s->cookie_rx[new])) - goto fail; - - s->active_rx = s->cookie_rx[!new]; - - dev_dbg(port->dev, "%s: cookie %d #%d, new active cookie %d\n", - __func__, s->cookie_rx[new], new, s->active_rx); - spin_unlock_irqrestore(&port->lock, flags); - return; - -fail: - spin_unlock_irqrestore(&port->lock, flags); - dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n"); - sci_rx_dma_release(s, true); -} - -static void work_fn_tx(struct work_struct *work) -{ - struct sci_port *s = container_of(work, struct sci_port, work_tx); - 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; - dma_addr_t buf; - - /* - * DMA is idle now. - * Port xmit buffer is already mapped, and it is one page... Just adjust - * offsets and lengths. Since it is a circular buffer, we have to - * transmit till the end, and then the rest. Take the port lock to get a - * consistent xmit buffer state. - */ - spin_lock_irq(&port->lock); - buf = s->tx_dma_addr + (xmit->tail & (UART_XMIT_SIZE - 1)); - s->tx_dma_len = min_t(unsigned int, - CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE), - CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE)); - spin_unlock_irq(&port->lock); - - desc = dmaengine_prep_slave_single(chan, buf, s->tx_dma_len, - DMA_MEM_TO_DEV, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - dev_warn(port->dev, "Failed preparing Tx DMA descriptor\n"); - /* switch to PIO */ - sci_tx_dma_release(s, true); - return; - } - - dma_sync_single_for_device(chan->device->dev, buf, s->tx_dma_len, - DMA_TO_DEVICE); - - spin_lock_irq(&port->lock); - desc->callback = sci_dma_tx_complete; - desc->callback_param = s; - spin_unlock_irq(&port->lock); - s->cookie_tx = dmaengine_submit(desc); - if (dma_submit_error(s->cookie_tx)) { - dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n"); - /* switch to PIO */ - sci_tx_dma_release(s, true); - return; - } - - dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", - __func__, xmit->buf, xmit->tail, xmit->head, s->cookie_tx); - - dma_async_issue_pending(chan); -} -#endif - -static void sci_start_tx(struct uart_port *port) -{ - struct sci_port *s = to_sci_port(port); - unsigned short ctrl; - -#ifdef CONFIG_SERIAL_SH_SCI_DMA - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - u16 new, scr = serial_port_in(port, SCSCR); - if (s->chan_tx) - new = scr | SCSCR_TDRQE; - else - new = scr & ~SCSCR_TDRQE; - if (new != scr) - serial_port_out(port, SCSCR, new); - } - - if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) && - dma_submit_error(s->cookie_tx)) { - s->cookie_tx = 0; - schedule_work(&s->work_tx); - } -#endif - - if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */ - ctrl = serial_port_in(port, SCSCR); - serial_port_out(port, SCSCR, ctrl | SCSCR_TIE); - } -} - -static void sci_stop_tx(struct uart_port *port) -{ - unsigned short ctrl; - - /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ - ctrl = serial_port_in(port, SCSCR); - - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - ctrl &= ~SCSCR_TDRQE; - - ctrl &= ~SCSCR_TIE; - - serial_port_out(port, SCSCR, ctrl); -} - -static void sci_start_rx(struct uart_port *port) -{ - unsigned short ctrl; - - ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port); - - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - ctrl &= ~SCSCR_RDRQE; - - serial_port_out(port, SCSCR, ctrl); -} - -static void sci_stop_rx(struct uart_port *port) -{ - unsigned short ctrl; - - ctrl = serial_port_in(port, SCSCR); - - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - ctrl &= ~SCSCR_RDRQE; - - ctrl &= ~port_rx_irq_mask(port); - - serial_port_out(port, SCSCR, ctrl); -} - static void sci_break_ctl(struct uart_port *port, int break_state) { struct sci_port *s = to_sci_port(port); @@ -1660,140 +1787,6 @@ static void sci_break_ctl(struct uart_port *port, int break_state) serial_port_out(port, SCSCR, scscr); } -#ifdef CONFIG_SERIAL_SH_SCI_DMA -static bool filter(struct dma_chan *chan, void *slave) -{ - struct sh_dmae_slave *param = slave; - - dev_dbg(chan->device->dev, "%s: slave ID %d\n", - __func__, param->shdma_slave.slave_id); - - chan->private = ¶m->shdma_slave; - return true; -} - -static void rx_timer_fn(unsigned long arg) -{ - struct sci_port *s = (struct sci_port *)arg; - struct uart_port *port = &s->port; - u16 scr = serial_port_in(port, SCSCR); - - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - scr &= ~SCSCR_RDRQE; - enable_irq(s->irqs[SCIx_RXI_IRQ]); - } - serial_port_out(port, SCSCR, scr | SCSCR_RIE); - dev_dbg(port->dev, "DMA Rx timed out\n"); - schedule_work(&s->work_rx); -} - -static void sci_request_dma(struct uart_port *port) -{ - struct sci_port *s = to_sci_port(port); - struct sh_dmae_slave *param; - struct dma_chan *chan; - dma_cap_mask_t mask; - - dev_dbg(port->dev, "%s: port %d\n", __func__, port->line); - - if (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0) - return; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - param = &s->param_tx; - - /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */ - param->shdma_slave.slave_id = s->cfg->dma_slave_tx; - - s->cookie_tx = -EINVAL; - chan = dma_request_channel(mask, filter, param); - dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan); - if (chan) { - s->chan_tx = chan; - /* UART circular tx buffer is an aligned page. */ - s->tx_dma_addr = dma_map_single(chan->device->dev, - port->state->xmit.buf, - UART_XMIT_SIZE, - DMA_TO_DEVICE); - if (dma_mapping_error(chan->device->dev, s->tx_dma_addr)) { - dev_warn(port->dev, "Failed mapping Tx DMA descriptor\n"); - dma_release_channel(chan); - s->chan_tx = NULL; - } else { - dev_dbg(port->dev, "%s: mapped %lu@%p to %pad\n", - __func__, UART_XMIT_SIZE, - port->state->xmit.buf, &s->tx_dma_addr); - } - - INIT_WORK(&s->work_tx, work_fn_tx); - } - - param = &s->param_rx; - - /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */ - param->shdma_slave.slave_id = s->cfg->dma_slave_rx; - - chan = dma_request_channel(mask, filter, param); - dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan); - if (chan) { - unsigned int i; - dma_addr_t dma; - void *buf; - - s->chan_rx = chan; - - s->buf_len_rx = 2 * max_t(size_t, 16, port->fifosize); - buf = dma_alloc_coherent(chan->device->dev, s->buf_len_rx * 2, - &dma, GFP_KERNEL); - if (!buf) { - dev_warn(port->dev, - "Failed to allocate Rx dma buffer, using PIO\n"); - dma_release_channel(chan); - s->chan_rx = NULL; - sci_start_rx(port); - return; - } - - for (i = 0; i < 2; i++) { - struct scatterlist *sg = &s->sg_rx[i]; - - sg_init_table(sg, 1); - s->rx_buf[i] = buf; - sg_dma_address(sg) = dma; - sg->length = s->buf_len_rx; - - buf += s->buf_len_rx; - dma += s->buf_len_rx; - } - - INIT_WORK(&s->work_rx, work_fn_rx); - setup_timer(&s->rx_timer, rx_timer_fn, (unsigned long)s); - - sci_submit_rx(s); - } -} - -static void sci_free_dma(struct uart_port *port) -{ - struct sci_port *s = to_sci_port(port); - - if (s->chan_tx) - sci_tx_dma_release(s, false); - if (s->chan_rx) - sci_rx_dma_release(s, false); -} -#else -static inline void sci_request_dma(struct uart_port *port) -{ -} - -static inline void sci_free_dma(struct uart_port *port) -{ -} -#endif - static int sci_startup(struct uart_port *port) { struct sci_port *s = to_sci_port(port);