summaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
authorRebecca Schultz Zavin <rebecca@android.com>2011-01-12 17:47:11 -0800
committerRebecca Schultz Zavin <rebecca@android.com>2011-01-12 17:47:11 -0800
commit5c15007c19b1f4dd634158cf71a9d4a9aa8afd1a (patch)
tree7a90dff1af7ad2852e8759c7e59c2a846819ce0e /drivers/video
parent263fc53856240c5ce982f5c9cace0c5e5d9ccd3d (diff)
parent5be6f571ae59b681eac6f3916cd102e4765ec85c (diff)
Merge remote branch 'tegra/linux-tegra-2.6.36' into android-tegra-2.6.36
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/tegra/fb.c44
-rw-r--r--drivers/video/tegra/nvmap/nvmap_dev.c55
2 files changed, 75 insertions, 24 deletions
diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c
index cc26c5977a20..5d6a11a4ba55 100644
--- a/drivers/video/tegra/fb.c
+++ b/drivers/video/tegra/fb.c
@@ -89,9 +89,27 @@ static int tegra_fb_open(struct fb_info *info, int user)
static int tegra_fb_release(struct fb_info *info, int user)
{
struct tegra_fb_info *tegra_fb = info->par;
+ struct fb_var_screeninfo *var = &info->var;
flush_workqueue(tegra_fb->flip_wq);
+ if (tegra_fb->win->cur_handle) {
+ nvmap_unpin(tegra_fb->fb_nvmap, tegra_fb->win->cur_handle);
+ nvmap_free(tegra_fb->fb_nvmap, tegra_fb->win->cur_handle);
+
+ tegra_fb->win->cur_handle = NULL;
+
+ tegra_fb->win->x = 0;
+ tegra_fb->win->y = 0;
+ tegra_fb->win->w = var->xres;
+ tegra_fb->win->h = var->yres;
+ tegra_fb->win->out_x = 0;
+ tegra_fb->win->out_y = 0;
+ tegra_fb->win->out_w = var->xres;
+ tegra_fb->win->out_h = var->yres;
+ tegra_fb->win->flags = TEGRA_WIN_FLAG_ENABLED;
+ }
+
if (tegra_fb->user_nvmap) {
nvmap_client_put(tegra_fb->user_nvmap);
tegra_fb->user_nvmap = NULL;
@@ -247,25 +265,21 @@ static int tegra_fb_pan_display(struct fb_var_screeninfo *var,
char __iomem *flush_end;
u32 addr;
- flush_start = info->screen_base + (var->yoffset * info->fix.line_length);
- flush_end = flush_start + (var->yres * info->fix.line_length);
-
- info->var.xoffset = var->xoffset;
- info->var.yoffset = var->yoffset;
+ if (!tegra_fb->win->cur_handle) {
+ flush_start = info->screen_base + (var->yoffset * info->fix.line_length);
+ flush_end = flush_start + (var->yres * info->fix.line_length);
- addr = info->fix.smem_start + (var->yoffset * info->fix.line_length) +
- (var->xoffset * (var->bits_per_pixel/8));
+ info->var.xoffset = var->xoffset;
+ info->var.yoffset = var->yoffset;
- tegra_fb->win->phys_addr = addr;
- /* TODO: update virt_addr */
+ addr = info->fix.smem_start + (var->yoffset * info->fix.line_length) +
+ (var->xoffset * (var->bits_per_pixel/8));
- tegra_dc_update_windows(&tegra_fb->win, 1);
- tegra_dc_sync_windows(&tegra_fb->win, 1);
+ tegra_fb->win->phys_addr = addr;
+ /* TODO: update virt_addr */
- if (WARN_ON(tegra_fb->win->cur_handle)) {
- nvmap_unpin(tegra_fb->fb_nvmap, tegra_fb->win->cur_handle);
- nvmap_free(tegra_fb->fb_nvmap, tegra_fb->win->cur_handle);
- tegra_fb->win->cur_handle = NULL;
+ tegra_dc_update_windows(&tegra_fb->win, 1);
+ tegra_dc_sync_windows(&tegra_fb->win, 1);
}
return 0;
diff --git a/drivers/video/tegra/nvmap/nvmap_dev.c b/drivers/video/tegra/nvmap/nvmap_dev.c
index 32008e21b01e..674b34ab6f45 100644
--- a/drivers/video/tegra/nvmap/nvmap_dev.c
+++ b/drivers/video/tegra/nvmap/nvmap_dev.c
@@ -325,6 +325,7 @@ static struct nvmap_client* get_client_from_carveout_commit(
}
#ifdef CONFIG_NVMAP_CARVEOUT_KILLER
+static DECLARE_WAIT_QUEUE_HEAD(wait_reclaim);
bool nvmap_shrink_carveout(struct nvmap_carveout_node *node)
{
struct nvmap_carveout_commit *commit;
@@ -332,7 +333,13 @@ bool nvmap_shrink_carveout(struct nvmap_carveout_node *node)
int selected_oom_adj = OOM_ADJUST_MIN;
struct task_struct *selected_task = NULL;
unsigned long flags;
- bool death_pending = false;
+ bool wait = false;
+ int current_oom_adj = OOM_ADJUST_MIN;
+
+ task_lock(current);
+ if (current->signal)
+ current_oom_adj = current->signal->oom_adj;
+ task_unlock(current);
spin_lock_irqsave(&node->clients_lock, flags);
/* find the task with the smallest oom_adj (lowest priority)
@@ -347,20 +354,27 @@ bool nvmap_shrink_carveout(struct nvmap_carveout_node *node)
if (!task)
continue;
+
+ task_lock(task);
sig = task->signal;
if (!task->mm || !sig)
- continue;
+ goto end;
+ /* don't try to kill higher priority tasks */
+ if (sig->oom_adj < current_oom_adj)
+ goto end;
if (sig->oom_adj < selected_oom_adj)
- continue;
+ goto end;
if (sig->oom_adj == selected_oom_adj &&
size <= selected_size)
- continue;
+ goto end;
selected_oom_adj = sig->oom_adj;
selected_size = size;
selected_task = task;
+end:
+ task_unlock(task);
}
if (selected_task) {
- death_pending = selected_task == current;
+ wait = selected_task != current;
if (fatal_signal_pending(selected_task)) {
pr_warning("carveout_killer: process %d dying "
"slowly\n", selected_task->pid);
@@ -373,7 +387,7 @@ bool nvmap_shrink_carveout(struct nvmap_carveout_node *node)
}
out:
spin_unlock_irqrestore(&node->clients_lock, flags);
- return death_pending;
+ return wait;
}
#endif
@@ -420,6 +434,8 @@ struct nvmap_heap_block *nvmap_carveout_alloc(struct nvmap_client *client,
int i;
unsigned long end = jiffies +
msecs_to_jiffies(NVMAP_CARVEOUT_KILLER_RETRY_TIME);
+ int count = 0;
+ DEFINE_WAIT(wait);
do {
block = do_nvmap_carveout_alloc(client, len, align, usage,
@@ -427,6 +443,13 @@ struct nvmap_heap_block *nvmap_carveout_alloc(struct nvmap_client *client,
if (block)
return block;
+ if (!count++)
+ printk("%s: failed to allocate %u bytes, "
+ "firing carveout killer!\n", __func__, len);
+ else
+ printk("%s: still can't allocate %u bytes, "
+ "attempt %d!\n", __func__, len, count);
+
/* shrink carveouts that matter and try again */
for (i = 0; i < dev->nr_carveouts; i++) {
co_heap = &dev->heaps[i];
@@ -435,13 +458,22 @@ struct nvmap_heap_block *nvmap_carveout_alloc(struct nvmap_client *client,
continue;
/* indicates we just delivered a sigkill to current,
- might as well stop trying so the process can exit */
- if (nvmap_shrink_carveout(co_heap))
+ or didn't find anything to kill might as well stop
+ trying */
+ if (!nvmap_shrink_carveout(co_heap))
return NULL;
+
+ prepare_to_wait(&wait_reclaim, &wait,
+ TASK_INTERRUPTIBLE);
+ schedule_timeout(end - jiffies);
+ finish_wait(&wait_reclaim, &wait);
}
- yield();
} while (time_is_after_jiffies(end));
+ if (time_is_before_jiffies(end))
+ printk("carveout_killer: timeout expired without allocation "
+ "succeeding.\n");
+
return NULL;
#else
block = do_nvmap_carveout_alloc(client, len, align, usage, prot);
@@ -583,6 +615,7 @@ static void destroy_client(struct nvmap_client *client)
if (!client)
return;
+
while ((n = rb_first(&client->handle_refs))) {
struct nvmap_handle_ref *ref;
int pins, dupes;
@@ -608,6 +641,10 @@ static void destroy_client(struct nvmap_client *client)
kfree(ref);
}
+#ifdef CONFIG_NVMAP_CARVEOUT_KILLER
+ wake_up_all(&wait_reclaim);
+#endif
+
for (i = 0; i < client->dev->nr_carveouts; i++)
list_del(&client->carveout_commit[i].list);