Hello there
About the problem of sdma_int_handler I seem to find the problem.
You try the following:
unsigned long stattemp=0;
struct sdma_engine *sdmatemp = NULL;
static irqreturn_t sdma_int_handler(int irq, void *dev_id)
{
struct sdma_engine *sdma = dev_id;
unsigned long stat;
sdmatemp = sdma;
stat = readl_relaxed(sdma->regs + SDMA_H_INTR);
writel_relaxed(stat, sdma->regs + SDMA_H_INTR);
/* channel 0 is special and not handled here, see run_channel0() */
stat &= ~1;
stattemp = stat;
while (stat) {
int channel = fls(stat) - 1;
struct sdma_channel *sdmac = &sdma->channel[channel];
struct sdma_desc *desc;
spin_lock(&sdmac->vc.lock);
desc = sdmac->desc;
if (desc) {
if (sdmac->flags & IMX_DMA_SG_LOOP) {
if (sdmac->peripheral_type != IMX_DMATYPE_HDMI)
sdma_update_channel_loop(sdmac);
else
vchan_cyclic_callback(&desc->vd);
} else {
mxc_sdma_handle_channel_normal(sdmac);
vchan_cookie_complete(&desc->vd);
if (!list_empty(&sdmac->pending))
list_del(&desc->node);
sdma_start_desc(sdmac);
}
}
__clear_bit(channel, &stat);
stattemp = stat;
spin_unlock(&sdmac->vc.lock);
}
return IRQ_HANDLED;
}
static void sdma_update_channel_loop(struct sdma_channel *sdmac)
{
struct sdma_buffer_descriptor *bd;
struct sdma_desc *desc = sdmac->desc;
int error = 0;
enum dma_status old_status = sdmac->status;
/*
* loop mode. Iterate over descriptors, re-setup them and
* call callback function.
*/
while (desc) {
bd = &desc->bd[desc->buf_tail];
if (bd->mode.status & BD_DONE)
break;
if (bd->mode.status & BD_RROR) {
bd->mode.status &= ~BD_RROR;
sdmac->status = DMA_ERROR;
error = -EIO;
}
/*
* We use bd->mode.count to calculate the residue, since contains
* the number of bytes present in the current buffer descriptor.
*/
sdmac->chn_real_count = bd->mode.count;
bd->mode.status |= BD_DONE;
bd->mode.count = sdmac->period_len;
desc->buf_ptail = desc->buf_tail;
desc->buf_tail = (desc->buf_tail + 1) % desc->num_bd;
if (error)
sdmac->status = old_status;
/*
* The callback is called from the interrupt context in order
* to reduce latency and to avoid the risk of altering the
* SDMA transaction status by the time the client tasklet is
* executed.
*/
spin_unlock(&sdmac->vc.lock);
printk("%s %s %d\n", __FILE__, __func__, __LINE__);
dmaengine_desc_get_callback_invoke(&desc->vd.tx, NULL);
printk("%s %s %d\n", __FILE__, __func__, __LINE__);
spin_lock(&sdmac->vc.lock);
desc = sdmac->desc;
}
}
static void sdma_desc_free(struct virt_dma_desc *vd)
{
// dump_stack();
int channel = fls(stattemp) - 1;
struct sdma_channel *sdmac = &sdmatemp->channel[channel];
printk("%s %s %d\n", __FILE__, __func__, __LINE__);
struct sdma_desc *desc = container_of(vd, struct sdma_desc, vd);
if (desc) {
printk("%s %s %d\n", __FILE__, __func__, __LINE__);
sdma_free_bd(desc);
printk("%s %s %d\n", __FILE__, __func__, __LINE__);
udelay(1000);
kfree(desc);
sdmac->desc = NULL;
}
}