summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/tegra/output.c
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2014-10-21 14:00:09 +0200
committerThierry Reding <treding@nvidia.com>2014-11-13 16:18:31 +0100
commit8fc8f7da9719c2d28fb32cdd74af9b6cd9bac20a (patch)
treef1d74b944c4205cd3941e4507d4aeb484f186718 /drivers/gpu/drm/tegra/output.c
parentc7679306a923c2feb383f709446c1110db1c56e4 (diff)
drm/tegra: Enable the hotplug interrupt only when necessary
The hotplug handling needs access to the DRM device, which only appears at ->init() time. Disable interrupts up until that time. Similarly, when an output is removed, disable the hotplug interrupt again because the DRM device (and with it the hotplug infrastructure) is going away. Also make sure to only access the DRM device if it's available. Given the above change for the hotplug interrupt this should really never happen, but the extra check doesn't hurt either. Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'drivers/gpu/drm/tegra/output.c')
-rw-r--r--drivers/gpu/drm/tegra/output.c24
1 files changed, 23 insertions, 1 deletions
diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c
index e6cfbde36f97..022462d3a413 100644
--- a/drivers/gpu/drm/tegra/output.c
+++ b/drivers/gpu/drm/tegra/output.c
@@ -183,7 +183,8 @@ static irqreturn_t hpd_irq(int irq, void *data)
{
struct tegra_output *output = data;
- drm_helper_hpd_irq_event(output->connector.dev);
+ if (output->connector.dev)
+ drm_helper_hpd_irq_event(output->connector.dev);
return IRQ_HANDLED;
}
@@ -255,6 +256,13 @@ int tegra_output_probe(struct tegra_output *output)
}
output->connector.polled = DRM_CONNECTOR_POLL_HPD;
+
+ /*
+ * Disable the interrupt until the connector has been
+ * initialized to avoid a race in the hotplug interrupt
+ * handler.
+ */
+ disable_irq(output->hpd_irq);
}
return 0;
@@ -320,10 +328,24 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
output->encoder.possible_crtcs = 0x3;
+ /*
+ * The connector is now registered and ready to receive hotplug events
+ * so the hotplug interrupt can be enabled.
+ */
+ if (gpio_is_valid(output->hpd_gpio))
+ enable_irq(output->hpd_irq);
+
return 0;
}
int tegra_output_exit(struct tegra_output *output)
{
+ /*
+ * The connector is going away, so the interrupt must be disabled to
+ * prevent the hotplug interrupt handler from potentially crashing.
+ */
+ if (gpio_is_valid(output->hpd_gpio))
+ disable_irq(output->hpd_irq);
+
return 0;
}