diff options
| -rw-r--r-- | drivers/dma/dw-edma/dw-edma-core.c | 44 | ||||
| -rw-r--r-- | drivers/dma/dw-edma/dw-edma-core.h | 16 | ||||
| -rw-r--r-- | drivers/dma/dw-edma/dw-edma-v0-core.c | 6 | ||||
| -rw-r--r-- | drivers/dma/dw-edma/dw-hdma-v0-core.c | 6 |
4 files changed, 44 insertions, 28 deletions
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c index bbfd82b12ab5..97de0ad4489a 100644 --- a/drivers/dma/dw-edma/dw-edma-core.c +++ b/drivers/dma/dw-edma/dw-edma-core.c @@ -702,17 +702,16 @@ dw_edma_device_prep_interleaved_dma(struct dma_chan *dchan, return dw_edma_device_transfer(&xfer, dw_edma_device_get_config(dchan, NULL)); } -static void dw_edma_done_interrupt(struct dw_edma_chan *chan) +/* Must be called with vc.lock held. */ +static void dw_edma_done_interrupt_locked(struct dw_edma_chan *chan) { struct dw_edma_desc *desc; struct virt_dma_desc *vd; - unsigned long flags; - spin_lock_irqsave(&chan->vc.lock, flags); - if (chan->status == EDMA_ST_PAUSE) { - spin_unlock_irqrestore(&chan->vc.lock, flags); + lockdep_assert_held(&chan->vc.lock); + + if (chan->status == EDMA_ST_PAUSE) return; - } switch (chan->request) { case EDMA_REQ_NONE: @@ -751,7 +750,14 @@ static void dw_edma_done_interrupt(struct dw_edma_chan *chan) break; } dw_edma_core_ch_maybe_doorbell(chan); +} +static void dw_edma_done_interrupt(struct dw_edma_chan *chan) +{ + unsigned long flags; + + spin_lock_irqsave(&chan->vc.lock, flags); + dw_edma_done_interrupt_locked(chan); spin_unlock_irqrestore(&chan->vc.lock, flags); } @@ -793,20 +799,24 @@ static void dw_edma_irq_work(struct work_struct *work) } static void dw_edma_queue_irq_work(struct dw_edma_chan *chan, - enum dw_edma_deferred_event event) + unsigned int events) { - atomic_or(event, &chan->irq_pending); + atomic_or(events, &chan->irq_pending); queue_work(chan->dw->wq, &chan->irq_work); } -static void dw_edma_done_interrupt_deferred(struct dw_edma_chan *chan) +static void dw_edma_record_irq(struct dw_edma_chan *chan, unsigned int events) { - dw_edma_queue_irq_work(chan, DW_EDMA_DEFERRED_DONE); -} + unsigned int pending = 0; -static void dw_edma_abort_interrupt_deferred(struct dw_edma_chan *chan) -{ - dw_edma_queue_irq_work(chan, DW_EDMA_DEFERRED_ABORT); + if (events & (DW_EDMA_IRQ_DONE | DW_EDMA_IRQ_PROGRESS | + DW_EDMA_IRQ_STOP)) + pending |= DW_EDMA_DEFERRED_DONE; + if (events & DW_EDMA_IRQ_ABORT) + pending |= DW_EDMA_DEFERRED_ABORT; + + if (pending) + dw_edma_queue_irq_work(chan, pending); } static void dw_edma_emul_irq_ack(struct irq_data *d) @@ -907,8 +917,7 @@ static inline irqreturn_t dw_edma_interrupt_write_inner(int irq, void *data) struct dw_edma_irq *dw_irq = data; return dw_edma_core_handle_int(dw_irq, EDMA_DIR_WRITE, - dw_edma_done_interrupt_deferred, - dw_edma_abort_interrupt_deferred); + dw_edma_record_irq); } static inline irqreturn_t dw_edma_interrupt_read_inner(int irq, void *data) @@ -916,8 +925,7 @@ static inline irqreturn_t dw_edma_interrupt_read_inner(int irq, void *data) struct dw_edma_irq *dw_irq = data; return dw_edma_core_handle_int(dw_irq, EDMA_DIR_READ, - dw_edma_done_interrupt_deferred, - dw_edma_abort_interrupt_deferred); + dw_edma_record_irq); } static inline irqreturn_t dw_edma_interrupt_write(int irq, void *data) diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h index 8d993e8cccbb..30b508eb3e3d 100644 --- a/drivers/dma/dw-edma/dw-edma-core.h +++ b/drivers/dma/dw-edma/dw-edma-core.h @@ -41,6 +41,13 @@ enum dw_edma_xfer_type { EDMA_XFER_INTERLEAVED }; +enum dw_edma_irq_event { + DW_EDMA_IRQ_DONE = BIT(0), + DW_EDMA_IRQ_PROGRESS = BIT(1), + DW_EDMA_IRQ_STOP = BIT(2), + DW_EDMA_IRQ_ABORT = BIT(3), +}; + struct dw_edma_chan; struct dw_edma_chunk; @@ -147,7 +154,8 @@ struct dw_edma { const struct dw_edma_core_ops *core; }; -typedef void (*dw_edma_handler_t)(struct dw_edma_chan *); +typedef void (*dw_edma_handler_t)(struct dw_edma_chan *chan, + unsigned int events); struct dw_edma_core_ops { void (*off)(struct dw_edma *dw); @@ -156,7 +164,7 @@ struct dw_edma_core_ops { u16 (*ch_count)(struct dw_edma *dw, enum dw_edma_dir dir); enum dma_status (*ch_status)(struct dw_edma_chan *chan); irqreturn_t (*handle_int)(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir, - dw_edma_handler_t done, dw_edma_handler_t abort); + dw_edma_handler_t handler); void (*non_ll_start)(struct dw_edma_chan *chan, struct dw_edma_burst *child); void (*ll_data)(struct dw_edma_chan *chan, struct dw_edma_burst *burst, u32 idx, bool cb, bool irq); @@ -256,9 +264,9 @@ enum dma_status dw_edma_core_ch_status(struct dw_edma_chan *chan) static inline irqreturn_t dw_edma_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir, - dw_edma_handler_t done, dw_edma_handler_t abort) + dw_edma_handler_t handler) { - return dw_irq->dw->core->handle_int(dw_irq, dir, done, abort); + return dw_irq->dw->core->handle_int(dw_irq, dir, handler); } static inline diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c index 9053354eda67..4a1bb128fa00 100644 --- a/drivers/dma/dw-edma/dw-edma-v0-core.c +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c @@ -336,7 +336,7 @@ static void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan) static irqreturn_t dw_edma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir, - dw_edma_handler_t done, dw_edma_handler_t abort) + dw_edma_handler_t handler) { struct dw_edma *dw = dw_irq->dw; unsigned long total, pos, val; @@ -375,7 +375,7 @@ dw_edma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir, continue; dw_edma_v0_core_clear_done_int(chan); - done(chan); + handler(chan, DW_EDMA_IRQ_DONE); ret = IRQ_HANDLED; } @@ -389,7 +389,7 @@ dw_edma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir, continue; dw_edma_v0_core_clear_abort_int(chan); - abort(chan); + handler(chan, DW_EDMA_IRQ_ABORT); ret = IRQ_HANDLED; } diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.c b/drivers/dma/dw-edma/dw-hdma-v0-core.c index 4acbace43519..c6d7f9885aa8 100644 --- a/drivers/dma/dw-edma/dw-hdma-v0-core.c +++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c @@ -174,7 +174,7 @@ static u32 dw_hdma_v0_core_status_int(struct dw_edma_chan *chan) static irqreturn_t dw_hdma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir, - dw_edma_handler_t done, dw_edma_handler_t abort) + dw_edma_handler_t handler) { struct dw_edma *dw = dw_irq->dw; unsigned long total, pos, val; @@ -200,14 +200,14 @@ dw_hdma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir, val = dw_hdma_v0_core_status_int(chan); if (FIELD_GET(HDMA_V0_STOP_INT_MASK, val)) { dw_hdma_v0_core_clear_done_int(chan); - done(chan); + handler(chan, DW_EDMA_IRQ_STOP); ret = IRQ_HANDLED; } if (FIELD_GET(HDMA_V0_ABORT_INT_MASK, val)) { dw_hdma_v0_core_clear_abort_int(chan); - abort(chan); + handler(chan, DW_EDMA_IRQ_ABORT); ret = IRQ_HANDLED; } |
