aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2014-04-13 14:44:46 -0400
committerSekhar Nori <nsekhar@ti.com>2014-04-29 10:03:49 -0400
commitcf7eb979116c2568e8bc3b6a7269c7a359864ace (patch)
tree379f4c3b5343a2ff3595f0569f04ad963214b17a /arch
parentc9eaa447e77efe77b7fa4c953bd62de8297fd6c5 (diff)
ARM: common: edma: Fix xbar mapping
This is another great example of trainwreck engineering: commit 2646a0e529 (ARM: edma: Add EDMA crossbar event mux support) added support for using EDMA on peripherals which have no direct EDMA event mapping. The code compiles and does not explode in your face, but that's it. 1) Reading an u16 array from an u32 device tree array simply does not work. Even if the function is named "edma_of_read_u32_to_s16_array". It merily calls of_property_read_u16_array. So the resulting 16bit array will have every other entry = 0. 2) The DT entry for the xbar registers related to xbar has length 0x10 instead of the real length: 0xfd0 - 0xf90 = 0x40. Not a real problem as it does not cross a page boundary, but wrong nevertheless. 3) But none of this matters as the mapping never happens: After reading nonsense edma_of_read_u32_to_s16_array() invalidates the first array entry pair, so nobody can ever notice the braindamage by immediate explosion. Seems the QA criteria for this code was solely not to explode when someone adds edma-xbar-event-map entries to the DT. Goal achieved, congratulations! Not really helpful if someone wants to use edma on a device which requires a xbar mapping. Fix the issues by: - annotating the device tree entry with "/bits/ 16" as documented in the of_property_read_u16_array kernel doc - make the size of the xbar register mapping correct - invalidating the end of the array and not the start This convoluted mess wants to be completely rewritten as there is no point to keep the xbar_chan array memory and the iomapping of the xbar regs around forever. Marking the xbar mapped channels as used should be done right there. But that's a different issue and this patch is small enough to make it work and allows a simple backport for stable. Cc: stable@vger.kernel.org # v3.12+ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/boot/dts/am33xx.dtsi2
-rw-r--r--arch/arm/common/edma.c48
2 files changed, 16 insertions, 34 deletions
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index 9770e35f2536..a23af78586d4 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -144,7 +144,7 @@
144 compatible = "ti,edma3"; 144 compatible = "ti,edma3";
145 ti,hwmods = "tpcc", "tptc0", "tptc1", "tptc2"; 145 ti,hwmods = "tpcc", "tptc0", "tptc1", "tptc2";
146 reg = <0x49000000 0x10000>, 146 reg = <0x49000000 0x10000>,
147 <0x44e10f90 0x10>; 147 <0x44e10f90 0x40>;
148 interrupts = <12 13 14>; 148 interrupts = <12 13 14>;
149 #dma-cells = <1>; 149 #dma-cells = <1>;
150 dma-channels = <64>; 150 dma-channels = <64>;
diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c
index 41bca32409fc..5339009b3c0c 100644
--- a/arch/arm/common/edma.c
+++ b/arch/arm/common/edma.c
@@ -1423,55 +1423,38 @@ EXPORT_SYMBOL(edma_clear_event);
1423 1423
1424#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_DMADEVICES) 1424#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_DMADEVICES)
1425 1425
1426static int edma_of_read_u32_to_s16_array(const struct device_node *np, 1426static int edma_xbar_event_map(struct device *dev, struct device_node *node,
1427 const char *propname, s16 *out_values, 1427 struct edma_soc_info *pdata, size_t sz)
1428 size_t sz)
1429{ 1428{
1430 int ret; 1429 const char pname[] = "ti,edma-xbar-event-map";
1431
1432 ret = of_property_read_u16_array(np, propname, out_values, sz);
1433 if (ret)
1434 return ret;
1435
1436 /* Terminate it */
1437 *out_values++ = -1;
1438 *out_values++ = -1;
1439
1440 return 0;
1441}
1442
1443static int edma_xbar_event_map(struct device *dev,
1444 struct device_node *node,
1445 struct edma_soc_info *pdata, int len)
1446{
1447 int ret, i;
1448 struct resource res; 1430 struct resource res;
1449 void __iomem *xbar; 1431 void __iomem *xbar;
1450 const s16 (*xbar_chans)[2]; 1432 s16 (*xbar_chans)[2];
1433 size_t nelm = sz / sizeof(s16);
1451 u32 shift, offset, mux; 1434 u32 shift, offset, mux;
1435 int ret, i;
1452 1436
1453 xbar_chans = devm_kzalloc(dev, 1437 xbar_chans = devm_kzalloc(dev, (nelm + 2) * sizeof(s16), GFP_KERNEL);
1454 len/sizeof(s16) + 2*sizeof(s16),
1455 GFP_KERNEL);
1456 if (!xbar_chans) 1438 if (!xbar_chans)
1457 return -ENOMEM; 1439 return -ENOMEM;
1458 1440
1459 ret = of_address_to_resource(node, 1, &res); 1441 ret = of_address_to_resource(node, 1, &res);
1460 if (ret) 1442 if (ret)
1461 return -EIO; 1443 return -ENOMEM;
1462 1444
1463 xbar = devm_ioremap(dev, res.start, resource_size(&res)); 1445 xbar = devm_ioremap(dev, res.start, resource_size(&res));
1464 if (!xbar) 1446 if (!xbar)
1465 return -ENOMEM; 1447 return -ENOMEM;
1466 1448
1467 ret = edma_of_read_u32_to_s16_array(node, 1449 ret = of_property_read_u16_array(node, pname, (u16 *)xbar_chans, nelm);
1468 "ti,edma-xbar-event-map",
1469 (s16 *)xbar_chans,
1470 len/sizeof(u32));
1471 if (ret) 1450 if (ret)
1472 return -EIO; 1451 return -EIO;
1473 1452
1474 for (i = 0; xbar_chans[i][0] != -1; i++) { 1453 /* Invalidate last entry for the other user of this mess */
1454 nelm >>= 1;
1455 xbar_chans[nelm][0] = xbar_chans[nelm][1] = -1;
1456
1457 for (i = 0; i < nelm; i++) {
1475 shift = (xbar_chans[i][1] & 0x03) << 3; 1458 shift = (xbar_chans[i][1] & 0x03) << 3;
1476 offset = xbar_chans[i][1] & 0xfffffffc; 1459 offset = xbar_chans[i][1] & 0xfffffffc;
1477 mux = readl(xbar + offset); 1460 mux = readl(xbar + offset);
@@ -1480,8 +1463,7 @@ static int edma_xbar_event_map(struct device *dev,
1480 writel(mux, (xbar + offset)); 1463 writel(mux, (xbar + offset));
1481 } 1464 }
1482 1465
1483 pdata->xbar_chans = xbar_chans; 1466 pdata->xbar_chans = (const s16 (*)[2]) xbar_chans;
1484
1485 return 0; 1467 return 0;
1486} 1468}
1487 1469