diff options
author | Colin Cross <ccross@android.com> | 2010-10-12 18:47:05 -0700 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2010-10-12 18:47:05 -0700 |
commit | 3d533ce331337e58f16b25e5de9a57f1665c4a73 (patch) | |
tree | 4022cf35ba4ff433311c3bbc24d6e1a628387ce7 /drivers | |
parent | 5c7c63142d2298d383e6e9daa733da78370b8aa1 (diff) | |
parent | 4beaf8cc13b10367d1bbb63bacbfe8d12b667c3c (diff) |
Merge branch 'linux-tegra-2.6.36' into android-tegra-2.6.36
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/spi/spi_tegra.c | 1 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dc.c | 18 | ||||
-rw-r--r-- | drivers/video/tegra/fb.c | 233 | ||||
-rw-r--r-- | drivers/video/tegra/host/debug.c | 82 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_cdma.c | 21 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_cdma.h | 2 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap.c | 15 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_dev.c | 8 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_handle.c | 2 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_ioctl.c | 5 |
10 files changed, 222 insertions, 165 deletions
diff --git a/drivers/spi/spi_tegra.c b/drivers/spi/spi_tegra.c index 6023da9a103a..3709d5dccd76 100644 --- a/drivers/spi/spi_tegra.c +++ b/drivers/spi/spi_tegra.c @@ -274,6 +274,7 @@ static void spi_tegra_start_transfer(struct spi_device *spi, val |= SLINK_TXEN; val |= SLINK_SS_EN_CS(spi->chip_select); val |= SLINK_SPIE; + val |= SLINK_SS_SETUP(3); spi_tegra_writel(tspi, val, SLINK_COMMAND2); val = spi_tegra_readl(tspi, SLINK_COMMAND); diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index 16e6a454336d..65a36ddd2514 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -328,20 +328,6 @@ struct tegra_dc *tegra_dc_get_dc(unsigned idx) } EXPORT_SYMBOL(tegra_dc_get_dc); -ssize_t tegra_dc_compute_stride(int xres, int bpp, enum tegra_win_layout layout) -{ - unsigned int raw_stride = (xres * bpp) / 8; - unsigned int k, n = 0; - - if (layout == TEGRA_WIN_LAYOUT_PITCH) - return ALIGN(raw_stride, TEGRA_DC_PITCH_ATOM); - else if (layout == TEGRA_WIN_LAYOUT_TILED) - return ALIGN(raw_stride, TEGRA_DC_TILED_ATOM); - else - return -EINVAL; -} -EXPORT_SYMBOL(tegra_dc_compute_stride); - struct tegra_dc_win *tegra_dc_get_window(struct tegra_dc *dc, unsigned win) { if (win >= dc->n_windows) @@ -1066,8 +1052,10 @@ static int tegra_dc_suspend(struct nvhost_device *ndev, pm_message_t state) dev_info(&ndev->dev, "suspend\n"); + mutex_lock(&dc->lock); if (dc->enabled) _tegra_dc_disable(dc); + mutex_unlock(&dc->lock); return 0; } @@ -1078,8 +1066,10 @@ static int tegra_dc_resume(struct nvhost_device *ndev) dev_info(&ndev->dev, "resume\n"); + mutex_lock(&dc->lock); if (dc->enabled) _tegra_dc_enable(dc); + mutex_unlock(&dc->lock); return 0; } diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c index 1656a6e49279..87ba58b06cd1 100644 --- a/drivers/video/tegra/fb.c +++ b/drivers/video/tegra/fb.c @@ -59,17 +59,16 @@ struct tegra_fb_info { }; struct tegra_fb_flip_win { - struct tegra_dc_win win_data; - struct tegra_dc_win *dc_win; - s32 pre_syncpt_id; - u32 pre_syncpt_val; + struct tegra_fb_windowattr attr; + struct nvmap_handle_ref *handle; + dma_addr_t phys_addr; }; struct tegra_fb_flip_data { - struct work_struct work; - struct tegra_fb_info *fb; - struct tegra_fb_flip_win windows[TEGRA_FB_FLIP_N_WINDOWS]; - u32 syncpt_max; + struct work_struct work; + struct tegra_fb_info *fb; + struct tegra_fb_flip_win win[TEGRA_FB_FLIP_N_WINDOWS]; + u32 syncpt_max; }; /* palette array used by the fbcon */ @@ -149,10 +148,7 @@ static int tegra_fb_set_par(struct fb_info *info) default: return -EINVAL; } - - info->fix.line_length = tegra_dc_compute_stride(var->xres, - var->bits_per_pixel, TEGRA_WIN_LAYOUT_PITCH); - tegra_fb->win->stride = info->fix.line_length; + info->fix.line_length = var->xres * var->bits_per_pixel / 8; if (var->pixclock) { struct tegra_dc_mode mode; @@ -251,10 +247,10 @@ static int tegra_fb_pan_display(struct fb_var_screeninfo *var, tegra_dc_update_windows(&tegra_fb->win, 1); tegra_dc_sync_windows(&tegra_fb->win, 1); - if (WARN_ON(tegra_fb->win->surface)) { - nvmap_unpin(tegra_fb->fb_nvmap, tegra_fb->win->surface); - nvmap_free(tegra_fb->fb_nvmap, tegra_fb->win->surface); - tegra_fb->win->surface = NULL; + 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; } return 0; @@ -299,131 +295,140 @@ static int tegra_fb_set_nvmap_fd(struct tegra_fb_info *tegra_fb, int fd) return 0; } -static int tegra_fb_set_windowattr(struct tegra_fb_info *tegra_fb, - struct tegra_dc_win *win, - const struct tegra_fb_windowattr *attr) +static int tegra_fb_pin_window(struct tegra_fb_info *tegra_fb, + struct tegra_fb_flip_win *flip_win) { - struct nvmap_handle_ref *r_dupe; - struct nvmap_handle *h_win; + struct nvmap_handle_ref *win_dupe; + struct nvmap_handle *win_handle; + unsigned long buff_id = flip_win->attr.buff_id; - if (!attr->buff_id) { - win->flags = 0; - win->surface = NULL; + if (!buff_id) return 0; - } - h_win = nvmap_get_handle_id(tegra_fb->user_nvmap, attr->buff_id); - if (h_win == NULL) { + win_handle = nvmap_get_handle_id(tegra_fb->user_nvmap, buff_id); + if (win_handle == NULL) { dev_err(&tegra_fb->ndev->dev, "%s: flip invalid " - "handle %08x\n", current->comm, attr->buff_id); + "handle %08lx\n", current->comm, buff_id); return -EPERM; } /* duplicate the new framebuffer's handle into the fb driver's * nvmap context, to ensure that the handle won't be freed as * long as it is in-use by the fb driver */ - r_dupe = nvmap_duplicate_handle_id(tegra_fb->fb_nvmap, attr->buff_id); - nvmap_handle_put(h_win); + win_dupe = nvmap_duplicate_handle_id(tegra_fb->fb_nvmap, buff_id); + nvmap_handle_put(win_handle); - if (IS_ERR(r_dupe)) { + if (IS_ERR(win_dupe)) { dev_err(&tegra_fb->ndev->dev, "couldn't duplicate handle\n"); - return PTR_ERR(r_dupe); + return PTR_ERR(win_dupe); + } + + flip_win->handle = win_dupe; + + flip_win->phys_addr = nvmap_pin(tegra_fb->fb_nvmap, win_dupe); + if (IS_ERR((void *)flip_win->phys_addr)) { + dev_err(&tegra_fb->ndev->dev, "couldn't pin handle\n"); + nvmap_free(tegra_fb->fb_nvmap, win_dupe); + return PTR_ERR((void *)flip_win->phys_addr); } - win->surface = r_dupe; + return 0; +} + +static int tegra_fb_set_windowattr(struct tegra_fb_info *tegra_fb, + struct tegra_dc_win *win, + const struct tegra_fb_flip_win *flip_win) +{ + if (flip_win->handle == NULL) { + win->flags = 0; + return 0; + } win->flags = TEGRA_WIN_FLAG_ENABLED; - if (attr->blend == TEGRA_FB_WIN_BLEND_PREMULT) + if (flip_win->attr.blend == TEGRA_FB_WIN_BLEND_PREMULT) win->flags |= TEGRA_WIN_FLAG_BLEND_PREMULT; - else if (attr->blend == TEGRA_FB_WIN_BLEND_COVERAGE) + else if (flip_win->attr.blend == TEGRA_FB_WIN_BLEND_COVERAGE) win->flags |= TEGRA_WIN_FLAG_BLEND_COVERAGE; - win->fmt = attr->pixformat; - win->x = attr->x; - win->y = attr->y; - win->w = attr->w; - win->h = attr->h; - win->out_x = attr->out_x; - win->out_y = attr->out_y; - win->out_w = attr->out_w; - win->out_h = attr->out_h; - win->z = attr->z; - - win->phys_addr = nvmap_pin(tegra_fb->fb_nvmap, r_dupe); - if (IS_ERR((void *)win->phys_addr)) { - dev_err(&tegra_fb->ndev->dev, "couldn't pin handle\n"); - nvmap_free(tegra_fb->fb_nvmap, r_dupe); - return (int)win->phys_addr; - } + win->fmt = flip_win->attr.pixformat; + win->x = flip_win->attr.x; + win->y = flip_win->attr.y; + win->w = flip_win->attr.w; + win->h = flip_win->attr.h; + win->out_x = flip_win->attr.out_x; + win->out_y = flip_win->attr.out_y; + win->out_w = flip_win->attr.out_w; + win->out_h = flip_win->attr.out_h; + win->z = flip_win->attr.z; + win->cur_handle = flip_win->handle; + /* STOPSHIP verify that this won't read outside of the surface */ - win->phys_addr += attr->offset; - win->stride = attr->stride; + win->phys_addr = flip_win->phys_addr + flip_win->attr.offset; + win->stride = flip_win->attr.stride; + + if ((s32)flip_win->attr.pre_syncpt_id >= 0) { + nvhost_syncpt_wait_timeout(&tegra_fb->ndev->host->syncpt, + flip_win->attr.pre_syncpt_id, + flip_win->attr.pre_syncpt_val, + msecs_to_jiffies(500)); + } + return 0; } -static void tegra_fb_flip_work(struct work_struct *work) +static void tegra_fb_flip_worker(struct work_struct *work) { - struct tegra_fb_flip_data *data; + struct tegra_fb_flip_data *data = + container_of(work, struct tegra_fb_flip_data, work); + struct tegra_fb_info *tegra_fb = data->fb; + struct tegra_dc_win *win; struct tegra_dc_win *wins[TEGRA_FB_FLIP_N_WINDOWS]; - struct nvmap_handle_ref *surfs[TEGRA_FB_FLIP_N_WINDOWS]; + struct nvmap_handle_ref *unpin_handles[TEGRA_FB_FLIP_N_WINDOWS]; int i, nr_win = 0, nr_unpin = 0; data = container_of(work, struct tegra_fb_flip_data, work); for (i = 0; i < TEGRA_FB_FLIP_N_WINDOWS; i++) { - struct tegra_fb_flip_win *flip_win = &data->windows[i]; + struct tegra_fb_flip_win *flip_win = &data->win[i]; + int idx = flip_win->attr.index; + win = tegra_dc_get_window(tegra_fb->win->dc, idx); - if (!flip_win->dc_win) + if (!win) continue; - if (flip_win->dc_win->flags && flip_win->dc_win->surface) - surfs[nr_unpin++] = flip_win->dc_win->surface; + if (win->flags && win->cur_handle) + unpin_handles[nr_unpin++] = win->cur_handle; - wins[nr_win++] = flip_win->dc_win; + tegra_fb_set_windowattr(tegra_fb, win, &data->win[i]); - flip_win->dc_win->flags = flip_win->win_data.flags; - if (!flip_win->dc_win->flags) - continue; + wins[nr_win++] = win; - flip_win->dc_win->surface = flip_win->win_data.surface; - flip_win->dc_win->fmt = flip_win->win_data.fmt; - flip_win->dc_win->x = flip_win->win_data.x; - flip_win->dc_win->y = flip_win->win_data.y; - flip_win->dc_win->w = flip_win->win_data.w; - flip_win->dc_win->h = flip_win->win_data.h; - flip_win->dc_win->out_x = flip_win->win_data.out_x; - flip_win->dc_win->out_y = flip_win->win_data.out_y; - flip_win->dc_win->out_w = flip_win->win_data.out_w; - flip_win->dc_win->out_h = flip_win->win_data.out_h; - flip_win->dc_win->z = flip_win->win_data.z; - flip_win->dc_win->phys_addr = flip_win->win_data.phys_addr; - flip_win->dc_win->stride = flip_win->win_data.stride; - - if (flip_win->pre_syncpt_id < 0) +#if 0 + if (flip_win->attr.pre_syncpt_id < 0) continue; + printk("%08x %08x\n", + flip_win->attr.pre_syncpt_id, + flip_win->attr.pre_syncpt_val); - nvhost_syncpt_wait_timeout(&data->fb->ndev->host->syncpt, - flip_win->pre_syncpt_id, - flip_win->pre_syncpt_val, + nvhost_syncpt_wait_timeout(&tegra_fb->ndev->host->syncpt, + flip_win->attr.pre_syncpt_id, + flip_win->attr.pre_syncpt_val, msecs_to_jiffies(500)); +#endif } - if (!nr_win) - goto free_data; - tegra_dc_update_windows(wins, nr_win); /* TODO: implement swapinterval here */ tegra_dc_sync_windows(wins, nr_win); - tegra_dc_incr_syncpt_min(data->fb->win->dc, data->syncpt_max); + tegra_dc_incr_syncpt_min(tegra_fb->win->dc, data->syncpt_max); /* unpin and deref previous front buffers */ for (i = 0; i < nr_unpin; i++) { - nvmap_unpin(data->fb->fb_nvmap, surfs[i]); - nvmap_free(data->fb->fb_nvmap, surfs[i]); + nvmap_unpin(tegra_fb->fb_nvmap, unpin_handles[i]); + nvmap_free(tegra_fb->fb_nvmap, unpin_handles[i]); } -free_data: kfree(data); } @@ -432,7 +437,6 @@ static int tegra_fb_flip(struct tegra_fb_info *tegra_fb, { struct tegra_fb_flip_data *data; struct tegra_fb_flip_win *flip_win; - struct tegra_dc *dc = tegra_fb->win->dc; u32 syncpt_max; int i, err; @@ -442,51 +446,46 @@ static int tegra_fb_flip(struct tegra_fb_info *tegra_fb, if (WARN_ON(!tegra_fb->ndev)) return -EFAULT; - data = kmalloc(sizeof(*data), GFP_KERNEL); - if (!data) { - dev_err(&tegra_fb->ndev->dev, "no memory for flip\n"); + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) { + dev_err(&tegra_fb->ndev->dev, + "can't allocate memory for flip\n"); return -ENOMEM; } - INIT_WORK(&data->work, tegra_fb_flip_work); + INIT_WORK(&data->work, tegra_fb_flip_worker); data->fb = tegra_fb; for (i = 0; i < TEGRA_FB_FLIP_N_WINDOWS; i++) { + flip_win = &data->win[i]; - flip_win = &data->windows[i]; - flip_win->dc_win = tegra_dc_get_window(dc, args->win[i].index); - flip_win->pre_syncpt_id = args->win[i].pre_syncpt_id; - flip_win->pre_syncpt_val = args->win[i].pre_syncpt_val; - - if (!flip_win->dc_win) - continue; + memcpy(&flip_win->attr, &args->win[i], sizeof(flip_win->attr)); - err = tegra_fb_set_windowattr(tegra_fb, &flip_win->win_data, - &args->win[i]); - if (err) { - dev_err(&tegra_fb->ndev->dev, "error setting window " - "attributes\n"); + err = tegra_fb_pin_window(tegra_fb, flip_win); + if (err < 0) { + dev_err(&tegra_fb->ndev->dev, + "error setting window attributes\n"); goto surf_err; } } - syncpt_max = tegra_dc_incr_syncpt_max(dc); + syncpt_max = tegra_dc_incr_syncpt_max(tegra_fb->win->dc); data->syncpt_max = syncpt_max; queue_work(tegra_fb->flip_wq, &data->work); args->post_syncpt_val = syncpt_max; - args->post_syncpt_id = tegra_dc_get_syncpt_id(dc); + args->post_syncpt_id = tegra_dc_get_syncpt_id(tegra_fb->win->dc); return 0; surf_err: while (i--) { - if (data->windows[i].win_data.surface) { + if (data->win[i].handle) { nvmap_unpin(tegra_fb->fb_nvmap, - data->windows[i].win_data.surface); + data->win[i].handle); nvmap_free(tegra_fb->fb_nvmap, - data->windows[i].win_data.surface); + data->win[i].handle); } } kfree(data); @@ -679,9 +678,7 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev, win->z = 0; win->phys_addr = fb_phys; win->virt_addr = fb_base; - win->layout = TEGRA_WIN_LAYOUT_PITCH; - win->stride = tegra_dc_compute_stride(fb_data->xres, - fb_data->bits_per_pixel, win->layout); + win->stride = fb_data->xres * fb_data->bits_per_pixel / 8; win->flags = TEGRA_WIN_FLAG_ENABLED; if (fb_mem) @@ -715,9 +712,9 @@ void tegra_fb_unregister(struct tegra_fb_info *fb_info) { struct fb_info *info = fb_info->info; - if (fb_info->win->surface) { - nvmap_unpin(fb_info->fb_nvmap, fb_info->win->surface); - nvmap_free(fb_info->fb_nvmap, fb_info->win->surface); + if (fb_info->win->cur_handle) { + nvmap_unpin(fb_info->fb_nvmap, fb_info->win->cur_handle); + nvmap_free(fb_info->fb_nvmap, fb_info->win->cur_handle); } if (fb_info->fb_nvmap) diff --git a/drivers/video/tegra/host/debug.c b/drivers/video/tegra/host/debug.c index c2dfe3156df3..c1cfd6ee229c 100644 --- a/drivers/video/tegra/host/debug.c +++ b/drivers/video/tegra/host/debug.c @@ -48,19 +48,19 @@ static int nvhost_debug_handle_cmd(struct seq_file *s, u32 val, int *count) } case 0x1: - seq_printf(s, "INCR(offset=%03x, [", val >> 16 & 0x3ff); + seq_printf(s, "INCR(offset=%03x, [", val >> 16 & 0xfff); *count = val & 0xffff; return NVHOST_DBG_STATE_DATA; case 0x2: - seq_printf(s, "NOMINCR(offset=%03x, [", val >> 16 & 0x3ff); + seq_printf(s, "NONINCR(offset=%03x, [", val >> 16 & 0xfff); *count = val & 0xffff; return NVHOST_DBG_STATE_DATA; case 0x3: mask = val & 0xffff; seq_printf(s, "MASK(offset=%03x, mask=%03x, [", - val >> 16 & 0x3ff, mask); + val >> 16 & 0xfff, mask); *count = hweight16(mask); return NVHOST_DBG_STATE_DATA; @@ -100,6 +100,33 @@ static int nvhost_debug_handle_cmd(struct seq_file *s, u32 val, int *count) } } +static void nvhost_debug_handle_word(struct seq_file *s, int *state, int *count, + unsigned long addr, int channel, u32 val) +{ + switch (*state) { + case NVHOST_DBG_STATE_CMD: + if (addr) + seq_printf(s, "%d: %08x: %08x:", channel, addr, val); + else + seq_printf(s, "%d: %08x:", channel, val); + + *state = nvhost_debug_handle_cmd(s, val, count); + if (*state == NVHOST_DBG_STATE_DATA && *count == 0) { + *state = NVHOST_DBG_STATE_CMD; + seq_printf(s, "])\n"); + } + break; + + case NVHOST_DBG_STATE_DATA: + (*count)--; + seq_printf(s, "%08x%s", val, *count > 0 ? ", " : "])\n"); + if (*count == 0) + *state = NVHOST_DBG_STATE_CMD; + break; + } +} + + static int nvhost_debug_show(struct seq_file *s, void *unused) { struct nvhost_master *m = s->private; @@ -116,7 +143,8 @@ static int nvhost_debug_show(struct seq_file *s, void *unused) unsigned start, end; unsigned wr_ptr, rd_ptr; int state; - int count = 0; + int count; + u32 phys_addr, size; dmaput = readl(regs + HOST1X_CHANNEL_DMAPUT); dmaget = readl(regs + HOST1X_CHANNEL_DMAGET); @@ -151,9 +179,35 @@ static int nvhost_debug_show(struct seq_file *s, void *unused) break; } + nvhost_cdma_find_gather(&m->channels[i].cdma, dmaget, &phys_addr, &size); + + /* If dmaget is in the pushbuffer (should always be?), + * check if we're executing a fetch, and if so dump + * it. */ + if (size) { + u32 offset = dmaget - m->channels[i].cdma.push_buffer.phys; + u32 map_base = phys_addr & PAGE_MASK; + u32 map_size = (size * 4 + PAGE_SIZE - 1) & PAGE_MASK; + u32 map_offset = phys_addr - map_base; + void *map_addr = ioremap_nocache(map_base, map_size); + + if (map_addr) { + u32 ii; + + seq_printf(s, "\n%d: gather (%d words)\n", i, size); + state = NVHOST_DBG_STATE_CMD; + for (ii = 0; ii < size; ii++) { + val = readl(map_addr + map_offset + ii*sizeof(u32)); + nvhost_debug_handle_word(s, &state, &count, phys_addr + ii, i, val); + } + iounmap(map_addr); + } + } + fifostat = readl(regs + HOST1X_CHANNEL_FIFOSTAT); if ((fifostat & 1 << 10) == 0 ) { + seq_printf(s, "\n%d: fifo:\n", i); writel(0x0, m->aperture + HOST1X_SYNC_CFPEEK_CTRL); writel(1 << 31 | i << 16, m->aperture + HOST1X_SYNC_CFPEEK_CTRL); rd_ptr = readl(m->aperture + HOST1X_SYNC_CFPEEK_PTRS) & 0x1ff; @@ -169,24 +223,7 @@ static int nvhost_debug_show(struct seq_file *s, void *unused) writel(1 << 31 | i << 16 | rd_ptr, m->aperture + HOST1X_SYNC_CFPEEK_CTRL); val = readl(m->aperture + HOST1X_SYNC_CFPEEK_READ); - switch (state) { - case NVHOST_DBG_STATE_CMD: - seq_printf(s, "%d: %08x:", i, val); - - state = nvhost_debug_handle_cmd(s, val, &count); - if (state == NVHOST_DBG_STATE_DATA && count == 0) { - state = NVHOST_DBG_STATE_CMD; - seq_printf(s, "])\n"); - } - break; - - case NVHOST_DBG_STATE_DATA: - count--; - seq_printf(s, "%08x%s", val, count > 0 ? ", " : "])\n"); - if (count == 0) - state = NVHOST_DBG_STATE_CMD; - break; - } + nvhost_debug_handle_word(s, &state, &count, 0, i, val); if (rd_ptr == end) rd_ptr = start; @@ -199,6 +236,7 @@ static int nvhost_debug_show(struct seq_file *s, void *unused) if (state == NVHOST_DBG_STATE_DATA) seq_printf(s, ", ...])\n"); } + seq_printf(s, "\n"); } diff --git a/drivers/video/tegra/host/nvhost_cdma.c b/drivers/video/tegra/host/nvhost_cdma.c index 4b90456696ad..f27656bac07b 100644 --- a/drivers/video/tegra/host/nvhost_cdma.c +++ b/drivers/video/tegra/host/nvhost_cdma.c @@ -627,3 +627,24 @@ void nvhost_cdma_flush(struct nvhost_cdma *cdma) } mutex_unlock(&cdma->lock); } + +/** + * Find the currently executing gather in the push buffer and return + * its physical address and size. + */ +void nvhost_cdma_find_gather(struct nvhost_cdma *cdma, u32 dmaget, u32 *addr, u32 *size) +{ + u32 offset = dmaget - cdma->push_buffer.phys; + + *addr = *size = 0; + + if (offset >= 8 && offset < cdma->push_buffer.cur) { + u32 *p = cdma->push_buffer.mapped + (offset - 8) / 4; + + /* Make sure we have a gather */ + if ((p[0] >> 28) == 6) { + *addr = p[1]; + *size = p[0] & 0x3fff; + } + } +} diff --git a/drivers/video/tegra/host/nvhost_cdma.h b/drivers/video/tegra/host/nvhost_cdma.h index 77493abe0e27..a7f17d0413d5 100644 --- a/drivers/video/tegra/host/nvhost_cdma.h +++ b/drivers/video/tegra/host/nvhost_cdma.h @@ -97,5 +97,7 @@ void nvhost_cdma_end(struct nvmap_client *user_nvmap, struct nvmap_handle **handles, unsigned int nr_handles); void nvhost_cdma_update(struct nvhost_cdma *cdma); void nvhost_cdma_flush(struct nvhost_cdma *cdma); +void nvhost_cdma_find_gather(struct nvhost_cdma *cdma, u32 dmaget, + u32 *addr, u32 *size); #endif diff --git a/drivers/video/tegra/nvmap/nvmap.c b/drivers/video/tegra/nvmap/nvmap.c index 7419731a7c52..506aef8408a9 100644 --- a/drivers/video/tegra/nvmap/nvmap.c +++ b/drivers/video/tegra/nvmap/nvmap.c @@ -225,12 +225,17 @@ int nvmap_pin_ids(struct nvmap_client *client, if (ref) { atomic_inc(&ref->pin); nvmap_handle_get(h[i]); - } else if (!client->super && (h[i]->owner != client) && - !h[i]->global) { - ret = -EPERM; } else { - nvmap_warn(client, "%s pinning unreferenced handle " - "%p\n", current->group_leader->comm, h[i]); + struct nvmap_handle *verify; + nvmap_ref_unlock(client); + verify = nvmap_validate_get(client, ids[i]); + if (verify) + nvmap_warn(client, "%s pinning unreferenced " + "handle %p\n", + current->group_leader->comm, h[i]); + else + ret = -EPERM; + nvmap_ref_lock(client); } } nvmap_ref_unlock(client); diff --git a/drivers/video/tegra/nvmap/nvmap_dev.c b/drivers/video/tegra/nvmap/nvmap_dev.c index b84a788dd33b..c6669ed86c24 100644 --- a/drivers/video/tegra/nvmap/nvmap_dev.c +++ b/drivers/video/tegra/nvmap/nvmap_dev.c @@ -353,6 +353,8 @@ struct nvmap_handle *nvmap_validate_get(struct nvmap_client *client, if ((unsigned long)h == id) { if (client->super || h->global || (h->owner == client)) h = nvmap_handle_get(h); + else + h = NULL; spin_unlock(&client->dev->handle_lock); return h; } @@ -696,9 +698,9 @@ static int nvmap_probe(struct platform_device *pdev) dev->dev_user.parent = &pdev->dev; dev->dev_super.minor = MISC_DYNAMIC_MINOR; - dev->dev_super.name = "kvmap"; - dev->dev_user.fops = &nvmap_super_fops; - dev->dev_user.parent = &pdev->dev; + dev->dev_super.name = "knvmap"; + dev->dev_super.fops = &nvmap_super_fops; + dev->dev_super.parent = &pdev->dev; dev->handles = RB_ROOT; diff --git a/drivers/video/tegra/nvmap/nvmap_handle.c b/drivers/video/tegra/nvmap/nvmap_handle.c index eed3403db02d..21cbf9c4d85d 100644 --- a/drivers/video/tegra/nvmap/nvmap_handle.c +++ b/drivers/video/tegra/nvmap/nvmap_handle.c @@ -38,7 +38,7 @@ #include "nvmap_mru.h" #define NVMAP_SECURE_HEAPS (NVMAP_HEAP_CARVEOUT_IRAM | NVMAP_HEAP_IOVMM) -#define GFP_NVMAP (GFP_KERNEL | __GFP_HIGHMEM | __GFP_NOWARN) +#define GFP_NVMAP (__GFP_HIGHMEM | __GFP_NOWARN) /* handles may be arbitrarily large (16+MiB), and any handle allocated from * the kernel (i.e., not a carveout handle) includes its array of pages. to * preserve kmalloc space, if the array of pages exceeds PAGELIST_VMALLOC_MIN, diff --git a/drivers/video/tegra/nvmap/nvmap_ioctl.c b/drivers/video/tegra/nvmap/nvmap_ioctl.c index 9051803aa68d..b943065a44c0 100644 --- a/drivers/video/tegra/nvmap/nvmap_ioctl.c +++ b/drivers/video/tegra/nvmap/nvmap_ioctl.c @@ -459,7 +459,8 @@ static int cache_maint(struct nvmap_client *client, struct nvmap_handle *h, } if (h->flags == NVMAP_HANDLE_UNCACHEABLE || - h->flags == NVMAP_HANDLE_WRITE_COMBINE) + h->flags == NVMAP_HANDLE_WRITE_COMBINE || + start == end) goto out; if (WARN_ON_ONCE(op == NVMAP_CACHE_OP_WB_INV)) @@ -607,7 +608,7 @@ static ssize_t rw_handle(struct nvmap_client *client, struct nvmap_handle *h, return PTR_ERR(pte); while (count--) { - if (h_offs + elem_size >= h->size) { + if (h_offs + elem_size > h->size) { nvmap_warn(client, "read/write outside of handle\n"); ret = -EFAULT; break; |