Commit 07fe944e authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/djbw/async_tx

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/djbw/async_tx:
  dmaengine: ack to flags: make use of the unused bits in the 'ack' field
  iop-adma: remove the workaround for missed interrupts on iop3xx
  async_tx: kill ->device_dependency_added
  async_tx: fix multiple dependency submission
  fsldma: Split the MPC83xx event from MPC85xx and refine irq codes.
  fsldma: Remove CONFIG_FSL_DMA_SELFTEST, keep fsl_dma_self_test() running always.
parents 8019aa94 636bdeaa
...@@ -77,7 +77,7 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset, ...@@ -77,7 +77,7 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
/* if ack is already set then we cannot be sure /* if ack is already set then we cannot be sure
* we are referring to the correct operation * we are referring to the correct operation
*/ */
BUG_ON(depend_tx->ack); BUG_ON(async_tx_test_ack(depend_tx));
if (dma_wait_for_async_tx(depend_tx) == DMA_ERROR) if (dma_wait_for_async_tx(depend_tx) == DMA_ERROR)
panic("%s: DMA_ERROR waiting for depend_tx\n", panic("%s: DMA_ERROR waiting for depend_tx\n",
__func__); __func__);
......
...@@ -89,13 +89,19 @@ dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx) ...@@ -89,13 +89,19 @@ dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx)
iter = tx; iter = tx;
/* find the root of the unsubmitted dependency chain */ /* find the root of the unsubmitted dependency chain */
while (iter->cookie == -EBUSY) { do {
parent = iter->parent; parent = iter->parent;
if (parent && parent->cookie == -EBUSY) if (!parent)
iter = iter->parent;
else
break; break;
} else
iter = parent;
} while (parent);
/* there is a small window for ->parent == NULL and
* ->cookie == -EBUSY
*/
while (iter->cookie == -EBUSY)
cpu_relax();
status = dma_sync_wait(iter->chan, iter->cookie); status = dma_sync_wait(iter->chan, iter->cookie);
} while (status == DMA_IN_PROGRESS || (iter != tx)); } while (status == DMA_IN_PROGRESS || (iter != tx));
...@@ -111,24 +117,33 @@ EXPORT_SYMBOL_GPL(dma_wait_for_async_tx); ...@@ -111,24 +117,33 @@ EXPORT_SYMBOL_GPL(dma_wait_for_async_tx);
void void
async_tx_run_dependencies(struct dma_async_tx_descriptor *tx) async_tx_run_dependencies(struct dma_async_tx_descriptor *tx)
{ {
struct dma_async_tx_descriptor *dep_tx, *_dep_tx; struct dma_async_tx_descriptor *next = tx->next;
struct dma_device *dev;
struct dma_chan *chan; struct dma_chan *chan;
list_for_each_entry_safe(dep_tx, _dep_tx, &tx->depend_list, if (!next)
depend_node) { return;
chan = dep_tx->chan;
dev = chan->device; tx->next = NULL;
/* we can't depend on ourselves */ chan = next->chan;
BUG_ON(chan == tx->chan);
list_del(&dep_tx->depend_node); /* keep submitting up until a channel switch is detected
tx->tx_submit(dep_tx); * in that case we will be called again as a result of
* processing the interrupt from async_tx_channel_switch
/* we need to poke the engine as client code does not
* know about dependency submission events
*/ */
dev->device_issue_pending(chan); while (next && next->chan == chan) {
struct dma_async_tx_descriptor *_next;
spin_lock_bh(&next->lock);
next->parent = NULL;
_next = next->next;
next->next = NULL;
spin_unlock_bh(&next->lock);
next->tx_submit(next);
next = _next;
} }
chan->device->device_issue_pending(chan);
} }
EXPORT_SYMBOL_GPL(async_tx_run_dependencies); EXPORT_SYMBOL_GPL(async_tx_run_dependencies);
...@@ -397,6 +412,92 @@ static void __exit async_tx_exit(void) ...@@ -397,6 +412,92 @@ static void __exit async_tx_exit(void)
} }
#endif #endif
/**
* async_tx_channel_switch - queue an interrupt descriptor with a dependency
* pre-attached.
* @depend_tx: the operation that must finish before the new operation runs
* @tx: the new operation
*/
static void
async_tx_channel_switch(struct dma_async_tx_descriptor *depend_tx,
struct dma_async_tx_descriptor *tx)
{
struct dma_chan *chan;
struct dma_device *device;
struct dma_async_tx_descriptor *intr_tx = (void *) ~0;
/* first check to see if we can still append to depend_tx */
spin_lock_bh(&depend_tx->lock);
if (depend_tx->parent && depend_tx->chan == tx->chan) {
tx->parent = depend_tx;
depend_tx->next = tx;
intr_tx = NULL;
}
spin_unlock_bh(&depend_tx->lock);
if (!intr_tx)
return;
chan = depend_tx->chan;
device = chan->device;
/* see if we can schedule an interrupt
* otherwise poll for completion
*/
if (dma_has_cap(DMA_INTERRUPT, device->cap_mask))
intr_tx = device->device_prep_dma_interrupt(chan, 0);
else
intr_tx = NULL;
if (intr_tx) {
intr_tx->callback = NULL;
intr_tx->callback_param = NULL;
tx->parent = intr_tx;
/* safe to set ->next outside the lock since we know we are
* not submitted yet
*/
intr_tx->next = tx;
/* check if we need to append */
spin_lock_bh(&depend_tx->lock);
if (depend_tx->parent) {
intr_tx->parent = depend_tx;
depend_tx->next = intr_tx;
async_tx_ack(intr_tx);
intr_tx = NULL;
}
spin_unlock_bh(&depend_tx->lock);
if (intr_tx) {
intr_tx->parent = NULL;
intr_tx->tx_submit(intr_tx);
async_tx_ack(intr_tx);
}
} else {
if (dma_wait_for_async_tx(depend_tx) == DMA_ERROR)
panic("%s: DMA_ERROR waiting for depend_tx\n",
__func__);
tx->tx_submit(tx);
}
}
/**
* submit_disposition - while holding depend_tx->lock we must avoid submitting
* new operations to prevent a circular locking dependency with
* drivers that already hold a channel lock when calling
* async_tx_run_dependencies.
* @ASYNC_TX_SUBMITTED: we were able to append the new operation under the lock
* @ASYNC_TX_CHANNEL_SWITCH: when the lock is dropped schedule a channel switch
* @ASYNC_TX_DIRECT_SUBMIT: when the lock is dropped submit directly
*/
enum submit_disposition {
ASYNC_TX_SUBMITTED,
ASYNC_TX_CHANNEL_SWITCH,
ASYNC_TX_DIRECT_SUBMIT,
};
void void
async_tx_submit(struct dma_chan *chan, struct dma_async_tx_descriptor *tx, async_tx_submit(struct dma_chan *chan, struct dma_async_tx_descriptor *tx,
enum async_tx_flags flags, struct dma_async_tx_descriptor *depend_tx, enum async_tx_flags flags, struct dma_async_tx_descriptor *depend_tx,
...@@ -405,28 +506,55 @@ async_tx_submit(struct dma_chan *chan, struct dma_async_tx_descriptor *tx, ...@@ -405,28 +506,55 @@ async_tx_submit(struct dma_chan *chan, struct dma_async_tx_descriptor *tx,
tx->callback = cb_fn; tx->callback = cb_fn;
tx->callback_param = cb_param; tx->callback_param = cb_param;
/* set this new tx to run after depend_tx if: if (depend_tx) {
* 1/ a dependency exists (depend_tx is !NULL) enum submit_disposition s;
* 2/ the tx can not be submitted to the current channel
*/ /* sanity check the dependency chain:
if (depend_tx && depend_tx->chan != chan) { * 1/ if ack is already set then we cannot be sure
/* if ack is already set then we cannot be sure
* we are referring to the correct operation * we are referring to the correct operation
* 2/ dependencies are 1:1 i.e. two transactions can
* not depend on the same parent
*/ */
BUG_ON(depend_tx->ack); BUG_ON(async_tx_test_ack(depend_tx) || depend_tx->next ||
tx->parent);
tx->parent = depend_tx; /* the lock prevents async_tx_run_dependencies from missing
* the setting of ->next when ->parent != NULL
*/
spin_lock_bh(&depend_tx->lock); spin_lock_bh(&depend_tx->lock);
list_add_tail(&tx->depend_node, &depend_tx->depend_list); if (depend_tx->parent) {
if (depend_tx->cookie == 0) { /* we have a parent so we can not submit directly
struct dma_chan *dep_chan = depend_tx->chan; * if we are staying on the same channel: append
struct dma_device *dep_dev = dep_chan->device; * else: channel switch
dep_dev->device_dependency_added(dep_chan); */
if (depend_tx->chan == chan) {
tx->parent = depend_tx;
depend_tx->next = tx;
s = ASYNC_TX_SUBMITTED;
} else
s = ASYNC_TX_CHANNEL_SWITCH;
} else {
/* we do not have a parent so we may be able to submit
* directly if we are staying on the same channel
*/
if (depend_tx->chan == chan)
s = ASYNC_TX_DIRECT_SUBMIT;
else
s = ASYNC_TX_CHANNEL_SWITCH;
} }
spin_unlock_bh(&depend_tx->lock); spin_unlock_bh(&depend_tx->lock);
/* schedule an interrupt to trigger the channel switch */ switch (s) {
async_trigger_callback(ASYNC_TX_ACK, depend_tx, NULL, NULL); case ASYNC_TX_SUBMITTED:
break;
case ASYNC_TX_CHANNEL_SWITCH:
async_tx_channel_switch(depend_tx, tx);
break;
case ASYNC_TX_DIRECT_SUBMIT:
tx->parent = NULL;
tx->tx_submit(tx);
break;
}
} else { } else {
tx->parent = NULL; tx->parent = NULL;
tx->tx_submit(tx); tx->tx_submit(tx);
...@@ -467,7 +595,7 @@ async_trigger_callback(enum async_tx_flags flags, ...@@ -467,7 +595,7 @@ async_trigger_callback(enum async_tx_flags flags,
if (device && !dma_has_cap(DMA_INTERRUPT, device->cap_mask)) if (device && !dma_has_cap(DMA_INTERRUPT, device->cap_mask))
device = NULL; device = NULL;
tx = device ? device->device_prep_dma_interrupt(chan) : NULL; tx = device ? device->device_prep_dma_interrupt(chan, 0) : NULL;
} else } else
tx = NULL; tx = NULL;
...@@ -483,7 +611,7 @@ async_trigger_callback(enum async_tx_flags flags, ...@@ -483,7 +611,7 @@ async_trigger_callback(enum async_tx_flags flags,
/* if ack is already set then we cannot be sure /* if ack is already set then we cannot be sure
* we are referring to the correct operation * we are referring to the correct operation
*/ */
BUG_ON(depend_tx->ack); BUG_ON(async_tx_test_ack(depend_tx));
if (dma_wait_for_async_tx(depend_tx) == DMA_ERROR) if (dma_wait_for_async_tx(depend_tx) == DMA_ERROR)
panic("%s: DMA_ERROR waiting for depend_tx\n", panic("%s: DMA_ERROR waiting for depend_tx\n",
__func__); __func__);
......
...@@ -191,7 +191,7 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset, ...@@ -191,7 +191,7 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset,
/* if ack is already set then we cannot be sure /* if ack is already set then we cannot be sure
* we are referring to the correct operation * we are referring to the correct operation
*/ */
BUG_ON(depend_tx->ack); BUG_ON(async_tx_test_ack(depend_tx));
if (dma_wait_for_async_tx(depend_tx) == if (dma_wait_for_async_tx(depend_tx) ==
DMA_ERROR) DMA_ERROR)
panic("%s: DMA_ERROR waiting for " panic("%s: DMA_ERROR waiting for "
......
...@@ -46,14 +46,6 @@ config FSL_DMA ...@@ -46,14 +46,6 @@ config FSL_DMA
MPC8560/40, MPC8555, MPC8548 and MPC8641 processors. MPC8560/40, MPC8555, MPC8548 and MPC8641 processors.
The MPC8349, MPC8360 is also supported. The MPC8349, MPC8360 is also supported.
config FSL_DMA_SELFTEST
bool "Enable the self test for each DMA channel"
depends on FSL_DMA
default y
---help---
Enable the self test for each DMA channel. A self test will be
performed after the channel probed to ensure the DMA works well.
config DMA_ENGINE config DMA_ENGINE
bool bool
......
...@@ -362,7 +362,6 @@ int dma_async_device_register(struct dma_device *device) ...@@ -362,7 +362,6 @@ int dma_async_device_register(struct dma_device *device)
BUG_ON(!device->device_alloc_chan_resources); BUG_ON(!device->device_alloc_chan_resources);
BUG_ON(!device->device_free_chan_resources); BUG_ON(!device->device_free_chan_resources);
BUG_ON(!device->device_dependency_added);
BUG_ON(!device->device_is_tx_complete); BUG_ON(!device->device_is_tx_complete);
BUG_ON(!device->device_issue_pending); BUG_ON(!device->device_issue_pending);
BUG_ON(!device->dev); BUG_ON(!device->dev);
...@@ -479,7 +478,8 @@ dma_async_memcpy_buf_to_buf(struct dma_chan *chan, void *dest, ...@@ -479,7 +478,8 @@ dma_async_memcpy_buf_to_buf(struct dma_chan *chan, void *dest,
dma_src = dma_map_single(dev->dev, src, len, DMA_TO_DEVICE); dma_src = dma_map_single(dev->dev, src, len, DMA_TO_DEVICE);
dma_dest = dma_map_single(dev->dev, dest, len, DMA_FROM_DEVICE); dma_dest = dma_map_single(dev->dev, dest, len, DMA_FROM_DEVICE);
tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len, 0); tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len,
DMA_CTRL_ACK);
if (!tx) { if (!tx) {
dma_unmap_single(dev->dev, dma_src, len, DMA_TO_DEVICE); dma_unmap_single(dev->dev, dma_src, len, DMA_TO_DEVICE);
...@@ -487,7 +487,6 @@ dma_async_memcpy_buf_to_buf(struct dma_chan *chan, void *dest, ...@@ -487,7 +487,6 @@ dma_async_memcpy_buf_to_buf(struct dma_chan *chan, void *dest,
return -ENOMEM; return -ENOMEM;
} }
tx->ack = 1;
tx->callback = NULL; tx->callback = NULL;
cookie = tx->tx_submit(tx); cookie = tx->tx_submit(tx);
...@@ -525,7 +524,8 @@ dma_async_memcpy_buf_to_pg(struct dma_chan *chan, struct page *page, ...@@ -525,7 +524,8 @@ dma_async_memcpy_buf_to_pg(struct dma_chan *chan, struct page *page,
dma_src = dma_map_single(dev->dev, kdata, len, DMA_TO_DEVICE); dma_src = dma_map_single(dev->dev, kdata, len, DMA_TO_DEVICE);
dma_dest = dma_map_page(dev->dev, page, offset, len, DMA_FROM_DEVICE); dma_dest = dma_map_page(dev->dev, page, offset, len, DMA_FROM_DEVICE);
tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len, 0); tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len,
DMA_CTRL_ACK);
if (!tx) { if (!tx) {
dma_unmap_single(dev->dev, dma_src, len, DMA_TO_DEVICE); dma_unmap_single(dev->dev, dma_src, len, DMA_TO_DEVICE);
...@@ -533,7 +533,6 @@ dma_async_memcpy_buf_to_pg(struct dma_chan *chan, struct page *page, ...@@ -533,7 +533,6 @@ dma_async_memcpy_buf_to_pg(struct dma_chan *chan, struct page *page,
return -ENOMEM; return -ENOMEM;
} }
tx->ack = 1;
tx->callback = NULL; tx->callback = NULL;
cookie = tx->tx_submit(tx); cookie = tx->tx_submit(tx);
...@@ -574,7 +573,8 @@ dma_async_memcpy_pg_to_pg(struct dma_chan *chan, struct page *dest_pg, ...@@ -574,7 +573,8 @@ dma_async_memcpy_pg_to_pg(struct dma_chan *chan, struct page *dest_pg,
dma_src = dma_map_page(dev->dev, src_pg, src_off, len, DMA_TO_DEVICE); dma_src = dma_map_page(dev->dev, src_pg, src_off, len, DMA_TO_DEVICE);
dma_dest = dma_map_page(dev->dev, dest_pg, dest_off, len, dma_dest = dma_map_page(dev->dev, dest_pg, dest_off, len,
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len, 0); tx = dev->device_prep_dma_memcpy(chan, dma_dest, dma_src, len,
DMA_CTRL_ACK);
if (!tx) { if (!tx) {
dma_unmap_page(dev->dev, dma_src, len, DMA_TO_DEVICE); dma_unmap_page(dev->dev, dma_src, len, DMA_TO_DEVICE);
...@@ -582,7 +582,6 @@ dma_async_memcpy_pg_to_pg(struct dma_chan *chan, struct page *dest_pg, ...@@ -582,7 +582,6 @@ dma_async_memcpy_pg_to_pg(struct dma_chan *chan, struct page *dest_pg,
return -ENOMEM; return -ENOMEM;
} }
tx->ack = 1;
tx->callback = NULL; tx->callback = NULL;
cookie = tx->tx_submit(tx); cookie = tx->tx_submit(tx);
...@@ -600,8 +599,6 @@ void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx, ...@@ -600,8 +599,6 @@ void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx,
{ {
tx->chan = chan; tx->chan = chan;
spin_lock_init(&tx->lock); spin_lock_init(&tx->lock);
INIT_LIST_HEAD(&tx->depend_node);
INIT_LIST_HEAD(&tx->depend_list);
} }
EXPORT_SYMBOL(dma_async_tx_descriptor_init); EXPORT_SYMBOL(dma_async_tx_descriptor_init);
......
...@@ -412,7 +412,7 @@ static void fsl_dma_free_chan_resources(struct dma_chan *chan) ...@@ -412,7 +412,7 @@ static void fsl_dma_free_chan_resources(struct dma_chan *chan)
} }
static struct dma_async_tx_descriptor * static struct dma_async_tx_descriptor *
fsl_dma_prep_interrupt(struct dma_chan *chan) fsl_dma_prep_interrupt(struct dma_chan *chan, unsigned long flags)
{ {
struct fsl_dma_chan *fsl_chan; struct fsl_dma_chan *fsl_chan;
struct fsl_desc_sw *new; struct fsl_desc_sw *new;
...@@ -429,7 +429,7 @@ fsl_dma_prep_interrupt(struct dma_chan *chan) ...@@ -429,7 +429,7 @@ fsl_dma_prep_interrupt(struct dma_chan *chan)
} }
new->async_tx.cookie = -EBUSY; new->async_tx.cookie = -EBUSY;
new->async_tx.ack = 0; new->async_tx.flags = flags;
/* Insert the link descriptor to the LD ring */ /* Insert the link descriptor to the LD ring */
list_add_tail(&new->node, &new->async_tx.tx_list); list_add_tail(&new->node, &new->async_tx.tx_list);
...@@ -482,7 +482,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy( ...@@ -482,7 +482,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
set_desc_next(fsl_chan, &prev->hw, new->async_tx.phys); set_desc_next(fsl_chan, &prev->hw, new->async_tx.phys);
new->async_tx.cookie = 0; new->async_tx.cookie = 0;
new->async_tx.ack = 1; async_tx_ack(&new->async_tx);
prev = new; prev = new;
len -= copy; len -= copy;
...@@ -493,7 +493,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy( ...@@ -493,7 +493,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
list_add_tail(&new->node, &first->async_tx.tx_list); list_add_tail(&new->node, &first->async_tx.tx_list);
} while (len); } while (len);
new->async_tx.ack = 0; /* client is in control of this ack */ new->async_tx.flags = flags; /* client is in control of this ack */
new->async_tx.cookie = -EBUSY; new->async_tx.cookie = -EBUSY;
/* Set End-of-link to the last link descriptor of new list*/ /* Set End-of-link to the last link descriptor of new list*/
...@@ -658,13 +658,6 @@ static void fsl_dma_memcpy_issue_pending(struct dma_chan *chan) ...@@ -658,13 +658,6 @@ static void fsl_dma_memcpy_issue_pending(struct dma_chan *chan)
fsl_chan_xfer_ld_queue(fsl_chan); fsl_chan_xfer_ld_queue(fsl_chan);
} }
static void fsl_dma_dependency_added(struct dma_chan *chan)
{
struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan);
fsl_chan_ld_cleanup(fsl_chan);
}
/** /**
* fsl_dma_is_complete - Determine the DMA status * fsl_dma_is_complete - Determine the DMA status
* @fsl_chan : Freescale DMA channel * @fsl_chan : Freescale DMA channel
...@@ -696,6 +689,8 @@ static irqreturn_t fsl_dma_chan_do_interrupt(int irq, void *data) ...@@ -696,6 +689,8 @@ static irqreturn_t fsl_dma_chan_do_interrupt(int irq, void *data)
{ {
struct fsl_dma_chan *fsl_chan = (struct fsl_dma_chan *)data; struct fsl_dma_chan *fsl_chan = (struct fsl_dma_chan *)data;
u32 stat; u32 stat;
int update_cookie = 0;
int xfer_ld_q = 0;
stat = get_sr(fsl_chan); stat = get_sr(fsl_chan);
dev_dbg(fsl_chan->dev, "event: channel %d, stat = 0x%x\n", dev_dbg(fsl_chan->dev, "event: channel %d, stat = 0x%x\n",
...@@ -720,8 +715,8 @@ static irqreturn_t fsl_dma_chan_do_interrupt(int irq, void *data) ...@@ -720,8 +715,8 @@ static irqreturn_t fsl_dma_chan_do_interrupt(int irq, void *data)
* Now, update the completed cookie, and continue the * Now, update the completed cookie, and continue the
* next uncompleted transfer. * next uncompleted transfer.
*/ */
fsl_dma_update_completed_cookie(fsl_chan); update_cookie = 1;
fsl_chan_xfer_ld_queue(fsl_chan); xfer_ld_q = 1;
} }
stat &= ~FSL_DMA_SR_PE; stat &= ~FSL_DMA_SR_PE;
} }
...@@ -734,19 +729,33 @@ static irqreturn_t fsl_dma_chan_do_interrupt(int irq, void *data) ...@@ -734,19 +729,33 @@ static irqreturn_t fsl_dma_chan_do_interrupt(int irq, void *data)
dev_dbg(fsl_chan->dev, "event: clndar %p, nlndar %p\n", dev_dbg(fsl_chan->dev, "event: clndar %p, nlndar %p\n",
(void *)get_cdar(fsl_chan), (void *)get_ndar(fsl_chan)); (void *)get_cdar(fsl_chan), (void *)get_ndar(fsl_chan));
stat &= ~FSL_DMA_SR_EOSI; stat &= ~FSL_DMA_SR_EOSI;
fsl_dma_update_completed_cookie(fsl_chan); update_cookie = 1;
}
/* For MPC8349, EOCDI event need to update cookie
* and start the next transfer if it exist.
*/
if (stat & FSL_DMA_SR_EOCDI) {
dev_dbg(fsl_chan->dev, "event: End-of-Chain link INT\n");
stat &= ~FSL_DMA_SR_EOCDI;
update_cookie = 1;
xfer_ld_q = 1;
} }
/* If it current transfer is the end-of-transfer, /* If it current transfer is the end-of-transfer,
* we should clear the Channel Start bit for * we should clear the Channel Start bit for
* prepare next transfer. * prepare next transfer.
*/ */
if (stat & (FSL_DMA_SR_EOLNI | FSL_DMA_SR_EOCDI)) { if (stat & FSL_DMA_SR_EOLNI) {
dev_dbg(fsl_chan->dev, "event: End-of-link INT\n"); dev_dbg(fsl_chan->dev, "event: End-of-link INT\n");
stat &= ~FSL_DMA_SR_EOLNI; stat &= ~FSL_DMA_SR_EOLNI;
fsl_chan_xfer_ld_queue(fsl_chan); xfer_ld_q = 1;
} }
if (update_cookie)
fsl_dma_update_completed_cookie(fsl_chan);
if (xfer_ld_q)
fsl_chan_xfer_ld_queue(fsl_chan);
if (stat) if (stat)
dev_dbg(fsl_chan->dev, "event: unhandled sr 0x%02x\n", dev_dbg(fsl_chan->dev, "event: unhandled sr 0x%02x\n",
stat); stat);
...@@ -776,15 +785,13 @@ static void dma_do_tasklet(unsigned long data) ...@@ -776,15 +785,13 @@ static void dma_do_tasklet(unsigned long data)
fsl_chan_ld_cleanup(fsl_chan); fsl_chan_ld_cleanup(fsl_chan);
} }
#ifdef FSL_DMA_CALLBACKTEST static void fsl_dma_callback_test(void *param)
static void fsl_dma_callback_test(struct fsl_dma_chan *fsl_chan)
{ {
struct fsl_dma_chan *fsl_chan = param;
if (fsl_chan) if (fsl_chan)
dev_info(fsl_chan->dev, "selftest: callback is ok!\n"); dev_dbg(fsl_chan->dev, "selftest: callback is ok!\n");
} }
#endif
#ifdef CONFIG_FSL_DMA_SELFTEST
static int fsl_dma_self_test(struct fsl_dma_chan *fsl_chan) static int fsl_dma_self_test(struct fsl_dma_chan *fsl_chan)
{ {
struct dma_chan *chan; struct dma_chan *chan;
...@@ -867,7 +874,7 @@ static int fsl_dma_self_test(struct fsl_dma_chan *fsl_chan) ...@@ -867,7 +874,7 @@ static int fsl_dma_self_test(struct fsl_dma_chan *fsl_chan)
async_tx_ack(tx3); async_tx_ack(tx3);
/* Interrupt tx test */ /* Interrupt tx test */
tx1 = fsl_dma_prep_interrupt(chan); tx1 = fsl_dma_prep_interrupt(chan, 0);
async_tx_ack(tx1); async_tx_ack(tx1);
cookie = fsl_dma_tx_submit(tx1); cookie = fsl_dma_tx_submit(tx1);
...@@ -875,13 +882,11 @@ static int fsl_dma_self_test(struct fsl_dma_chan *fsl_chan) ...@@ -875,13 +882,11 @@ static int fsl_dma_self_test(struct fsl_dma_chan *fsl_chan)
cookie = fsl_dma_tx_submit(tx3); cookie = fsl_dma_tx_submit(tx3);
cookie = fsl_dma_tx_submit(tx2); cookie = fsl_dma_tx_submit(tx2);
#ifdef FSL_DMA_CALLBACKTEST
if (dma_has_cap(DMA_INTERRUPT, ((struct fsl_dma_device *) if (dma_has_cap(DMA_INTERRUPT, ((struct fsl_dma_device *)
dev_get_drvdata(fsl_chan->dev->parent))->common.cap_mask)) { dev_get_drvdata(fsl_chan->dev->parent))->common.cap_mask)) {
tx3->callback = fsl_dma_callback_test; tx3->callback = fsl_dma_callback_test;
tx3->callback_param = fsl_chan; tx3->callback_param = fsl_chan;
} }
#endif
fsl_dma_memcpy_issue_pending(chan); fsl_dma_memcpy_issue_pending(chan);
msleep(2); msleep(2);
...@@ -906,7 +911,6 @@ static int fsl_dma_self_test(struct fsl_dma_chan *fsl_chan) ...@@ -906,7 +911,6 @@ static int fsl_dma_self_test(struct fsl_dma_chan *fsl_chan)
kfree(src); kfree(src);
return err; return err;
} }
#endif
static int __devinit of_fsl_dma_chan_probe(struct of_device *dev, static int __devinit of_fsl_dma_chan_probe(struct of_device *dev,
const struct of_device_id *match) const struct of_device_id *match)
...@@ -997,11 +1001,9 @@ static int __devinit of_fsl_dma_chan_probe(struct of_device *dev, ...@@ -997,11 +1001,9 @@ static int __devinit of_fsl_dma_chan_probe(struct of_device *dev,
} }
} }
#ifdef CONFIG_FSL_DMA_SELFTEST
err = fsl_dma_self_test(new_fsl_chan); err = fsl_dma_self_test(new_fsl_chan);
if (err) if (err)
goto err; goto err;
#endif
dev_info(&dev->dev, "#%d (%s), irq %d\n", new_fsl_chan->id, dev_info(&dev->dev, "#%d (%s), irq %d\n", new_fsl_chan->id,
match->compatible, new_fsl_chan->irq); match->compatible, new_fsl_chan->irq);
...@@ -1080,7 +1082,6 @@ static int __devinit of_fsl_dma_probe(struct of_device *dev, ...@@ -1080,7 +1082,6 @@ static int __devinit of_fsl_dma_probe(struct of_device *dev,
fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy; fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy;
fdev->common.device_is_tx_complete = fsl_dma_is_complete; fdev->common.device_is_tx_complete = fsl_dma_is_complete;
fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending; fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending;
fdev->common.device_dependency_added = fsl_dma_dependency_added;
fdev->common.dev = &dev->dev; fdev->common.dev = &dev->dev;
irq = irq_of_parse_and_map(dev->node, 0); irq = irq_of_parse_and_map(dev->node, 0);
......
...@@ -212,14 +212,14 @@ static dma_cookie_t ioat1_tx_submit(struct dma_async_tx_descriptor *tx) ...@@ -212,14 +212,14 @@ static dma_cookie_t ioat1_tx_submit(struct dma_async_tx_descriptor *tx)
u32 copy; u32 copy;
size_t len; size_t len;
dma_addr_t src, dst; dma_addr_t src, dst;
int orig_ack; unsigned long orig_flags;
unsigned int desc_count = 0; unsigned int desc_count = 0;
/* src and dest and len are stored in the initial descriptor */ /* src and dest and len are stored in the initial descriptor */
len = first->len; len = first->len;
src = first->src; src = first->src;
dst = first->dst; dst = first->dst;
orig_ack = first->async_tx.ack; orig_flags = first->async_tx.flags;
new = first; new = first;
spin_lock_bh(&ioat_chan->desc_lock); spin_lock_bh(&ioat_chan->desc_lock);
...@@ -228,7 +228,7 @@ static dma_cookie_t ioat1_tx_submit(struct dma_async_tx_descriptor *tx) ...@@ -228,7 +228,7 @@ static dma_cookie_t ioat1_tx_submit(struct dma_async_tx_descriptor *tx)
do { do {
copy = min_t(size_t, len, ioat_chan->xfercap); copy = min_t(size_t, len, ioat_chan->xfercap);
new->async_tx.ack = 1; async_tx_ack(&new->async_tx);
hw = new->hw; hw = new->hw;
hw->size = copy; hw->size = copy;
...@@ -264,7 +264,7 @@ static dma_cookie_t ioat1_tx_submit(struct dma_async_tx_descriptor *tx) ...@@ -264,7 +264,7 @@ static dma_cookie_t ioat1_tx_submit(struct dma_async_tx_descriptor *tx)
} }
new->tx_cnt = desc_count; new->tx_cnt = desc_count;
new->async_tx.ack = orig_ack; /* client is in control of this ack */ new->async_tx.flags = orig_flags; /* client is in control of this ack */
/* store the original values for use in later cleanup */ /* store the original values for use in later cleanup */
if (new != first) { if (new != first) {
...@@ -304,14 +304,14 @@ static dma_cookie_t ioat2_tx_submit(struct dma_async_tx_descriptor *tx) ...@@ -304,14 +304,14 @@ static dma_cookie_t ioat2_tx_submit(struct dma_async_tx_descriptor *tx)
u32 copy; u32 copy;
size_t len; size_t len;
dma_addr_t src, dst; dma_addr_t src, dst;
int orig_ack; unsigned long orig_flags;
unsigned int desc_count = 0; unsigned int desc_count = 0;
/* src and dest and len are stored in the initial descriptor */ /* src and dest and len are stored in the initial descriptor */
len = first->len; len = first->len;
src = first->src; src = first->src;
dst = first->dst; dst = first->dst;
orig_ack = first->async_tx.ack; orig_flags = first->async_tx.flags;
new = first; new = first;
/* /*
...@@ -321,7 +321,7 @@ static dma_cookie_t ioat2_tx_submit(struct dma_async_tx_descriptor *tx) ...@@ -321,7 +321,7 @@ static dma_cookie_t ioat2_tx_submit(struct dma_async_tx_descriptor *tx)
do { do {
copy = min_t(size_t, len, ioat_chan->xfercap); copy = min_t(size_t, len, ioat_chan->xfercap);
new->async_tx.ack = 1; async_tx_ack(&new->async_tx);
hw = new->hw; hw = new->hw;
hw->size = copy; hw->size = copy;
...@@ -349,7 +349,7 @@ static dma_cookie_t ioat2_tx_submit(struct dma_async_tx_descriptor *tx) ...@@ -349,7 +349,7 @@ static dma_cookie_t ioat2_tx_submit(struct dma_async_tx_descriptor *tx)
} }
new->tx_cnt = desc_count; new->tx_cnt = desc_count;
new->async_tx.ack = orig_ack; /* client is in control of this ack */ new->async_tx.flags = orig_flags; /* client is in control of this ack */
/* store the original values for use in later cleanup */ /* store the original values for use in later cleanup */
if (new != first) { if (new != first) {
...@@ -714,7 +714,7 @@ static struct dma_async_tx_descriptor *ioat1_dma_prep_memcpy( ...@@ -714,7 +714,7 @@ static struct dma_async_tx_descriptor *ioat1_dma_prep_memcpy(
new->len = len; new->len = len;
new->dst = dma_dest; new->dst = dma_dest;
new->src = dma_src; new->src = dma_src;
new->async_tx.ack = 0; new->async_tx.flags = flags;
return &new->async_tx; return &new->async_tx;
} else } else
return NULL; return NULL;
...@@ -742,7 +742,7 @@ static struct dma_async_tx_descriptor *ioat2_dma_prep_memcpy( ...@@ -742,7 +742,7 @@ static struct dma_async_tx_descriptor *ioat2_dma_prep_memcpy(
new->len = len; new->len = len;
new->dst = dma_dest; new->dst = dma_dest;
new->src = dma_src; new->src = dma_src;
new->async_tx.ack = 0; new->async_tx.flags = flags;
return &new->async_tx; return &new->async_tx;
} else } else
return NULL; return NULL;
...@@ -842,7 +842,7 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan) ...@@ -842,7 +842,7 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan)
* a completed entry, but not the last, so clean * a completed entry, but not the last, so clean
* up if the client is done with the descriptor * up if the client is done with the descriptor
*/ */
if (desc->async_tx.ack) { if (async_tx_test_ack(&desc->async_tx)) {
list_del(&desc->node); list_del(&desc->node);
list_add_tail(&desc->node, list_add_tail(&desc->node,
&ioat_chan->free_desc); &ioat_chan->free_desc);
...@@ -924,17 +924,6 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan) ...@@ -924,17 +924,6 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan)
spin_unlock_bh(&ioat_chan->cleanup_lock); spin_unlock_bh(&ioat_chan->cleanup_lock);
} }
static void ioat_dma_dependency_added(struct dma_chan *chan)
{
struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
spin_lock_bh(&ioat_chan->desc_lock);
if (ioat_chan->pending == 0) {
spin_unlock_bh(&ioat_chan->desc_lock);
ioat_dma_memcpy_cleanup(ioat_chan);
} else
spin_unlock_bh(&ioat_chan->desc_lock);
}
/** /**
* ioat_dma_is_complete - poll the status of a IOAT DMA transaction * ioat_dma_is_complete - poll the status of a IOAT DMA transaction
* @chan: IOAT DMA channel handle * @chan: IOAT DMA channel handle
...@@ -990,7 +979,7 @@ static void ioat_dma_start_null_desc(struct ioat_dma_chan *ioat_chan) ...@@ -990,7 +979,7 @@ static void ioat_dma_start_null_desc(struct ioat_dma_chan *ioat_chan)
desc->hw->size = 0; desc->hw->size = 0;
desc->hw->src_addr = 0; desc->hw->src_addr = 0;
desc->hw->dst_addr = 0; desc->hw->dst_addr = 0;
desc->async_tx.ack = 1; async_tx_ack(&desc->async_tx);
switch (ioat_chan->device->version) { switch (ioat_chan->device->version) {
case IOAT_VER_1_2: case IOAT_VER_1_2:
desc->hw->next = 0; desc->hw->next = 0;
...@@ -1316,7 +1305,6 @@ struct ioatdma_device *ioat_dma_probe(struct pci_dev *pdev, ...@@ -1316,7 +1305,6 @@ struct ioatdma_device *ioat_dma_probe(struct pci_dev *pdev,
dma_cap_set(DMA_MEMCPY, device->common.cap_mask); dma_cap_set(DMA_MEMCPY, device->common.cap_mask);
device->common.device_is_tx_complete = ioat_dma_is_complete; device->common.device_is_tx_complete = ioat_dma_is_complete;
device->common.device_dependency_added = ioat_dma_dependency_added;
switch (device->version) { switch (device->version) {
case IOAT_VER_1_2: case IOAT_VER_1_2:
device->common.device_prep_dma_memcpy = ioat1_dma_prep_memcpy; device->common.device_prep_dma_memcpy = ioat1_dma_prep_memcpy;
......
...@@ -63,7 +63,6 @@ iop_adma_run_tx_complete_actions(struct iop_adma_desc_slot *desc, ...@@ -63,7 +63,6 @@ iop_adma_run_tx_complete_actions(struct iop_adma_desc_slot *desc,
struct iop_adma_chan *iop_chan, dma_cookie_t cookie) struct iop_adma_chan *iop_chan, dma_cookie_t cookie)
{ {
BUG_ON(desc->async_tx.cookie < 0); BUG_ON(desc->async_tx.cookie < 0);
spin_lock_bh(&desc->async_tx.lock);
if (desc->async_tx.cookie > 0) { if (desc->async_tx.cookie > 0) {
cookie = desc->async_tx.cookie; cookie = desc->async_tx.cookie;
desc->async_tx.cookie = 0; desc->async_tx.cookie = 0;
...@@ -101,7 +100,6 @@ iop_adma_run_tx_complete_actions(struct iop_adma_desc_slot *desc, ...@@ -101,7 +100,6 @@ iop_adma_run_tx_complete_actions(struct iop_adma_desc_slot *desc,
/* run dependent operations */ /* run dependent operations */
async_tx_run_dependencies(&desc->async_tx); async_tx_run_dependencies(&desc->async_tx);
spin_unlock_bh(&desc->async_tx.lock);
return cookie; return cookie;
} }
...@@ -113,7 +111,7 @@ iop_adma_clean_slot(struct iop_adma_desc_slot *desc, ...@@ -113,7 +111,7 @@ iop_adma_clean_slot(struct iop_adma_desc_slot *desc,
/* the client is allowed to attach dependent operations /* the client is allowed to attach dependent operations
* until 'ack' is set * until 'ack' is set
*/ */
if (!desc->async_tx.ack) if (!async_tx_test_ack(&desc->async_tx))
return 0; return 0;
/* leave the last descriptor in the chain /* leave the last descriptor in the chain
...@@ -150,7 +148,7 @@ static void __iop_adma_slot_cleanup(struct iop_adma_chan *iop_chan) ...@@ -150,7 +148,7 @@ static void __iop_adma_slot_cleanup(struct iop_adma_chan *iop_chan)
"this_desc: %#x next_desc: %#x ack: %d\n", "this_desc: %#x next_desc: %#x ack: %d\n",
iter->async_tx.cookie, iter->idx, busy, iter->async_tx.cookie, iter->idx, busy,
iter->async_tx.phys, iop_desc_get_next_desc(iter), iter->async_tx.phys, iop_desc_get_next_desc(iter),
iter->async_tx.ack); async_tx_test_ack(&iter->async_tx));
prefetch(_iter); prefetch(_iter);
prefetch(&_iter->async_tx); prefetch(&_iter->async_tx);
...@@ -257,8 +255,6 @@ static void __iop_adma_slot_cleanup(struct iop_adma_chan *iop_chan) ...@@ -257,8 +255,6 @@ static void __iop_adma_slot_cleanup(struct iop_adma_chan *iop_chan)
BUG_ON(!seen_current); BUG_ON(!seen_current);
iop_chan_idle(busy, iop_chan);
if (cookie > 0) { if (cookie > 0) {
iop_chan->completed_cookie = cookie; iop_chan->completed_cookie = cookie;
pr_debug("\tcompleted cookie %d\n", cookie); pr_debug("\tcompleted cookie %d\n", cookie);
...@@ -275,8 +271,11 @@ iop_adma_slot_cleanup(struct iop_adma_chan *iop_chan) ...@@ -275,8 +271,11 @@ iop_adma_slot_cleanup(struct iop_adma_chan *iop_chan)
static void iop_adma_tasklet(unsigned long data) static void iop_adma_tasklet(unsigned long data)
{ {
struct iop_adma_chan *chan = (struct iop_adma_chan *) data; struct iop_adma_chan *iop_chan = (struct iop_adma_chan *) data;
__iop_adma_slot_cleanup(chan);
spin_lock(&iop_chan->lock);
__iop_adma_slot_cleanup(iop_chan);
spin_unlock(&iop_chan->lock);
} }
static struct iop_adma_desc_slot * static struct iop_adma_desc_slot *
...@@ -339,9 +338,7 @@ iop_adma_alloc_slots(struct iop_adma_chan *iop_chan, int num_slots, ...@@ -339,9 +338,7 @@ iop_adma_alloc_slots(struct iop_adma_chan *iop_chan, int num_slots,
/* pre-ack all but the last descriptor */ /* pre-ack all but the last descriptor */
if (num_slots != slots_per_op) if (num_slots != slots_per_op)
iter->async_tx.ack = 1; async_tx_ack(&iter->async_tx);
else
iter->async_tx.ack = 0;
list_add_tail(&iter->chain_node, &chain); list_add_tail(&iter->chain_node, &chain);
alloc_tail = iter; alloc_tail = iter;
...@@ -514,7 +511,7 @@ static int iop_adma_alloc_chan_resources(struct dma_chan *chan) ...@@ -514,7 +511,7 @@ static int iop_adma_alloc_chan_resources(struct dma_chan *chan)
} }
static struct dma_async_tx_descriptor * static struct dma_async_tx_descriptor *
iop_adma_prep_dma_interrupt(struct dma_chan *chan) iop_adma_prep_dma_interrupt(struct dma_chan *chan, unsigned long flags)
{ {
struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan); struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
struct iop_adma_desc_slot *sw_desc, *grp_start; struct iop_adma_desc_slot *sw_desc, *grp_start;
...@@ -529,6 +526,7 @@ iop_adma_prep_dma_interrupt(struct dma_chan *chan) ...@@ -529,6 +526,7 @@ iop_adma_prep_dma_interrupt(struct dma_chan *chan)
grp_start = sw_desc->group_head; grp_start = sw_desc->group_head;
iop_desc_init_interrupt(grp_start, iop_chan); iop_desc_init_interrupt(grp_start, iop_chan);
grp_start->unmap_len = 0; grp_start->unmap_len = 0;
sw_desc->async_tx.flags = flags;
} }
spin_unlock_bh(&iop_chan->lock); spin_unlock_bh(&iop_chan->lock);
...@@ -561,6 +559,7 @@ iop_adma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dma_dest, ...@@ -561,6 +559,7 @@ iop_adma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dma_dest,
iop_desc_set_memcpy_src_addr(grp_start, dma_src); iop_desc_set_memcpy_src_addr(grp_start, dma_src);
sw_desc->unmap_src_cnt = 1; sw_desc->unmap_src_cnt = 1;
sw_desc->unmap_len = len; sw_desc->unmap_len = len;
sw_desc->async_tx.flags = flags;
} }
spin_unlock_bh(&iop_chan->lock); spin_unlock_bh(&iop_chan->lock);
...@@ -593,6 +592,7 @@ iop_adma_prep_dma_memset(struct dma_chan *chan, dma_addr_t dma_dest, ...@@ -593,6 +592,7 @@ iop_adma_prep_dma_memset(struct dma_chan *chan, dma_addr_t dma_dest,
iop_desc_set_dest_addr(grp_start, iop_chan, dma_dest); iop_desc_set_dest_addr(grp_start, iop_chan, dma_dest);
sw_desc->unmap_src_cnt = 1; sw_desc->unmap_src_cnt = 1;
sw_desc->unmap_len = len; sw_desc->unmap_len = len;
sw_desc->async_tx.flags = flags;
} }
spin_unlock_bh(&iop_chan->lock); spin_unlock_bh(&iop_chan->lock);
...@@ -626,6 +626,7 @@ iop_adma_prep_dma_xor(struct dma_chan *chan, dma_addr_t dma_dest, ...@@ -626,6 +626,7 @@ iop_adma_prep_dma_xor(struct dma_chan *chan, dma_addr_t dma_dest,
iop_desc_set_dest_addr(grp_start, iop_chan, dma_dest); iop_desc_set_dest_addr(grp_start, iop_chan, dma_dest);
sw_desc->unmap_src_cnt = src_cnt; sw_desc->unmap_src_cnt = src_cnt;
sw_desc->unmap_len = len; sw_desc->unmap_len = len;
sw_desc->async_tx.flags = flags;
while (src_cnt--) while (src_cnt--)
iop_desc_set_xor_src_addr(grp_start, src_cnt, iop_desc_set_xor_src_addr(grp_start, src_cnt,
dma_src[src_cnt]); dma_src[src_cnt]);
...@@ -662,6 +663,7 @@ iop_adma_prep_dma_zero_sum(struct dma_chan *chan, dma_addr_t *dma_src, ...@@ -662,6 +663,7 @@ iop_adma_prep_dma_zero_sum(struct dma_chan *chan, dma_addr_t *dma_src,
__func__, grp_start->xor_check_result); __func__, grp_start->xor_check_result);
sw_desc->unmap_src_cnt = src_cnt; sw_desc->unmap_src_cnt = src_cnt;
sw_desc->unmap_len = len; sw_desc->unmap_len = len;
sw_desc->async_tx.flags = flags;
while (src_cnt--) while (src_cnt--)
iop_desc_set_zero_sum_src_addr(grp_start, src_cnt, iop_desc_set_zero_sum_src_addr(grp_start, src_cnt,
dma_src[src_cnt]); dma_src[src_cnt]);
...@@ -671,12 +673,6 @@ iop_adma_prep_dma_zero_sum(struct dma_chan *chan, dma_addr_t *dma_src, ...@@ -671,12 +673,6 @@ iop_adma_prep_dma_zero_sum(struct dma_chan *chan, dma_addr_t *dma_src,
return sw_desc ? &sw_desc->async_tx : NULL; return sw_desc ? &sw_desc->async_tx : NULL;
} }
static void iop_adma_dependency_added(struct dma_chan *chan)
{
struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
tasklet_schedule(&iop_chan->irq_tasklet);
}
static void iop_adma_free_chan_resources(struct dma_chan *chan) static void iop_adma_free_chan_resources(struct dma_chan *chan)
{ {
struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan); struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
...@@ -854,11 +850,11 @@ static int __devinit iop_adma_memcpy_self_test(struct iop_adma_device *device) ...@@ -854,11 +850,11 @@ static int __devinit iop_adma_memcpy_self_test(struct iop_adma_device *device)
src_dma = dma_map_single(dma_chan->device->dev, src, src_dma = dma_map_single(dma_chan->device->dev, src,
IOP_ADMA_TEST_SIZE, DMA_TO_DEVICE); IOP_ADMA_TEST_SIZE, DMA_TO_DEVICE);
tx = iop_adma_prep_dma_memcpy(dma_chan, dest_dma, src_dma, tx = iop_adma_prep_dma_memcpy(dma_chan, dest_dma, src_dma,
IOP_ADMA_TEST_SIZE, 1); IOP_ADMA_TEST_SIZE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
cookie = iop_adma_tx_submit(tx); cookie = iop_adma_tx_submit(tx);
iop_adma_issue_pending(dma_chan); iop_adma_issue_pending(dma_chan);
async_tx_ack(tx);
msleep(1); msleep(1);
if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) != if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) !=
...@@ -954,11 +950,11 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device) ...@@ -954,11 +950,11 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device)
dma_srcs[i] = dma_map_page(dma_chan->device->dev, xor_srcs[i], dma_srcs[i] = dma_map_page(dma_chan->device->dev, xor_srcs[i],
0, PAGE_SIZE, DMA_TO_DEVICE); 0, PAGE_SIZE, DMA_TO_DEVICE);
tx = iop_adma_prep_dma_xor(dma_chan, dest_dma, dma_srcs, tx = iop_adma_prep_dma_xor(dma_chan, dest_dma, dma_srcs,
IOP_ADMA_NUM_SRC_TEST, PAGE_SIZE, 1); IOP_ADMA_NUM_SRC_TEST, PAGE_SIZE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
cookie = iop_adma_tx_submit(tx); cookie = iop_adma_tx_submit(tx);
iop_adma_issue_pending(dma_chan); iop_adma_issue_pending(dma_chan);
async_tx_ack(tx);
msleep(8); msleep(8);
if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) != if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) !=
...@@ -1001,11 +997,11 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device) ...@@ -1001,11 +997,11 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device)
DMA_TO_DEVICE); DMA_TO_DEVICE);
tx = iop_adma_prep_dma_zero_sum(dma_chan, dma_srcs, tx = iop_adma_prep_dma_zero_sum(dma_chan, dma_srcs,
IOP_ADMA_NUM_SRC_TEST + 1, PAGE_SIZE, IOP_ADMA_NUM_SRC_TEST + 1, PAGE_SIZE,
&zero_sum_result, 1); &zero_sum_result,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
cookie = iop_adma_tx_submit(tx); cookie = iop_adma_tx_submit(tx);
iop_adma_issue_pending(dma_chan); iop_adma_issue_pending(dma_chan);
async_tx_ack(tx);
msleep(8); msleep(8);
if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) { if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) {
...@@ -1025,11 +1021,11 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device) ...@@ -1025,11 +1021,11 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device)
/* test memset */ /* test memset */
dma_addr = dma_map_page(dma_chan->device->dev, dest, 0, dma_addr = dma_map_page(dma_chan->device->dev, dest, 0,
PAGE_SIZE, DMA_FROM_DEVICE); PAGE_SIZE, DMA_FROM_DEVICE);
tx = iop_adma_prep_dma_memset(dma_chan, dma_addr, 0, PAGE_SIZE, 1); tx = iop_adma_prep_dma_memset(dma_chan, dma_addr, 0, PAGE_SIZE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
cookie = iop_adma_tx_submit(tx); cookie = iop_adma_tx_submit(tx);
iop_adma_issue_pending(dma_chan); iop_adma_issue_pending(dma_chan);
async_tx_ack(tx);
msleep(8); msleep(8);
if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) { if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) {
...@@ -1057,11 +1053,11 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device) ...@@ -1057,11 +1053,11 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device)
DMA_TO_DEVICE); DMA_TO_DEVICE);
tx = iop_adma_prep_dma_zero_sum(dma_chan, dma_srcs, tx = iop_adma_prep_dma_zero_sum(dma_chan, dma_srcs,
IOP_ADMA_NUM_SRC_TEST + 1, PAGE_SIZE, IOP_ADMA_NUM_SRC_TEST + 1, PAGE_SIZE,
&zero_sum_result, 1); &zero_sum_result,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
cookie = iop_adma_tx_submit(tx); cookie = iop_adma_tx_submit(tx);
iop_adma_issue_pending(dma_chan); iop_adma_issue_pending(dma_chan);
async_tx_ack(tx);
msleep(8); msleep(8);
if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) { if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) {
...@@ -1177,7 +1173,6 @@ static int __devinit iop_adma_probe(struct platform_device *pdev) ...@@ -1177,7 +1173,6 @@ static int __devinit iop_adma_probe(struct platform_device *pdev)
dma_dev->device_free_chan_resources = iop_adma_free_chan_resources; dma_dev->device_free_chan_resources = iop_adma_free_chan_resources;
dma_dev->device_is_tx_complete = iop_adma_is_complete; dma_dev->device_is_tx_complete = iop_adma_is_complete;
dma_dev->device_issue_pending = iop_adma_issue_pending; dma_dev->device_issue_pending = iop_adma_issue_pending;
dma_dev->device_dependency_added = iop_adma_dependency_added;
dma_dev->dev = &pdev->dev; dma_dev->dev = &pdev->dev;
/* set prep routines based on capability */ /* set prep routines based on capability */
...@@ -1232,9 +1227,6 @@ static int __devinit iop_adma_probe(struct platform_device *pdev) ...@@ -1232,9 +1227,6 @@ static int __devinit iop_adma_probe(struct platform_device *pdev)
} }
spin_lock_init(&iop_chan->lock); spin_lock_init(&iop_chan->lock);
init_timer(&iop_chan->cleanup_watchdog);
iop_chan->cleanup_watchdog.data = (unsigned long) iop_chan;
iop_chan->cleanup_watchdog.function = iop_adma_tasklet;
INIT_LIST_HEAD(&iop_chan->chain); INIT_LIST_HEAD(&iop_chan->chain);
INIT_LIST_HEAD(&iop_chan->all_slots); INIT_LIST_HEAD(&iop_chan->all_slots);
INIT_RCU_HEAD(&iop_chan->common.rcu); INIT_RCU_HEAD(&iop_chan->common.rcu);
...@@ -1298,7 +1290,7 @@ static void iop_chan_start_null_memcpy(struct iop_adma_chan *iop_chan) ...@@ -1298,7 +1290,7 @@ static void iop_chan_start_null_memcpy(struct iop_adma_chan *iop_chan)
grp_start = sw_desc->group_head; grp_start = sw_desc->group_head;
list_splice_init(&sw_desc->async_tx.tx_list, &iop_chan->chain); list_splice_init(&sw_desc->async_tx.tx_list, &iop_chan->chain);
sw_desc->async_tx.ack = 1; async_tx_ack(&sw_desc->async_tx);
iop_desc_init_memcpy(grp_start, 0); iop_desc_init_memcpy(grp_start, 0);
iop_desc_set_byte_count(grp_start, iop_chan, 0); iop_desc_set_byte_count(grp_start, iop_chan, 0);
iop_desc_set_dest_addr(grp_start, iop_chan, 0); iop_desc_set_dest_addr(grp_start, iop_chan, 0);
...@@ -1354,7 +1346,7 @@ static void iop_chan_start_null_xor(struct iop_adma_chan *iop_chan) ...@@ -1354,7 +1346,7 @@ static void iop_chan_start_null_xor(struct iop_adma_chan *iop_chan)
if (sw_desc) { if (sw_desc) {
grp_start = sw_desc->group_head; grp_start = sw_desc->group_head;
list_splice_init(&sw_desc->async_tx.tx_list, &iop_chan->chain); list_splice_init(&sw_desc->async_tx.tx_list, &iop_chan->chain);
sw_desc->async_tx.ack = 1; async_tx_ack(&sw_desc->async_tx);
iop_desc_init_null_xor(grp_start, 2, 0); iop_desc_init_null_xor(grp_start, 2, 0);
iop_desc_set_byte_count(grp_start, iop_chan, 0); iop_desc_set_byte_count(grp_start, iop_chan, 0);
iop_desc_set_dest_addr(grp_start, iop_chan, 0); iop_desc_set_dest_addr(grp_start, iop_chan, 0);
......
...@@ -454,11 +454,6 @@ static inline void iop_chan_append(struct iop_adma_chan *chan) ...@@ -454,11 +454,6 @@ static inline void iop_chan_append(struct iop_adma_chan *chan)
__raw_writel(adma_accr, ADMA_ACCR(chan)); __raw_writel(adma_accr, ADMA_ACCR(chan));
} }
static inline void iop_chan_idle(int busy, struct iop_adma_chan *chan)
{
do { } while (0);
}
static inline u32 iop_chan_get_status(struct iop_adma_chan *chan) static inline u32 iop_chan_get_status(struct iop_adma_chan *chan)
{ {
return __raw_readl(ADMA_ACSR(chan)); return __raw_readl(ADMA_ACSR(chan));
......
...@@ -767,20 +767,12 @@ static inline int iop_desc_get_zero_result(struct iop_adma_desc_slot *desc) ...@@ -767,20 +767,12 @@ static inline int iop_desc_get_zero_result(struct iop_adma_desc_slot *desc)
static inline void iop_chan_append(struct iop_adma_chan *chan) static inline void iop_chan_append(struct iop_adma_chan *chan)
{ {
u32 dma_chan_ctrl; u32 dma_chan_ctrl;
/* workaround dropped interrupts on 3xx */
mod_timer(&chan->cleanup_watchdog, jiffies + msecs_to_jiffies(3));
dma_chan_ctrl = __raw_readl(DMA_CCR(chan)); dma_chan_ctrl = __raw_readl(DMA_CCR(chan));
dma_chan_ctrl |= 0x2; dma_chan_ctrl |= 0x2;
__raw_writel(dma_chan_ctrl, DMA_CCR(chan)); __raw_writel(dma_chan_ctrl, DMA_CCR(chan));
} }
static inline void iop_chan_idle(int busy, struct iop_adma_chan *chan)
{
if (!busy)
del_timer(&chan->cleanup_watchdog);
}
static inline u32 iop_chan_get_status(struct iop_adma_chan *chan) static inline u32 iop_chan_get_status(struct iop_adma_chan *chan)
{ {
return __raw_readl(DMA_CSR(chan)); return __raw_readl(DMA_CSR(chan));
......
...@@ -51,7 +51,6 @@ struct iop_adma_device { ...@@ -51,7 +51,6 @@ struct iop_adma_device {
* @common: common dmaengine channel object members * @common: common dmaengine channel object members
* @last_used: place holder for allocation to continue from where it left off * @last_used: place holder for allocation to continue from where it left off
* @all_slots: complete domain of slots usable by the channel * @all_slots: complete domain of slots usable by the channel
* @cleanup_watchdog: workaround missed interrupts on iop3xx
* @slots_allocated: records the actual size of the descriptor slot pool * @slots_allocated: records the actual size of the descriptor slot pool
* @irq_tasklet: bottom half where iop_adma_slot_cleanup runs * @irq_tasklet: bottom half where iop_adma_slot_cleanup runs
*/ */
...@@ -65,7 +64,6 @@ struct iop_adma_chan { ...@@ -65,7 +64,6 @@ struct iop_adma_chan {
struct dma_chan common; struct dma_chan common;
struct iop_adma_desc_slot *last_used; struct iop_adma_desc_slot *last_used;
struct list_head all_slots; struct list_head all_slots;
struct timer_list cleanup_watchdog;
int slots_allocated; int slots_allocated;
struct tasklet_struct irq_tasklet; struct tasklet_struct irq_tasklet;
}; };
......
...@@ -95,12 +95,17 @@ enum dma_transaction_type { ...@@ -95,12 +95,17 @@ enum dma_transaction_type {
#define DMA_TX_TYPE_END (DMA_INTERRUPT + 1) #define DMA_TX_TYPE_END (DMA_INTERRUPT + 1)
/** /**
* enum dma_prep_flags - DMA flags to augment operation preparation * enum dma_ctrl_flags - DMA flags to augment operation preparation,
* control completion, and communicate status.
* @DMA_PREP_INTERRUPT - trigger an interrupt (callback) upon completion of * @DMA_PREP_INTERRUPT - trigger an interrupt (callback) upon completion of
* this transaction * this transaction
* @DMA_CTRL_ACK - the descriptor cannot be reused until the client
* acknowledges receipt, i.e. has has a chance to establish any
* dependency chains
*/ */
enum dma_prep_flags { enum dma_ctrl_flags {
DMA_PREP_INTERRUPT = (1 << 0), DMA_PREP_INTERRUPT = (1 << 0),
DMA_CTRL_ACK = (1 << 1),
}; };
/** /**
...@@ -211,8 +216,8 @@ typedef void (*dma_async_tx_callback)(void *dma_async_param); ...@@ -211,8 +216,8 @@ typedef void (*dma_async_tx_callback)(void *dma_async_param);
* ---dma generic offload fields--- * ---dma generic offload fields---
* @cookie: tracking cookie for this transaction, set to -EBUSY if * @cookie: tracking cookie for this transaction, set to -EBUSY if
* this tx is sitting on a dependency list * this tx is sitting on a dependency list
* @ack: the descriptor can not be reused until the client acknowledges * @flags: flags to augment operation preparation, control completion, and
* receipt, i.e. has has a chance to establish any dependency chains * communicate status
* @phys: physical address of the descriptor * @phys: physical address of the descriptor
* @tx_list: driver common field for operations that require multiple * @tx_list: driver common field for operations that require multiple
* descriptors * descriptors
...@@ -221,23 +226,20 @@ typedef void (*dma_async_tx_callback)(void *dma_async_param); ...@@ -221,23 +226,20 @@ typedef void (*dma_async_tx_callback)(void *dma_async_param);
* @callback: routine to call after this operation is complete * @callback: routine to call after this operation is complete
* @callback_param: general parameter to pass to the callback routine * @callback_param: general parameter to pass to the callback routine
* ---async_tx api specific fields--- * ---async_tx api specific fields---
* @depend_list: at completion this list of transactions are submitted * @next: at completion submit this descriptor
* @depend_node: allow this transaction to be executed after another
* transaction has completed, possibly on another channel
* @parent: pointer to the next level up in the dependency chain * @parent: pointer to the next level up in the dependency chain
* @lock: protect the dependency list * @lock: protect the parent and next pointers
*/ */
struct dma_async_tx_descriptor { struct dma_async_tx_descriptor {
dma_cookie_t cookie; dma_cookie_t cookie;
int ack; enum dma_ctrl_flags flags; /* not a 'long' to pack with cookie */
dma_addr_t phys; dma_addr_t phys;
struct list_head tx_list; struct list_head tx_list;
struct dma_chan *chan; struct dma_chan *chan;
dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx); dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx);
dma_async_tx_callback callback; dma_async_tx_callback callback;
void *callback_param; void *callback_param;
struct list_head depend_list; struct dma_async_tx_descriptor *next;
struct list_head depend_node;
struct dma_async_tx_descriptor *parent; struct dma_async_tx_descriptor *parent;
spinlock_t lock; spinlock_t lock;
}; };
...@@ -261,7 +263,6 @@ struct dma_async_tx_descriptor { ...@@ -261,7 +263,6 @@ struct dma_async_tx_descriptor {
* @device_prep_dma_zero_sum: prepares a zero_sum operation * @device_prep_dma_zero_sum: prepares a zero_sum operation
* @device_prep_dma_memset: prepares a memset operation * @device_prep_dma_memset: prepares a memset operation
* @device_prep_dma_interrupt: prepares an end of chain interrupt operation * @device_prep_dma_interrupt: prepares an end of chain interrupt operation
* @device_dependency_added: async_tx notifies the channel about new deps
* @device_issue_pending: push pending transactions to hardware * @device_issue_pending: push pending transactions to hardware
*/ */
struct dma_device { struct dma_device {
...@@ -294,9 +295,8 @@ struct dma_device { ...@@ -294,9 +295,8 @@ struct dma_device {
struct dma_chan *chan, dma_addr_t dest, int value, size_t len, struct dma_chan *chan, dma_addr_t dest, int value, size_t len,
unsigned long flags); unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)( struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)(
struct dma_chan *chan); struct dma_chan *chan, unsigned long flags);
void (*device_dependency_added)(struct dma_chan *chan);
enum dma_status (*device_is_tx_complete)(struct dma_chan *chan, enum dma_status (*device_is_tx_complete)(struct dma_chan *chan,
dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t cookie, dma_cookie_t *last,
dma_cookie_t *used); dma_cookie_t *used);
...@@ -321,7 +321,13 @@ void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx, ...@@ -321,7 +321,13 @@ void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx,
static inline void static inline void
async_tx_ack(struct dma_async_tx_descriptor *tx) async_tx_ack(struct dma_async_tx_descriptor *tx)
{ {
tx->ack = 1; tx->flags |= DMA_CTRL_ACK;
}
static inline int
async_tx_test_ack(struct dma_async_tx_descriptor *tx)
{
return tx->flags & DMA_CTRL_ACK;
} }
#define first_dma_cap(mask) __first_dma_cap(&(mask)) #define first_dma_cap(mask) __first_dma_cap(&(mask))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment