summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2021-05-27 20:09:08 +0200
committerThierry Reding <treding@nvidia.com>2021-05-27 20:11:13 +0200
commitb79b6081c440c0c197a3e8a51e8b9cf343fb210f (patch)
treea0a5fde150c1963327e1b672cb19cb151465f551 /drivers/gpu/drm
parent1d15a10395e5a036f571ac727f202f9572e255f9 (diff)
drm/tegra: sor: Fix AUX device reference leak
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>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/tegra/output.c5
-rw-r--r--drivers/gpu/drm/tegra/sor.c29
2 files changed, 20 insertions, 14 deletions
diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c
index 2dacce1ab6ee..47d26b5d9945 100644
--- a/drivers/gpu/drm/tegra/output.c
+++ b/drivers/gpu/drm/tegra/output.c
@@ -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);
}
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
index 8f99de08b2be..0ea320c1092b 100644
--- a/drivers/gpu/drm/tegra/sor.c
+++ b/drivers/gpu/drm/tegra/sor.c
@@ -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;