Commit 2cd6f792 authored by Vinod Koul's avatar Vinod Koul
Browse files

Merge branch 'topic/slave_caps_device_control_fix_rebased' into for-linus

parents c914570f 5cf5aec5
Loading
Loading
Loading
Loading
+55 −42
Original line number Diff line number Diff line
@@ -113,6 +113,31 @@ need to initialize a few fields in there:
  * channels:	should be initialized as a list using the
		INIT_LIST_HEAD macro for example

  * src_addr_widths:
    - should contain a bitmask of the supported source transfer width

  * dst_addr_widths:
    - should contain a bitmask of the supported destination transfer
      width

  * directions:
    - should contain a bitmask of the supported slave directions
      (i.e. excluding mem2mem transfers)

  * residue_granularity:
    - Granularity of the transfer residue reported to dma_set_residue.
    - This can be either:
      + Descriptor
        -> Your device doesn't support any kind of residue
           reporting. The framework will only know that a particular
           transaction descriptor is done.
      + Segment
        -> Your device is able to report which chunks have been
           transferred
      + Burst
        -> Your device is able to report which burst have been
           transferred

  * dev: 	should hold the pointer to the struct device associated
		to your current driver instance.

@@ -274,48 +299,36 @@ supported.
       account the current period.
     - This function can be called in an interrupt context.

   * device_control
     - Used by client drivers to control and configure the channel it
       has a handle on.
     - Called with a command and an argument
       + The command is one of the values listed by the enum
         dma_ctrl_cmd. The valid commands are:
         + DMA_PAUSE
           + Pauses a transfer on the channel
           + This command should operate synchronously on the channel,
   * device_config
     - Reconfigures the channel with the configuration given as
       argument
     - This command should NOT perform synchronously, or on any
       currently queued transfers, but only on subsequent ones
     - In this case, the function will receive a dma_slave_config
       structure pointer as an argument, that will detail which
       configuration to use.
     - Even though that structure contains a direction field, this
       field is deprecated in favor of the direction argument given to
       the prep_* functions
     - This call is mandatory for slave operations only. This should NOT be
       set or expected to be set for memcpy operations.
       If a driver support both, it should use this call for slave
       operations only and not for memcpy ones.

   * device_pause
     - Pauses a transfer on the channel
     - This command should operate synchronously on the channel,
       pausing right away the work of the given channel

   * device_resume
     - Resumes a transfer on the channel
     - This command should operate synchronously on the channel,
       pausing right away the work of the given channel
         + DMA_RESUME
           + Restarts a transfer on the channel
           + This command should operate synchronously on the channel,
             resuming right away the work of the given channel
         + DMA_TERMINATE_ALL
           + Aborts all the pending and ongoing transfers on the
             channel
           + This command should operate synchronously on the channel,

   * device_terminate_all
     - Aborts all the pending and ongoing transfers on the channel
     - This command should operate synchronously on the channel,
       terminating right away all the channels
         + DMA_SLAVE_CONFIG
           + Reconfigures the channel with passed configuration
           + This command should NOT perform synchronously, or on any
             currently queued transfers, but only on subsequent ones
           + In this case, the function will receive a
             dma_slave_config structure pointer as an argument, that
             will detail which configuration to use.
           + Even though that structure contains a direction field,
             this field is deprecated in favor of the direction
             argument given to the prep_* functions
         + FSLDMA_EXTERNAL_START
           + TODO: Why does that even exist?
       + The argument is an opaque unsigned long. This actually is a
         pointer to a struct dma_slave_config that should be used only
         in the DMA_SLAVE_CONFIG.

  * device_slave_caps
    - Called through the framework by client drivers in order to have
      an idea of what are the properties of the channel allocated to
      them.
    - Such properties are the buswidth, available directions, etc.
    - Required for every generic layer doing DMA transfers, such as
      ASoC.

Misc notes (stuff that should be documented, but don't really know
where to put them)
+2 −2
Original line number Diff line number Diff line
@@ -606,12 +606,12 @@ static void cryp_dma_done(struct cryp_ctx *ctx)
	dev_dbg(ctx->device->dev, "[%s]: ", __func__);

	chan = ctx->device->dma.chan_mem2cryp;
	dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0);
	dmaengine_terminate_all(chan);
	dma_unmap_sg(chan->device->dev, ctx->device->dma.sg_src,
		     ctx->device->dma.sg_src_len, DMA_TO_DEVICE);

	chan = ctx->device->dma.chan_cryp2mem;
	dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0);
	dmaengine_terminate_all(chan);
	dma_unmap_sg(chan->device->dev, ctx->device->dma.sg_dst,
		     ctx->device->dma.sg_dst_len, DMA_FROM_DEVICE);
}
+1 −1
Original line number Diff line number Diff line
@@ -202,7 +202,7 @@ static void hash_dma_done(struct hash_ctx *ctx)
	struct dma_chan *chan;

	chan = ctx->device->dma.chan_mem2hash;
	dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0);
	dmaengine_terminate_all(chan);
	dma_unmap_sg(chan->device->dev, ctx->device->dma.sg,
		     ctx->device->dma.sg_len, DMA_TO_DEVICE);
}
+90 −66
Original line number Diff line number Diff line
@@ -1386,32 +1386,6 @@ static u32 pl08x_get_cctl(struct pl08x_dma_chan *plchan,
	return pl08x_cctl(cctl);
}

static int dma_set_runtime_config(struct dma_chan *chan,
				  struct dma_slave_config *config)
{
	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
	struct pl08x_driver_data *pl08x = plchan->host;

	if (!plchan->slave)
		return -EINVAL;

	/* Reject definitely invalid configurations */
	if (config->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES ||
	    config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES)
		return -EINVAL;

	if (config->device_fc && pl08x->vd->pl080s) {
		dev_err(&pl08x->adev->dev,
			"%s: PL080S does not support peripheral flow control\n",
			__func__);
		return -EINVAL;
	}

	plchan->cfg = *config;

	return 0;
}

/*
 * Slave transactions callback to the slave device to allow
 * synchronization of slave DMA signals with the DMAC enable
@@ -1693,32 +1667,44 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_cyclic(
	return vchan_tx_prep(&plchan->vc, &txd->vd, flags);
}

static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
			 unsigned long arg)
static int pl08x_config(struct dma_chan *chan,
			struct dma_slave_config *config)
{
	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
	struct pl08x_driver_data *pl08x = plchan->host;
	unsigned long flags;
	int ret = 0;

	/* Controls applicable to inactive channels */
	if (cmd == DMA_SLAVE_CONFIG) {
		return dma_set_runtime_config(chan,
					      (struct dma_slave_config *)arg);
	if (!plchan->slave)
		return -EINVAL;

	/* Reject definitely invalid configurations */
	if (config->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES ||
	    config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES)
		return -EINVAL;

	if (config->device_fc && pl08x->vd->pl080s) {
		dev_err(&pl08x->adev->dev,
			"%s: PL080S does not support peripheral flow control\n",
			__func__);
		return -EINVAL;
	}

	plchan->cfg = *config;

	return 0;
}

	/*
	 * Anything succeeds on channels with no physical allocation and
	 * no queued transfers.
	 */
static int pl08x_terminate_all(struct dma_chan *chan)
{
	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
	struct pl08x_driver_data *pl08x = plchan->host;
	unsigned long flags;

	spin_lock_irqsave(&plchan->vc.lock, flags);
	if (!plchan->phychan && !plchan->at) {
		spin_unlock_irqrestore(&plchan->vc.lock, flags);
		return 0;
	}

	switch (cmd) {
	case DMA_TERMINATE_ALL:
	plchan->state = PL08X_CHAN_IDLE;

	if (plchan->phychan) {
@@ -1735,24 +1721,56 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
	}
	/* Dequeue jobs not yet fired as well */
	pl08x_free_txd_list(pl08x, plchan);
		break;
	case DMA_PAUSE:

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

	return 0;
}

static int pl08x_pause(struct dma_chan *chan)
{
	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
	unsigned long flags;

	/*
	 * Anything succeeds on channels with no physical allocation and
	 * no queued transfers.
	 */
	spin_lock_irqsave(&plchan->vc.lock, flags);
	if (!plchan->phychan && !plchan->at) {
		spin_unlock_irqrestore(&plchan->vc.lock, flags);
		return 0;
	}

	pl08x_pause_phy_chan(plchan->phychan);
	plchan->state = PL08X_CHAN_PAUSED;
		break;
	case DMA_RESUME:

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

	return 0;
}

static int pl08x_resume(struct dma_chan *chan)
{
	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
	unsigned long flags;

	/*
	 * Anything succeeds on channels with no physical allocation and
	 * no queued transfers.
	 */
	spin_lock_irqsave(&plchan->vc.lock, flags);
	if (!plchan->phychan && !plchan->at) {
		spin_unlock_irqrestore(&plchan->vc.lock, flags);
		return 0;
	}

	pl08x_resume_phy_chan(plchan->phychan);
	plchan->state = PL08X_CHAN_RUNNING;
		break;
	default:
		/* Unknown command */
		ret = -ENXIO;
		break;
	}

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

	return ret;
	return 0;
}

bool pl08x_filter_id(struct dma_chan *chan, void *chan_id)
@@ -2048,7 +2066,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
	pl08x->memcpy.device_prep_dma_interrupt = pl08x_prep_dma_interrupt;
	pl08x->memcpy.device_tx_status = pl08x_dma_tx_status;
	pl08x->memcpy.device_issue_pending = pl08x_issue_pending;
	pl08x->memcpy.device_control = pl08x_control;
	pl08x->memcpy.device_config = pl08x_config;
	pl08x->memcpy.device_pause = pl08x_pause;
	pl08x->memcpy.device_resume = pl08x_resume;
	pl08x->memcpy.device_terminate_all = pl08x_terminate_all;

	/* Initialize slave engine */
	dma_cap_set(DMA_SLAVE, pl08x->slave.cap_mask);
@@ -2061,7 +2082,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
	pl08x->slave.device_issue_pending = pl08x_issue_pending;
	pl08x->slave.device_prep_slave_sg = pl08x_prep_slave_sg;
	pl08x->slave.device_prep_dma_cyclic = pl08x_prep_dma_cyclic;
	pl08x->slave.device_control = pl08x_control;
	pl08x->slave.device_config = pl08x_config;
	pl08x->slave.device_pause = pl08x_pause;
	pl08x->slave.device_resume = pl08x_resume;
	pl08x->slave.device_terminate_all = pl08x_terminate_all;

	/* Get the platform data */
	pl08x->pd = dev_get_platdata(&adev->dev);
+82 −48
Original line number Diff line number Diff line
@@ -42,6 +42,11 @@
#define	ATC_DEFAULT_CFG		(ATC_FIFOCFG_HALFFIFO)
#define	ATC_DEFAULT_CTRLB	(ATC_SIF(AT_DMA_MEM_IF) \
				|ATC_DIF(AT_DMA_MEM_IF))
#define ATC_DMA_BUSWIDTHS\
	(BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) |\
	BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |\
	BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |\
	BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))

/*
 * Initial number of descriptors to allocate for each channel. This could
@@ -972,11 +977,13 @@ err_out:
	return NULL;
}

static int set_runtime_config(struct dma_chan *chan,
static int atc_config(struct dma_chan *chan,
		      struct dma_slave_config *sconfig)
{
	struct at_dma_chan	*atchan = to_at_dma_chan(chan);

	dev_vdbg(chan2dev(chan), "%s\n", __func__);

	/* Check if it is chan is configured for slave transfers */
	if (!chan->private)
		return -EINVAL;
@@ -989,9 +996,7 @@ static int set_runtime_config(struct dma_chan *chan,
	return 0;
}


static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
		       unsigned long arg)
static int atc_pause(struct dma_chan *chan)
{
	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
	struct at_dma		*atdma = to_at_dma(chan->device);
@@ -1000,16 +1005,29 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,

	LIST_HEAD(list);

	dev_vdbg(chan2dev(chan), "atc_control (%d)\n", cmd);
	dev_vdbg(chan2dev(chan), "%s\n", __func__);

	if (cmd == DMA_PAUSE) {
	spin_lock_irqsave(&atchan->lock, flags);

	dma_writel(atdma, CHER, AT_DMA_SUSP(chan_id));
	set_bit(ATC_IS_PAUSED, &atchan->status);

	spin_unlock_irqrestore(&atchan->lock, flags);
	} else if (cmd == DMA_RESUME) {

	return 0;
}

static int atc_resume(struct dma_chan *chan)
{
	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
	struct at_dma		*atdma = to_at_dma(chan->device);
	int			chan_id = atchan->chan_common.chan_id;
	unsigned long		flags;

	LIST_HEAD(list);

	dev_vdbg(chan2dev(chan), "%s\n", __func__);

	if (!atc_chan_is_paused(atchan))
		return 0;

@@ -1019,8 +1037,22 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
	clear_bit(ATC_IS_PAUSED, &atchan->status);

	spin_unlock_irqrestore(&atchan->lock, flags);
	} else if (cmd == DMA_TERMINATE_ALL) {

	return 0;
}

static int atc_terminate_all(struct dma_chan *chan)
{
	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
	struct at_dma		*atdma = to_at_dma(chan->device);
	int			chan_id = atchan->chan_common.chan_id;
	struct at_desc		*desc, *_desc;
	unsigned long		flags;

	LIST_HEAD(list);

	dev_vdbg(chan2dev(chan), "%s\n", __func__);

	/*
	 * This is only called when something went wrong elsewhere, so
	 * we don't really care about the data. Just disable the
@@ -1049,11 +1081,6 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
	clear_bit(ATC_IS_CYCLIC, &atchan->status);

	spin_unlock_irqrestore(&atchan->lock, flags);
	} else if (cmd == DMA_SLAVE_CONFIG) {
		return set_runtime_config(chan, (struct dma_slave_config *)arg);
	} else {
		return -ENXIO;
	}

	return 0;
}
@@ -1505,7 +1532,14 @@ static int __init at_dma_probe(struct platform_device *pdev)
		/* controller can do slave DMA: can trigger cyclic transfers */
		dma_cap_set(DMA_CYCLIC, atdma->dma_common.cap_mask);
		atdma->dma_common.device_prep_dma_cyclic = atc_prep_dma_cyclic;
		atdma->dma_common.device_control = atc_control;
		atdma->dma_common.device_config = atc_config;
		atdma->dma_common.device_pause = atc_pause;
		atdma->dma_common.device_resume = atc_resume;
		atdma->dma_common.device_terminate_all = atc_terminate_all;
		atdma->dma_common.src_addr_widths = ATC_DMA_BUSWIDTHS;
		atdma->dma_common.dst_addr_widths = ATC_DMA_BUSWIDTHS;
		atdma->dma_common.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
		atdma->dma_common.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
	}

	dma_writel(atdma, EN, AT_DMA_ENABLE);
@@ -1622,7 +1656,7 @@ static void atc_suspend_cyclic(struct at_dma_chan *atchan)
	if (!atc_chan_is_paused(atchan)) {
		dev_warn(chan2dev(chan),
		"cyclic channel not paused, should be done by channel user\n");
		atc_control(chan, DMA_PAUSE, 0);
		atc_pause(chan);
	}

	/* now preserve additional data for cyclic operations */
Loading