aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/ipu/ipu_idmac.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dma/ipu/ipu_idmac.c')
-rw-r--r--drivers/dma/ipu/ipu_idmac.c96
1 files changed, 51 insertions, 45 deletions
diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c
index c2b017ad139d..b54f62de9232 100644
--- a/drivers/dma/ipu/ipu_idmac.c
+++ b/drivers/dma/ipu/ipu_idmac.c
@@ -1398,76 +1398,81 @@ static void idmac_issue_pending(struct dma_chan *chan)
1398 */ 1398 */
1399} 1399}
1400 1400
1401static int __idmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, 1401static int idmac_pause(struct dma_chan *chan)
1402 unsigned long arg)
1403{ 1402{
1404 struct idmac_channel *ichan = to_idmac_chan(chan); 1403 struct idmac_channel *ichan = to_idmac_chan(chan);
1405 struct idmac *idmac = to_idmac(chan->device); 1404 struct idmac *idmac = to_idmac(chan->device);
1406 struct ipu *ipu = to_ipu(idmac); 1405 struct ipu *ipu = to_ipu(idmac);
1407 struct list_head *list, *tmp; 1406 struct list_head *list, *tmp;
1408 unsigned long flags; 1407 unsigned long flags;
1409 int i;
1410 1408
1411 switch (cmd) { 1409 mutex_lock(&ichan->chan_mutex);
1412 case DMA_PAUSE:
1413 spin_lock_irqsave(&ipu->lock, flags);
1414 ipu_ic_disable_task(ipu, chan->chan_id);
1415 1410
1416 /* Return all descriptors into "prepared" state */ 1411 spin_lock_irqsave(&ipu->lock, flags);
1417 list_for_each_safe(list, tmp, &ichan->queue) 1412 ipu_ic_disable_task(ipu, chan->chan_id);
1418 list_del_init(list);
1419 1413
1420 ichan->sg[0] = NULL; 1414 /* Return all descriptors into "prepared" state */
1421 ichan->sg[1] = NULL; 1415 list_for_each_safe(list, tmp, &ichan->queue)
1416 list_del_init(list);
1422 1417
1423 spin_unlock_irqrestore(&ipu->lock, flags); 1418 ichan->sg[0] = NULL;
1419 ichan->sg[1] = NULL;
1424 1420
1425 ichan->status = IPU_CHANNEL_INITIALIZED; 1421 spin_unlock_irqrestore(&ipu->lock, flags);
1426 break;
1427 case DMA_TERMINATE_ALL:
1428 ipu_disable_channel(idmac, ichan,
1429 ichan->status >= IPU_CHANNEL_ENABLED);
1430 1422
1431 tasklet_disable(&ipu->tasklet); 1423 ichan->status = IPU_CHANNEL_INITIALIZED;
1432 1424
1433 /* ichan->queue is modified in ISR, have to spinlock */ 1425 mutex_unlock(&ichan->chan_mutex);
1434 spin_lock_irqsave(&ichan->lock, flags);
1435 list_splice_init(&ichan->queue, &ichan->free_list);
1436 1426
1437 if (ichan->desc) 1427 return 0;
1438 for (i = 0; i < ichan->n_tx_desc; i++) { 1428}
1439 struct idmac_tx_desc *desc = ichan->desc + i;
1440 if (list_empty(&desc->list))
1441 /* Descriptor was prepared, but not submitted */
1442 list_add(&desc->list, &ichan->free_list);
1443 1429
1444 async_tx_clear_ack(&desc->txd); 1430static int __idmac_terminate_all(struct dma_chan *chan)
1445 } 1431{
1432 struct idmac_channel *ichan = to_idmac_chan(chan);
1433 struct idmac *idmac = to_idmac(chan->device);
1434 struct ipu *ipu = to_ipu(idmac);
1435 unsigned long flags;
1436 int i;
1446 1437
1447 ichan->sg[0] = NULL; 1438 ipu_disable_channel(idmac, ichan,
1448 ichan->sg[1] = NULL; 1439 ichan->status >= IPU_CHANNEL_ENABLED);
1449 spin_unlock_irqrestore(&ichan->lock, flags);
1450 1440
1451 tasklet_enable(&ipu->tasklet); 1441 tasklet_disable(&ipu->tasklet);
1452 1442
1453 ichan->status = IPU_CHANNEL_INITIALIZED; 1443 /* ichan->queue is modified in ISR, have to spinlock */
1454 break; 1444 spin_lock_irqsave(&ichan->lock, flags);
1455 default: 1445 list_splice_init(&ichan->queue, &ichan->free_list);
1456 return -ENOSYS; 1446
1457 } 1447 if (ichan->desc)
1448 for (i = 0; i < ichan->n_tx_desc; i++) {
1449 struct idmac_tx_desc *desc = ichan->desc + i;
1450 if (list_empty(&desc->list))
1451 /* Descriptor was prepared, but not submitted */
1452 list_add(&desc->list, &ichan->free_list);
1453
1454 async_tx_clear_ack(&desc->txd);
1455 }
1456
1457 ichan->sg[0] = NULL;
1458 ichan->sg[1] = NULL;
1459 spin_unlock_irqrestore(&ichan->lock, flags);
1460
1461 tasklet_enable(&ipu->tasklet);
1462
1463 ichan->status = IPU_CHANNEL_INITIALIZED;
1458 1464
1459 return 0; 1465 return 0;
1460} 1466}
1461 1467
1462static int idmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, 1468static int idmac_terminate_all(struct dma_chan *chan)
1463 unsigned long arg)
1464{ 1469{
1465 struct idmac_channel *ichan = to_idmac_chan(chan); 1470 struct idmac_channel *ichan = to_idmac_chan(chan);
1466 int ret; 1471 int ret;
1467 1472
1468 mutex_lock(&ichan->chan_mutex); 1473 mutex_lock(&ichan->chan_mutex);
1469 1474
1470 ret = __idmac_control(chan, cmd, arg); 1475 ret = __idmac_terminate_all(chan);
1471 1476
1472 mutex_unlock(&ichan->chan_mutex); 1477 mutex_unlock(&ichan->chan_mutex);
1473 1478
@@ -1568,7 +1573,7 @@ static void idmac_free_chan_resources(struct dma_chan *chan)
1568 1573
1569 mutex_lock(&ichan->chan_mutex); 1574 mutex_lock(&ichan->chan_mutex);
1570 1575
1571 __idmac_control(chan, DMA_TERMINATE_ALL, 0); 1576 __idmac_terminate_all(chan);
1572 1577
1573 if (ichan->status > IPU_CHANNEL_FREE) { 1578 if (ichan->status > IPU_CHANNEL_FREE) {
1574#ifdef DEBUG 1579#ifdef DEBUG
@@ -1622,7 +1627,8 @@ static int __init ipu_idmac_init(struct ipu *ipu)
1622 1627
1623 /* Compulsory for DMA_SLAVE fields */ 1628 /* Compulsory for DMA_SLAVE fields */
1624 dma->device_prep_slave_sg = idmac_prep_slave_sg; 1629 dma->device_prep_slave_sg = idmac_prep_slave_sg;
1625 dma->device_control = idmac_control; 1630 dma->device_pause = idmac_pause;
1631 dma->device_terminate_all = idmac_terminate_all;
1626 1632
1627 INIT_LIST_HEAD(&dma->channels); 1633 INIT_LIST_HEAD(&dma->channels);
1628 for (i = 0; i < IPU_CHANNELS_NUM; i++) { 1634 for (i = 0; i < IPU_CHANNELS_NUM; i++) {
@@ -1655,7 +1661,7 @@ static void ipu_idmac_exit(struct ipu *ipu)
1655 for (i = 0; i < IPU_CHANNELS_NUM; i++) { 1661 for (i = 0; i < IPU_CHANNELS_NUM; i++) {
1656 struct idmac_channel *ichan = ipu->channel + i; 1662 struct idmac_channel *ichan = ipu->channel + i;
1657 1663
1658 idmac_control(&ichan->dma_chan, DMA_TERMINATE_ALL, 0); 1664 idmac_terminate_all(&ichan->dma_chan);
1659 } 1665 }
1660 1666
1661 dma_async_device_unregister(&idmac->dma); 1667 dma_async_device_unregister(&idmac->dma);