Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a936e793 authored by Russell King's avatar Russell King
Browse files

dmaengine: PL08x: convert to a list of completed descriptors



Convert PL08x to use a list of completed descriptors rather than
merely relying upon a single pointer.  This makes it possible to
schedule the tasklet for other purposes, and makes our behaviour
similar to virt-dma.

Acked-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Tested-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 5e2479bd
Loading
Loading
Loading
Loading
+20 −10
Original line number Original line Diff line number Diff line
@@ -219,6 +219,7 @@ enum pl08x_dma_chan_state {
 * @cd: channel platform data
 * @cd: channel platform data
 * @runtime_addr: address for RX/TX according to the runtime config
 * @runtime_addr: address for RX/TX according to the runtime config
 * @pend_list: queued transactions pending on this channel
 * @pend_list: queued transactions pending on this channel
 * @done_list: list of completed transactions
 * @at: active transaction on this channel
 * @at: active transaction on this channel
 * @lock: a lock for this channel data
 * @lock: a lock for this channel data
 * @host: a pointer to the host (internal use)
 * @host: a pointer to the host (internal use)
@@ -238,6 +239,7 @@ struct pl08x_dma_chan {
	const struct pl08x_channel_data *cd;
	const struct pl08x_channel_data *cd;
	struct dma_slave_config cfg;
	struct dma_slave_config cfg;
	struct list_head pend_list;
	struct list_head pend_list;
	struct list_head done_list;
	struct pl08x_txd *at;
	struct pl08x_txd *at;
	spinlock_t lock;
	spinlock_t lock;
	struct pl08x_driver_data *host;
	struct pl08x_driver_data *host;
@@ -1673,18 +1675,11 @@ static void pl08x_tasklet(unsigned long data)
{
{
	struct pl08x_dma_chan *plchan = (struct pl08x_dma_chan *) data;
	struct pl08x_dma_chan *plchan = (struct pl08x_dma_chan *) data;
	struct pl08x_driver_data *pl08x = plchan->host;
	struct pl08x_driver_data *pl08x = plchan->host;
	struct pl08x_txd *txd;
	unsigned long flags;
	unsigned long flags;
	LIST_HEAD(head);


	spin_lock_irqsave(&plchan->lock, flags);
	spin_lock_irqsave(&plchan->lock, flags);

	list_splice_tail_init(&plchan->done_list, &head);
	txd = plchan->at;
	plchan->at = NULL;

	if (txd) {
		/* Update last completed */
		dma_cookie_complete(&txd->tx);
	}


	/* If a new descriptor is queued, set it up plchan->at is NULL here */
	/* If a new descriptor is queued, set it up plchan->at is NULL here */
	if (!list_empty(&plchan->pend_list)) {
	if (!list_empty(&plchan->pend_list)) {
@@ -1739,10 +1734,14 @@ static void pl08x_tasklet(unsigned long data)


	spin_unlock_irqrestore(&plchan->lock, flags);
	spin_unlock_irqrestore(&plchan->lock, flags);


	if (txd) {
	while (!list_empty(&head)) {
		struct pl08x_txd *txd = list_first_entry(&head,
						struct pl08x_txd, node);
		dma_async_tx_callback callback = txd->tx.callback;
		dma_async_tx_callback callback = txd->tx.callback;
		void *callback_param = txd->tx.callback_param;
		void *callback_param = txd->tx.callback_param;


		list_del(&txd->node);

		/* Don't try to unmap buffers on slave channels */
		/* Don't try to unmap buffers on slave channels */
		if (!plchan->slave)
		if (!plchan->slave)
			pl08x_unmap_buffers(txd);
			pl08x_unmap_buffers(txd);
@@ -1782,6 +1781,7 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
			/* Locate physical channel */
			/* Locate physical channel */
			struct pl08x_phy_chan *phychan = &pl08x->phy_chans[i];
			struct pl08x_phy_chan *phychan = &pl08x->phy_chans[i];
			struct pl08x_dma_chan *plchan = phychan->serving;
			struct pl08x_dma_chan *plchan = phychan->serving;
			struct pl08x_txd *tx;


			if (!plchan) {
			if (!plchan) {
				dev_err(&pl08x->adev->dev,
				dev_err(&pl08x->adev->dev,
@@ -1790,6 +1790,15 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
				continue;
				continue;
			}
			}


			spin_lock(&plchan->lock);
			tx = plchan->at;
			if (tx) {
				plchan->at = NULL;
				dma_cookie_complete(&tx->tx);
				list_add_tail(&tx->node, &plchan->done_list);
			}
			spin_unlock(&plchan->lock);

			/* Schedule tasklet on this channel */
			/* Schedule tasklet on this channel */
			tasklet_schedule(&plchan->tasklet);
			tasklet_schedule(&plchan->tasklet);
			mask |= (1 << i);
			mask |= (1 << i);
@@ -1856,6 +1865,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,


		spin_lock_init(&chan->lock);
		spin_lock_init(&chan->lock);
		INIT_LIST_HEAD(&chan->pend_list);
		INIT_LIST_HEAD(&chan->pend_list);
		INIT_LIST_HEAD(&chan->done_list);
		tasklet_init(&chan->tasklet, pl08x_tasklet,
		tasklet_init(&chan->tasklet, pl08x_tasklet,
			     (unsigned long) chan);
			     (unsigned long) chan);