Commit 76c33d27 authored by Sascha Hauer's avatar Sascha Hauer Committed by Vinod Koul
Browse files

dmaengine: imx-sdma: factor out a struct sdma_desc from struct sdma_channel



This is a preparation step to make the adding of virt-dma easier.
We create a struct sdma_desc, move some fields from struct sdma_channel
there and add a pointer from the former to the latter. For now we
allocate the data statically in struct sdma_channel, but with
virt-dma support it will be dynamically allocated.

Signed-off-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: default avatarRobin Gong <yibin.gong@nxp.com>
Reviewed-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
Tested-by: default avatarLucas Stach <l.stach@pengutronix.de>
Signed-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent ce397d21
Loading
Loading
Loading
Loading
+83 −54
Original line number Diff line number Diff line
@@ -288,6 +288,30 @@ struct sdma_context_data {

struct sdma_engine;

/**
 * struct sdma_desc - descriptor structor for one transfer
 * @vd			descriptor for virt dma
 * @num_bd		max NUM_BD. number of descriptors currently handling
 * @buf_tail		ID of the buffer that was processed
 * @buf_ptail		ID of the previous buffer that was processed
 * @period_len		period length, used in cyclic.
 * @chn_real_count	the real count updated from bd->mode.count
 * @chn_count		the transfer count setuped
 * @sdmac		sdma_channel pointer
 * @bd			pointer of alloced bd
 */
struct sdma_desc {
	unsigned int		num_bd;
	dma_addr_t		bd_phys;
	unsigned int		buf_tail;
	unsigned int		buf_ptail;
	unsigned int		period_len;
	unsigned int		chn_real_count;
	unsigned int		chn_count;
	struct sdma_channel	*sdmac;
	struct sdma_buffer_descriptor *bd;
};

/**
 * struct sdma_channel - housekeeping for a SDMA channel
 *
@@ -298,11 +322,10 @@ struct sdma_engine;
 * @event_id0		aka dma request line
 * @event_id1		for channels that use 2 events
 * @word_size		peripheral access size
 * @buf_tail		ID of the buffer that was processed
 * @buf_ptail		ID of the previous buffer that was processed
 * @num_bd		max NUM_BD. number of descriptors currently handling
 */
struct sdma_channel {
	struct sdma_desc		*desc;
	struct sdma_desc		_desc;
	struct sdma_engine		*sdma;
	unsigned int			channel;
	enum dma_transfer_direction		direction;
@@ -310,12 +333,6 @@ struct sdma_channel {
	unsigned int			event_id0;
	unsigned int			event_id1;
	enum dma_slave_buswidth		word_size;
	unsigned int			buf_tail;
	unsigned int			buf_ptail;
	unsigned int			num_bd;
	unsigned int			period_len;
	struct sdma_buffer_descriptor	*bd;
	dma_addr_t			bd_phys;
	unsigned int			pc_from_device, pc_to_device;
	unsigned int			device_to_device;
	unsigned long			flags;
@@ -325,10 +342,8 @@ struct sdma_channel {
	u32				shp_addr, per_addr;
	struct dma_chan			chan;
	spinlock_t			lock;
	struct dma_async_tx_descriptor	desc;
	struct dma_async_tx_descriptor	txdesc;
	enum dma_status			status;
	unsigned int			chn_count;
	unsigned int			chn_real_count;
	struct tasklet_struct		tasklet;
	struct imx_dma_data		data;
	bool				enabled;
@@ -391,6 +406,8 @@ struct sdma_engine {
	u32				spba_start_addr;
	u32				spba_end_addr;
	unsigned int			irq;
	dma_addr_t			bd0_phys;
	struct sdma_buffer_descriptor	*bd0;
};

static struct sdma_driver_data sdma_imx31 = {
@@ -625,7 +642,7 @@ static int sdma_run_channel0(struct sdma_engine *sdma)
static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
		u32 address)
{
	struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
	struct sdma_buffer_descriptor *bd0 = sdma->bd0;
	void *buf_virt;
	dma_addr_t buf_phys;
	int ret;
@@ -700,7 +717,9 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
	 * call callback function.
	 */
	while (1) {
		bd = &sdmac->bd[sdmac->buf_tail];
		struct sdma_desc *desc = sdmac->desc;

		bd = &desc->bd[desc->buf_tail];

		if (bd->mode.status & BD_DONE)
			break;
@@ -716,11 +735,11 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
		* the number of bytes present in the current buffer descriptor.
		*/

		sdmac->chn_real_count = bd->mode.count;
		desc->chn_real_count = bd->mode.count;
		bd->mode.status |= BD_DONE;
		bd->mode.count = sdmac->period_len;
		sdmac->buf_ptail = sdmac->buf_tail;
		sdmac->buf_tail = (sdmac->buf_tail + 1) % sdmac->num_bd;
		bd->mode.count = desc->period_len;
		desc->buf_ptail = desc->buf_tail;
		desc->buf_tail = (desc->buf_tail + 1) % desc->num_bd;

		/*
		 * The callback is called from the interrupt context in order
@@ -729,7 +748,7 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
		 * executed.
		 */

		dmaengine_desc_get_callback_invoke(&sdmac->desc, NULL);
		dmaengine_desc_get_callback_invoke(&sdmac->txdesc, NULL);

		if (error)
			sdmac->status = old_status;
@@ -742,17 +761,17 @@ static void mxc_sdma_handle_channel_normal(unsigned long data)
	struct sdma_buffer_descriptor *bd;
	int i, error = 0;

	sdmac->chn_real_count = 0;
	sdmac->desc->chn_real_count = 0;
	/*
	 * non loop mode. Iterate over all descriptors, collect
	 * errors and call callback function
	 */
	for (i = 0; i < sdmac->num_bd; i++) {
		bd = &sdmac->bd[i];
	for (i = 0; i < sdmac->desc->num_bd; i++) {
		bd = &sdmac->desc->bd[i];

		 if (bd->mode.status & (BD_DONE | BD_RROR))
			error = -EIO;
		 sdmac->chn_real_count += bd->mode.count;
		 sdmac->desc->chn_real_count += bd->mode.count;
	}

	if (error)
@@ -760,9 +779,9 @@ static void mxc_sdma_handle_channel_normal(unsigned long data)
	else
		sdmac->status = DMA_COMPLETE;

	dma_cookie_complete(&sdmac->desc);
	dma_cookie_complete(&sdmac->txdesc);

	dmaengine_desc_get_callback_invoke(&sdmac->desc, NULL);
	dmaengine_desc_get_callback_invoke(&sdmac->txdesc, NULL);
}

static irqreturn_t sdma_int_handler(int irq, void *dev_id)
@@ -890,7 +909,7 @@ static int sdma_load_context(struct sdma_channel *sdmac)
	int channel = sdmac->channel;
	int load_address;
	struct sdma_context_data *context = sdma->context;
	struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
	struct sdma_buffer_descriptor *bd0 = sdma->bd0;
	int ret;
	unsigned long flags;

@@ -1093,18 +1112,22 @@ static int sdma_set_channel_priority(struct sdma_channel *sdmac,
static int sdma_request_channel(struct sdma_channel *sdmac)
{
	struct sdma_engine *sdma = sdmac->sdma;
	struct sdma_desc *desc;
	int channel = sdmac->channel;
	int ret = -EBUSY;

	sdmac->bd = dma_zalloc_coherent(NULL, PAGE_SIZE, &sdmac->bd_phys,
	sdmac->desc = &sdmac->_desc;
	desc = sdmac->desc;

	desc->bd = dma_zalloc_coherent(NULL, PAGE_SIZE, &desc->bd_phys,
					GFP_KERNEL);
	if (!sdmac->bd) {
	if (!desc->bd) {
		ret = -ENOMEM;
		goto out;
	}

	sdma->channel_control[channel].base_bd_ptr = sdmac->bd_phys;
	sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
	sdma->channel_control[channel].base_bd_ptr = desc->bd_phys;
	sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;

	sdma_set_channel_priority(sdmac, MXC_SDMA_DEFAULT_PRIORITY);
	return 0;
@@ -1169,10 +1192,10 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan)
	if (ret)
		goto disable_clk_ahb;

	dma_async_tx_descriptor_init(&sdmac->desc, chan);
	sdmac->desc.tx_submit = sdma_tx_submit;
	dma_async_tx_descriptor_init(&sdmac->txdesc, chan);
	sdmac->txdesc.tx_submit = sdma_tx_submit;
	/* txd.flags will be overwritten in prep funcs */
	sdmac->desc.flags = DMA_CTRL_ACK;
	sdmac->txdesc.flags = DMA_CTRL_ACK;

	return 0;

@@ -1187,6 +1210,7 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
{
	struct sdma_channel *sdmac = to_sdma_chan(chan);
	struct sdma_engine *sdma = sdmac->sdma;
	struct sdma_desc *desc = sdmac->desc;

	sdma_disable_channel(chan);

@@ -1200,7 +1224,7 @@ static void sdma_free_chan_resources(struct dma_chan *chan)

	sdma_set_channel_priority(sdmac, 0);

	dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys);
	dma_free_coherent(NULL, PAGE_SIZE, desc->bd, desc->bd_phys);

	clk_disable(sdma->clk_ipg);
	clk_disable(sdma->clk_ahb);
@@ -1216,6 +1240,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
	int ret, i, count;
	int channel = sdmac->channel;
	struct scatterlist *sg;
	struct sdma_desc *desc = sdmac->desc;

	if (sdmac->status == DMA_IN_PROGRESS)
		return NULL;
@@ -1223,9 +1248,9 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(

	sdmac->flags = 0;

	sdmac->buf_tail = 0;
	sdmac->buf_ptail = 0;
	sdmac->chn_real_count = 0;
	desc->buf_tail = 0;
	desc->buf_ptail = 0;
	desc->chn_real_count = 0;

	dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n",
			sg_len, channel);
@@ -1242,9 +1267,9 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
		goto err_out;
	}

	sdmac->chn_count = 0;
	desc->chn_count = 0;
	for_each_sg(sgl, sg, sg_len, i) {
		struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
		struct sdma_buffer_descriptor *bd = &desc->bd[i];
		int param;

		bd->buffer_addr = sg->dma_address;
@@ -1259,7 +1284,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
		}

		bd->mode.count = count;
		sdmac->chn_count += count;
		desc->chn_count += count;

		if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES) {
			ret =  -EINVAL;
@@ -1300,10 +1325,10 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
		bd->mode.status = param;
	}

	sdmac->num_bd = sg_len;
	sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
	desc->num_bd = sg_len;
	sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;

	return &sdmac->desc;
	return &sdmac->txdesc;
err_out:
	sdmac->status = DMA_ERROR;
	return NULL;
@@ -1319,6 +1344,7 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
	int num_periods = buf_len / period_len;
	int channel = sdmac->channel;
	int ret, i = 0, buf = 0;
	struct sdma_desc *desc = sdmac->desc;

	dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);

@@ -1327,10 +1353,10 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(

	sdmac->status = DMA_IN_PROGRESS;

	sdmac->buf_tail = 0;
	sdmac->buf_ptail = 0;
	sdmac->chn_real_count = 0;
	sdmac->period_len = period_len;
	desc->buf_tail = 0;
	desc->buf_ptail = 0;
	desc->chn_real_count = 0;
	desc->period_len = period_len;

	sdmac->flags |= IMX_DMA_SG_LOOP;
	sdmac->direction = direction;
@@ -1351,7 +1377,7 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
	}

	while (buf < buf_len) {
		struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
		struct sdma_buffer_descriptor *bd = &desc->bd[i];
		int param;

		bd->buffer_addr = dma_addr;
@@ -1382,10 +1408,10 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
		i++;
	}

	sdmac->num_bd = num_periods;
	sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
	desc->num_bd = num_periods;
	sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;

	return &sdmac->desc;
	return &sdmac->txdesc;
err_out:
	sdmac->status = DMA_ERROR;
	return NULL;
@@ -1424,13 +1450,14 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan,
				      struct dma_tx_state *txstate)
{
	struct sdma_channel *sdmac = to_sdma_chan(chan);
	struct sdma_desc *desc = sdmac->desc;
	u32 residue;

	if (sdmac->flags & IMX_DMA_SG_LOOP)
		residue = (sdmac->num_bd - sdmac->buf_ptail) *
			   sdmac->period_len - sdmac->chn_real_count;
		residue = (desc->num_bd - desc->buf_ptail) *
			   desc->period_len - desc->chn_real_count;
	else
		residue = sdmac->chn_count - sdmac->chn_real_count;
		residue = desc->chn_count - desc->chn_real_count;

	dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
			 residue);
@@ -1654,6 +1681,8 @@ static int sdma_init(struct sdma_engine *sdma)
	if (ret)
		goto err_dma_alloc;

	sdma->bd0 = sdma->channel[0].desc->bd;

	sdma_config_ownership(&sdma->channel[0], false, true, false);

	/* Set Command Channel (Channel Zero) */