summaryrefslogtreecommitdiff
path: root/drivers/video/tegra
diff options
context:
space:
mode:
authorRobert Morell <rmorell@nvidia.com>2011-03-03 20:54:09 -0800
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:48:12 -0800
commit63a79e26218daabc625acf3a21224be2ad6624ed (patch)
tree5974427b9f6433059b0bf66e926061e3702225ab /drivers/video/tegra
parentcd42c053c598d720c12ca8d2e13715ee490f6717 (diff)
video: tegra: Prevent hang when output disabled
This adds code to track when the dc is disabled and prevent flips or cursor moves. This prevents system hangs since the dc is powergated when it's disabled. bug 818525 Original-Change-Id: I061da1f6a831fa14a216520e603e0fbc5dbb0437 Signed-off-by: Robert Morell <rmorell@nvidia.com> Reviewed-on: http://git-master/r/40519 Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com> Rebase-Id: Rb648ef48bd3528344cf090c49093dcb258c20150
Diffstat (limited to 'drivers/video/tegra')
-rw-r--r--drivers/video/tegra/dc/dc.c23
-rw-r--r--drivers/video/tegra/dc/ext/cursor.c35
-rw-r--r--drivers/video/tegra/dc/ext/dev.c39
-rw-r--r--drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h2
4 files changed, 83 insertions, 16 deletions
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index 36834743a9db..976770ce8e74 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -2047,6 +2047,8 @@ static bool _tegra_dc_controller_enable(struct tegra_dc *dc)
/* force a full blending update */
dc->blend.z[0] = -1;
+ tegra_dc_ext_enable(dc->ext);
+
return true;
}
@@ -2204,6 +2206,8 @@ void tegra_dc_disable(struct tegra_dc *dc)
if (dc->overlay)
tegra_overlay_disable(dc->overlay);
+ tegra_dc_ext_disable(dc->ext);
+
mutex_lock(&dc->lock);
if (dc->enabled) {
@@ -2226,6 +2230,8 @@ static void tegra_dc_reset_worker(struct work_struct *work)
dev_warn(&dc->ndev->dev, "overlay stuck in underflow state. resetting.\n");
+ tegra_dc_ext_disable(dc->ext);
+
mutex_lock(&shared_lock);
mutex_lock(&dc->lock);
@@ -2385,6 +2391,12 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
else
dev_err(&ndev->dev, "No default output specified. Leaving output disabled.\n");
+ dc->ext = tegra_dc_ext_register(ndev, dc);
+ if (IS_ERR_OR_NULL(dc->ext)) {
+ dev_warn(&ndev->dev, "Failed to enable Tegra DC extensions.\n");
+ dc->ext = NULL;
+ }
+
mutex_lock(&dc->lock);
if (dc->enabled)
_tegra_dc_enable(dc);
@@ -2420,12 +2432,6 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
if (dc->out && dc->out->hotplug_init)
dc->out->hotplug_init();
- dc->ext = tegra_dc_ext_register(ndev, dc);
- if (IS_ERR_OR_NULL(dc->ext)) {
- dev_warn(&ndev->dev, "Failed to enable Tegra DC extensions.\n");
- dc->ext = NULL;
- }
-
if (dc->out_ops && dc->out_ops->detect)
dc->out_ops->detect(dc);
@@ -2468,6 +2474,8 @@ static int tegra_dc_remove(struct nvhost_device *ndev)
release_resource(dc->fb_mem);
}
+ tegra_dc_ext_disable(dc->ext);
+
if (dc->ext)
tegra_dc_ext_unregister(dc->ext);
@@ -2495,13 +2503,14 @@ static int tegra_dc_suspend(struct nvhost_device *ndev, pm_message_t state)
if (dc->overlay)
tegra_overlay_disable(dc->overlay);
+ tegra_dc_ext_disable(dc->ext);
+
mutex_lock(&dc->lock);
if (dc->out_ops && dc->out_ops->suspend)
dc->out_ops->suspend(dc);
if (dc->enabled) {
- tegra_dc_ext_suspend(dc->ext);
_tegra_dc_disable(dc);
dc->suspended = true;
diff --git a/drivers/video/tegra/dc/ext/cursor.c b/drivers/video/tegra/dc/ext/cursor.c
index e25ca0fd3fc2..d8fa5fd8e6d9 100644
--- a/drivers/video/tegra/dc/ext/cursor.c
+++ b/drivers/video/tegra/dc/ext/cursor.c
@@ -105,17 +105,20 @@ int tegra_dc_ext_set_cursor_image(struct tegra_dc_ext_user *user,
mutex_lock(&ext->cursor.lock);
if (ext->cursor.user != user) {
- mutex_unlock(&ext->cursor.lock);
- return -EACCES;
+ ret = -EACCES;
+ goto unlock;
+ }
+
+ if (!ext->enabled) {
+ ret = -ENXIO;
+ goto unlock;
}
old_handle = ext->cursor.cur_handle;
ret = tegra_dc_ext_pin_window(user, args->buff_id, &handle, &phys_addr);
- if (ret) {
- mutex_unlock(&ext->cursor.lock);
- return -EACCES;
- }
+ if (ret)
+ goto unlock;
ext->cursor.cur_handle = handle;
@@ -138,6 +141,11 @@ int tegra_dc_ext_set_cursor_image(struct tegra_dc_ext_user *user,
}
return 0;
+
+unlock:
+ mutex_unlock(&ext->cursor.lock);
+
+ return ret;
}
int tegra_dc_ext_set_cursor(struct tegra_dc_ext_user *user,
@@ -147,12 +155,18 @@ int tegra_dc_ext_set_cursor(struct tegra_dc_ext_user *user,
struct tegra_dc *dc = ext->dc;
u32 win_options;
bool enable;
+ int ret;
mutex_lock(&ext->cursor.lock);
if (ext->cursor.user != user) {
- mutex_unlock(&ext->cursor.lock);
- return -EACCES;
+ ret = -EACCES;
+ goto unlock;
+ }
+
+ if (!ext->enabled) {
+ ret = -ENXIO;
+ goto unlock;
}
enable = !!(args->flags & TEGRA_DC_EXT_CURSOR_FLAGS_VISIBLE);
@@ -181,4 +195,9 @@ int tegra_dc_ext_set_cursor(struct tegra_dc_ext_user *user,
mutex_unlock(&ext->cursor.lock);
return 0;
+
+unlock:
+ mutex_unlock(&ext->cursor.lock);
+
+ return ret;
}
diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c
index b51b9378c551..7e077737f910 100644
--- a/drivers/video/tegra/dc/ext/dev.c
+++ b/drivers/video/tegra/dc/ext/dev.c
@@ -124,10 +124,39 @@ static int tegra_dc_ext_put_window(struct tegra_dc_ext_user *user,
return ret;
}
-void tegra_dc_ext_suspend(struct tegra_dc_ext *ext)
+static void set_enable(struct tegra_dc_ext *ext, bool en)
{
int i;
+ /*
+ * Take all locks to make sure any flip requests or cursor moves are
+ * out of their critical sections
+ */
+ for (i = 0; i < ext->dc->n_windows; i++)
+ mutex_lock(&ext->win[i].lock);
+ mutex_lock(&ext->cursor.lock);
+
+ ext->enabled = en;
+
+ mutex_unlock(&ext->cursor.lock);
+ for (i = ext->dc->n_windows - 1; i >= 0 ; i--)
+ mutex_unlock(&ext->win[i].lock);
+}
+
+void tegra_dc_ext_enable(struct tegra_dc_ext *ext)
+{
+ set_enable(ext, true);
+}
+
+void tegra_dc_ext_disable(struct tegra_dc_ext *ext)
+{
+ int i;
+ set_enable(ext, false);
+
+ /*
+ * Flush the flip queue -- note that this must be called with dc->lock
+ * unlocked or else it will hang.
+ */
for (i = 0; i < ext->dc->n_windows; i++) {
struct tegra_dc_ext_win *win = &ext->win[i];
@@ -357,6 +386,11 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
if (ret)
goto fail_pin;
+ if (!ext->enabled) {
+ ret = -ENXIO;
+ goto unlock;
+ }
+
for (i = 0; i < DC_N_WINDOWS; i++) {
u32 syncpt_max;
int index = args->win[i].index;
@@ -382,6 +416,9 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
return 0;
+unlock:
+ unlock_windows_for_flip(user, args);
+
fail_pin:
while (i--) {
if (!data->win[i].handle)
diff --git a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
index 3040cf7fc601..251c072683c7 100644
--- a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
+++ b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
@@ -63,6 +63,8 @@ struct tegra_dc_ext {
struct nvmap_handle_ref *cur_handle;
struct mutex lock;
} cursor;
+
+ bool enabled;
};
extern int tegra_dc_ext_pin_window(struct tegra_dc_ext_user *user, u32 id,