Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 218795
b: refs/heads/master
c: c143304
h: refs/heads/master
i:
  218793: 4738080
  218791: bde6352
v: v3
  • Loading branch information
Ira Snyder authored and Dan Williams committed Oct 7, 2010
1 parent fbb14b8 commit 7143d2e
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 4 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a86ee03ce6f279ebe581a7a8c0c4393eaeb789ee
refs/heads/master: c14330417ef2050f4bf38ac20e125785fea14351
128 changes: 125 additions & 3 deletions trunk/drivers/dma/fsldma.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
#include <asm/fsldma.h>
#include "fsldma.h"

static const char msg_ld_oom[] = "No free memory for link descriptor\n";

static void dma_init(struct fsldma_chan *chan)
{
/* Reset the channel */
Expand Down Expand Up @@ -499,7 +501,7 @@ fsl_dma_prep_interrupt(struct dma_chan *dchan, unsigned long flags)

new = fsl_dma_alloc_descriptor(chan);
if (!new) {
dev_err(chan->dev, "No free memory for link descriptor\n");
dev_err(chan->dev, msg_ld_oom);
return NULL;
}

Expand Down Expand Up @@ -536,8 +538,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
/* Allocate the link descriptor from DMA pool */
new = fsl_dma_alloc_descriptor(chan);
if (!new) {
dev_err(chan->dev,
"No free memory for link descriptor\n");
dev_err(chan->dev, msg_ld_oom);
goto fail;
}
#ifdef FSL_DMA_LD_DEBUG
Expand Down Expand Up @@ -583,6 +584,125 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
return NULL;
}

static struct dma_async_tx_descriptor *fsl_dma_prep_sg(struct dma_chan *dchan,
struct scatterlist *dst_sg, unsigned int dst_nents,
struct scatterlist *src_sg, unsigned int src_nents,
unsigned long flags)
{
struct fsl_desc_sw *first = NULL, *prev = NULL, *new = NULL;
struct fsldma_chan *chan = to_fsl_chan(dchan);
size_t dst_avail, src_avail;
dma_addr_t dst, src;
size_t len;

/* basic sanity checks */
if (dst_nents == 0 || src_nents == 0)
return NULL;

if (dst_sg == NULL || src_sg == NULL)
return NULL;

/*
* TODO: should we check that both scatterlists have the same
* TODO: number of bytes in total? Is that really an error?
*/

/* get prepared for the loop */
dst_avail = sg_dma_len(dst_sg);
src_avail = sg_dma_len(src_sg);

/* run until we are out of scatterlist entries */
while (true) {

/* create the largest transaction possible */
len = min_t(size_t, src_avail, dst_avail);
len = min_t(size_t, len, FSL_DMA_BCR_MAX_CNT);
if (len == 0)
goto fetch;

dst = sg_dma_address(dst_sg) + sg_dma_len(dst_sg) - dst_avail;
src = sg_dma_address(src_sg) + sg_dma_len(src_sg) - src_avail;

/* allocate and populate the descriptor */
new = fsl_dma_alloc_descriptor(chan);
if (!new) {
dev_err(chan->dev, msg_ld_oom);
goto fail;
}
#ifdef FSL_DMA_LD_DEBUG
dev_dbg(chan->dev, "new link desc alloc %p\n", new);
#endif

set_desc_cnt(chan, &new->hw, len);
set_desc_src(chan, &new->hw, src);
set_desc_dst(chan, &new->hw, dst);

if (!first)
first = new;
else
set_desc_next(chan, &prev->hw, new->async_tx.phys);

new->async_tx.cookie = 0;
async_tx_ack(&new->async_tx);
prev = new;

/* Insert the link descriptor to the LD ring */
list_add_tail(&new->node, &first->tx_list);

/* update metadata */
dst_avail -= len;
src_avail -= len;

fetch:
/* fetch the next dst scatterlist entry */
if (dst_avail == 0) {

/* no more entries: we're done */
if (dst_nents == 0)
break;

/* fetch the next entry: if there are no more: done */
dst_sg = sg_next(dst_sg);
if (dst_sg == NULL)
break;

dst_nents--;
dst_avail = sg_dma_len(dst_sg);
}

/* fetch the next src scatterlist entry */
if (src_avail == 0) {

/* no more entries: we're done */
if (src_nents == 0)
break;

/* fetch the next entry: if there are no more: done */
src_sg = sg_next(src_sg);
if (src_sg == NULL)
break;

src_nents--;
src_avail = sg_dma_len(src_sg);
}
}

new->async_tx.flags = flags; /* client is in control of this ack */
new->async_tx.cookie = -EBUSY;

/* Set End-of-link to the last link descriptor of new list */
set_ld_eol(chan, new);

return &first->async_tx;

fail:
if (!first)
return NULL;

fsldma_free_desc_list_reverse(chan, &first->tx_list);
return NULL;
}

/**
* fsl_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
* @chan: DMA channel
Expand Down Expand Up @@ -1327,11 +1447,13 @@ static int __devinit fsldma_of_probe(struct platform_device *op,

dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask);
dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask);
dma_cap_set(DMA_SG, fdev->common.cap_mask);
dma_cap_set(DMA_SLAVE, fdev->common.cap_mask);
fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources;
fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources;
fdev->common.device_prep_dma_interrupt = fsl_dma_prep_interrupt;
fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy;
fdev->common.device_prep_dma_sg = fsl_dma_prep_sg;
fdev->common.device_tx_status = fsl_tx_status;
fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending;
fdev->common.device_prep_slave_sg = fsl_dma_prep_slave_sg;
Expand Down

0 comments on commit 7143d2e

Please sign in to comment.