diff options
author | Rebecca Schultz Zavin <rebecca@android.com> | 2011-01-12 17:47:11 -0800 |
---|---|---|
committer | Rebecca Schultz Zavin <rebecca@android.com> | 2011-01-12 17:47:11 -0800 |
commit | 5c15007c19b1f4dd634158cf71a9d4a9aa8afd1a (patch) | |
tree | 7a90dff1af7ad2852e8759c7e59c2a846819ce0e /drivers/video | |
parent | 263fc53856240c5ce982f5c9cace0c5e5d9ccd3d (diff) | |
parent | 5be6f571ae59b681eac6f3916cd102e4765ec85c (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.c | 44 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_dev.c | 55 |
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); |