diff options
Diffstat (limited to 'drivers/dma')
-rw-r--r-- | drivers/dma/shdma.c | 55 |
1 files changed, 28 insertions, 27 deletions
diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index 7f49235..e7bb747 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -265,8 +265,9 @@ static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx) struct sh_dmae_chan *sh_chan = to_sh_chan(tx->chan); dma_async_tx_callback callback = tx->callback; dma_cookie_t cookie; + unsigned long flags; - spin_lock_bh(&sh_chan->desc_lock); + spin_lock_irqsave(&sh_chan->desc_lock, flags); cookie = sh_chan->common.cookie; cookie++; @@ -302,7 +303,7 @@ static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx) tx->cookie, &last->async_tx, sh_chan->id, desc->hw.sar, desc->hw.tcr, desc->hw.dar); - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irqrestore(&sh_chan->desc_lock, flags); return cookie; } @@ -374,24 +375,18 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan) dmae_init(sh_chan); } - spin_lock_bh(&sh_chan->desc_lock); while (sh_chan->descs_allocated < NR_DESCS_PER_CHANNEL) { - spin_unlock_bh(&sh_chan->desc_lock); desc = kzalloc(sizeof(struct sh_desc), GFP_KERNEL); - if (!desc) { - spin_lock_bh(&sh_chan->desc_lock); + if (!desc) break; - } dma_async_tx_descriptor_init(&desc->async_tx, &sh_chan->common); desc->async_tx.tx_submit = sh_dmae_tx_submit; desc->mark = DESC_IDLE; - spin_lock_bh(&sh_chan->desc_lock); list_add(&desc->node, &sh_chan->ld_free); sh_chan->descs_allocated++; } - spin_unlock_bh(&sh_chan->desc_lock); if (!sh_chan->descs_allocated) { ret = -ENOMEM; @@ -405,6 +400,7 @@ edescalloc: clear_bit(param->slave_id, sh_dmae_slave_used); etestused: efindslave: + chan->private = NULL; pm_runtime_put(sh_chan->dev); return ret; } @@ -437,12 +433,12 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan) chan->private = NULL; } - spin_lock_bh(&sh_chan->desc_lock); + spin_lock_irq(&sh_chan->desc_lock); list_splice_init(&sh_chan->ld_free, &list); sh_chan->descs_allocated = 0; - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irq(&sh_chan->desc_lock); if (descs > 0) pm_runtime_put(sh_chan->dev); @@ -534,6 +530,7 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_sg(struct sh_dmae_chan *sh_c struct sh_desc *first = NULL, *new = NULL /* compiler... */; LIST_HEAD(tx_list); int chunks = 0; + unsigned long irq_flags; int i; if (!sg_len) @@ -544,7 +541,7 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_sg(struct sh_dmae_chan *sh_c (SH_DMA_TCR_MAX + 1); /* Have to lock the whole loop to protect against concurrent release */ - spin_lock_bh(&sh_chan->desc_lock); + spin_lock_irqsave(&sh_chan->desc_lock, irq_flags); /* * Chaining: @@ -590,7 +587,7 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_sg(struct sh_dmae_chan *sh_c /* Put them back on the free list, so, they don't get lost */ list_splice_tail(&tx_list, &sh_chan->ld_free); - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irqrestore(&sh_chan->desc_lock, irq_flags); return &first->async_tx; @@ -599,7 +596,7 @@ err_get_desc: new->mark = DESC_IDLE; list_splice(&tx_list, &sh_chan->ld_free); - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irqrestore(&sh_chan->desc_lock, irq_flags); return NULL; } @@ -661,6 +658,7 @@ static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg) { struct sh_dmae_chan *sh_chan = to_sh_chan(chan); + unsigned long flags; /* Only supports DMA_TERMINATE_ALL */ if (cmd != DMA_TERMINATE_ALL) @@ -669,7 +667,7 @@ static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, if (!chan) return -EINVAL; - spin_lock_bh(&sh_chan->desc_lock); + spin_lock_irqsave(&sh_chan->desc_lock, flags); dmae_halt(sh_chan); if (!list_empty(&sh_chan->ld_queue)) { @@ -680,7 +678,7 @@ static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, sh_chan->xmit_shift; } - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irqrestore(&sh_chan->desc_lock, flags); sh_dmae_chan_ld_cleanup(sh_chan, true); @@ -695,8 +693,9 @@ static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all dma_cookie_t cookie = 0; dma_async_tx_callback callback = NULL; void *param = NULL; + unsigned long flags; - spin_lock_bh(&sh_chan->desc_lock); + spin_lock_irqsave(&sh_chan->desc_lock, flags); list_for_each_entry_safe(desc, _desc, &sh_chan->ld_queue, node) { struct dma_async_tx_descriptor *tx = &desc->async_tx; @@ -773,7 +772,7 @@ static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all */ sh_chan->completed_cookie = sh_chan->common.cookie; - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irqrestore(&sh_chan->desc_lock, flags); if (callback) callback(param); @@ -796,10 +795,12 @@ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan) { struct sh_desc *desc; - spin_lock_bh(&sh_chan->desc_lock); + spin_lock_irq(&sh_chan->desc_lock); /* DMA work check */ - if (dmae_is_busy(sh_chan)) - goto sh_chan_xfer_ld_queue_end; + if (dmae_is_busy(sh_chan)) { + spin_unlock_irq(&sh_chan->desc_lock); + return; + } /* Find the first not transferred descriptor */ list_for_each_entry(desc, &sh_chan->ld_queue, node) @@ -813,8 +814,7 @@ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan) break; } -sh_chan_xfer_ld_queue_end: - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irq(&sh_chan->desc_lock); } static void sh_dmae_memcpy_issue_pending(struct dma_chan *chan) @@ -831,6 +831,7 @@ static enum dma_status sh_dmae_tx_status(struct dma_chan *chan, dma_cookie_t last_used; dma_cookie_t last_complete; enum dma_status status; + unsigned long flags; sh_dmae_chan_ld_cleanup(sh_chan, false); @@ -841,7 +842,7 @@ static enum dma_status sh_dmae_tx_status(struct dma_chan *chan, BUG_ON(last_complete < 0); dma_set_tx_state(txstate, last_complete, last_used, 0); - spin_lock_bh(&sh_chan->desc_lock); + spin_lock_irqsave(&sh_chan->desc_lock, flags); status = dma_async_is_complete(cookie, last_complete, last_used); @@ -859,7 +860,7 @@ static enum dma_status sh_dmae_tx_status(struct dma_chan *chan, } } - spin_unlock_bh(&sh_chan->desc_lock); + spin_unlock_irqrestore(&sh_chan->desc_lock, flags); return status; } @@ -952,7 +953,7 @@ static void dmae_do_tasklet(unsigned long data) u32 sar_buf = sh_dmae_readl(sh_chan, SAR); u32 dar_buf = sh_dmae_readl(sh_chan, DAR); - spin_lock(&sh_chan->desc_lock); + spin_lock_irq(&sh_chan->desc_lock); list_for_each_entry(desc, &sh_chan->ld_queue, node) { if (desc->mark == DESC_SUBMITTED && ((desc->direction == DMA_FROM_DEVICE && @@ -965,7 +966,7 @@ static void dmae_do_tasklet(unsigned long data) break; } } - spin_unlock(&sh_chan->desc_lock); + spin_unlock_irq(&sh_chan->desc_lock); /* Next desc */ sh_chan_xfer_ld_queue(sh_chan); |