summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorRobert Morell <rmorell@nvidia.com>2011-03-03 20:54:09 -0800
committerVarun Colbert <vcolbert@nvidia.com>2011-08-11 11:52:28 -0700
commitcd73bb54da8c388f7ec143c1fca204aa15705661 (patch)
tree799f3715752d49a84fad3c043ef218d697274a4b /drivers
parentb8ddd1da9311ba55893f97326937cc4c8ffff004 (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 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>
Diffstat (limited to 'drivers')
-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 aa76570924e2..61f913808238 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -2049,6 +2049,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;
}
@@ -2206,6 +2208,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) {
@@ -2230,6 +2234,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);
@@ -2404,6 +2410,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);
@@ -2439,12 +2451,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);
@@ -2487,6 +2493,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);
@@ -2515,13 +2523,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,