diff options
Diffstat (limited to 'drivers/dma/ipu/ipu_idmac.c')
-rw-r--r-- | drivers/dma/ipu/ipu_idmac.c | 96 |
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 | ||
1401 | static int __idmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, | 1401 | static 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); | 1430 | static 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 | ||
1462 | static int idmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, | 1468 | static 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); |