Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+20 -14
+1 -4
drivers/gpu/drm/tegra/output.c
··· 180 180 181 181 void tegra_output_remove(struct tegra_output *output) 182 182 { 183 - int connector_type = output->connector.connector_type; 184 - 185 183 if (output->hpd_gpio) 186 184 free_irq(output->hpd_irq, output); 187 185 188 - if (connector_type != DRM_MODE_CONNECTOR_eDP && 189 - connector_type != DRM_MODE_CONNECTOR_DisplayPort && output->ddc) 186 + if (output->ddc) 190 187 i2c_put_adapter(output->ddc); 191 188 } 192 189
+19 -10
drivers/gpu/drm/tegra/sor.c
··· 3745 3745 if (!sor->aux) 3746 3746 return -EPROBE_DEFER; 3747 3747 3748 - if (get_device(sor->aux->dev)) { 3749 - if (try_module_get(sor->aux->dev->driver->owner)) 3750 - sor->output.ddc = &sor->aux->ddc; 3751 - else 3752 - put_device(sor->aux->dev); 3753 - } 3748 + if (get_device(sor->aux->dev)) 3749 + sor->output.ddc = &sor->aux->ddc; 3754 3750 } 3755 3751 3756 3752 if (!sor->aux) { ··· 3774 3778 3775 3779 err = tegra_sor_parse_dt(sor); 3776 3780 if (err < 0) 3777 - return err; 3781 + goto put_aux; 3778 3782 3779 3783 err = tegra_output_probe(&sor->output); 3780 - if (err < 0) 3781 - return dev_err_probe(&pdev->dev, err, 3782 - "failed to probe output\n"); 3784 + if (err < 0) { 3785 + dev_err_probe(&pdev->dev, err, "failed to probe output\n"); 3786 + goto put_aux; 3787 + } 3783 3788 3784 3789 if (sor->ops && sor->ops->probe) { 3785 3790 err = sor->ops->probe(sor); ··· 3967 3970 host1x_client_exit(&sor->client); 3968 3971 pm_runtime_disable(&pdev->dev); 3969 3972 remove: 3973 + if (sor->aux) 3974 + sor->output.ddc = NULL; 3975 + 3970 3976 tegra_output_remove(&sor->output); 3977 + put_aux: 3978 + if (sor->aux) 3979 + put_device(sor->aux->dev); 3980 + 3971 3981 return err; 3972 3982 } 3973 3983 ··· 3991 3987 } 3992 3988 3993 3989 pm_runtime_disable(&pdev->dev); 3990 + 3991 + if (sor->aux) { 3992 + put_device(sor->aux->dev); 3993 + sor->output.ddc = NULL; 3994 + } 3994 3995 3995 3996 tegra_output_remove(&sor->output); 3996 3997