Skip to content

Commit

Permalink
dmaengine: dw-edma: Create a new dw_edma_core_ops structure to abstra…
Browse files Browse the repository at this point in the history
…ct controller operation

The structure dw_edma_core_ops has a set of the pointers
abstracting out the DW eDMA vX and DW HDMA Native controllers.
And use dw_edma_v0_core_register to set up operation.

Signed-off-by: Cai Huoqing <cai.huoqing@linux.dev>
Reviewed-by: Serge Semin <fancer.lancer@gmail.com>
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Tested-by: Serge Semin <fancer.lancer@gmail.com>
Link: https://lore.kernel.org/r/20230520050854.73160-3-cai.huoqing@linux.dev
Signed-off-by: Vinod Koul <vkoul@kernel.org>
  • Loading branch information
caihuoq authored and vinodkoul committed May 24, 2023
1 parent 4875175 commit f9c3403
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 82 deletions.
82 changes: 25 additions & 57 deletions drivers/dma/dw-edma/dw-edma-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ static void vchan_free_desc(struct virt_dma_desc *vdesc)

static int dw_edma_start_transfer(struct dw_edma_chan *chan)
{
struct dw_edma *dw = chan->dw;
struct dw_edma_chunk *child;
struct dw_edma_desc *desc;
struct virt_dma_desc *vd;
Expand All @@ -200,7 +201,7 @@ static int dw_edma_start_transfer(struct dw_edma_chan *chan)
if (!child)
return 0;

dw_edma_v0_core_start(child, !desc->xfer_sz);
dw_edma_core_start(dw, child, !desc->xfer_sz);
desc->xfer_sz += child->ll_region.sz;
dw_edma_free_burst(child);
list_del(&child->list);
Expand Down Expand Up @@ -287,7 +288,7 @@ static int dw_edma_device_terminate_all(struct dma_chan *dchan)
chan->configured = false;
} else if (chan->status == EDMA_ST_IDLE) {
chan->configured = false;
} else if (dw_edma_v0_core_ch_status(chan) == DMA_COMPLETE) {
} else if (dw_edma_core_ch_status(chan) == DMA_COMPLETE) {
/*
* The channel is in a false BUSY state, probably didn't
* receive or lost an interrupt
Expand Down Expand Up @@ -599,8 +600,6 @@ static void dw_edma_done_interrupt(struct dw_edma_chan *chan)
struct virt_dma_desc *vd;
unsigned long flags;

dw_edma_v0_core_clear_done_int(chan);

spin_lock_irqsave(&chan->vc.lock, flags);
vd = vchan_next_desc(&chan->vc);
if (vd) {
Expand Down Expand Up @@ -641,8 +640,6 @@ static void dw_edma_abort_interrupt(struct dw_edma_chan *chan)
struct virt_dma_desc *vd;
unsigned long flags;

dw_edma_v0_core_clear_abort_int(chan);

spin_lock_irqsave(&chan->vc.lock, flags);
vd = vchan_next_desc(&chan->vc);
if (vd) {
Expand All @@ -654,63 +651,32 @@ static void dw_edma_abort_interrupt(struct dw_edma_chan *chan)
chan->status = EDMA_ST_IDLE;
}

static irqreturn_t dw_edma_interrupt(int irq, void *data, bool write)
static inline irqreturn_t dw_edma_interrupt_write(int irq, void *data)
{
struct dw_edma_irq *dw_irq = data;
struct dw_edma *dw = dw_irq->dw;
unsigned long total, pos, val;
unsigned long off;
u32 mask;

if (write) {
total = dw->wr_ch_cnt;
off = 0;
mask = dw_irq->wr_mask;
} else {
total = dw->rd_ch_cnt;
off = dw->wr_ch_cnt;
mask = dw_irq->rd_mask;
}

val = dw_edma_v0_core_status_done_int(dw, write ?
EDMA_DIR_WRITE :
EDMA_DIR_READ);
val &= mask;
for_each_set_bit(pos, &val, total) {
struct dw_edma_chan *chan = &dw->chan[pos + off];

dw_edma_done_interrupt(chan);
}

val = dw_edma_v0_core_status_abort_int(dw, write ?
EDMA_DIR_WRITE :
EDMA_DIR_READ);
val &= mask;
for_each_set_bit(pos, &val, total) {
struct dw_edma_chan *chan = &dw->chan[pos + off];

dw_edma_abort_interrupt(chan);
}

return IRQ_HANDLED;
}

static inline irqreturn_t dw_edma_interrupt_write(int irq, void *data)
{
return dw_edma_interrupt(irq, data, true);
return dw_edma_core_handle_int(dw_irq, EDMA_DIR_WRITE,
dw_edma_done_interrupt,
dw_edma_abort_interrupt);
}

static inline irqreturn_t dw_edma_interrupt_read(int irq, void *data)
{
return dw_edma_interrupt(irq, data, false);
struct dw_edma_irq *dw_irq = data;

return dw_edma_core_handle_int(dw_irq, EDMA_DIR_READ,
dw_edma_done_interrupt,
dw_edma_abort_interrupt);
}

static irqreturn_t dw_edma_interrupt_common(int irq, void *data)
{
dw_edma_interrupt(irq, data, true);
dw_edma_interrupt(irq, data, false);
irqreturn_t ret = IRQ_NONE;

ret |= dw_edma_interrupt_write(irq, data);
ret |= dw_edma_interrupt_read(irq, data);

return IRQ_HANDLED;
return ret;
}

static int dw_edma_alloc_chan_resources(struct dma_chan *dchan)
Expand Down Expand Up @@ -811,7 +777,7 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)

vchan_init(&chan->vc, dma);

dw_edma_v0_core_device_config(chan);
dw_edma_core_ch_config(chan);
}

/* Set DMA channel capabilities */
Expand Down Expand Up @@ -956,14 +922,16 @@ int dw_edma_probe(struct dw_edma_chip *chip)

dw->chip = chip;

dw_edma_v0_core_register(dw);

raw_spin_lock_init(&dw->lock);

dw->wr_ch_cnt = min_t(u16, chip->ll_wr_cnt,
dw_edma_v0_core_ch_count(dw, EDMA_DIR_WRITE));
dw_edma_core_ch_count(dw, EDMA_DIR_WRITE));
dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, EDMA_MAX_WR_CH);

dw->rd_ch_cnt = min_t(u16, chip->ll_rd_cnt,
dw_edma_v0_core_ch_count(dw, EDMA_DIR_READ));
dw_edma_core_ch_count(dw, EDMA_DIR_READ));
dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, EDMA_MAX_RD_CH);

if (!dw->wr_ch_cnt && !dw->rd_ch_cnt)
Expand All @@ -982,7 +950,7 @@ int dw_edma_probe(struct dw_edma_chip *chip)
dev_name(chip->dev));

/* Disable eDMA, only to establish the ideal initial conditions */
dw_edma_v0_core_off(dw);
dw_edma_core_off(dw);

/* Request IRQs */
err = dw_edma_irq_request(dw, &wr_alloc, &rd_alloc);
Expand All @@ -995,7 +963,7 @@ int dw_edma_probe(struct dw_edma_chip *chip)
goto err_irq_free;

/* Turn debugfs on */
dw_edma_v0_core_debugfs_on(dw);
dw_edma_core_debugfs_on(dw);

chip->dw = dw;

Expand All @@ -1021,7 +989,7 @@ int dw_edma_remove(struct dw_edma_chip *chip)
return -ENODEV;

/* Disable eDMA */
dw_edma_v0_core_off(dw);
dw_edma_core_off(dw);

/* Free irqs */
for (i = (dw->nr_irqs - 1); i >= 0; i--)
Expand Down
58 changes: 58 additions & 0 deletions drivers/dma/dw-edma/dw-edma-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,21 @@ struct dw_edma {
raw_spinlock_t lock; /* Only for legacy */

struct dw_edma_chip *chip;

const struct dw_edma_core_ops *core;
};

typedef void (*dw_edma_handler_t)(struct dw_edma_chan *);

struct dw_edma_core_ops {
void (*off)(struct dw_edma *dw);
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);
void (*start)(struct dw_edma_chunk *chunk, bool first);
void (*ch_config)(struct dw_edma_chan *chan);
void (*debugfs_on)(struct dw_edma *dw);
};

struct dw_edma_sg {
Expand Down Expand Up @@ -148,4 +163,47 @@ struct dw_edma_chan *dchan2dw_edma_chan(struct dma_chan *dchan)
return vc2dw_edma_chan(to_virt_chan(dchan));
}

static inline
void dw_edma_core_off(struct dw_edma *dw)
{
dw->core->off(dw);
}

static inline
u16 dw_edma_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir)
{
return dw->core->ch_count(dw, dir);
}

static inline
enum dma_status dw_edma_core_ch_status(struct dw_edma_chan *chan)
{
return chan->dw->core->ch_status(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)
{
return dw_irq->dw->core->handle_int(dw_irq, dir, done, abort);
}

static inline
void dw_edma_core_start(struct dw_edma *dw, struct dw_edma_chunk *chunk, bool first)
{
dw->core->start(chunk, first);
}

static inline
void dw_edma_core_ch_config(struct dw_edma_chan *chan)
{
chan->dw->core->ch_config(chan);
}

static inline
void dw_edma_core_debugfs_on(struct dw_edma *dw)
{
dw->core->debugfs_on(dw);
}

#endif /* _DW_EDMA_CORE_H */
Loading

0 comments on commit f9c3403

Please sign in to comment.