-----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@xxxxxx> Runtime tested on hawkboard with 3.6.0-rc2 with rootfs on SD and running bonnie++ on it. Tested-by: Koen Kooi <koen@xxxxxxxxxxxxxxxxxxxxx> > --- 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----- -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html