Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 197516
b: refs/heads/master
c: 84c8447
h: refs/heads/master
v: v3
  • Loading branch information
Linus Walleij authored and Dan Williams committed Mar 24, 2010
1 parent d549813 commit 8a58c86
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 9 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: cecd87da83869ad4157295b87a2e51e38c3e03bf
refs/heads/master: 84c8447c544bc7579097649273bc3f4e1b5de6af
96 changes: 88 additions & 8 deletions trunk/drivers/dma/coh901318.c
Original file line number Diff line number Diff line change
Expand Up @@ -408,25 +408,100 @@ coh901318_first_queued(struct coh901318_chan *cohc)
return d;
}

static inline u32 coh901318_get_bytes_in_lli(struct coh901318_lli *in_lli)
{
struct coh901318_lli *lli = in_lli;
u32 bytes = 0;

while (lli) {
bytes += lli->control & COH901318_CX_CTRL_TC_VALUE_MASK;
lli = lli->virt_link_addr;
}
return bytes;
}

/*
* DMA start/stop controls
* Get the number of bytes left to transfer on this channel,
* it is unwise to call this before stopping the channel for
* absolute measures, but for a rough guess you can still call
* it.
*/
u32 coh901318_get_bytes_left(struct dma_chan *chan)
{
unsigned long flags;
u32 ret;
struct coh901318_chan *cohc = to_coh901318_chan(chan);
struct coh901318_desc *cohd;
struct list_head *pos;
unsigned long flags;
u32 left = 0;
int i = 0;

spin_lock_irqsave(&cohc->lock, flags);

/* Read transfer count value */
ret = readl(cohc->base->virtbase +
COH901318_CX_CTRL+COH901318_CX_CTRL_SPACING *
cohc->id) & COH901318_CX_CTRL_TC_VALUE_MASK;
/*
* If there are many queued jobs, we iterate and add the
* size of them all. We take a special look on the first
* job though, since it is probably active.
*/
list_for_each(pos, &cohc->active) {
/*
* The first job in the list will be working on the
* hardware. The job can be stopped but still active,
* so that the transfer counter is somewhere inside
* the buffer.
*/
cohd = list_entry(pos, struct coh901318_desc, node);

if (i == 0) {
struct coh901318_lli *lli;
dma_addr_t ladd;

/* Read current transfer count value */
left = readl(cohc->base->virtbase +
COH901318_CX_CTRL +
COH901318_CX_CTRL_SPACING * cohc->id) &
COH901318_CX_CTRL_TC_VALUE_MASK;

/* See if the transfer is linked... */
ladd = readl(cohc->base->virtbase +
COH901318_CX_LNK_ADDR +
COH901318_CX_LNK_ADDR_SPACING *
cohc->id) &
~COH901318_CX_LNK_LINK_IMMEDIATE;
/* Single transaction */
if (!ladd)
continue;

/*
* Linked transaction, follow the lli, find the
* currently processing lli, and proceed to the next
*/
lli = cohd->lli;
while (lli && lli->link_addr != ladd)
lli = lli->virt_link_addr;

if (lli)
lli = lli->virt_link_addr;

/*
* Follow remaining lli links around to count the total
* number of bytes left
*/
left += coh901318_get_bytes_in_lli(lli);
} else {
left += coh901318_get_bytes_in_lli(cohd->lli);
}
i++;
}

/* Also count bytes in the queued jobs */
list_for_each(pos, &cohc->queue) {
cohd = list_entry(pos, struct coh901318_desc, node);
left += coh901318_get_bytes_in_lli(cohd->lli);
}

spin_unlock_irqrestore(&cohc->lock, flags);

return ret;
return left;
}
EXPORT_SYMBOL(coh901318_get_bytes_left);

Expand Down Expand Up @@ -831,18 +906,23 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
static int coh901318_alloc_chan_resources(struct dma_chan *chan)
{
struct coh901318_chan *cohc = to_coh901318_chan(chan);
unsigned long flags;

dev_vdbg(COHC_2_DEV(cohc), "[%s] DMA channel %d\n",
__func__, cohc->id);

if (chan->client_count > 1)
return -EBUSY;

spin_lock_irqsave(&cohc->lock, flags);

coh901318_config(cohc, NULL);

cohc->allocated = 1;
cohc->completed = chan->cookie = 1;

spin_unlock_irqrestore(&cohc->lock, flags);

return 1;
}

Expand Down

0 comments on commit 8a58c86

Please sign in to comment.