drm/tegra: sor: Fix AUX device reference leak
authorThierry Reding <treding@nvidia.com>
Thu, 27 May 2021 18:09:08 +0000 (20:09 +0200)
committerThierry Reding <treding@nvidia.com>
Thu, 27 May 2021 18:11:13 +0000 (20:11 +0200)
In the case where the AUX provides an I2C-over-AUX DDC channel, a
reference is taken on the AUX parent device of the DDC channel rather
than the DDC channel like it would be for regular I2C controllers. To
make sure the correct reference is dropped, move the unreferencing code
into the SOR driver and make sure not to drop the I2C adapter reference
in that case.

Signed-off-by: Thierry Reding <treding@nvidia.com>
drivers/gpu/drm/tegra/output.c
drivers/gpu/drm/tegra/sor.c

index 2dacce1ab6ee8266aee695cd7a6c36e4f5b853b3..47d26b5d99456bdd0a3d1facc99f2d90949075a8 100644 (file)
@@ -180,13 +180,10 @@ int tegra_output_probe(struct tegra_output *output)
 
 void tegra_output_remove(struct tegra_output *output)
 {
-       int connector_type = output->connector.connector_type;
-
        if (output->hpd_gpio)
                free_irq(output->hpd_irq, output);
 
-       if (connector_type != DRM_MODE_CONNECTOR_eDP &&
-           connector_type != DRM_MODE_CONNECTOR_DisplayPort && output->ddc)
+       if (output->ddc)
                i2c_put_adapter(output->ddc);
 }
 
index 8f99de08b2bee64b933cff9933017e0593cc4a89..0ea320c1092bd2e68308f546037d0af7375d6b0c 100644 (file)
@@ -3745,12 +3745,8 @@ static int tegra_sor_probe(struct platform_device *pdev)
                if (!sor->aux)
                        return -EPROBE_DEFER;
 
-               if (get_device(sor->aux->dev)) {
-                       if (try_module_get(sor->aux->dev->driver->owner))
-                               sor->output.ddc = &sor->aux->ddc;
-                       else
-                               put_device(sor->aux->dev);
-               }
+               if (get_device(sor->aux->dev))
+                       sor->output.ddc = &sor->aux->ddc;
        }
 
        if (!sor->aux) {
@@ -3778,12 +3774,13 @@ static int tegra_sor_probe(struct platform_device *pdev)
 
        err = tegra_sor_parse_dt(sor);
        if (err < 0)
-               return err;
+               goto put_aux;
 
        err = tegra_output_probe(&sor->output);
-       if (err < 0)
-               return dev_err_probe(&pdev->dev, err,
-                                    "failed to probe output\n");
+       if (err < 0) {
+               dev_err_probe(&pdev->dev, err, "failed to probe output\n");
+               goto put_aux;
+       }
 
        if (sor->ops && sor->ops->probe) {
                err = sor->ops->probe(sor);
@@ -3970,7 +3967,14 @@ uninit:
        host1x_client_exit(&sor->client);
        pm_runtime_disable(&pdev->dev);
 remove:
+       if (sor->aux)
+               sor->output.ddc = NULL;
+
        tegra_output_remove(&sor->output);
+put_aux:
+       if (sor->aux)
+               put_device(sor->aux->dev);
+
        return err;
 }
 
@@ -3988,6 +3992,11 @@ static int tegra_sor_remove(struct platform_device *pdev)
 
        pm_runtime_disable(&pdev->dev);
 
+       if (sor->aux) {
+               put_device(sor->aux->dev);
+               sor->output.ddc = NULL;
+       }
+
        tegra_output_remove(&sor->output);
 
        return 0;