dmaengine: shdma: Fix SH_DMAC_MAX_CHANNELS handling
Magnus Damm [Tue, 24 May 2011 10:31:20 +0000 (10:31 +0000)]
Fix the shdma.c handing of SH_DMAC_MAX_CHANNELS
to avoid overwriting the chan_irq[] and chan_flag[]
arrays in the case of pdata->channel_num is larger
than SH_DMAC_MAX_CHANNELS.

With this patch applied up to SH_DMAC_MAX_CHANNELS
will be used by the shdma.c driver. If more channels
are available in the platform data the user will
be notified on the console.

Signed-off-by: Magnus Damm <damm@opensource.se>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>

drivers/dma/shdma.c

index 3391b15..636e409 100644 (file)
@@ -1083,7 +1083,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
        unsigned long irqflags = IRQF_DISABLED,
                chan_flag[SH_DMAC_MAX_CHANNELS] = {};
        int errirq, chan_irq[SH_DMAC_MAX_CHANNELS];
-       int err, i, irq_cnt = 0, irqres = 0;
+       int err, i, irq_cnt = 0, irqres = 0, irq_cap = 0;
        struct sh_dmae_device *shdev;
        struct resource *chan, *dmars, *errirq_res, *chanirq_res;
 
@@ -1208,8 +1208,13 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
            !platform_get_resource(pdev, IORESOURCE_IRQ, 1)) {
                /* Special case - all multiplexed */
                for (; irq_cnt < pdata->channel_num; irq_cnt++) {
-                       chan_irq[irq_cnt] = chanirq_res->start;
-                       chan_flag[irq_cnt] = IRQF_SHARED;
+                       if (irq_cnt < SH_DMAC_MAX_CHANNELS) {
+                               chan_irq[irq_cnt] = chanirq_res->start;
+                               chan_flag[irq_cnt] = IRQF_SHARED;
+                       } else {
+                               irq_cap = 1;
+                               break;
+                       }
                }
        } else {
                do {
@@ -1223,22 +1228,32 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
                                        "Found IRQ %d for channel %d\n",
                                        i, irq_cnt);
                                chan_irq[irq_cnt++] = i;
+
+                               if (irq_cnt >= SH_DMAC_MAX_CHANNELS)
+                                       break;
+                       }
+
+                       if (irq_cnt >= SH_DMAC_MAX_CHANNELS) {
+                               irq_cap = 1;
+                               break;
                        }
                        chanirq_res = platform_get_resource(pdev,
                                                IORESOURCE_IRQ, ++irqres);
                } while (irq_cnt < pdata->channel_num && chanirq_res);
        }
 
-       if (irq_cnt < pdata->channel_num)
-               goto eirqres;
-
        /* Create DMA Channel */
-       for (i = 0; i < pdata->channel_num; i++) {
+       for (i = 0; i < irq_cnt; i++) {
                err = sh_dmae_chan_probe(shdev, i, chan_irq[i], chan_flag[i]);
                if (err)
                        goto chan_probe_err;
        }
 
+       if (irq_cap)
+               dev_notice(&pdev->dev, "Attempting to register %d DMA "
+                          "channels when a maximum of %d are supported.\n",
+                          pdata->channel_num, SH_DMAC_MAX_CHANNELS);
+
        pm_runtime_put(&pdev->dev);
 
        platform_set_drvdata(pdev, shdev);
@@ -1248,7 +1263,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
 
 chan_probe_err:
        sh_dmae_chan_remove(shdev);
-eirqres:
+
 #if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
        free_irq(errirq, shdev);
 eirq_err: