From 31705e21f9b5a0628c043f88ff4d20488b47b8ab Mon Sep 17 00:00:00 2001
From: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Date: Mon, 2 May 2011 07:59:02 +0000
Subject: [PATCH] dmaengine: shdma: synchronize RCU before freeing, simplify
 spinlock

List elements, deleted using list_del_rcu(), cannot be freed without
synchronising RCU. Further, the spinlock, used to protect the RCU
writer, is called in process context, so, we don't have to save flags.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
---
 drivers/dma/shdma.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c
index 00b5f320b0e8..dcc1b2139fff 100644
--- a/drivers/dma/shdma.c
+++ b/drivers/dma/shdma.c
@@ -1077,7 +1077,6 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
 	struct sh_dmae_pdata *pdata = pdev->dev.platform_data;
 	unsigned long irqflags = IRQF_DISABLED,
 		chan_flag[SH_DMAC_MAX_CHANNELS] = {};
-	unsigned long flags;
 	int errirq, chan_irq[SH_DMAC_MAX_CHANNELS];
 	int err, i, irq_cnt = 0, irqres = 0;
 	struct sh_dmae_device *shdev;
@@ -1143,9 +1142,9 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_get_sync(&pdev->dev);
 
-	spin_lock_irqsave(&sh_dmae_lock, flags);
+	spin_lock_irq(&sh_dmae_lock);
 	list_add_tail_rcu(&shdev->node, &sh_dmae_devices);
-	spin_unlock_irqrestore(&sh_dmae_lock, flags);
+	spin_unlock_irq(&sh_dmae_lock);
 
 	/* reset dma controller - only needed as a test */
 	err = sh_dmae_rst(shdev);
@@ -1250,9 +1249,9 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
 eirq_err:
 #endif
 rst_err:
-	spin_lock_irqsave(&sh_dmae_lock, flags);
+	spin_lock_irq(&sh_dmae_lock);
 	list_del_rcu(&shdev->node);
-	spin_unlock_irqrestore(&sh_dmae_lock, flags);
+	spin_unlock_irq(&sh_dmae_lock);
 
 	pm_runtime_put(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
@@ -1261,6 +1260,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
 		iounmap(shdev->dmars);
 emapdmars:
 	iounmap(shdev->chan_reg);
+	synchronize_rcu();
 emapchan:
 	kfree(shdev);
 ealloc:
@@ -1276,7 +1276,6 @@ static int __exit sh_dmae_remove(struct platform_device *pdev)
 {
 	struct sh_dmae_device *shdev = platform_get_drvdata(pdev);
 	struct resource *res;
-	unsigned long flags;
 	int errirq = platform_get_irq(pdev, 0);
 
 	dma_async_device_unregister(&shdev->common);
@@ -1284,9 +1283,9 @@ static int __exit sh_dmae_remove(struct platform_device *pdev)
 	if (errirq > 0)
 		free_irq(errirq, shdev);
 
-	spin_lock_irqsave(&sh_dmae_lock, flags);
+	spin_lock_irq(&sh_dmae_lock);
 	list_del_rcu(&shdev->node);
-	spin_unlock_irqrestore(&sh_dmae_lock, flags);
+	spin_unlock_irq(&sh_dmae_lock);
 
 	/* channel data remove */
 	sh_dmae_chan_remove(shdev);
@@ -1297,6 +1296,7 @@ static int __exit sh_dmae_remove(struct platform_device *pdev)
 		iounmap(shdev->dmars);
 	iounmap(shdev->chan_reg);
 
+	synchronize_rcu();
 	kfree(shdev);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);