From 37282485dd4c95c4a637cfa263a0753216f1ec24 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 10 Apr 2017 16:28:04 +0100 Subject: [PATCH 1/6] net: mvmdio: disable interrupts in driver failure path When the mvmdio driver has an interrupt, it enables the "done" interrupt after requesting its interrupt handler. However, probe failure results in the interrupt being left enabled. Disable it on the failure path. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvmdio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index a0d1b084ecec9..7aea0beca56e5 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -251,6 +251,8 @@ static int orion_mdio_probe(struct platform_device *pdev) return 0; out_mdio: + if (dev->err_interrupt > 0) + writel(0, dev->regs + MVMDIO_ERR_INT_MASK); if (!IS_ERR(dev->clk)) clk_disable_unprepare(dev->clk); return ret; From 7093a9702e00274fde609d634010a5833b45b229 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 10 Apr 2017 16:28:09 +0100 Subject: [PATCH 2/6] net: mvmdio: fix interrupt disable in remove path The pre-existing write to disable interrupts on the remove path happens whether we have an interrupt or not. While this may seem to be a good idea, this driver is re-used in many different implementations, some where the binding only specifies four bytes of register space. This access causes us to access registers outside of the binding. Make it conditional on the interrupt being present, which is the same condition used when enabling the interrupt in the first place. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvmdio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index 7aea0beca56e5..6ea5caddca62b 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -263,7 +263,8 @@ static int orion_mdio_remove(struct platform_device *pdev) struct mii_bus *bus = platform_get_drvdata(pdev); struct orion_mdio_dev *dev = bus->priv; - writel(0, dev->regs + MVMDIO_ERR_INT_MASK); + if (dev->err_interrupt > 0) + writel(0, dev->regs + MVMDIO_ERR_INT_MASK); mdiobus_unregister(bus); if (!IS_ERR(dev->clk)) clk_disable_unprepare(dev->clk); From 2c26122e2c8d9b76b98995a7bd9f13a79dacfabe Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 10 Apr 2017 16:28:15 +0100 Subject: [PATCH 3/6] dt-bindings: correct marvell orion MDIO binding document Correct the Marvell Orion MDIO binding document to properly reflect the cases where an interrupt is present. Augment the examples to show this. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- .../bindings/net/marvell-orion-mdio.txt | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/net/marvell-orion-mdio.txt b/Documentation/devicetree/bindings/net/marvell-orion-mdio.txt index 9417e54c26c0e..ca733ff68ab9b 100644 --- a/Documentation/devicetree/bindings/net/marvell-orion-mdio.txt +++ b/Documentation/devicetree/bindings/net/marvell-orion-mdio.txt @@ -7,7 +7,10 @@ interface. Required properties: - compatible: "marvell,orion-mdio" -- reg: address and length of the SMI register +- reg: address and length of the MDIO registers. When an interrupt is + not present, the length is the size of the SMI register (4 bytes) + otherwise it must be 0x84 bytes to cover the interrupt control + registers. Optional properties: - interrupts: interrupt line number for the SMI error/done interrupt @@ -17,7 +20,7 @@ The child nodes of the MDIO driver are the individual PHY devices connected to this MDIO bus. They must have a "reg" property given the PHY address on the MDIO bus. -Example at the SoC level: +Example at the SoC level without an interrupt property: mdio { #address-cells = <1>; @@ -26,6 +29,16 @@ mdio { reg = <0xd0072004 0x4>; }; +Example with an interrupt property: + +mdio { + #address-cells = <1>; + #size-cells = <0>; + compatible = "marvell,orion-mdio"; + reg = <0xd0072004 0x84>; + interrupts = <30>; +}; + And at the board level: mdio { From a51e2c9da44acad7494ac3f57c48f296890cbe2a Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 10 Apr 2017 16:28:20 +0100 Subject: [PATCH 4/6] net: mvmdio: disable interrupt if resource size is too small Disable the MDIO interrupt, falling back to polled mode, if the resource size does not allow us to access the interrupt registers. All current DT bindings use a size of 0x84, which allows access, but verifying it is good practice. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvmdio.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index 6ea5caddca62b..614dfde657fe7 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -221,6 +221,12 @@ static int orion_mdio_probe(struct platform_device *pdev) clk_prepare_enable(dev->clk); dev->err_interrupt = platform_get_irq(pdev, 0); + if (dev->err_interrupt > 0 && + resource_size(r) < MVMDIO_ERR_INT_MASK + 4) { + dev_err(&pdev->dev, + "disabling interrupt, resource size is too small\n"); + dev->err_interrupt = 0; + } if (dev->err_interrupt > 0) { ret = devm_request_irq(&pdev->dev, dev->err_interrupt, orion_mdio_err_irq, From 6d6a331f44a18accbff5f693d03f2842b0e8c581 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 10 Apr 2017 16:28:25 +0100 Subject: [PATCH 5/6] dt-bindings: allow up to three clocks for orion-mdio Armada 8040 needs three clocks to be enabled for MDIO accesses to work. Update the binding to allow the extra clocks to be specified. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/marvell-orion-mdio.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/net/marvell-orion-mdio.txt b/Documentation/devicetree/bindings/net/marvell-orion-mdio.txt index ca733ff68ab9b..ccdabdcc8618c 100644 --- a/Documentation/devicetree/bindings/net/marvell-orion-mdio.txt +++ b/Documentation/devicetree/bindings/net/marvell-orion-mdio.txt @@ -14,7 +14,7 @@ Required properties: Optional properties: - interrupts: interrupt line number for the SMI error/done interrupt -- clocks: Phandle to the clock control device and gate bit +- clocks: phandle for up to three required clocks for the MDIO instance The child nodes of the MDIO driver are the individual PHY devices connected to this MDIO bus. They must have a "reg" property given the From 96cb4342382290c935d933a08feb57d6d0183071 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 10 Apr 2017 16:28:31 +0100 Subject: [PATCH 6/6] net: mvmdio: allow up to three clocks to be specified for orion-mdio Allow up to three clocks to be specified and enabled for the orion-mdio interface, which are required for this interface to be accessible on Armada 8k platforms. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvmdio.c | 33 +++++++++++++++++++-------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index 614dfde657fe7..90a60b98c28ef 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -53,7 +53,7 @@ struct orion_mdio_dev { struct mutex lock; void __iomem *regs; - struct clk *clk; + struct clk *clk[3]; /* * If we have access to the error interrupt pin (which is * somewhat misnamed as it not only reflects internal errors @@ -187,7 +187,7 @@ static int orion_mdio_probe(struct platform_device *pdev) struct resource *r; struct mii_bus *bus; struct orion_mdio_dev *dev; - int ret; + int i, ret; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) { @@ -216,9 +216,12 @@ static int orion_mdio_probe(struct platform_device *pdev) init_waitqueue_head(&dev->smi_busy_wait); - dev->clk = devm_clk_get(&pdev->dev, NULL); - if (!IS_ERR(dev->clk)) - clk_prepare_enable(dev->clk); + for (i = 0; i < ARRAY_SIZE(dev->clk); i++) { + dev->clk[i] = of_clk_get(pdev->dev.of_node, i); + if (IS_ERR(dev->clk[i])) + break; + clk_prepare_enable(dev->clk[i]); + } dev->err_interrupt = platform_get_irq(pdev, 0); if (dev->err_interrupt > 0 && @@ -259,8 +262,14 @@ static int orion_mdio_probe(struct platform_device *pdev) out_mdio: if (dev->err_interrupt > 0) writel(0, dev->regs + MVMDIO_ERR_INT_MASK); - if (!IS_ERR(dev->clk)) - clk_disable_unprepare(dev->clk); + + for (i = 0; i < ARRAY_SIZE(dev->clk); i++) { + if (IS_ERR(dev->clk[i])) + break; + clk_disable_unprepare(dev->clk[i]); + clk_put(dev->clk[i]); + } + return ret; } @@ -268,12 +277,18 @@ static int orion_mdio_remove(struct platform_device *pdev) { struct mii_bus *bus = platform_get_drvdata(pdev); struct orion_mdio_dev *dev = bus->priv; + int i; if (dev->err_interrupt > 0) writel(0, dev->regs + MVMDIO_ERR_INT_MASK); mdiobus_unregister(bus); - if (!IS_ERR(dev->clk)) - clk_disable_unprepare(dev->clk); + + for (i = 0; i < ARRAY_SIZE(dev->clk); i++) { + if (IS_ERR(dev->clk[i])) + break; + clk_disable_unprepare(dev->clk[i]); + clk_put(dev->clk[i]); + } return 0; }