Skip to content

Commit 2c4ee23

Browse files
geertugregkh
authored andcommitted
serial: sh-sci: Postpone DMA release when falling back to PIO
When the sh-sci driver detects an issue with DMA during operation, it falls backs to PIO, and releases all DMA resources. As releasing DMA resources immediately has no advantages, but complicates the code, and is susceptible to races, it is better to postpone this to port shutdown. This allows to remove the locking from sci_rx_dma_release() and sci_tx_dma_release(), but requires keeping a copy of the DMA channel pointers for release during port shutdown. Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent c5a9262 commit 2c4ee23

File tree

1 file changed

+41
-42
lines changed

1 file changed

+41
-42
lines changed

drivers/tty/serial/sh-sci.c

Lines changed: 41 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ struct sci_port {
135135
struct dma_chan *chan_rx;
136136

137137
#ifdef CONFIG_SERIAL_SH_SCI_DMA
138+
struct dma_chan *chan_tx_saved;
139+
struct dma_chan *chan_rx_saved;
138140
dma_cookie_t cookie_tx;
139141
dma_cookie_t cookie_rx[2];
140142
dma_cookie_t active_rx;
@@ -1212,25 +1214,16 @@ static int sci_dma_rx_find_active(struct sci_port *s)
12121214
return -1;
12131215
}
12141216

1215-
static void sci_rx_dma_release(struct sci_port *s, bool enable_pio)
1217+
static void sci_rx_dma_release(struct sci_port *s)
12161218
{
1217-
struct dma_chan *chan = s->chan_rx;
1218-
struct uart_port *port = &s->port;
1219-
unsigned long flags;
1219+
struct dma_chan *chan = s->chan_rx_saved;
12201220

1221-
spin_lock_irqsave(&port->lock, flags);
1222-
s->chan_rx = NULL;
1221+
s->chan_rx_saved = s->chan_rx = NULL;
12231222
s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL;
1224-
spin_unlock_irqrestore(&port->lock, flags);
12251223
dmaengine_terminate_all(chan);
12261224
dma_free_coherent(chan->device->dev, s->buf_len_rx * 2, s->rx_buf[0],
12271225
sg_dma_address(&s->sg_rx[0]));
12281226
dma_release_channel(chan);
1229-
if (enable_pio) {
1230-
spin_lock_irqsave(&port->lock, flags);
1231-
sci_start_rx(port);
1232-
spin_unlock_irqrestore(&port->lock, flags);
1233-
}
12341227
}
12351228

12361229
static void start_hrtimer_us(struct hrtimer *hrt, unsigned long usec)
@@ -1289,33 +1282,30 @@ static void sci_dma_rx_complete(void *arg)
12891282
fail:
12901283
spin_unlock_irqrestore(&port->lock, flags);
12911284
dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
1292-
sci_rx_dma_release(s, true);
1285+
/* Switch to PIO */
1286+
spin_lock_irqsave(&port->lock, flags);
1287+
s->chan_rx = NULL;
1288+
sci_start_rx(port);
1289+
spin_unlock_irqrestore(&port->lock, flags);
12931290
}
12941291

1295-
static void sci_tx_dma_release(struct sci_port *s, bool enable_pio)
1292+
static void sci_tx_dma_release(struct sci_port *s)
12961293
{
1297-
struct dma_chan *chan = s->chan_tx;
1298-
struct uart_port *port = &s->port;
1299-
unsigned long flags;
1294+
struct dma_chan *chan = s->chan_tx_saved;
13001295

1301-
spin_lock_irqsave(&port->lock, flags);
1302-
s->chan_tx = NULL;
1296+
s->chan_tx_saved = s->chan_tx = NULL;
13031297
s->cookie_tx = -EINVAL;
1304-
spin_unlock_irqrestore(&port->lock, flags);
13051298
dmaengine_terminate_all(chan);
13061299
dma_unmap_single(chan->device->dev, s->tx_dma_addr, UART_XMIT_SIZE,
13071300
DMA_TO_DEVICE);
13081301
dma_release_channel(chan);
1309-
if (enable_pio) {
1310-
spin_lock_irqsave(&port->lock, flags);
1311-
sci_start_tx(port);
1312-
spin_unlock_irqrestore(&port->lock, flags);
1313-
}
13141302
}
13151303

13161304
static void sci_submit_rx(struct sci_port *s)
13171305
{
13181306
struct dma_chan *chan = s->chan_rx;
1307+
struct uart_port *port = &s->port;
1308+
unsigned long flags;
13191309
int i;
13201310

13211311
for (i = 0; i < 2; i++) {
@@ -1347,7 +1337,11 @@ static void sci_submit_rx(struct sci_port *s)
13471337
for (i = 0; i < 2; i++)
13481338
s->cookie_rx[i] = -EINVAL;
13491339
s->active_rx = -EINVAL;
1350-
sci_rx_dma_release(s, true);
1340+
/* Switch to PIO */
1341+
spin_lock_irqsave(&port->lock, flags);
1342+
s->chan_rx = NULL;
1343+
sci_start_rx(port);
1344+
spin_unlock_irqrestore(&port->lock, flags);
13511345
}
13521346

13531347
static void work_fn_tx(struct work_struct *work)
@@ -1357,6 +1351,7 @@ static void work_fn_tx(struct work_struct *work)
13571351
struct dma_chan *chan = s->chan_tx;
13581352
struct uart_port *port = &s->port;
13591353
struct circ_buf *xmit = &port->state->xmit;
1354+
unsigned long flags;
13601355
dma_addr_t buf;
13611356

13621357
/*
@@ -1378,9 +1373,7 @@ static void work_fn_tx(struct work_struct *work)
13781373
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
13791374
if (!desc) {
13801375
dev_warn(port->dev, "Failed preparing Tx DMA descriptor\n");
1381-
/* switch to PIO */
1382-
sci_tx_dma_release(s, true);
1383-
return;
1376+
goto switch_to_pio;
13841377
}
13851378

13861379
dma_sync_single_for_device(chan->device->dev, buf, s->tx_dma_len,
@@ -1393,15 +1386,21 @@ static void work_fn_tx(struct work_struct *work)
13931386
s->cookie_tx = dmaengine_submit(desc);
13941387
if (dma_submit_error(s->cookie_tx)) {
13951388
dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n");
1396-
/* switch to PIO */
1397-
sci_tx_dma_release(s, true);
1398-
return;
1389+
goto switch_to_pio;
13991390
}
14001391

14011392
dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n",
14021393
__func__, xmit->buf, xmit->tail, xmit->head, s->cookie_tx);
14031394

14041395
dma_async_issue_pending(chan);
1396+
return;
1397+
1398+
switch_to_pio:
1399+
spin_lock_irqsave(&port->lock, flags);
1400+
s->chan_tx = NULL;
1401+
sci_start_tx(port);
1402+
spin_unlock_irqrestore(&port->lock, flags);
1403+
return;
14051404
}
14061405

14071406
static enum hrtimer_restart rx_timer_fn(struct hrtimer *t)
@@ -1535,7 +1534,6 @@ static void sci_request_dma(struct uart_port *port)
15351534
chan = sci_request_dma_chan(port, DMA_MEM_TO_DEV);
15361535
dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan);
15371536
if (chan) {
1538-
s->chan_tx = chan;
15391537
/* UART circular tx buffer is an aligned page. */
15401538
s->tx_dma_addr = dma_map_single(chan->device->dev,
15411539
port->state->xmit.buf,
@@ -1544,11 +1542,13 @@ static void sci_request_dma(struct uart_port *port)
15441542
if (dma_mapping_error(chan->device->dev, s->tx_dma_addr)) {
15451543
dev_warn(port->dev, "Failed mapping Tx DMA descriptor\n");
15461544
dma_release_channel(chan);
1547-
s->chan_tx = NULL;
1545+
chan = NULL;
15481546
} else {
15491547
dev_dbg(port->dev, "%s: mapped %lu@%p to %pad\n",
15501548
__func__, UART_XMIT_SIZE,
15511549
port->state->xmit.buf, &s->tx_dma_addr);
1550+
1551+
s->chan_tx_saved = s->chan_tx = chan;
15521552
}
15531553

15541554
INIT_WORK(&s->work_tx, work_fn_tx);
@@ -1561,16 +1561,13 @@ static void sci_request_dma(struct uart_port *port)
15611561
dma_addr_t dma;
15621562
void *buf;
15631563

1564-
s->chan_rx = chan;
1565-
15661564
s->buf_len_rx = 2 * max_t(size_t, 16, port->fifosize);
15671565
buf = dma_alloc_coherent(chan->device->dev, s->buf_len_rx * 2,
15681566
&dma, GFP_KERNEL);
15691567
if (!buf) {
15701568
dev_warn(port->dev,
15711569
"Failed to allocate Rx dma buffer, using PIO\n");
15721570
dma_release_channel(chan);
1573-
s->chan_rx = NULL;
15741571
return;
15751572
}
15761573

@@ -1591,17 +1588,19 @@ static void sci_request_dma(struct uart_port *port)
15911588

15921589
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
15931590
sci_submit_rx(s);
1591+
1592+
s->chan_rx_saved = s->chan_rx = chan;
15941593
}
15951594
}
15961595

15971596
static void sci_free_dma(struct uart_port *port)
15981597
{
15991598
struct sci_port *s = to_sci_port(port);
16001599

1601-
if (s->chan_tx)
1602-
sci_tx_dma_release(s, false);
1603-
if (s->chan_rx)
1604-
sci_rx_dma_release(s, false);
1600+
if (s->chan_tx_saved)
1601+
sci_tx_dma_release(s);
1602+
if (s->chan_rx_saved)
1603+
sci_rx_dma_release(s);
16051604
}
16061605

16071606
static void sci_flush_buffer(struct uart_port *port)
@@ -2092,7 +2091,7 @@ static void sci_shutdown(struct uart_port *port)
20922091
spin_unlock_irqrestore(&port->lock, flags);
20932092

20942093
#ifdef CONFIG_SERIAL_SH_SCI_DMA
2095-
if (s->chan_rx) {
2094+
if (s->chan_rx_saved) {
20962095
dev_dbg(port->dev, "%s(%d) deleting rx_timer\n", __func__,
20972096
port->line);
20982097
hrtimer_cancel(&s->rx_timer);

0 commit comments

Comments
 (0)