tty: msm_serial: use dmaengine_prep_slave_sg()
This is a preparatory for the serial-to-kfifo switch. kfifo understands only scatter-gatter approach, so switch to that. No functional change intended, it's just dmaengine_prep_slave_single() inline expanded. And in this case, switch from dma_map_single() to dma_map_sg() too. This needs struct msm_dma changes. I split the rx and tx parts into an union. TX is now struct scatterlist, RX remains the old good phys-virt-count triple. Signed-off-by: Jiri Slaby (SUSE) <jirislaby@kernel.org> Cc: Bjorn Andersson <andersson@kernel.org> Cc: Konrad Dybcio <konrad.dybcio@linaro.org> Cc: linux-arm-msm@vger.kernel.org Link: https://lore.kernel.org/r/20240405060826.2521-12-jirislaby@kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
9054605ab8
commit
f8fef2fa41
@ -161,11 +161,16 @@ enum {
|
|||||||
struct msm_dma {
|
struct msm_dma {
|
||||||
struct dma_chan *chan;
|
struct dma_chan *chan;
|
||||||
enum dma_data_direction dir;
|
enum dma_data_direction dir;
|
||||||
dma_addr_t phys;
|
union {
|
||||||
unsigned char *virt;
|
struct {
|
||||||
|
dma_addr_t phys;
|
||||||
|
unsigned char *virt;
|
||||||
|
unsigned int count;
|
||||||
|
} rx;
|
||||||
|
struct scatterlist tx_sg;
|
||||||
|
};
|
||||||
dma_cookie_t cookie;
|
dma_cookie_t cookie;
|
||||||
u32 enable_bit;
|
u32 enable_bit;
|
||||||
unsigned int count;
|
|
||||||
struct dma_async_tx_descriptor *desc;
|
struct dma_async_tx_descriptor *desc;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -249,8 +254,12 @@ static void msm_stop_dma(struct uart_port *port, struct msm_dma *dma)
|
|||||||
unsigned int mapped;
|
unsigned int mapped;
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
mapped = dma->count;
|
if (dma->dir == DMA_TO_DEVICE) {
|
||||||
dma->count = 0;
|
mapped = sg_dma_len(&dma->tx_sg);
|
||||||
|
} else {
|
||||||
|
mapped = dma->rx.count;
|
||||||
|
dma->rx.count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
dmaengine_terminate_all(dma->chan);
|
dmaengine_terminate_all(dma->chan);
|
||||||
|
|
||||||
@ -265,8 +274,13 @@ static void msm_stop_dma(struct uart_port *port, struct msm_dma *dma)
|
|||||||
val &= ~dma->enable_bit;
|
val &= ~dma->enable_bit;
|
||||||
msm_write(port, val, UARTDM_DMEN);
|
msm_write(port, val, UARTDM_DMEN);
|
||||||
|
|
||||||
if (mapped)
|
if (mapped) {
|
||||||
dma_unmap_single(dev, dma->phys, mapped, dma->dir);
|
if (dma->dir == DMA_TO_DEVICE) {
|
||||||
|
dma_unmap_sg(dev, &dma->tx_sg, 1, dma->dir);
|
||||||
|
sg_init_table(&dma->tx_sg, 1);
|
||||||
|
} else
|
||||||
|
dma_unmap_single(dev, dma->rx.phys, mapped, dma->dir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void msm_release_dma(struct msm_port *msm_port)
|
static void msm_release_dma(struct msm_port *msm_port)
|
||||||
@ -285,7 +299,7 @@ static void msm_release_dma(struct msm_port *msm_port)
|
|||||||
if (dma->chan) {
|
if (dma->chan) {
|
||||||
msm_stop_dma(&msm_port->uart, dma);
|
msm_stop_dma(&msm_port->uart, dma);
|
||||||
dma_release_channel(dma->chan);
|
dma_release_channel(dma->chan);
|
||||||
kfree(dma->virt);
|
kfree(dma->rx.virt);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(dma, 0, sizeof(*dma));
|
memset(dma, 0, sizeof(*dma));
|
||||||
@ -357,8 +371,8 @@ static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base)
|
|||||||
|
|
||||||
of_property_read_u32(dev->of_node, "qcom,rx-crci", &crci);
|
of_property_read_u32(dev->of_node, "qcom,rx-crci", &crci);
|
||||||
|
|
||||||
dma->virt = kzalloc(UARTDM_RX_SIZE, GFP_KERNEL);
|
dma->rx.virt = kzalloc(UARTDM_RX_SIZE, GFP_KERNEL);
|
||||||
if (!dma->virt)
|
if (!dma->rx.virt)
|
||||||
goto rel_rx;
|
goto rel_rx;
|
||||||
|
|
||||||
memset(&conf, 0, sizeof(conf));
|
memset(&conf, 0, sizeof(conf));
|
||||||
@ -385,7 +399,7 @@ static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base)
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
err:
|
err:
|
||||||
kfree(dma->virt);
|
kfree(dma->rx.virt);
|
||||||
rel_rx:
|
rel_rx:
|
||||||
dma_release_channel(dma->chan);
|
dma_release_channel(dma->chan);
|
||||||
no_rx:
|
no_rx:
|
||||||
@ -420,7 +434,7 @@ static void msm_start_tx(struct uart_port *port)
|
|||||||
struct msm_dma *dma = &msm_port->tx_dma;
|
struct msm_dma *dma = &msm_port->tx_dma;
|
||||||
|
|
||||||
/* Already started in DMA mode */
|
/* Already started in DMA mode */
|
||||||
if (dma->count)
|
if (sg_dma_len(&dma->tx_sg))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
msm_port->imr |= MSM_UART_IMR_TXLEV;
|
msm_port->imr |= MSM_UART_IMR_TXLEV;
|
||||||
@ -448,12 +462,12 @@ static void msm_complete_tx_dma(void *args)
|
|||||||
uart_port_lock_irqsave(port, &flags);
|
uart_port_lock_irqsave(port, &flags);
|
||||||
|
|
||||||
/* Already stopped */
|
/* Already stopped */
|
||||||
if (!dma->count)
|
if (!sg_dma_len(&dma->tx_sg))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
dmaengine_tx_status(dma->chan, dma->cookie, &state);
|
dmaengine_tx_status(dma->chan, dma->cookie, &state);
|
||||||
|
|
||||||
dma_unmap_single(port->dev, dma->phys, dma->count, dma->dir);
|
dma_unmap_sg(port->dev, &dma->tx_sg, 1, dma->dir);
|
||||||
|
|
||||||
val = msm_read(port, UARTDM_DMEN);
|
val = msm_read(port, UARTDM_DMEN);
|
||||||
val &= ~dma->enable_bit;
|
val &= ~dma->enable_bit;
|
||||||
@ -464,9 +478,9 @@ static void msm_complete_tx_dma(void *args)
|
|||||||
msm_write(port, MSM_UART_CR_TX_ENABLE, MSM_UART_CR);
|
msm_write(port, MSM_UART_CR_TX_ENABLE, MSM_UART_CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
count = dma->count - state.residue;
|
count = sg_dma_len(&dma->tx_sg) - state.residue;
|
||||||
uart_xmit_advance(port, count);
|
uart_xmit_advance(port, count);
|
||||||
dma->count = 0;
|
sg_init_table(&dma->tx_sg, 1);
|
||||||
|
|
||||||
/* Restore "Tx FIFO below watermark" interrupt */
|
/* Restore "Tx FIFO below watermark" interrupt */
|
||||||
msm_port->imr |= MSM_UART_IMR_TXLEV;
|
msm_port->imr |= MSM_UART_IMR_TXLEV;
|
||||||
@ -485,19 +499,18 @@ static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count)
|
|||||||
struct circ_buf *xmit = &msm_port->uart.state->xmit;
|
struct circ_buf *xmit = &msm_port->uart.state->xmit;
|
||||||
struct uart_port *port = &msm_port->uart;
|
struct uart_port *port = &msm_port->uart;
|
||||||
struct msm_dma *dma = &msm_port->tx_dma;
|
struct msm_dma *dma = &msm_port->tx_dma;
|
||||||
void *cpu_addr;
|
|
||||||
int ret;
|
int ret;
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
cpu_addr = &xmit->buf[xmit->tail];
|
sg_init_table(&dma->tx_sg, 1);
|
||||||
|
sg_set_buf(&dma->tx_sg, &xmit->buf[xmit->tail], count);
|
||||||
|
|
||||||
dma->phys = dma_map_single(port->dev, cpu_addr, count, dma->dir);
|
ret = dma_map_sg(port->dev, &dma->tx_sg, 1, dma->dir);
|
||||||
ret = dma_mapping_error(port->dev, dma->phys);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
dma->desc = dmaengine_prep_slave_single(dma->chan, dma->phys,
|
dma->desc = dmaengine_prep_slave_sg(dma->chan, &dma->tx_sg, 1,
|
||||||
count, DMA_MEM_TO_DEV,
|
DMA_MEM_TO_DEV,
|
||||||
DMA_PREP_INTERRUPT |
|
DMA_PREP_INTERRUPT |
|
||||||
DMA_PREP_FENCE);
|
DMA_PREP_FENCE);
|
||||||
if (!dma->desc) {
|
if (!dma->desc) {
|
||||||
@ -520,8 +533,6 @@ static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count)
|
|||||||
msm_port->imr &= ~MSM_UART_IMR_TXLEV;
|
msm_port->imr &= ~MSM_UART_IMR_TXLEV;
|
||||||
msm_write(port, msm_port->imr, MSM_UART_IMR);
|
msm_write(port, msm_port->imr, MSM_UART_IMR);
|
||||||
|
|
||||||
dma->count = count;
|
|
||||||
|
|
||||||
val = msm_read(port, UARTDM_DMEN);
|
val = msm_read(port, UARTDM_DMEN);
|
||||||
val |= dma->enable_bit;
|
val |= dma->enable_bit;
|
||||||
|
|
||||||
@ -536,7 +547,8 @@ static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count)
|
|||||||
dma_async_issue_pending(dma->chan);
|
dma_async_issue_pending(dma->chan);
|
||||||
return 0;
|
return 0;
|
||||||
unmap:
|
unmap:
|
||||||
dma_unmap_single(port->dev, dma->phys, count, dma->dir);
|
dma_unmap_sg(port->dev, &dma->tx_sg, 1, dma->dir);
|
||||||
|
sg_init_table(&dma->tx_sg, 1);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -553,7 +565,7 @@ static void msm_complete_rx_dma(void *args)
|
|||||||
uart_port_lock_irqsave(port, &flags);
|
uart_port_lock_irqsave(port, &flags);
|
||||||
|
|
||||||
/* Already stopped */
|
/* Already stopped */
|
||||||
if (!dma->count)
|
if (!dma->rx.count)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
val = msm_read(port, UARTDM_DMEN);
|
val = msm_read(port, UARTDM_DMEN);
|
||||||
@ -570,14 +582,14 @@ static void msm_complete_rx_dma(void *args)
|
|||||||
|
|
||||||
port->icount.rx += count;
|
port->icount.rx += count;
|
||||||
|
|
||||||
dma->count = 0;
|
dma->rx.count = 0;
|
||||||
|
|
||||||
dma_unmap_single(port->dev, dma->phys, UARTDM_RX_SIZE, dma->dir);
|
dma_unmap_single(port->dev, dma->rx.phys, UARTDM_RX_SIZE, dma->dir);
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
char flag = TTY_NORMAL;
|
char flag = TTY_NORMAL;
|
||||||
|
|
||||||
if (msm_port->break_detected && dma->virt[i] == 0) {
|
if (msm_port->break_detected && dma->rx.virt[i] == 0) {
|
||||||
port->icount.brk++;
|
port->icount.brk++;
|
||||||
flag = TTY_BREAK;
|
flag = TTY_BREAK;
|
||||||
msm_port->break_detected = false;
|
msm_port->break_detected = false;
|
||||||
@ -588,9 +600,9 @@ static void msm_complete_rx_dma(void *args)
|
|||||||
if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK))
|
if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK))
|
||||||
flag = TTY_NORMAL;
|
flag = TTY_NORMAL;
|
||||||
|
|
||||||
sysrq = uart_prepare_sysrq_char(port, dma->virt[i]);
|
sysrq = uart_prepare_sysrq_char(port, dma->rx.virt[i]);
|
||||||
if (!sysrq)
|
if (!sysrq)
|
||||||
tty_insert_flip_char(tport, dma->virt[i], flag);
|
tty_insert_flip_char(tport, dma->rx.virt[i], flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
msm_start_rx_dma(msm_port);
|
msm_start_rx_dma(msm_port);
|
||||||
@ -614,13 +626,13 @@ static void msm_start_rx_dma(struct msm_port *msm_port)
|
|||||||
if (!dma->chan)
|
if (!dma->chan)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dma->phys = dma_map_single(uart->dev, dma->virt,
|
dma->rx.phys = dma_map_single(uart->dev, dma->rx.virt,
|
||||||
UARTDM_RX_SIZE, dma->dir);
|
UARTDM_RX_SIZE, dma->dir);
|
||||||
ret = dma_mapping_error(uart->dev, dma->phys);
|
ret = dma_mapping_error(uart->dev, dma->rx.phys);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto sw_mode;
|
goto sw_mode;
|
||||||
|
|
||||||
dma->desc = dmaengine_prep_slave_single(dma->chan, dma->phys,
|
dma->desc = dmaengine_prep_slave_single(dma->chan, dma->rx.phys,
|
||||||
UARTDM_RX_SIZE, DMA_DEV_TO_MEM,
|
UARTDM_RX_SIZE, DMA_DEV_TO_MEM,
|
||||||
DMA_PREP_INTERRUPT);
|
DMA_PREP_INTERRUPT);
|
||||||
if (!dma->desc)
|
if (!dma->desc)
|
||||||
@ -648,7 +660,7 @@ static void msm_start_rx_dma(struct msm_port *msm_port)
|
|||||||
|
|
||||||
msm_write(uart, msm_port->imr, MSM_UART_IMR);
|
msm_write(uart, msm_port->imr, MSM_UART_IMR);
|
||||||
|
|
||||||
dma->count = UARTDM_RX_SIZE;
|
dma->rx.count = UARTDM_RX_SIZE;
|
||||||
|
|
||||||
dma_async_issue_pending(dma->chan);
|
dma_async_issue_pending(dma->chan);
|
||||||
|
|
||||||
@ -668,7 +680,7 @@ static void msm_start_rx_dma(struct msm_port *msm_port)
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
unmap:
|
unmap:
|
||||||
dma_unmap_single(uart->dev, dma->phys, UARTDM_RX_SIZE, dma->dir);
|
dma_unmap_single(uart->dev, dma->rx.phys, UARTDM_RX_SIZE, dma->dir);
|
||||||
|
|
||||||
sw_mode:
|
sw_mode:
|
||||||
/*
|
/*
|
||||||
@ -955,7 +967,7 @@ static irqreturn_t msm_uart_irq(int irq, void *dev_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (misr & (MSM_UART_IMR_RXLEV | MSM_UART_IMR_RXSTALE)) {
|
if (misr & (MSM_UART_IMR_RXLEV | MSM_UART_IMR_RXSTALE)) {
|
||||||
if (dma->count) {
|
if (dma->rx.count) {
|
||||||
val = MSM_UART_CR_CMD_STALE_EVENT_DISABLE;
|
val = MSM_UART_CR_CMD_STALE_EVENT_DISABLE;
|
||||||
msm_write(port, val, MSM_UART_CR);
|
msm_write(port, val, MSM_UART_CR);
|
||||||
val = MSM_UART_CR_CMD_RESET_STALE_INT;
|
val = MSM_UART_CR_CMD_RESET_STALE_INT;
|
||||||
|
Loading…
Reference in New Issue
Block a user