Commit 437a91ba authored by Federico Vaga's avatar Federico Vaga

Merge branch 'bugfix/dma-pool-leak' into develop

parents 7555fa98 b23a39b4
...@@ -535,6 +535,32 @@ err: ...@@ -535,6 +535,32 @@ err:
return NULL; return NULL;
} }
static void gn412x_dma_tx_free(struct gn412x_dma_tx *tx)
{
struct gn412x_dma_device *gn412x_dma;
int i;
if (unlikely(!tx))
return;
gn412x_dma = to_gn412x_dma_device(tx->tx.chan->device);
for (i = 0; i < tx->sg_len; ++i) {
dma_addr_t phys;
dev_dbg(&gn412x_dma->pdev->dev,
"Release TX (%p) DMA desc %d\n", tx, i);
if (i == 0) {
phys = tx->tx.phys;
} else {
phys = tx->sgl_hw[i - 1]->next_addr_h;
phys <<= 32;
phys |= tx->sgl_hw[i - 1]->next_addr_l;
}
dma_pool_free(gn412x_dma->pool, tx->sgl_hw[i], phys);
}
kfree(tx->sgl_hw);
kfree(tx);
}
static void gn412x_dma_schedule_next(struct gn412x_dma_chan *gn412x_dma_chan) static void gn412x_dma_schedule_next(struct gn412x_dma_chan *gn412x_dma_chan)
{ {
unsigned long flags; unsigned long flags;
...@@ -609,27 +635,39 @@ static int gn412x_dma_slave_config(struct dma_chan *chan, ...@@ -609,27 +635,39 @@ static int gn412x_dma_slave_config(struct dma_chan *chan,
static int gn412x_dma_terminate_all(struct dma_chan *chan) static int gn412x_dma_terminate_all(struct dma_chan *chan)
{ {
struct gn412x_dma_chan *gn412x_dma_chan = to_gn412x_dma_chan(chan);
struct gn412x_dma_device *gn412x_dma; struct gn412x_dma_device *gn412x_dma;
struct gn412x_dma_tx *tx; struct gn412x_dma_tx *tx, *tx_tmp;
unsigned long flags;
gn412x_dma = to_gn412x_dma_device(chan->device); gn412x_dma = to_gn412x_dma_device(chan->device);
gn412x_dma_ctrl_abort(gn412x_dma);
/* FIXME remove all pending */ spin_lock_irqsave(&gn412x_dma_chan->lock, flags);
if (!gn412x_dma_is_abort(gn412x_dma)) { tx = gn412x_dma_chan->tx_curr;
dev_err(&gn412x_dma->pdev->dev, if (tx) {
"Failed to abort DMA transfer\n"); gn412x_dma_ctrl_abort(gn412x_dma);
return -EINVAL; gn412x_dma_chan->tx_curr = NULL;
} }
tx = to_gn412x_dma_chan(chan)->tx_curr; gn412x_dma_tx_free(tx);
if (tx && tx->tx.callback_result) { list_for_each_entry_safe(tx, tx_tmp,
const struct dmaengine_result result = { &gn412x_dma_chan->pending_list, list) {
.result = DMA_TRANS_ABORTED, list_del(&tx->list);
.residue = 0, gn412x_dma_tx_free(tx);
}; }
spin_unlock_irqrestore(&gn412x_dma_chan->lock, flags);
tx->tx.callback_result(tx->tx.callback_param, &result); if (gn412x_dma_is_abort(gn412x_dma)) {
if (tx && tx->tx.callback_result) {
const struct dmaengine_result result = {
.result = DMA_TRANS_ABORTED,
.residue = 0,
};
tx->tx.callback_result(tx->tx.callback_param, &result);
}
} }
return 0; return 0;
} }
...@@ -656,13 +694,13 @@ static int gn412x_dma_device_control(struct dma_chan *chan, ...@@ -656,13 +694,13 @@ static int gn412x_dma_device_control(struct dma_chan *chan,
} }
#endif #endif
static irqreturn_t gn412x_dma_irq_handler(int irq, void *arg) static irqreturn_t gn412x_dma_irq_handler(int irq, void *arg)
{ {
struct gn412x_dma_device *gn412x_dma = arg; struct gn412x_dma_device *gn412x_dma = arg;
struct gn412x_dma_chan *chan = &gn412x_dma->chan; struct gn412x_dma_chan *chan = &gn412x_dma->chan;
struct gn412x_dma_tx *tx; struct gn412x_dma_tx *tx;
unsigned long flags; unsigned long flags;
unsigned int i;
enum gn412x_dma_state state; enum gn412x_dma_state state;
/* FIXME check for spurious - need HDL fix */ /* FIXME check for spurious - need HDL fix */
...@@ -717,11 +755,7 @@ static irqreturn_t gn412x_dma_irq_handler(int irq, void *arg) ...@@ -717,11 +755,7 @@ static irqreturn_t gn412x_dma_irq_handler(int irq, void *arg)
} }
/* Clean up memory */ /* Clean up memory */
for (i = 0; i < tx->sg_len; ++i) gn412x_dma_tx_free(tx);
dma_pool_free(gn412x_dma->pool, tx->sgl_hw[i], tx->tx.phys);
kfree(tx->sgl_hw);
kfree(tx);
gn412x_dma_schedule_next(chan); gn412x_dma_schedule_next(chan);
return IRQ_HANDLED; return IRQ_HANDLED;
......
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