From 37282485dd4c95c4a637cfa263a0753216f1ec24 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 10 Apr 2017 16:28:04 +0100 Subject: 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(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index a0d1b084ecec..7aea0beca56e 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; -- cgit v1.2.3 From 7093a9702e00274fde609d634010a5833b45b229 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 10 Apr 2017 16:28:09 +0100 Subject: 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(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index 7aea0beca56e..6ea5caddca62 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); -- cgit v1.2.3 From a51e2c9da44acad7494ac3f57c48f296890cbe2a Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 10 Apr 2017 16:28:20 +0100 Subject: 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(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index 6ea5caddca62..614dfde657fe 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, -- cgit v1.2.3 From 96cb4342382290c935d933a08feb57d6d0183071 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 10 Apr 2017 16:28:31 +0100 Subject: 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(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index 614dfde657fe..90a60b98c28e 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; } -- cgit v1.2.3