All of lore.kernel.org
 help / color / mirror / Atom feed
From: Koen Kooi <koen@dominion.thruhere.net>
To: linux-mmc@vger.kernel.org
Cc: spi-devel-general@lists.sourceforge.net,
	davinci-linux-open-source@linux.davincidsp.com,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.orgspi-devel-general@lists.sourceforge.netlinux-kernel@vger.kernel.orglinux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH v2 2/3] mmc: davinci_mmc: convert to DMA engine API
Date: Wed, 22 Aug 2012 20:53:43 +0200	[thread overview]
Message-ID: <k139rl$gbm$2@ger.gmane.org> (raw)
In-Reply-To: <1345574589-24757-3-git-send-email-mporter@ti.com>

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Op 21-08-12 20:43, Matt Porter schreef:
> Removes use of the DaVinci EDMA private DMA API and replaces it with use
> of the DMA engine API.
> 
> Signed-off-by: Matt Porter <mporter@ti.com>

Runtime tested on hawkboard with 3.6.0-rc2 with rootfs on SD and running
bonnie++ on it.

Tested-by: Koen Kooi <koen@dominion.thruhere.net>

> --- drivers/mmc/host/davinci_mmc.c |  271
> ++++++++++++---------------------------- 1 file changed, 82
> insertions(+), 189 deletions(-)
> 
> diff --git a/drivers/mmc/host/davinci_mmc.c
> b/drivers/mmc/host/davinci_mmc.c index 7cf6c62..c5e1eeb 100644 ---
> a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@
> -30,11 +30,12 @@ #include <linux/io.h> #include <linux/irq.h> #include
> <linux/delay.h> +#include <linux/dmaengine.h> #include
> <linux/dma-mapping.h> +#include <linux/edma.h> #include
> <linux/mmc/mmc.h>
> 
> #include <mach/mmc.h> -#include <mach/edma.h>
> 
> /* * Register Definitions @@ -200,21 +201,13 @@ struct mmc_davinci_host
> { u32 bytes_left;
> 
> u32 rxdma, txdma; +	struct dma_chan *dma_tx; +	struct dma_chan *dma_rx; 
> bool use_dma; bool do_dma; bool sdio_int; bool active_request;
> 
> -	/* Scatterlist DMA uses one or more parameter RAM entries: -	 * the
> main one (associated with rxdma or txdma) plus zero or -	 * more links.
> The entries for a given transfer differ only -	 * by memory buffer
> (address, length) and link field. -	 */ -	struct edmacc_param
> tx_template; -	struct edmacc_param	rx_template; -	unsigned		n_link; -	u32
> links[MAX_NR_SG - 1]; - /* For PIO we walk scatterlists one segment at a
> time. */ unsigned int		sg_len; struct scatterlist *sg; @@ -410,153
> +403,74 @@ static void mmc_davinci_start_command(struct mmc_davinci_host
> *host,
> 
> static void davinci_abort_dma(struct mmc_davinci_host *host) { -	int
> sync_dev; +	struct dma_chan *sync_dev;
> 
> if (host->data_dir == DAVINCI_MMC_DATADIR_READ) -		sync_dev =
> host->rxdma; +		sync_dev = host->dma_rx; else -		sync_dev = host->txdma; 
> - -	edma_stop(sync_dev); -	edma_clean_channel(sync_dev); -} - -static
> void -mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct
> mmc_data *data); - -static void mmc_davinci_dma_cb(unsigned channel, u16
> ch_status, void *data) -{ -	if (DMA_COMPLETE != ch_status) { -		struct
> mmc_davinci_host *host = data; - -		/* Currently means:  DMA Event
> Missed, or "null" transfer -		 * request was seen.  In the future, TC
> errors (like bad -		 * addresses) might be presented too. -		 */ -
> dev_warn(mmc_dev(host->mmc), "DMA %s error\n", -			(host->data->flags &
> MMC_DATA_WRITE) -				? "write" : "read"); -		host->data->error = -EIO; -
> mmc_davinci_xfer_done(host, host->data); -	} -} - -/* Set up tx or rx
> template, to be modified and updated later */ -static void __init
> mmc_davinci_dma_setup(struct mmc_davinci_host *host, -		bool tx, struct
> edmacc_param *template) -{ -	unsigned	sync_dev; -	const u16	acnt = 4; -
> const u16	bcnt = rw_threshold >> 2; -	const u16	ccnt = 0; -	u32		src_port
> = 0; -	u32		dst_port = 0; -	s16		src_bidx, dst_bidx; -	s16		src_cidx,
> dst_cidx; - -	/* -	 * A-B Sync transfer:  each DMA request is for one
> "frame" of -	 * rw_threshold bytes, broken into "acnt"-size chunks
> repeated -	 * "bcnt" times.  Each segment needs "ccnt" such frames;
> since -	 * we tell the block layer our mmc->max_seg_size limit, we can -
> * trust (later) that it's within bounds. -	 * -	 * The FIFOs are
> read/written in 4-byte chunks (acnt == 4) and -	 * EDMA will optimize
> memory operations to use larger bursts. -	 */ -	if (tx) { -		sync_dev =
> host->txdma; - -		/* src_prt, ccnt, and link to be set up later */ -
> src_bidx = acnt; -		src_cidx = acnt * bcnt; - -		dst_port =
> host->mem_res->start + DAVINCI_MMCDXR; -		dst_bidx = 0; -		dst_cidx = 0; 
> -	} else { -		sync_dev = host->rxdma; - -		src_port =
> host->mem_res->start + DAVINCI_MMCDRR; -		src_bidx = 0; -		src_cidx = 0; 
> - -		/* dst_prt, ccnt, and link to be set up later */ -		dst_bidx =
> acnt; -		dst_cidx = acnt * bcnt; -	} - -	/* -	 * We can't use FIFO mode
> for the FIFOs because MMC FIFO addresses -	 * are not 256-bit (32-byte)
> aligned.  So we use INCR, and the W8BIT -	 * parameter is ignored. -	 */ 
> -	edma_set_src(sync_dev, src_port, INCR, W8BIT); -
> edma_set_dest(sync_dev, dst_port, INCR, W8BIT); +		sync_dev =
> host->dma_tx;
> 
> -	edma_set_src_index(sync_dev, src_bidx, src_cidx); -
> edma_set_dest_index(sync_dev, dst_bidx, dst_cidx); - -
> edma_set_transfer_params(sync_dev, acnt, bcnt, ccnt, 8, ABSYNC); - -
> edma_read_slot(sync_dev, template); - -	/* don't bother with irqs or
> chaining */ -	template->opt |= EDMA_CHAN_SLOT(sync_dev) << 12; +
> dmaengine_terminate_all(sync_dev); }
> 
> -static void mmc_davinci_send_dma_request(struct mmc_davinci_host *host, 
> +static int mmc_davinci_send_dma_request(struct mmc_davinci_host *host, 
> struct mmc_data *data) { -	struct edmacc_param	*template; -	int
> channel, slot; -	unsigned		link; -	struct scatterlist	*sg; -	unsigned
> sg_len; -	unsigned		bytes_left = host->bytes_left; -	const unsigned
> shift = ffs(rw_threshold) - 1; +	struct dma_chan *chan; +	struct
> dma_async_tx_descriptor *desc; +	int ret = 0;
> 
> if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) { -		template =
> &host->tx_template; -		channel = host->txdma; +		struct dma_slave_config
> dma_tx_conf = { +			.direction = DMA_MEM_TO_DEV, +			.dst_addr =
> host->mem_res->start + DAVINCI_MMCDXR, +			.dst_addr_width =
> DMA_SLAVE_BUSWIDTH_4_BYTES, +			.dst_maxburst = +				rw_threshold /
> DMA_SLAVE_BUSWIDTH_4_BYTES, +		}; +		chan = host->dma_tx; +
> dmaengine_slave_config(host->dma_tx, &dma_tx_conf); + +		desc =
> dmaengine_prep_slave_sg(host->dma_tx, +				data->sg, +				host->sg_len, +
> DMA_MEM_TO_DEV, +				DMA_PREP_INTERRUPT | DMA_CTRL_ACK); +		if (!desc) { 
> +			dev_dbg(mmc_dev(host->mmc), +				"failed to allocate DMA TX
> descriptor"); +			ret = -1; +			goto out; +		} } else { -		template =
> &host->rx_template; -		channel = host->rxdma; -	} - -	/* We know sg_len
> and ccnt will never be out of range because -	 * we told the mmc layer
> which in turn tells the block layer -	 * to ensure that it only hands us
> one scatterlist segment -	 * per EDMA PARAM entry.  Update the PARAM -	 *
> entries needed for each segment of this scatterlist. -	 */ -	for (slot =
> channel, link = 0, sg = data->sg, sg_len = host->sg_len; -			sg_len-- !=
> 0 && bytes_left; -			sg = sg_next(sg), slot = host->links[link++]) { -
> u32		buf = sg_dma_address(sg); -		unsigned	count = sg_dma_len(sg); - -
> template->link_bcntrld = sg_len -				? (EDMA_CHAN_SLOT(host->links[link])
> << 5) -				: 0xffff; - -		if (count > bytes_left) -			count =
> bytes_left; -		bytes_left -= count; - -		if (host->data_dir ==
> DAVINCI_MMC_DATADIR_WRITE) -			template->src = buf; -		else -
> template->dst = buf; -		template->ccnt = count >> shift; - -
> edma_write_slot(slot, template); +		struct dma_slave_config dma_rx_conf =
> { +			.direction = DMA_DEV_TO_MEM, +			.src_addr = host->mem_res->start +
> DAVINCI_MMCDRR, +			.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, +
> .src_maxburst = +				rw_threshold / DMA_SLAVE_BUSWIDTH_4_BYTES, +		}; +
> chan = host->dma_rx; +		dmaengine_slave_config(host->dma_rx,
> &dma_rx_conf); + +		desc = dmaengine_prep_slave_sg(host->dma_rx, +
> data->sg, +				host->sg_len, +				DMA_DEV_TO_MEM, +				DMA_PREP_INTERRUPT
> | DMA_CTRL_ACK); +		if (!desc) { +			dev_dbg(mmc_dev(host->mmc), +
> "failed to allocate DMA RX descriptor"); +			ret = -1; +			goto out; +
> } }
> 
> -	if (host->version == MMC_CTLR_VERSION_2) -		edma_clear_event(channel); 
> +	dmaengine_submit(desc); +	dma_async_issue_pending(chan);
> 
> -	edma_start(channel); +out: +	return ret; }
> 
> static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host, 
> @@ -564,6 +478,7 @@ static int mmc_davinci_start_dma_transfer(struct
> mmc_davinci_host *host, { int i; int mask = rw_threshold - 1; +	int ret =
> 0;
> 
> host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, 
> ((data->flags & MMC_DATA_WRITE) @@ -583,70 +498,48 @@ static int
> mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host, }
> 
> host->do_dma = 1; -	mmc_davinci_send_dma_request(host, data); +	ret =
> mmc_davinci_send_dma_request(host, data);
> 
> -	return 0; +	return ret; }
> 
> static void __init_or_module davinci_release_dma_channels(struct
> mmc_davinci_host *host) { -	unsigned	i; - if (!host->use_dma) return;
> 
> -	for (i = 0; i < host->n_link; i++) -		edma_free_slot(host->links[i]); 
> - -	edma_free_channel(host->txdma); -	edma_free_channel(host->rxdma); +
> dma_release_channel(host->dma_tx); +	dma_release_channel(host->dma_rx); 
> }
> 
> static int __init davinci_acquire_dma_channels(struct mmc_davinci_host
> *host) { -	u32 link_size; -	int r, i; - -	/* Acquire master DMA write
> channel */ -	r = edma_alloc_channel(host->txdma, mmc_davinci_dma_cb,
> host, -			EVENTQ_DEFAULT); -	if (r < 0) { -		dev_warn(mmc_dev(host->mmc),
> "alloc %s channel err %d\n", -				"tx", r); -		return r; -	} -
> mmc_davinci_dma_setup(host, true, &host->tx_template); - -	/* Acquire
> master DMA read channel */ -	r = edma_alloc_channel(host->rxdma,
> mmc_davinci_dma_cb, host, -			EVENTQ_DEFAULT); -	if (r < 0) { -
> dev_warn(mmc_dev(host->mmc), "alloc %s channel err %d\n", -				"rx", r); 
> -		goto free_master_write; +	int r; +	dma_cap_mask_t mask; + +
> dma_cap_zero(mask); +	dma_cap_set(DMA_SLAVE, mask); + +	host->dma_tx = +
> dma_request_channel(mask, edma_filter_fn, &host->txdma); +	if
> (!host->dma_tx) { +		dev_err(mmc_dev(host->mmc), "Can't get dma_tx
> channel\n"); +		return -ENODEV; } -	mmc_davinci_dma_setup(host, false,
> &host->rx_template);
> 
> -	/* Allocate parameter RAM slots, which will later be bound to a -	 *
> channel as needed to handle a scatterlist. -	 */ -	link_size =
> min_t(unsigned, host->nr_sg, ARRAY_SIZE(host->links)); -	for (i = 0; i <
> link_size; i++) { -		r = edma_alloc_slot(EDMA_CTLR(host->txdma),
> EDMA_SLOT_ANY); -		if (r < 0) { -			dev_dbg(mmc_dev(host->mmc), "dma
> PaRAM alloc --> %d\n", -				r); -			break; -		} -		host->links[i] = r; +
> host->dma_rx = +		dma_request_channel(mask, edma_filter_fn,
> &host->rxdma); +	if (!host->dma_rx) { +		dev_err(mmc_dev(host->mmc),
> "Can't get dma_rx channel\n"); +		r = -ENODEV; +		goto
> free_master_write; } -	host->n_link = i;
> 
> return 0;
> 
> free_master_write: -	edma_free_channel(host->txdma); +
> dma_release_channel(host->dma_tx);
> 
> return r; } @@ -1359,7 +1252,7 @@ static int __init
> davinci_mmcsd_probe(struct platform_device *pdev) * Each hw_seg uses one
> EDMA parameter RAM slot, always one * channel and then usually some
> linked slots. */ -	mmc->max_segs		= 1 + host->n_link; +	mmc->max_segs		=
> MAX_NR_SG;
> 
> /* EDMA limit per hw segment (one or two MBytes) */ mmc->max_seg_size	=
> MAX_CCNT * rw_threshold;
> 

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (Darwin)
Comment: GPGTools - http://gpgtools.org

iD8DBQFQNSq3MkyGM64RGpERAtYeAKCAw+H7rVY1JjuI5sNTDXCpDRiYNgCeKhq/
8QNkFCA4uG1wcb5cg7BjQl0=
=XQE4
-----END PGP SIGNATURE-----


WARNING: multiple messages have this Message-ID (diff)
From: Koen Kooi <koen@dominion.thruhere.net>
To: linux-mmc@vger.kernel.org
Cc: spi-devel-general@lists.sourceforge.net,
	davinci-linux-open-source@linux.davincidsp.com,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org
Cc: spi-devel-general@lists.sourceforge.net,
	linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH v2 2/3] mmc: davinci_mmc: convert to DMA engine API
Date: Wed, 22 Aug 2012 20:53:43 +0200	[thread overview]
Message-ID: <k139rl$gbm$2@ger.gmane.org> (raw)
In-Reply-To: <1345574589-24757-3-git-send-email-mporter@ti.com>

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Op 21-08-12 20:43, Matt Porter schreef:
> Removes use of the DaVinci EDMA private DMA API and replaces it with use
> of the DMA engine API.
> 
> Signed-off-by: Matt Porter <mporter@ti.com>

Runtime tested on hawkboard with 3.6.0-rc2 with rootfs on SD and running
bonnie++ on it.

Tested-by: Koen Kooi <koen@dominion.thruhere.net>

> --- drivers/mmc/host/davinci_mmc.c |  271
> ++++++++++++---------------------------- 1 file changed, 82
> insertions(+), 189 deletions(-)
> 
> diff --git a/drivers/mmc/host/davinci_mmc.c
> b/drivers/mmc/host/davinci_mmc.c index 7cf6c62..c5e1eeb 100644 ---
> a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@
> -30,11 +30,12 @@ #include <linux/io.h> #include <linux/irq.h> #include
> <linux/delay.h> +#include <linux/dmaengine.h> #include
> <linux/dma-mapping.h> +#include <linux/edma.h> #include
> <linux/mmc/mmc.h>
> 
> #include <mach/mmc.h> -#include <mach/edma.h>
> 
> /* * Register Definitions @@ -200,21 +201,13 @@ struct mmc_davinci_host
> { u32 bytes_left;
> 
> u32 rxdma, txdma; +	struct dma_chan *dma_tx; +	struct dma_chan *dma_rx; 
> bool use_dma; bool do_dma; bool sdio_int; bool active_request;
> 
> -	/* Scatterlist DMA uses one or more parameter RAM entries: -	 * the
> main one (associated with rxdma or txdma) plus zero or -	 * more links.
> The entries for a given transfer differ only -	 * by memory buffer
> (address, length) and link field. -	 */ -	struct edmacc_param
> tx_template; -	struct edmacc_param	rx_template; -	unsigned		n_link; -	u32
> links[MAX_NR_SG - 1]; - /* For PIO we walk scatterlists one segment at a
> time. */ unsigned int		sg_len; struct scatterlist *sg; @@ -410,153
> +403,74 @@ static void mmc_davinci_start_command(struct mmc_davinci_host
> *host,
> 
> static void davinci_abort_dma(struct mmc_davinci_host *host) { -	int
> sync_dev; +	struct dma_chan *sync_dev;
> 
> if (host->data_dir == DAVINCI_MMC_DATADIR_READ) -		sync_dev =
> host->rxdma; +		sync_dev = host->dma_rx; else -		sync_dev = host->txdma; 
> - -	edma_stop(sync_dev); -	edma_clean_channel(sync_dev); -} - -static
> void -mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct
> mmc_data *data); - -static void mmc_davinci_dma_cb(unsigned channel, u16
> ch_status, void *data) -{ -	if (DMA_COMPLETE != ch_status) { -		struct
> mmc_davinci_host *host = data; - -		/* Currently means:  DMA Event
> Missed, or "null" transfer -		 * request was seen.  In the future, TC
> errors (like bad -		 * addresses) might be presented too. -		 */ -
> dev_warn(mmc_dev(host->mmc), "DMA %s error\n", -			(host->data->flags &
> MMC_DATA_WRITE) -				? "write" : "read"); -		host->data->error = -EIO; -
> mmc_davinci_xfer_done(host, host->data); -	} -} - -/* Set up tx or rx
> template, to be modified and updated later */ -static void __init
> mmc_davinci_dma_setup(struct mmc_davinci_host *host, -		bool tx, struct
> edmacc_param *template) -{ -	unsigned	sync_dev; -	const u16	acnt = 4; -
> const u16	bcnt = rw_threshold >> 2; -	const u16	ccnt = 0; -	u32		src_port
> = 0; -	u32		dst_port = 0; -	s16		src_bidx, dst_bidx; -	s16		src_cidx,
> dst_cidx; - -	/* -	 * A-B Sync transfer:  each DMA request is for one
> "frame" of -	 * rw_threshold bytes, broken into "acnt"-size chunks
> repeated -	 * "bcnt" times.  Each segment needs "ccnt" such frames;
> since -	 * we tell the block layer our mmc->max_seg_size limit, we can -
> * trust (later) that it's within bounds. -	 * -	 * The FIFOs are
> read/written in 4-byte chunks (acnt == 4) and -	 * EDMA will optimize
> memory operations to use larger bursts. -	 */ -	if (tx) { -		sync_dev =
> host->txdma; - -		/* src_prt, ccnt, and link to be set up later */ -
> src_bidx = acnt; -		src_cidx = acnt * bcnt; - -		dst_port =
> host->mem_res->start + DAVINCI_MMCDXR; -		dst_bidx = 0; -		dst_cidx = 0; 
> -	} else { -		sync_dev = host->rxdma; - -		src_port =
> host->mem_res->start + DAVINCI_MMCDRR; -		src_bidx = 0; -		src_cidx = 0; 
> - -		/* dst_prt, ccnt, and link to be set up later */ -		dst_bidx =
> acnt; -		dst_cidx = acnt * bcnt; -	} - -	/* -	 * We can't use FIFO mode
> for the FIFOs because MMC FIFO addresses -	 * are not 256-bit (32-byte)
> aligned.  So we use INCR, and the W8BIT -	 * parameter is ignored. -	 */ 
> -	edma_set_src(sync_dev, src_port, INCR, W8BIT); -
> edma_set_dest(sync_dev, dst_port, INCR, W8BIT); +		sync_dev =
> host->dma_tx;
> 
> -	edma_set_src_index(sync_dev, src_bidx, src_cidx); -
> edma_set_dest_index(sync_dev, dst_bidx, dst_cidx); - -
> edma_set_transfer_params(sync_dev, acnt, bcnt, ccnt, 8, ABSYNC); - -
> edma_read_slot(sync_dev, template); - -	/* don't bother with irqs or
> chaining */ -	template->opt |= EDMA_CHAN_SLOT(sync_dev) << 12; +
> dmaengine_terminate_all(sync_dev); }
> 
> -static void mmc_davinci_send_dma_request(struct mmc_davinci_host *host, 
> +static int mmc_davinci_send_dma_request(struct mmc_davinci_host *host, 
> struct mmc_data *data) { -	struct edmacc_param	*template; -	int
> channel, slot; -	unsigned		link; -	struct scatterlist	*sg; -	unsigned
> sg_len; -	unsigned		bytes_left = host->bytes_left; -	const unsigned
> shift = ffs(rw_threshold) - 1; +	struct dma_chan *chan; +	struct
> dma_async_tx_descriptor *desc; +	int ret = 0;
> 
> if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) { -		template =
> &host->tx_template; -		channel = host->txdma; +		struct dma_slave_config
> dma_tx_conf = { +			.direction = DMA_MEM_TO_DEV, +			.dst_addr =
> host->mem_res->start + DAVINCI_MMCDXR, +			.dst_addr_width =
> DMA_SLAVE_BUSWIDTH_4_BYTES, +			.dst_maxburst = +				rw_threshold /
> DMA_SLAVE_BUSWIDTH_4_BYTES, +		}; +		chan = host->dma_tx; +
> dmaengine_slave_config(host->dma_tx, &dma_tx_conf); + +		desc =
> dmaengine_prep_slave_sg(host->dma_tx, +				data->sg, +				host->sg_len, +
> DMA_MEM_TO_DEV, +				DMA_PREP_INTERRUPT | DMA_CTRL_ACK); +		if (!desc) { 
> +			dev_dbg(mmc_dev(host->mmc), +				"failed to allocate DMA TX
> descriptor"); +			ret = -1; +			goto out; +		} } else { -		template =
> &host->rx_template; -		channel = host->rxdma; -	} - -	/* We know sg_len
> and ccnt will never be out of range because -	 * we told the mmc layer
> which in turn tells the block layer -	 * to ensure that it only hands us
> one scatterlist segment -	 * per EDMA PARAM entry.  Update the PARAM -	 *
> entries needed for each segment of this scatterlist. -	 */ -	for (slot =
> channel, link = 0, sg = data->sg, sg_len = host->sg_len; -			sg_len-- !=
> 0 && bytes_left; -			sg = sg_next(sg), slot = host->links[link++]) { -
> u32		buf = sg_dma_address(sg); -		unsigned	count = sg_dma_len(sg); - -
> template->link_bcntrld = sg_len -				? (EDMA_CHAN_SLOT(host->links[link])
> << 5) -				: 0xffff; - -		if (count > bytes_left) -			count =
> bytes_left; -		bytes_left -= count; - -		if (host->data_dir ==
> DAVINCI_MMC_DATADIR_WRITE) -			template->src = buf; -		else -
> template->dst = buf; -		template->ccnt = count >> shift; - -
> edma_write_slot(slot, template); +		struct dma_slave_config dma_rx_conf =
> { +			.direction = DMA_DEV_TO_MEM, +			.src_addr = host->mem_res->start +
> DAVINCI_MMCDRR, +			.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, +
> .src_maxburst = +				rw_threshold / DMA_SLAVE_BUSWIDTH_4_BYTES, +		}; +
> chan = host->dma_rx; +		dmaengine_slave_config(host->dma_rx,
> &dma_rx_conf); + +		desc = dmaengine_prep_slave_sg(host->dma_rx, +
> data->sg, +				host->sg_len, +				DMA_DEV_TO_MEM, +				DMA_PREP_INTERRUPT
> | DMA_CTRL_ACK); +		if (!desc) { +			dev_dbg(mmc_dev(host->mmc), +
> "failed to allocate DMA RX descriptor"); +			ret = -1; +			goto out; +
> } }
> 
> -	if (host->version == MMC_CTLR_VERSION_2) -		edma_clear_event(channel); 
> +	dmaengine_submit(desc); +	dma_async_issue_pending(chan);
> 
> -	edma_start(channel); +out: +	return ret; }
> 
> static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host, 
> @@ -564,6 +478,7 @@ static int mmc_davinci_start_dma_transfer(struct
> mmc_davinci_host *host, { int i; int mask = rw_threshold - 1; +	int ret =
> 0;
> 
> host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, 
> ((data->flags & MMC_DATA_WRITE) @@ -583,70 +498,48 @@ static int
> mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host, }
> 
> host->do_dma = 1; -	mmc_davinci_send_dma_request(host, data); +	ret =
> mmc_davinci_send_dma_request(host, data);
> 
> -	return 0; +	return ret; }
> 
> static void __init_or_module davinci_release_dma_channels(struct
> mmc_davinci_host *host) { -	unsigned	i; - if (!host->use_dma) return;
> 
> -	for (i = 0; i < host->n_link; i++) -		edma_free_slot(host->links[i]); 
> - -	edma_free_channel(host->txdma); -	edma_free_channel(host->rxdma); +
> dma_release_channel(host->dma_tx); +	dma_release_channel(host->dma_rx); 
> }
> 
> static int __init davinci_acquire_dma_channels(struct mmc_davinci_host
> *host) { -	u32 link_size; -	int r, i; - -	/* Acquire master DMA write
> channel */ -	r = edma_alloc_channel(host->txdma, mmc_davinci_dma_cb,
> host, -			EVENTQ_DEFAULT); -	if (r < 0) { -		dev_warn(mmc_dev(host->mmc),
> "alloc %s channel err %d\n", -				"tx", r); -		return r; -	} -
> mmc_davinci_dma_setup(host, true, &host->tx_template); - -	/* Acquire
> master DMA read channel */ -	r = edma_alloc_channel(host->rxdma,
> mmc_davinci_dma_cb, host, -			EVENTQ_DEFAULT); -	if (r < 0) { -
> dev_warn(mmc_dev(host->mmc), "alloc %s channel err %d\n", -				"rx", r); 
> -		goto free_master_write; +	int r; +	dma_cap_mask_t mask; + +
> dma_cap_zero(mask); +	dma_cap_set(DMA_SLAVE, mask); + +	host->dma_tx = +
> dma_request_channel(mask, edma_filter_fn, &host->txdma); +	if
> (!host->dma_tx) { +		dev_err(mmc_dev(host->mmc), "Can't get dma_tx
> channel\n"); +		return -ENODEV; } -	mmc_davinci_dma_setup(host, false,
> &host->rx_template);
> 
> -	/* Allocate parameter RAM slots, which will later be bound to a -	 *
> channel as needed to handle a scatterlist. -	 */ -	link_size =
> min_t(unsigned, host->nr_sg, ARRAY_SIZE(host->links)); -	for (i = 0; i <
> link_size; i++) { -		r = edma_alloc_slot(EDMA_CTLR(host->txdma),
> EDMA_SLOT_ANY); -		if (r < 0) { -			dev_dbg(mmc_dev(host->mmc), "dma
> PaRAM alloc --> %d\n", -				r); -			break; -		} -		host->links[i] = r; +
> host->dma_rx = +		dma_request_channel(mask, edma_filter_fn,
> &host->rxdma); +	if (!host->dma_rx) { +		dev_err(mmc_dev(host->mmc),
> "Can't get dma_rx channel\n"); +		r = -ENODEV; +		goto
> free_master_write; } -	host->n_link = i;
> 
> return 0;
> 
> free_master_write: -	edma_free_channel(host->txdma); +
> dma_release_channel(host->dma_tx);
> 
> return r; } @@ -1359,7 +1252,7 @@ static int __init
> davinci_mmcsd_probe(struct platform_device *pdev) * Each hw_seg uses one
> EDMA parameter RAM slot, always one * channel and then usually some
> linked slots. */ -	mmc->max_segs		= 1 + host->n_link; +	mmc->max_segs		=
> MAX_NR_SG;
> 
> /* EDMA limit per hw segment (one or two MBytes) */ mmc->max_seg_size	=
> MAX_CCNT * rw_threshold;
> 

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (Darwin)
Comment: GPGTools - http://gpgtools.org

iD8DBQFQNSq3MkyGM64RGpERAtYeAKCAw+H7rVY1JjuI5sNTDXCpDRiYNgCeKhq/
8QNkFCA4uG1wcb5cg7BjQl0=
=XQE4
-----END PGP SIGNATURE-----


WARNING: multiple messages have this Message-ID (diff)
From: koen@dominion.thruhere.net (Koen Kooi)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v2 2/3] mmc: davinci_mmc: convert to DMA engine API
Date: Wed, 22 Aug 2012 20:53:43 +0200	[thread overview]
Message-ID: <k139rl$gbm$2@ger.gmane.org> (raw)
In-Reply-To: <1345574589-24757-3-git-send-email-mporter@ti.com>

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Op 21-08-12 20:43, Matt Porter schreef:
> Removes use of the DaVinci EDMA private DMA API and replaces it with use
> of the DMA engine API.
> 
> Signed-off-by: Matt Porter <mporter@ti.com>

Runtime tested on hawkboard with 3.6.0-rc2 with rootfs on SD and running
bonnie++ on it.

Tested-by: Koen Kooi <koen@dominion.thruhere.net>

> --- drivers/mmc/host/davinci_mmc.c |  271
> ++++++++++++---------------------------- 1 file changed, 82
> insertions(+), 189 deletions(-)
> 
> diff --git a/drivers/mmc/host/davinci_mmc.c
> b/drivers/mmc/host/davinci_mmc.c index 7cf6c62..c5e1eeb 100644 ---
> a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@
> -30,11 +30,12 @@ #include <linux/io.h> #include <linux/irq.h> #include
> <linux/delay.h> +#include <linux/dmaengine.h> #include
> <linux/dma-mapping.h> +#include <linux/edma.h> #include
> <linux/mmc/mmc.h>
> 
> #include <mach/mmc.h> -#include <mach/edma.h>
> 
> /* * Register Definitions @@ -200,21 +201,13 @@ struct mmc_davinci_host
> { u32 bytes_left;
> 
> u32 rxdma, txdma; +	struct dma_chan *dma_tx; +	struct dma_chan *dma_rx; 
> bool use_dma; bool do_dma; bool sdio_int; bool active_request;
> 
> -	/* Scatterlist DMA uses one or more parameter RAM entries: -	 * the
> main one (associated with rxdma or txdma) plus zero or -	 * more links.
> The entries for a given transfer differ only -	 * by memory buffer
> (address, length) and link field. -	 */ -	struct edmacc_param
> tx_template; -	struct edmacc_param	rx_template; -	unsigned		n_link; -	u32
> links[MAX_NR_SG - 1]; - /* For PIO we walk scatterlists one segment at a
> time. */ unsigned int		sg_len; struct scatterlist *sg; @@ -410,153
> +403,74 @@ static void mmc_davinci_start_command(struct mmc_davinci_host
> *host,
> 
> static void davinci_abort_dma(struct mmc_davinci_host *host) { -	int
> sync_dev; +	struct dma_chan *sync_dev;
> 
> if (host->data_dir == DAVINCI_MMC_DATADIR_READ) -		sync_dev =
> host->rxdma; +		sync_dev = host->dma_rx; else -		sync_dev = host->txdma; 
> - -	edma_stop(sync_dev); -	edma_clean_channel(sync_dev); -} - -static
> void -mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct
> mmc_data *data); - -static void mmc_davinci_dma_cb(unsigned channel, u16
> ch_status, void *data) -{ -	if (DMA_COMPLETE != ch_status) { -		struct
> mmc_davinci_host *host = data; - -		/* Currently means:  DMA Event
> Missed, or "null" transfer -		 * request was seen.  In the future, TC
> errors (like bad -		 * addresses) might be presented too. -		 */ -
> dev_warn(mmc_dev(host->mmc), "DMA %s error\n", -			(host->data->flags &
> MMC_DATA_WRITE) -				? "write" : "read"); -		host->data->error = -EIO; -
> mmc_davinci_xfer_done(host, host->data); -	} -} - -/* Set up tx or rx
> template, to be modified and updated later */ -static void __init
> mmc_davinci_dma_setup(struct mmc_davinci_host *host, -		bool tx, struct
> edmacc_param *template) -{ -	unsigned	sync_dev; -	const u16	acnt = 4; -
> const u16	bcnt = rw_threshold >> 2; -	const u16	ccnt = 0; -	u32		src_port
> = 0; -	u32		dst_port = 0; -	s16		src_bidx, dst_bidx; -	s16		src_cidx,
> dst_cidx; - -	/* -	 * A-B Sync transfer:  each DMA request is for one
> "frame" of -	 * rw_threshold bytes, broken into "acnt"-size chunks
> repeated -	 * "bcnt" times.  Each segment needs "ccnt" such frames;
> since -	 * we tell the block layer our mmc->max_seg_size limit, we can -
> * trust (later) that it's within bounds. -	 * -	 * The FIFOs are
> read/written in 4-byte chunks (acnt == 4) and -	 * EDMA will optimize
> memory operations to use larger bursts. -	 */ -	if (tx) { -		sync_dev =
> host->txdma; - -		/* src_prt, ccnt, and link to be set up later */ -
> src_bidx = acnt; -		src_cidx = acnt * bcnt; - -		dst_port =
> host->mem_res->start + DAVINCI_MMCDXR; -		dst_bidx = 0; -		dst_cidx = 0; 
> -	} else { -		sync_dev = host->rxdma; - -		src_port =
> host->mem_res->start + DAVINCI_MMCDRR; -		src_bidx = 0; -		src_cidx = 0; 
> - -		/* dst_prt, ccnt, and link to be set up later */ -		dst_bidx =
> acnt; -		dst_cidx = acnt * bcnt; -	} - -	/* -	 * We can't use FIFO mode
> for the FIFOs because MMC FIFO addresses -	 * are not 256-bit (32-byte)
> aligned.  So we use INCR, and the W8BIT -	 * parameter is ignored. -	 */ 
> -	edma_set_src(sync_dev, src_port, INCR, W8BIT); -
> edma_set_dest(sync_dev, dst_port, INCR, W8BIT); +		sync_dev =
> host->dma_tx;
> 
> -	edma_set_src_index(sync_dev, src_bidx, src_cidx); -
> edma_set_dest_index(sync_dev, dst_bidx, dst_cidx); - -
> edma_set_transfer_params(sync_dev, acnt, bcnt, ccnt, 8, ABSYNC); - -
> edma_read_slot(sync_dev, template); - -	/* don't bother with irqs or
> chaining */ -	template->opt |= EDMA_CHAN_SLOT(sync_dev) << 12; +
> dmaengine_terminate_all(sync_dev); }
> 
> -static void mmc_davinci_send_dma_request(struct mmc_davinci_host *host, 
> +static int mmc_davinci_send_dma_request(struct mmc_davinci_host *host, 
> struct mmc_data *data) { -	struct edmacc_param	*template; -	int
> channel, slot; -	unsigned		link; -	struct scatterlist	*sg; -	unsigned
> sg_len; -	unsigned		bytes_left = host->bytes_left; -	const unsigned
> shift = ffs(rw_threshold) - 1; +	struct dma_chan *chan; +	struct
> dma_async_tx_descriptor *desc; +	int ret = 0;
> 
> if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) { -		template =
> &host->tx_template; -		channel = host->txdma; +		struct dma_slave_config
> dma_tx_conf = { +			.direction = DMA_MEM_TO_DEV, +			.dst_addr =
> host->mem_res->start + DAVINCI_MMCDXR, +			.dst_addr_width =
> DMA_SLAVE_BUSWIDTH_4_BYTES, +			.dst_maxburst = +				rw_threshold /
> DMA_SLAVE_BUSWIDTH_4_BYTES, +		}; +		chan = host->dma_tx; +
> dmaengine_slave_config(host->dma_tx, &dma_tx_conf); + +		desc =
> dmaengine_prep_slave_sg(host->dma_tx, +				data->sg, +				host->sg_len, +
> DMA_MEM_TO_DEV, +				DMA_PREP_INTERRUPT | DMA_CTRL_ACK); +		if (!desc) { 
> +			dev_dbg(mmc_dev(host->mmc), +				"failed to allocate DMA TX
> descriptor"); +			ret = -1; +			goto out; +		} } else { -		template =
> &host->rx_template; -		channel = host->rxdma; -	} - -	/* We know sg_len
> and ccnt will never be out of range because -	 * we told the mmc layer
> which in turn tells the block layer -	 * to ensure that it only hands us
> one scatterlist segment -	 * per EDMA PARAM entry.  Update the PARAM -	 *
> entries needed for each segment of this scatterlist. -	 */ -	for (slot =
> channel, link = 0, sg = data->sg, sg_len = host->sg_len; -			sg_len-- !=
> 0 && bytes_left; -			sg = sg_next(sg), slot = host->links[link++]) { -
> u32		buf = sg_dma_address(sg); -		unsigned	count = sg_dma_len(sg); - -
> template->link_bcntrld = sg_len -				? (EDMA_CHAN_SLOT(host->links[link])
> << 5) -				: 0xffff; - -		if (count > bytes_left) -			count =
> bytes_left; -		bytes_left -= count; - -		if (host->data_dir ==
> DAVINCI_MMC_DATADIR_WRITE) -			template->src = buf; -		else -
> template->dst = buf; -		template->ccnt = count >> shift; - -
> edma_write_slot(slot, template); +		struct dma_slave_config dma_rx_conf =
> { +			.direction = DMA_DEV_TO_MEM, +			.src_addr = host->mem_res->start +
> DAVINCI_MMCDRR, +			.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, +
> .src_maxburst = +				rw_threshold / DMA_SLAVE_BUSWIDTH_4_BYTES, +		}; +
> chan = host->dma_rx; +		dmaengine_slave_config(host->dma_rx,
> &dma_rx_conf); + +		desc = dmaengine_prep_slave_sg(host->dma_rx, +
> data->sg, +				host->sg_len, +				DMA_DEV_TO_MEM, +				DMA_PREP_INTERRUPT
> | DMA_CTRL_ACK); +		if (!desc) { +			dev_dbg(mmc_dev(host->mmc), +
> "failed to allocate DMA RX descriptor"); +			ret = -1; +			goto out; +
> } }
> 
> -	if (host->version == MMC_CTLR_VERSION_2) -		edma_clear_event(channel); 
> +	dmaengine_submit(desc); +	dma_async_issue_pending(chan);
> 
> -	edma_start(channel); +out: +	return ret; }
> 
> static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host, 
> @@ -564,6 +478,7 @@ static int mmc_davinci_start_dma_transfer(struct
> mmc_davinci_host *host, { int i; int mask = rw_threshold - 1; +	int ret =
> 0;
> 
> host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, 
> ((data->flags & MMC_DATA_WRITE) @@ -583,70 +498,48 @@ static int
> mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host, }
> 
> host->do_dma = 1; -	mmc_davinci_send_dma_request(host, data); +	ret =
> mmc_davinci_send_dma_request(host, data);
> 
> -	return 0; +	return ret; }
> 
> static void __init_or_module davinci_release_dma_channels(struct
> mmc_davinci_host *host) { -	unsigned	i; - if (!host->use_dma) return;
> 
> -	for (i = 0; i < host->n_link; i++) -		edma_free_slot(host->links[i]); 
> - -	edma_free_channel(host->txdma); -	edma_free_channel(host->rxdma); +
> dma_release_channel(host->dma_tx); +	dma_release_channel(host->dma_rx); 
> }
> 
> static int __init davinci_acquire_dma_channels(struct mmc_davinci_host
> *host) { -	u32 link_size; -	int r, i; - -	/* Acquire master DMA write
> channel */ -	r = edma_alloc_channel(host->txdma, mmc_davinci_dma_cb,
> host, -			EVENTQ_DEFAULT); -	if (r < 0) { -		dev_warn(mmc_dev(host->mmc),
> "alloc %s channel err %d\n", -				"tx", r); -		return r; -	} -
> mmc_davinci_dma_setup(host, true, &host->tx_template); - -	/* Acquire
> master DMA read channel */ -	r = edma_alloc_channel(host->rxdma,
> mmc_davinci_dma_cb, host, -			EVENTQ_DEFAULT); -	if (r < 0) { -
> dev_warn(mmc_dev(host->mmc), "alloc %s channel err %d\n", -				"rx", r); 
> -		goto free_master_write; +	int r; +	dma_cap_mask_t mask; + +
> dma_cap_zero(mask); +	dma_cap_set(DMA_SLAVE, mask); + +	host->dma_tx = +
> dma_request_channel(mask, edma_filter_fn, &host->txdma); +	if
> (!host->dma_tx) { +		dev_err(mmc_dev(host->mmc), "Can't get dma_tx
> channel\n"); +		return -ENODEV; } -	mmc_davinci_dma_setup(host, false,
> &host->rx_template);
> 
> -	/* Allocate parameter RAM slots, which will later be bound to a -	 *
> channel as needed to handle a scatterlist. -	 */ -	link_size =
> min_t(unsigned, host->nr_sg, ARRAY_SIZE(host->links)); -	for (i = 0; i <
> link_size; i++) { -		r = edma_alloc_slot(EDMA_CTLR(host->txdma),
> EDMA_SLOT_ANY); -		if (r < 0) { -			dev_dbg(mmc_dev(host->mmc), "dma
> PaRAM alloc --> %d\n", -				r); -			break; -		} -		host->links[i] = r; +
> host->dma_rx = +		dma_request_channel(mask, edma_filter_fn,
> &host->rxdma); +	if (!host->dma_rx) { +		dev_err(mmc_dev(host->mmc),
> "Can't get dma_rx channel\n"); +		r = -ENODEV; +		goto
> free_master_write; } -	host->n_link = i;
> 
> return 0;
> 
> free_master_write: -	edma_free_channel(host->txdma); +
> dma_release_channel(host->dma_tx);
> 
> return r; } @@ -1359,7 +1252,7 @@ static int __init
> davinci_mmcsd_probe(struct platform_device *pdev) * Each hw_seg uses one
> EDMA parameter RAM slot, always one * channel and then usually some
> linked slots. */ -	mmc->max_segs		= 1 + host->n_link; +	mmc->max_segs		=
> MAX_NR_SG;
> 
> /* EDMA limit per hw segment (one or two MBytes) */ mmc->max_seg_size	=
> MAX_CCNT * rw_threshold;
> 

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (Darwin)
Comment: GPGTools - http://gpgtools.org

iD8DBQFQNSq3MkyGM64RGpERAtYeAKCAw+H7rVY1JjuI5sNTDXCpDRiYNgCeKhq/
8QNkFCA4uG1wcb5cg7BjQl0=
=XQE4
-----END PGP SIGNATURE-----

WARNING: multiple messages have this Message-ID (diff)
From: Koen Kooi <koen@dominion.thruhere.net>
To: linux-kernel@vger.kernel.org
Cc: spi-devel-general@lists.sourceforge.net,
	davinci-linux-open-source@linux.davincidsp.com,
	linux-mmc@vger.kernel.org, linux-arm-kernel@lists.infradead.org
Cc: spi-devel-general@lists.sourceforge.net,
	linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH v2 2/3] mmc: davinci_mmc: convert to DMA engine API
Date: Wed, 22 Aug 2012 20:53:43 +0200	[thread overview]
Message-ID: <k139rl$gbm$2@ger.gmane.org> (raw)
In-Reply-To: <1345574589-24757-3-git-send-email-mporter@ti.com>

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Op 21-08-12 20:43, Matt Porter schreef:
> Removes use of the DaVinci EDMA private DMA API and replaces it with use
> of the DMA engine API.
> 
> Signed-off-by: Matt Porter <mporter@ti.com>

Runtime tested on hawkboard with 3.6.0-rc2 with rootfs on SD and running
bonnie++ on it.

Tested-by: Koen Kooi <koen@dominion.thruhere.net>

> --- drivers/mmc/host/davinci_mmc.c |  271
> ++++++++++++---------------------------- 1 file changed, 82
> insertions(+), 189 deletions(-)
> 
> diff --git a/drivers/mmc/host/davinci_mmc.c
> b/drivers/mmc/host/davinci_mmc.c index 7cf6c62..c5e1eeb 100644 ---
> a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@
> -30,11 +30,12 @@ #include <linux/io.h> #include <linux/irq.h> #include
> <linux/delay.h> +#include <linux/dmaengine.h> #include
> <linux/dma-mapping.h> +#include <linux/edma.h> #include
> <linux/mmc/mmc.h>
> 
> #include <mach/mmc.h> -#include <mach/edma.h>
> 
> /* * Register Definitions @@ -200,21 +201,13 @@ struct mmc_davinci_host
> { u32 bytes_left;
> 
> u32 rxdma, txdma; +	struct dma_chan *dma_tx; +	struct dma_chan *dma_rx; 
> bool use_dma; bool do_dma; bool sdio_int; bool active_request;
> 
> -	/* Scatterlist DMA uses one or more parameter RAM entries: -	 * the
> main one (associated with rxdma or txdma) plus zero or -	 * more links.
> The entries for a given transfer differ only -	 * by memory buffer
> (address, length) and link field. -	 */ -	struct edmacc_param
> tx_template; -	struct edmacc_param	rx_template; -	unsigned		n_link; -	u32
> links[MAX_NR_SG - 1]; - /* For PIO we walk scatterlists one segment at a
> time. */ unsigned int		sg_len; struct scatterlist *sg; @@ -410,153
> +403,74 @@ static void mmc_davinci_start_command(struct mmc_davinci_host
> *host,
> 
> static void davinci_abort_dma(struct mmc_davinci_host *host) { -	int
> sync_dev; +	struct dma_chan *sync_dev;
> 
> if (host->data_dir == DAVINCI_MMC_DATADIR_READ) -		sync_dev =
> host->rxdma; +		sync_dev = host->dma_rx; else -		sync_dev = host->txdma; 
> - -	edma_stop(sync_dev); -	edma_clean_channel(sync_dev); -} - -static
> void -mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct
> mmc_data *data); - -static void mmc_davinci_dma_cb(unsigned channel, u16
> ch_status, void *data) -{ -	if (DMA_COMPLETE != ch_status) { -		struct
> mmc_davinci_host *host = data; - -		/* Currently means:  DMA Event
> Missed, or "null" transfer -		 * request was seen.  In the future, TC
> errors (like bad -		 * addresses) might be presented too. -		 */ -
> dev_warn(mmc_dev(host->mmc), "DMA %s error\n", -			(host->data->flags &
> MMC_DATA_WRITE) -				? "write" : "read"); -		host->data->error = -EIO; -
> mmc_davinci_xfer_done(host, host->data); -	} -} - -/* Set up tx or rx
> template, to be modified and updated later */ -static void __init
> mmc_davinci_dma_setup(struct mmc_davinci_host *host, -		bool tx, struct
> edmacc_param *template) -{ -	unsigned	sync_dev; -	const u16	acnt = 4; -
> const u16	bcnt = rw_threshold >> 2; -	const u16	ccnt = 0; -	u32		src_port
> = 0; -	u32		dst_port = 0; -	s16		src_bidx, dst_bidx; -	s16		src_cidx,
> dst_cidx; - -	/* -	 * A-B Sync transfer:  each DMA request is for one
> "frame" of -	 * rw_threshold bytes, broken into "acnt"-size chunks
> repeated -	 * "bcnt" times.  Each segment needs "ccnt" such frames;
> since -	 * we tell the block layer our mmc->max_seg_size limit, we can -
> * trust (later) that it's within bounds. -	 * -	 * The FIFOs are
> read/written in 4-byte chunks (acnt == 4) and -	 * EDMA will optimize
> memory operations to use larger bursts. -	 */ -	if (tx) { -		sync_dev =
> host->txdma; - -		/* src_prt, ccnt, and link to be set up later */ -
> src_bidx = acnt; -		src_cidx = acnt * bcnt; - -		dst_port =
> host->mem_res->start + DAVINCI_MMCDXR; -		dst_bidx = 0; -		dst_cidx = 0; 
> -	} else { -		sync_dev = host->rxdma; - -		src_port =
> host->mem_res->start + DAVINCI_MMCDRR; -		src_bidx = 0; -		src_cidx = 0; 
> - -		/* dst_prt, ccnt, and link to be set up later */ -		dst_bidx =
> acnt; -		dst_cidx = acnt * bcnt; -	} - -	/* -	 * We can't use FIFO mode
> for the FIFOs because MMC FIFO addresses -	 * are not 256-bit (32-byte)
> aligned.  So we use INCR, and the W8BIT -	 * parameter is ignored. -	 */ 
> -	edma_set_src(sync_dev, src_port, INCR, W8BIT); -
> edma_set_dest(sync_dev, dst_port, INCR, W8BIT); +		sync_dev =
> host->dma_tx;
> 
> -	edma_set_src_index(sync_dev, src_bidx, src_cidx); -
> edma_set_dest_index(sync_dev, dst_bidx, dst_cidx); - -
> edma_set_transfer_params(sync_dev, acnt, bcnt, ccnt, 8, ABSYNC); - -
> edma_read_slot(sync_dev, template); - -	/* don't bother with irqs or
> chaining */ -	template->opt |= EDMA_CHAN_SLOT(sync_dev) << 12; +
> dmaengine_terminate_all(sync_dev); }
> 
> -static void mmc_davinci_send_dma_request(struct mmc_davinci_host *host, 
> +static int mmc_davinci_send_dma_request(struct mmc_davinci_host *host, 
> struct mmc_data *data) { -	struct edmacc_param	*template; -	int
> channel, slot; -	unsigned		link; -	struct scatterlist	*sg; -	unsigned
> sg_len; -	unsigned		bytes_left = host->bytes_left; -	const unsigned
> shift = ffs(rw_threshold) - 1; +	struct dma_chan *chan; +	struct
> dma_async_tx_descriptor *desc; +	int ret = 0;
> 
> if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) { -		template =
> &host->tx_template; -		channel = host->txdma; +		struct dma_slave_config
> dma_tx_conf = { +			.direction = DMA_MEM_TO_DEV, +			.dst_addr =
> host->mem_res->start + DAVINCI_MMCDXR, +			.dst_addr_width =
> DMA_SLAVE_BUSWIDTH_4_BYTES, +			.dst_maxburst = +				rw_threshold /
> DMA_SLAVE_BUSWIDTH_4_BYTES, +		}; +		chan = host->dma_tx; +
> dmaengine_slave_config(host->dma_tx, &dma_tx_conf); + +		desc =
> dmaengine_prep_slave_sg(host->dma_tx, +				data->sg, +				host->sg_len, +
> DMA_MEM_TO_DEV, +				DMA_PREP_INTERRUPT | DMA_CTRL_ACK); +		if (!desc) { 
> +			dev_dbg(mmc_dev(host->mmc), +				"failed to allocate DMA TX
> descriptor"); +			ret = -1; +			goto out; +		} } else { -		template =
> &host->rx_template; -		channel = host->rxdma; -	} - -	/* We know sg_len
> and ccnt will never be out of range because -	 * we told the mmc layer
> which in turn tells the block layer -	 * to ensure that it only hands us
> one scatterlist segment -	 * per EDMA PARAM entry.  Update the PARAM -	 *
> entries needed for each segment of this scatterlist. -	 */ -	for (slot =
> channel, link = 0, sg = data->sg, sg_len = host->sg_len; -			sg_len-- !=
> 0 && bytes_left; -			sg = sg_next(sg), slot = host->links[link++]) { -
> u32		buf = sg_dma_address(sg); -		unsigned	count = sg_dma_len(sg); - -
> template->link_bcntrld = sg_len -				? (EDMA_CHAN_SLOT(host->links[link])
> << 5) -				: 0xffff; - -		if (count > bytes_left) -			count =
> bytes_left; -		bytes_left -= count; - -		if (host->data_dir ==
> DAVINCI_MMC_DATADIR_WRITE) -			template->src = buf; -		else -
> template->dst = buf; -		template->ccnt = count >> shift; - -
> edma_write_slot(slot, template); +		struct dma_slave_config dma_rx_conf =
> { +			.direction = DMA_DEV_TO_MEM, +			.src_addr = host->mem_res->start +
> DAVINCI_MMCDRR, +			.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, +
> .src_maxburst = +				rw_threshold / DMA_SLAVE_BUSWIDTH_4_BYTES, +		}; +
> chan = host->dma_rx; +		dmaengine_slave_config(host->dma_rx,
> &dma_rx_conf); + +		desc = dmaengine_prep_slave_sg(host->dma_rx, +
> data->sg, +				host->sg_len, +				DMA_DEV_TO_MEM, +				DMA_PREP_INTERRUPT
> | DMA_CTRL_ACK); +		if (!desc) { +			dev_dbg(mmc_dev(host->mmc), +
> "failed to allocate DMA RX descriptor"); +			ret = -1; +			goto out; +
> } }
> 
> -	if (host->version == MMC_CTLR_VERSION_2) -		edma_clear_event(channel); 
> +	dmaengine_submit(desc); +	dma_async_issue_pending(chan);
> 
> -	edma_start(channel); +out: +	return ret; }
> 
> static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host, 
> @@ -564,6 +478,7 @@ static int mmc_davinci_start_dma_transfer(struct
> mmc_davinci_host *host, { int i; int mask = rw_threshold - 1; +	int ret =
> 0;
> 
> host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, 
> ((data->flags & MMC_DATA_WRITE) @@ -583,70 +498,48 @@ static int
> mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host, }
> 
> host->do_dma = 1; -	mmc_davinci_send_dma_request(host, data); +	ret =
> mmc_davinci_send_dma_request(host, data);
> 
> -	return 0; +	return ret; }
> 
> static void __init_or_module davinci_release_dma_channels(struct
> mmc_davinci_host *host) { -	unsigned	i; - if (!host->use_dma) return;
> 
> -	for (i = 0; i < host->n_link; i++) -		edma_free_slot(host->links[i]); 
> - -	edma_free_channel(host->txdma); -	edma_free_channel(host->rxdma); +
> dma_release_channel(host->dma_tx); +	dma_release_channel(host->dma_rx); 
> }
> 
> static int __init davinci_acquire_dma_channels(struct mmc_davinci_host
> *host) { -	u32 link_size; -	int r, i; - -	/* Acquire master DMA write
> channel */ -	r = edma_alloc_channel(host->txdma, mmc_davinci_dma_cb,
> host, -			EVENTQ_DEFAULT); -	if (r < 0) { -		dev_warn(mmc_dev(host->mmc),
> "alloc %s channel err %d\n", -				"tx", r); -		return r; -	} -
> mmc_davinci_dma_setup(host, true, &host->tx_template); - -	/* Acquire
> master DMA read channel */ -	r = edma_alloc_channel(host->rxdma,
> mmc_davinci_dma_cb, host, -			EVENTQ_DEFAULT); -	if (r < 0) { -
> dev_warn(mmc_dev(host->mmc), "alloc %s channel err %d\n", -				"rx", r); 
> -		goto free_master_write; +	int r; +	dma_cap_mask_t mask; + +
> dma_cap_zero(mask); +	dma_cap_set(DMA_SLAVE, mask); + +	host->dma_tx = +
> dma_request_channel(mask, edma_filter_fn, &host->txdma); +	if
> (!host->dma_tx) { +		dev_err(mmc_dev(host->mmc), "Can't get dma_tx
> channel\n"); +		return -ENODEV; } -	mmc_davinci_dma_setup(host, false,
> &host->rx_template);
> 
> -	/* Allocate parameter RAM slots, which will later be bound to a -	 *
> channel as needed to handle a scatterlist. -	 */ -	link_size =
> min_t(unsigned, host->nr_sg, ARRAY_SIZE(host->links)); -	for (i = 0; i <
> link_size; i++) { -		r = edma_alloc_slot(EDMA_CTLR(host->txdma),
> EDMA_SLOT_ANY); -		if (r < 0) { -			dev_dbg(mmc_dev(host->mmc), "dma
> PaRAM alloc --> %d\n", -				r); -			break; -		} -		host->links[i] = r; +
> host->dma_rx = +		dma_request_channel(mask, edma_filter_fn,
> &host->rxdma); +	if (!host->dma_rx) { +		dev_err(mmc_dev(host->mmc),
> "Can't get dma_rx channel\n"); +		r = -ENODEV; +		goto
> free_master_write; } -	host->n_link = i;
> 
> return 0;
> 
> free_master_write: -	edma_free_channel(host->txdma); +
> dma_release_channel(host->dma_tx);
> 
> return r; } @@ -1359,7 +1252,7 @@ static int __init
> davinci_mmcsd_probe(struct platform_device *pdev) * Each hw_seg uses one
> EDMA parameter RAM slot, always one * channel and then usually some
> linked slots. */ -	mmc->max_segs		= 1 + host->n_link; +	mmc->max_segs		=
> MAX_NR_SG;
> 
> /* EDMA limit per hw segment (one or two MBytes) */ mmc->max_seg_size	=
> MAX_CCNT * rw_threshold;
> 

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (Darwin)
Comment: GPGTools - http://gpgtools.org

iD8DBQFQNSq3MkyGM64RGpERAtYeAKCAw+H7rVY1JjuI5sNTDXCpDRiYNgCeKhq/
8QNkFCA4uG1wcb5cg7BjQl0=
=XQE4
-----END PGP SIGNATURE-----


  reply	other threads:[~2012-08-22 19:00 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-08-21 18:43 [PATCH v2 0/3] DaVinci DMA engine conversion Matt Porter
2012-08-21 18:43 ` Matt Porter
2012-08-21 18:43 ` Matt Porter
     [not found] ` <1345574589-24757-1-git-send-email-mporter-l0cyMroinI0@public.gmane.org>
2012-08-21 18:43   ` [PATCH v2 1/3] dmaengine: add TI EDMA DMA engine driver Matt Porter
2012-08-21 18:43     ` Matt Porter
2012-08-21 18:43     ` Matt Porter
2012-08-22  3:39     ` Vinod Koul
2012-08-22  3:39       ` Vinod Koul
2012-08-22 16:21       ` Matt Porter
2012-08-22 16:21         ` Matt Porter
2012-08-22 16:21         ` Matt Porter
2012-08-22 12:37     ` Hebbar, Gururaja
2012-08-22 12:37       ` Hebbar, Gururaja
2012-08-22 17:10       ` Matt Porter
2012-08-22 17:10         ` Matt Porter
2012-08-21 18:43   ` [PATCH v2 2/3] mmc: davinci_mmc: convert to DMA engine API Matt Porter
2012-08-21 18:43     ` Matt Porter
2012-08-21 18:43     ` Matt Porter
2012-08-22 18:53     ` Koen Kooi [this message]
2012-08-22 18:53       ` Koen Kooi
2012-08-22 18:53       ` Koen Kooi
2012-08-22 18:53       ` Koen Kooi
2012-09-17  7:52       ` Chris Ball
2012-09-17  7:52         ` Chris Ball
2012-08-21 18:43   ` [PATCH v2 3/3] spi: spi-davinci: " Matt Porter
2012-08-21 18:43     ` Matt Porter
2012-08-21 18:43     ` Matt Porter
     [not found]     ` <1345574589-24757-4-git-send-email-mporter-l0cyMroinI0@public.gmane.org>
2012-08-22  3:45       ` Vinod Koul
2012-08-22  3:45         ` Vinod Koul
2012-08-22  3:45         ` Vinod Koul
2012-08-22 16:04         ` Matt Porter
2012-08-22 16:04           ` Matt Porter
2012-08-23  3:59           ` Vinod Koul
2012-08-23  3:59             ` Vinod Koul
2012-08-23  3:59             ` Vinod Koul

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='k139rl$gbm$2@ger.gmane.org' \
    --to=koen@dominion.thruhere.net \
    --cc=davinci-linux-open-source@linux.davincidsp.com \
    --cc=linux-arm-kernel@lists.infradead.orgspi-devel-general \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mmc@vger.kernel.org \
    --cc=spi-devel-general@lists.sourceforge.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.