summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2015-08-24 14:47:10 +0200
committerThierry Reding <treding@nvidia.com>2015-10-30 18:40:52 +0100
commit2bcdcbfae2895764372ef973a969f395a548f1ea (patch)
tree4725c0bc83dc24e65c09d00a79f1521623a8e2d5
parentdrm/tegra: fb: Remove gratuituous blank line (diff)
downloadlinux-2bcdcbfae2895764372ef973a969f395a548f1ea.tar.xz
linux-2bcdcbfae2895764372ef973a969f395a548f1ea.zip
drm/tegra: dc: Request/free syncpoint at init/exit
syncpoints are resources provided by host1x and their lifetime is tied to the host1x device. They are not properly reference counted either, so removing the host1x device before any of its clients causes a use-after- free error. Adding proper reference counting would be a major enterprise so work around it for now by requesting and freeing the syncpoint at init and exit time, respectively. The host1x device is guaranteed to be around at this point. Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r--drivers/gpu/drm/tegra/dc.c14
1 files changed, 7 insertions, 7 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index ddefb85dc4f7..b463fd9805a3 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -1696,6 +1696,7 @@ static int tegra_dc_debugfs_exit(struct tegra_dc *dc)
static int tegra_dc_init(struct host1x_client *client)
{
struct drm_device *drm = dev_get_drvdata(client->parent);
+ unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;
struct tegra_dc *dc = host1x_client_to_dc(client);
struct tegra_drm *tegra = drm->dev_private;
struct drm_plane *primary = NULL;
@@ -1703,6 +1704,10 @@ static int tegra_dc_init(struct host1x_client *client)
u32 value;
int err;
+ dc->syncpt = host1x_syncpt_request(dc->dev, flags);
+ if (!dc->syncpt)
+ dev_warn(dc->dev, "failed to allocate syncpoint\n");
+
if (tegra->domain) {
err = iommu_attach_device(tegra->domain, dc->dev);
if (err < 0) {
@@ -1849,6 +1854,8 @@ static int tegra_dc_exit(struct host1x_client *client)
dc->domain = NULL;
}
+ host1x_syncpt_free(dc->syncpt);
+
return 0;
}
@@ -1961,7 +1968,6 @@ static int tegra_dc_parse_dt(struct tegra_dc *dc)
static int tegra_dc_probe(struct platform_device *pdev)
{
- unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;
const struct of_device_id *id;
struct resource *regs;
struct tegra_dc *dc;
@@ -2036,10 +2042,6 @@ static int tegra_dc_probe(struct platform_device *pdev)
return -ENXIO;
}
- dc->syncpt = host1x_syncpt_request(&pdev->dev, flags);
- if (!dc->syncpt)
- dev_warn(&pdev->dev, "failed to allocate syncpoint\n");
-
INIT_LIST_HEAD(&dc->client.list);
dc->client.ops = &dc_client_ops;
dc->client.dev = &pdev->dev;
@@ -2067,8 +2069,6 @@ static int tegra_dc_remove(struct platform_device *pdev)
struct tegra_dc *dc = platform_get_drvdata(pdev);
int err;
- host1x_syncpt_free(dc->syncpt);
-
err = host1x_client_unregister(&dc->client);
if (err < 0) {
dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",