|
|
@@ -201,6 +201,7 @@ struct ep93xx_dma_engine {
|
|
|
struct dma_device dma_dev;
|
|
|
bool m2m;
|
|
|
int (*hw_setup)(struct ep93xx_dma_chan *);
|
|
|
+ void (*hw_synchronize)(struct ep93xx_dma_chan *);
|
|
|
void (*hw_shutdown)(struct ep93xx_dma_chan *);
|
|
|
void (*hw_submit)(struct ep93xx_dma_chan *);
|
|
|
int (*hw_interrupt)(struct ep93xx_dma_chan *);
|
|
|
@@ -333,21 +334,27 @@ static inline u32 m2p_channel_state(struct ep93xx_dma_chan *edmac)
|
|
|
return (readl(edmac->regs + M2P_STATUS) >> 4) & 0x3;
|
|
|
}
|
|
|
|
|
|
-static void m2p_hw_shutdown(struct ep93xx_dma_chan *edmac)
|
|
|
+static void m2p_hw_synchronize(struct ep93xx_dma_chan *edmac)
|
|
|
{
|
|
|
+ unsigned long flags;
|
|
|
u32 control;
|
|
|
|
|
|
+ spin_lock_irqsave(&edmac->lock, flags);
|
|
|
control = readl(edmac->regs + M2P_CONTROL);
|
|
|
control &= ~(M2P_CONTROL_STALLINT | M2P_CONTROL_NFBINT);
|
|
|
m2p_set_control(edmac, control);
|
|
|
+ spin_unlock_irqrestore(&edmac->lock, flags);
|
|
|
|
|
|
while (m2p_channel_state(edmac) >= M2P_STATE_ON)
|
|
|
- cpu_relax();
|
|
|
+ schedule();
|
|
|
+}
|
|
|
|
|
|
+static void m2p_hw_shutdown(struct ep93xx_dma_chan *edmac)
|
|
|
+{
|
|
|
m2p_set_control(edmac, 0);
|
|
|
|
|
|
- while (m2p_channel_state(edmac) == M2P_STATE_STALL)
|
|
|
- cpu_relax();
|
|
|
+ while (m2p_channel_state(edmac) != M2P_STATE_IDLE)
|
|
|
+ dev_warn(chan2dev(edmac), "M2P: Not yet IDLE\n");
|
|
|
}
|
|
|
|
|
|
static void m2p_fill_desc(struct ep93xx_dma_chan *edmac)
|
|
|
@@ -1162,6 +1169,26 @@ fail:
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * ep93xx_dma_synchronize - Synchronizes the termination of transfers to the
|
|
|
+ * current context.
|
|
|
+ * @chan: channel
|
|
|
+ *
|
|
|
+ * Synchronizes the DMA channel termination to the current context. When this
|
|
|
+ * function returns it is guaranteed that all transfers for previously issued
|
|
|
+ * descriptors have stopped and and it is safe to free the memory associated
|
|
|
+ * with them. Furthermore it is guaranteed that all complete callback functions
|
|
|
+ * for a previously submitted descriptor have finished running and it is safe to
|
|
|
+ * free resources accessed from within the complete callbacks.
|
|
|
+ */
|
|
|
+static void ep93xx_dma_synchronize(struct dma_chan *chan)
|
|
|
+{
|
|
|
+ struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
|
|
|
+
|
|
|
+ if (edmac->edma->hw_synchronize)
|
|
|
+ edmac->edma->hw_synchronize(edmac);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* ep93xx_dma_terminate_all - terminate all transactions
|
|
|
* @chan: channel
|
|
|
@@ -1325,6 +1352,7 @@ static int __init ep93xx_dma_probe(struct platform_device *pdev)
|
|
|
dma_dev->device_prep_slave_sg = ep93xx_dma_prep_slave_sg;
|
|
|
dma_dev->device_prep_dma_cyclic = ep93xx_dma_prep_dma_cyclic;
|
|
|
dma_dev->device_config = ep93xx_dma_slave_config;
|
|
|
+ dma_dev->device_synchronize = ep93xx_dma_synchronize;
|
|
|
dma_dev->device_terminate_all = ep93xx_dma_terminate_all;
|
|
|
dma_dev->device_issue_pending = ep93xx_dma_issue_pending;
|
|
|
dma_dev->device_tx_status = ep93xx_dma_tx_status;
|
|
|
@@ -1342,6 +1370,7 @@ static int __init ep93xx_dma_probe(struct platform_device *pdev)
|
|
|
} else {
|
|
|
dma_cap_set(DMA_PRIVATE, dma_dev->cap_mask);
|
|
|
|
|
|
+ edma->hw_synchronize = m2p_hw_synchronize;
|
|
|
edma->hw_setup = m2p_hw_setup;
|
|
|
edma->hw_shutdown = m2p_hw_shutdown;
|
|
|
edma->hw_submit = m2p_hw_submit;
|