}
}
+static bool _pause(struct pl330_thread *thrd)
+{
+ void __iomem *regs = thrd->dmac->pinfo->base;
+ u8 insn[6] = {0, 0, 0, 0, 0, 0};
+
+ if (_state(thrd) == PL330_STATE_FAULT_COMPLETING)
+ UNTIL(thrd, PL330_STATE_FAULTING | PL330_STATE_KILLING);
+
+ /* Return false if dma channel has fault */
+ if (_state(thrd) == PL330_STATE_COMPLETING ||
+ _state(thrd) == PL330_STATE_KILLING ||
+ _state(thrd) == PL330_STATE_FAULTING)
+ return false;
+
+ _emit_WFE(0, insn, thrd->ev, 1);
+
+ /* Stop generating interrupts for SEV */
+ writel(readl(regs + INTEN) & ~(1 << thrd->ev), regs + INTEN);
+
+ _execute_DBGINSN(thrd, insn, is_manager(thrd));
+
+ return true;
+}
+
+static bool _resume(struct pl330_thread *thrd)
+{
+ void __iomem *regs = thrd->dmac->pinfo->base;
+
+ if (_state(thrd) == PL330_STATE_FAULT_COMPLETING)
+ UNTIL(thrd, PL330_STATE_FAULTING | PL330_STATE_KILLING);
+
+ /* Return false if dma channel has fault */
+ if (_state(thrd) == PL330_STATE_COMPLETING ||
+ _state(thrd) == PL330_STATE_KILLING ||
+ _state(thrd) == PL330_STATE_FAULTING)
+ return false;
+
+ /* Start generating interrupts for SEV */
+ writel(readl(regs + INTEN) | (1 << thrd->ev), regs + INTEN);
+
+ return true;
+}
+
static inline int _ldst_memtomem(unsigned dry_run, u8 buf[],
const struct _xfer_spec *pxs, int cyc)
{
ret = -EIO;
break;
+ case PL330_OP_PAUSE:
+ if ((active != -1) && !_pause(thrd))
+ ret = -EIO;
+ break;
+
+ case PL330_OP_RESUME:
+ if ((active != -1) && !_resume(thrd))
+ ret = -EIO;
+ break;
+
default:
ret = -EINVAL;
}
}
break;
case DMA_PAUSE:
- /* TODO: set up dma channel and config register if any */
+ spin_lock_irqsave(&pch->lock, flags);
+ pl330_chan_ctrl(pch->pl330_chid, PL330_OP_PAUSE);
+ spin_unlock_irqrestore(&pch->lock, flags);
break;
case DMA_RESUME:
- /* TODO: set up dma channel and config register if any */
+ spin_lock_irqsave(&pch->lock, flags);
+ pl330_chan_ctrl(pch->pl330_chid, PL330_OP_RESUME);
+ spin_unlock_irqrestore(&pch->lock, flags);
break;
default:
dev_err(pch->dmac->pif.dev, "Not supported command.\n");