Exemplo n.º 1
0
/* Prepares DMA data for current or next transfer.
 * A request can be in-flight when this is called.
 */
static int jz4740_mmc_prepare_dma_data(struct jz4740_mmc_host *host,
				       struct mmc_data *data,
				       int cookie)
{
	struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
	enum dma_data_direction dir = mmc_get_dma_dir(data);
	int sg_count;

	if (data->host_cookie == COOKIE_PREMAPPED)
		return data->sg_count;

	sg_count = dma_map_sg(chan->device->dev,
			data->sg,
			data->sg_len,
			dir);

	if (sg_count <= 0) {
		dev_err(mmc_dev(host->mmc),
			"Failed to map scatterlist for DMA operation\n");
		return -EINVAL;
	}

	data->sg_count = sg_count;
	data->host_cookie = cookie;

	return data->sg_count;
}
Exemplo n.º 2
0
static void jz4740_mmc_dma_unmap(struct jz4740_mmc_host *host,
				 struct mmc_data *data)
{
	struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
	enum dma_data_direction dir = jz4740_mmc_get_dma_dir(data);

	dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir);
}
Exemplo n.º 3
0
static int jz4740_mmc_start_dma_transfer(struct jz4740_mmc_host *host,
					 struct mmc_data *data)
{
	struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
	struct dma_async_tx_descriptor *desc;
	struct dma_slave_config conf = {
		.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
		.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
		.src_maxburst = JZ4740_MMC_FIFO_HALF_SIZE,
		.dst_maxburst = JZ4740_MMC_FIFO_HALF_SIZE,
	};
	int sg_count;

	if (data->flags & MMC_DATA_WRITE) {
		conf.direction = DMA_MEM_TO_DEV;
		conf.dst_addr = host->mem_res->start + JZ_REG_MMC_TXFIFO;
		conf.slave_id = JZ4740_DMA_TYPE_MMC_TRANSMIT;
	} else {
		conf.direction = DMA_DEV_TO_MEM;
		conf.src_addr = host->mem_res->start + JZ_REG_MMC_RXFIFO;
		conf.slave_id = JZ4740_DMA_TYPE_MMC_RECEIVE;
	}

	sg_count = jz4740_mmc_prepare_dma_data(host, data, COOKIE_MAPPED);
	if (sg_count < 0)
		return sg_count;

	dmaengine_slave_config(chan, &conf);
	desc = dmaengine_prep_slave_sg(chan, data->sg, sg_count,
			conf.direction,
			DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
	if (!desc) {
		dev_err(mmc_dev(host->mmc),
			"Failed to allocate DMA %s descriptor",
			 conf.direction == DMA_MEM_TO_DEV ? "TX" : "RX");
		goto dma_unmap;
	}

	dmaengine_submit(desc);
	dma_async_issue_pending(chan);

	return 0;

dma_unmap:
	if (data->host_cookie == COOKIE_MAPPED)
		jz4740_mmc_dma_unmap(host, data);
	return -ENOMEM;
}
Exemplo n.º 4
0
static void jz4740_mmc_post_request(struct mmc_host *mmc,
				    struct mmc_request *mrq,
				    int err)
{
	struct jz4740_mmc_host *host = mmc_priv(mmc);
	struct mmc_data *data = mrq->data;

	if (data && data->host_cookie != COOKIE_UNMAPPED)
		jz4740_mmc_dma_unmap(host, data);

	if (err) {
		struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);

		dmaengine_terminate_all(chan);
	}
}
Exemplo n.º 5
0
static void jz4740_mmc_pre_request(struct mmc_host *mmc,
				   struct mmc_request *mrq,
				   bool is_first_req)
{
	struct jz4740_mmc_host *host = mmc_priv(mmc);
	struct mmc_data *data = mrq->data;
	struct jz4740_mmc_host_next *next_data = &host->next_data;

	BUG_ON(data->host_cookie);

	if (host->use_dma) {
		struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);

		if (jz4740_mmc_prepare_dma_data(host, data, next_data, chan))
			data->host_cookie = 0;
	}
}