sh_eth: fix TSU resource handling
authorSergei Shtylyov <sergei.shtylyov@cogentembedded.com>
Wed, 3 Jan 2018 17:09:49 +0000 (20:09 +0300)
committerDavid S. Miller <davem@davemloft.net>
Thu, 4 Jan 2018 19:17:34 +0000 (14:17 -0500)
When switching  the driver to the managed device API,  I managed to break
the  case of a  dual Ether devices sharing a single TSU: the 2nd Ether port
wouldn't probe. Iwamatsu-san has tried to fix this but his patch was buggy
and he then dropped the ball...

The solution is to  limit calling devm_request_mem_region() to the first
of  the two  ports  sharing the same TSU, so devm_ioremap_resource() can't
be used anymore for the TSU resource...

Fixes: d5e07e69218f ("sh_eth: use managed device API")
Reported-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/renesas/sh_eth.c

index 75323000c3646bc781c12287367f8b455ada5a6a..1bdd67a8a8690de987609911f7dbfd061b876698 100644 (file)
@@ -3225,10 +3225,29 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
        /* ioremap the TSU registers */
        if (mdp->cd->tsu) {
                struct resource *rtsu;
+
                rtsu = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-               mdp->tsu_addr = devm_ioremap_resource(&pdev->dev, rtsu);
-               if (IS_ERR(mdp->tsu_addr)) {
-                       ret = PTR_ERR(mdp->tsu_addr);
+               if (!rtsu) {
+                       dev_err(&pdev->dev, "no TSU resource\n");
+                       ret = -ENODEV;
+                       goto out_release;
+               }
+               /* We can only request the  TSU region  for the first port
+                * of the two  sharing this TSU for the probe to succeed...
+                */
+               if (devno % 2 == 0 &&
+                   !devm_request_mem_region(&pdev->dev, rtsu->start,
+                                            resource_size(rtsu),
+                                            dev_name(&pdev->dev))) {
+                       dev_err(&pdev->dev, "can't request TSU resource.\n");
+                       ret = -EBUSY;
+                       goto out_release;
+               }
+               mdp->tsu_addr = devm_ioremap(&pdev->dev, rtsu->start,
+                                            resource_size(rtsu));
+               if (!mdp->tsu_addr) {
+                       dev_err(&pdev->dev, "TSU region ioremap() failed.\n");
+                       ret = -ENOMEM;
                        goto out_release;
                }
                mdp->port = devno % 2;