浏览代码

Merge branch 'topic/rcar' into for-linus

Vinod Koul 8 年之前
父节点
当前提交
3edc85023a

+ 3 - 2
Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt

@@ -30,8 +30,9 @@ Required Properties:
 
 
 - interrupts: interrupt specifiers for the DMAC, one for each entry in
 - interrupts: interrupt specifiers for the DMAC, one for each entry in
   interrupt-names.
   interrupt-names.
-- interrupt-names: one entry per channel, named "ch%u", where %u is the
-  channel number ranging from zero to the number of channels minus one.
+- interrupt-names: one entry for the error interrupt, named "error", plus one
+  entry per channel, named "ch%u", where %u is the channel number ranging from
+  zero to the number of channels minus one.
 
 
 - clock-names: "fck" for the functional clock
 - clock-names: "fck" for the functional clock
 - clocks: a list of phandle + clock-specifier pairs, one for each entry
 - clocks: a list of phandle + clock-specifier pairs, one for each entry

+ 1 - 1
Documentation/devicetree/bindings/dma/shdma.txt

@@ -1,6 +1,6 @@
 * SHDMA Device Tree bindings
 * SHDMA Device Tree bindings
 
 
-Sh-/r-mobile and r-car systems often have multiple identical DMA controller
+Sh-/r-mobile and R-Car systems often have multiple identical DMA controller
 instances, capable of serving any of a common set of DMA slave devices, using
 instances, capable of serving any of a common set of DMA slave devices, using
 the same configuration. To describe this topology we require all compatible
 the same configuration. To describe this topology we require all compatible
 SHDMA DT nodes to be placed under a DMA multiplexer node. All such compatible
 SHDMA DT nodes to be placed under a DMA multiplexer node. All such compatible

+ 21 - 6
drivers/dma/sh/rcar-dmac.c

@@ -144,6 +144,7 @@ struct rcar_dmac_chan_map {
  * @chan: base DMA channel object
  * @chan: base DMA channel object
  * @iomem: channel I/O memory base
  * @iomem: channel I/O memory base
  * @index: index of this channel in the controller
  * @index: index of this channel in the controller
+ * @irq: channel IRQ
  * @src: slave memory address and size on the source side
  * @src: slave memory address and size on the source side
  * @dst: slave memory address and size on the destination side
  * @dst: slave memory address and size on the destination side
  * @mid_rid: hardware MID/RID for the DMA client using this channel
  * @mid_rid: hardware MID/RID for the DMA client using this channel
@@ -161,6 +162,7 @@ struct rcar_dmac_chan {
 	struct dma_chan chan;
 	struct dma_chan chan;
 	void __iomem *iomem;
 	void __iomem *iomem;
 	unsigned int index;
 	unsigned int index;
+	int irq;
 
 
 	struct rcar_dmac_chan_slave src;
 	struct rcar_dmac_chan_slave src;
 	struct rcar_dmac_chan_slave dst;
 	struct rcar_dmac_chan_slave dst;
@@ -1008,7 +1010,11 @@ static void rcar_dmac_free_chan_resources(struct dma_chan *chan)
 	rcar_dmac_chan_halt(rchan);
 	rcar_dmac_chan_halt(rchan);
 	spin_unlock_irq(&rchan->lock);
 	spin_unlock_irq(&rchan->lock);
 
 
-	/* Now no new interrupts will occur */
+	/*
+	 * Now no new interrupts will occur, but one might already be
+	 * running. Wait for it to finish before freeing resources.
+	 */
+	synchronize_irq(rchan->irq);
 
 
 	if (rchan->mid_rid >= 0) {
 	if (rchan->mid_rid >= 0) {
 		/* The caller is holding dma_list_mutex */
 		/* The caller is holding dma_list_mutex */
@@ -1363,6 +1369,13 @@ done:
 	spin_unlock_irqrestore(&rchan->lock, flags);
 	spin_unlock_irqrestore(&rchan->lock, flags);
 }
 }
 
 
+static void rcar_dmac_device_synchronize(struct dma_chan *chan)
+{
+	struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
+
+	synchronize_irq(rchan->irq);
+}
+
 /* -----------------------------------------------------------------------------
 /* -----------------------------------------------------------------------------
  * IRQ handling
  * IRQ handling
  */
  */
@@ -1647,7 +1660,6 @@ static int rcar_dmac_chan_probe(struct rcar_dmac *dmac,
 	struct dma_chan *chan = &rchan->chan;
 	struct dma_chan *chan = &rchan->chan;
 	char pdev_irqname[5];
 	char pdev_irqname[5];
 	char *irqname;
 	char *irqname;
-	int irq;
 	int ret;
 	int ret;
 
 
 	rchan->index = index;
 	rchan->index = index;
@@ -1664,8 +1676,8 @@ static int rcar_dmac_chan_probe(struct rcar_dmac *dmac,
 
 
 	/* Request the channel interrupt. */
 	/* Request the channel interrupt. */
 	sprintf(pdev_irqname, "ch%u", index);
 	sprintf(pdev_irqname, "ch%u", index);
-	irq = platform_get_irq_byname(pdev, pdev_irqname);
-	if (irq < 0) {
+	rchan->irq = platform_get_irq_byname(pdev, pdev_irqname);
+	if (rchan->irq < 0) {
 		dev_err(dmac->dev, "no IRQ specified for channel %u\n", index);
 		dev_err(dmac->dev, "no IRQ specified for channel %u\n", index);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
@@ -1675,11 +1687,13 @@ static int rcar_dmac_chan_probe(struct rcar_dmac *dmac,
 	if (!irqname)
 	if (!irqname)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	ret = devm_request_threaded_irq(dmac->dev, irq, rcar_dmac_isr_channel,
+	ret = devm_request_threaded_irq(dmac->dev, rchan->irq,
+					rcar_dmac_isr_channel,
 					rcar_dmac_isr_channel_thread, 0,
 					rcar_dmac_isr_channel_thread, 0,
 					irqname, rchan);
 					irqname, rchan);
 	if (ret) {
 	if (ret) {
-		dev_err(dmac->dev, "failed to request IRQ %u (%d)\n", irq, ret);
+		dev_err(dmac->dev, "failed to request IRQ %u (%d)\n",
+			rchan->irq, ret);
 		return ret;
 		return ret;
 	}
 	}
 
 
@@ -1843,6 +1857,7 @@ static int rcar_dmac_probe(struct platform_device *pdev)
 	engine->device_terminate_all = rcar_dmac_chan_terminate_all;
 	engine->device_terminate_all = rcar_dmac_chan_terminate_all;
 	engine->device_tx_status = rcar_dmac_tx_status;
 	engine->device_tx_status = rcar_dmac_tx_status;
 	engine->device_issue_pending = rcar_dmac_issue_pending;
 	engine->device_issue_pending = rcar_dmac_issue_pending;
+	engine->device_synchronize = rcar_dmac_device_synchronize;
 
 
 	ret = dma_async_device_register(engine);
 	ret = dma_async_device_register(engine);
 	if (ret < 0)
 	if (ret < 0)