From: Rob Clark rob@ti.com
Can be set at boot or module load time to prevent YWRAP scrolling from being enabled.
Signed-off-by: Rob Clark rob@ti.com --- drivers/staging/omapdrm/omap_fbdev.c | 15 ++++++++++----- 1 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/staging/omapdrm/omap_fbdev.c b/drivers/staging/omapdrm/omap_fbdev.c index d8962e8..093ae2f 100644 --- a/drivers/staging/omapdrm/omap_fbdev.c +++ b/drivers/staging/omapdrm/omap_fbdev.c @@ -22,6 +22,10 @@ #include "drm_crtc.h" #include "drm_fb_helper.h"
+MODULE_PARM_DESC(ywrap, "Enable ywrap scrolling (omap44xx and later, default 'y')"); +static bool ywrap_enabled = true; +module_param_named(ywrap, ywrap_enabled, bool, 0644); + /* * fbdev funcs, to implement legacy fbdev interface on top of drm driver */ @@ -32,6 +36,7 @@ struct omap_fbdev { struct drm_fb_helper base; struct drm_framebuffer *fb; struct drm_gem_object *bo; + bool ywrap_enabled; };
static void omap_fbdev_flush(struct fb_info *fbi, int x, int y, int w, int h); @@ -75,14 +80,12 @@ static int omap_fbdev_pan_display(struct fb_var_screeninfo *var, { struct drm_fb_helper *helper = get_fb(fbi); struct omap_fbdev *fbdev = to_omap_fbdev(helper); - struct omap_drm_private *priv; int npages;
if (!helper) goto fallback;
- priv = helper->dev->dev_private; - if (!priv->has_dmm) + if (!fbdev->ywrap_enabled) goto fallback;
/* DMM roll shifts in 4K pages: */ @@ -152,7 +155,8 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, mode_cmd.width * ((mode_cmd.bpp + 7) / 8), mode_cmd.width, mode_cmd.bpp);
- if (priv->has_dmm) { + fbdev->ywrap_enabled = priv->has_dmm && ywrap_enabled; + if (fbdev->ywrap_enabled) { /* need to align pitch to page size if using DMM scrolling */ mode_cmd.pitch = ALIGN(mode_cmd.pitch, PAGE_SIZE); } @@ -218,12 +222,13 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, /* if we have DMM, then we can use it for scrolling by just * shuffling pages around in DMM rather than doing sw blit. */ - if (priv->has_dmm) { + if (fbdev->ywrap_enabled) { DRM_INFO("Enabling DMM ywrap scrolling\n"); fbi->flags |= FBINFO_HWACCEL_YWRAP | FBINFO_READS_FAST; fbi->fix.ywrapstep = 1; }
+ DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres); DBG("allocated %dx%d fb", fbdev->fb->width, fbdev->fb->height);
From: Rob Clark rob@ti.com
omap_gem_roll() could be called by fbcon in atomic context. Avoid aquiring mutex, or calling tiler_pin() (which itself is not safe for atomic context) in these cases.
Signed-off-by: Rob Clark rob@ti.com --- drivers/staging/omapdrm/omap_gem.c | 16 ++++++++++++++-- 1 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/omapdrm/omap_gem.c b/drivers/staging/omapdrm/omap_gem.c index 9684891..2bc570a 100644 --- a/drivers/staging/omapdrm/omap_gem.c +++ b/drivers/staging/omapdrm/omap_gem.c @@ -538,10 +538,22 @@ int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll) return -EINVAL; }
- mutex_lock(&obj->dev->struct_mutex); - omap_obj->roll = roll;
+ if (in_atomic()) { + /* this can get called from fbcon in atomic context.. so + * just ignore it and wait for next time called from + * interruptible context to update the PAT.. the result + * may be that user sees wrap-around instead of scrolling + * momentarily on the screen. If we wanted to be fancier + * we could perhaps schedule some workqueue work at this + * point. + */ + return 0; + } + + mutex_lock(&obj->dev->struct_mutex); + /* if we aren't mapped yet, we don't need to do anything */ if (omap_obj->block) { struct page **pages;
On Thu, Dec 15, 2011 at 9:05 PM, Rob Clark rob.clark@linaro.org wrote:
From: Rob Clark rob@ti.com
omap_gem_roll() could be called by fbcon in atomic context. Avoid aquiring mutex, or calling tiler_pin() (which itself is not safe for atomic context) in these cases.
Signed-off-by: Rob Clark rob@ti.com
drivers/staging/omapdrm/omap_gem.c | 16 ++++++++++++++-- 1 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/omapdrm/omap_gem.c b/drivers/staging/omapdrm/omap_gem.c index 9684891..2bc570a 100644 --- a/drivers/staging/omapdrm/omap_gem.c +++ b/drivers/staging/omapdrm/omap_gem.c @@ -538,10 +538,22 @@ int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll) return -EINVAL; }
- mutex_lock(&obj->dev->struct_mutex);
omap_obj->roll = roll;
- if (in_atomic()) {
ugg, this isn't even sufficient if you have any debug printks that can be enabled within struct_mutex critical section..
updated patch coming
BR, -R
- /* this can get called from fbcon in atomic context.. so
- * just ignore it and wait for next time called from
- * interruptible context to update the PAT.. the result
- * may be that user sees wrap-around instead of scrolling
- * momentarily on the screen. If we wanted to be fancier
- * we could perhaps schedule some workqueue work at this
- * point.
- */
- return 0;
- }
- mutex_lock(&obj->dev->struct_mutex);
/* if we aren't mapped yet, we don't need to do anything */ if (omap_obj->block) { struct page **pages; -- 1.7.5.4
From: Rob Clark rob@ti.com
omap_gem_roll() could be called by fbcon in atomic context or when struct_mutext is held. Avoid aquiring mutex (deadlock), or calling tiler_pin() (which itself is not safe for atomic context) in these cases.
Signed-off-by: Rob Clark rob@ti.com --- drivers/staging/omapdrm/omap_gem.c | 16 ++++++++++++++-- 1 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/omapdrm/omap_gem.c b/drivers/staging/omapdrm/omap_gem.c index 9684891..63490f7 100644 --- a/drivers/staging/omapdrm/omap_gem.c +++ b/drivers/staging/omapdrm/omap_gem.c @@ -538,10 +538,22 @@ int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll) return -EINVAL; }
- mutex_lock(&obj->dev->struct_mutex); - omap_obj->roll = roll;
+ if (in_atomic() || mutex_is_locked(&obj->dev->struct_mutex)) { + /* this can get called from fbcon in atomic context.. so + * just ignore it and wait for next time called from + * interruptible context to update the PAT.. the result + * may be that user sees wrap-around instead of scrolling + * momentarily on the screen. If we wanted to be fancier + * we could perhaps schedule some workqueue work at this + * point. + */ + return 0; + } + + mutex_lock(&obj->dev->struct_mutex); + /* if we aren't mapped yet, we don't need to do anything */ if (omap_obj->block) { struct page **pages;
On Fri, Dec 16, 2011 at 7:34 PM, Rob Clark rob.clark@linaro.org wrote:
--- a/drivers/staging/omapdrm/omap_gem.c +++ b/drivers/staging/omapdrm/omap_gem.c @@ -538,10 +538,22 @@ int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll) return -EINVAL; }
- mutex_lock(&obj->dev->struct_mutex);
omap_obj->roll = roll;
- if (in_atomic() || mutex_is_locked(&obj->dev->struct_mutex)) {
- /* this can get called from fbcon in atomic context.. so
- * just ignore it and wait for next time called from
- * interruptible context to update the PAT.. the result
- * may be that user sees wrap-around instead of scrolling
- * momentarily on the screen. If we wanted to be fancier
- * we could perhaps schedule some workqueue work at this
- * point.
- */
Multi-line comments are supposed to be of the form: /* * Foo. */
- return 0;
- }
- mutex_lock(&obj->dev->struct_mutex);
/* if we aren't mapped yet, we don't need to do anything */ if (omap_obj->block) { struct page **pages; --
Cheers.
From: Andy Gross andy.gross@ti.com
Right now just a tiler_map file to dump a 2d map of which areas in tiler/dmm have pinned buffers (or reservations). In the future more could be added.
Signed-off-by: Rob Clark rob@ti.com --- drivers/staging/omapdrm/Makefile | 1 + drivers/staging/omapdrm/omap_debugfs.c | 42 +++++++++ drivers/staging/omapdrm/omap_dmm_tiler.c | 149 ++++++++++++++++++++++++++++++ drivers/staging/omapdrm/omap_dmm_tiler.h | 4 + drivers/staging/omapdrm/omap_drv.c | 4 + drivers/staging/omapdrm/omap_drv.h | 5 + 6 files changed, 205 insertions(+), 0 deletions(-) create mode 100644 drivers/staging/omapdrm/omap_debugfs.c
diff --git a/drivers/staging/omapdrm/Makefile b/drivers/staging/omapdrm/Makefile index 275054a..592cf69 100644 --- a/drivers/staging/omapdrm/Makefile +++ b/drivers/staging/omapdrm/Makefile @@ -5,6 +5,7 @@
ccflags-y := -Iinclude/drm -Werror omapdrm-y := omap_drv.o \ + omap_debugfs.o \ omap_crtc.o \ omap_encoder.o \ omap_connector.o \ diff --git a/drivers/staging/omapdrm/omap_debugfs.c b/drivers/staging/omapdrm/omap_debugfs.c new file mode 100644 index 0000000..da920df --- /dev/null +++ b/drivers/staging/omapdrm/omap_debugfs.c @@ -0,0 +1,42 @@ +/* + * drivers/staging/omapdrm/omap_debugfs.c + * + * Copyright (C) 2011 Texas Instruments + * Author: Rob Clark rob.clark@linaro.org + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see http://www.gnu.org/licenses/. + */ + +#include "omap_drv.h" +#include "omap_dmm_tiler.h" + +#ifdef CONFIG_DEBUG_FS + +static struct drm_info_list omap_debugfs_list[] = { + {"tiler_map", tiler_map_show, 0}, +}; + +int omap_debugfs_init(struct drm_minor *minor) +{ + return drm_debugfs_create_files(omap_debugfs_list, + ARRAY_SIZE(omap_debugfs_list), + minor->debugfs_root, minor); +} + +void omap_debugfs_cleanup(struct drm_minor *minor) +{ + drm_debugfs_remove_files(omap_debugfs_list, + ARRAY_SIZE(omap_debugfs_list), minor); +} + +#endif diff --git a/drivers/staging/omapdrm/omap_dmm_tiler.c b/drivers/staging/omapdrm/omap_dmm_tiler.c index b182de5..852d944 100644 --- a/drivers/staging/omapdrm/omap_dmm_tiler.c +++ b/drivers/staging/omapdrm/omap_dmm_tiler.c @@ -679,3 +679,152 @@ fail: omap_dmm_remove(); return ret; } + +/* + * debugfs support + */ + +#ifdef CONFIG_DEBUG_FS + +static const char *alphabet = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; +static const char *special = ".,:;'"`~!^-+"; + +static void fill_map(char **map, int xdiv, int ydiv, struct tcm_area *a, + char c, bool ovw) +{ + int x, y; + for (y = a->p0.y / ydiv; y <= a->p1.y / ydiv; y++) + for (x = a->p0.x / xdiv; x <= a->p1.x / xdiv; x++) + if (map[y][x] == ' ' || ovw) + map[y][x] = c; +} + +static void fill_map_pt(char **map, int xdiv, int ydiv, struct tcm_pt *p, + char c) +{ + map[p->y / ydiv][p->x / xdiv] = c; +} + +static char read_map_pt(char **map, int xdiv, int ydiv, struct tcm_pt *p) +{ + return map[p->y / ydiv][p->x / xdiv]; +} + +static int map_width(int xdiv, int x0, int x1) +{ + return (x1 / xdiv) - (x0 / xdiv) + 1; +} + +static void text_map(char **map, int xdiv, char *nice, int yd, int x0, int x1) +{ + char *p = map[yd] + (x0 / xdiv); + int w = (map_width(xdiv, x0, x1) - strlen(nice)) / 2; + if (w >= 0) { + p += w; + while (*nice) + *p++ = *nice++; + } +} + +static void map_1d_info(char **map, int xdiv, int ydiv, char *nice, + struct tcm_area *a) +{ + sprintf(nice, "%dK", tcm_sizeof(*a) * 4); + if (a->p0.y + 1 < a->p1.y) { + text_map(map, xdiv, nice, (a->p0.y + a->p1.y) / 2 / ydiv, 0, + 256 - 1); + } else if (a->p0.y < a->p1.y) { + if (strlen(nice) < map_width(xdiv, a->p0.x, 256 - 1)) + text_map(map, xdiv, nice, a->p0.y / ydiv, + a->p0.x + xdiv, 256 - 1); + else if (strlen(nice) < map_width(xdiv, 0, a->p1.x)) + text_map(map, xdiv, nice, a->p1.y / ydiv, + 0, a->p1.y - xdiv); + } else if (strlen(nice) + 1 < map_width(xdiv, a->p0.x, a->p1.x)) { + text_map(map, xdiv, nice, a->p0.y / ydiv, a->p0.x, a->p1.x); + } +} + +static void map_2d_info(char **map, int xdiv, int ydiv, char *nice, + struct tcm_area *a) +{ + sprintf(nice, "(%d*%d)", tcm_awidth(*a), tcm_aheight(*a)); + if (strlen(nice) + 1 < map_width(xdiv, a->p0.x, a->p1.x)) + text_map(map, xdiv, nice, (a->p0.y + a->p1.y) / 2 / ydiv, + a->p0.x, a->p1.x); +} + +int tiler_map_show(struct seq_file *s, void *arg) +{ + int xdiv = 2, ydiv = 1; + char **map = NULL, *global_map; + struct tiler_block *block; + struct tcm_area a, p; + int i; + const char *m2d = alphabet; + const char *a2d = special; + const char *m2dp = m2d, *a2dp = a2d; + char nice[128]; + int h_adj = omap_dmm->lut_height / ydiv; + int w_adj = omap_dmm->lut_width / xdiv; + unsigned long flags; + + map = kzalloc(h_adj * sizeof(*map), GFP_KERNEL); + global_map = kzalloc((w_adj + 1) * h_adj, GFP_KERNEL); + + if (!map || !global_map) + goto error; + + memset(global_map, ' ', (w_adj + 1) * h_adj); + for (i = 0; i < omap_dmm->lut_height; i++) { + map[i] = global_map + i * (w_adj + 1); + map[i][w_adj] = 0; + } + spin_lock_irqsave(&omap_dmm->list_lock, flags); + + list_for_each_entry(block, &omap_dmm->alloc_head, alloc_node) { + if (block->fmt != TILFMT_PAGE) { + fill_map(map, xdiv, ydiv, &block->area, *m2dp, true); + if (!*++a2dp) + a2dp = a2d; + if (!*++m2dp) + m2dp = m2d; + map_2d_info(map, xdiv, ydiv, nice, &block->area); + } else { + bool start = read_map_pt(map, xdiv, ydiv, + &block->area.p0) + == ' '; + bool end = read_map_pt(map, xdiv, ydiv, &block->area.p1) + == ' '; + tcm_for_each_slice(a, block->area, p) + fill_map(map, xdiv, ydiv, &a, '=', true); + fill_map_pt(map, xdiv, ydiv, &block->area.p0, + start ? '<' : 'X'); + fill_map_pt(map, xdiv, ydiv, &block->area.p1, + end ? '>' : 'X'); + map_1d_info(map, xdiv, ydiv, nice, &block->area); + } + } + + spin_unlock_irqrestore(&omap_dmm->list_lock, flags); + + if (s) { + seq_printf(s, "BEGIN DMM TILER MAP\n"); + for (i = 0; i < 128; i++) + seq_printf(s, "%03d:%s\n", i, map[i]); + seq_printf(s, "END TILER MAP\n"); + } else { + dev_dbg(omap_dmm->dev, "BEGIN DMM TILER MAP\n"); + for (i = 0; i < 128; i++) + dev_dbg(omap_dmm->dev, "%03d:%s\n", i, map[i]); + dev_dbg(omap_dmm->dev, "END TILER MAP\n"); + } + +error: + kfree(map); + kfree(global_map); + + return 0; +} +#endif diff --git a/drivers/staging/omapdrm/omap_dmm_tiler.h b/drivers/staging/omapdrm/omap_dmm_tiler.h index 58aa046..f87cb65 100644 --- a/drivers/staging/omapdrm/omap_dmm_tiler.h +++ b/drivers/staging/omapdrm/omap_dmm_tiler.h @@ -76,6 +76,10 @@ struct tiler_block { int omap_dmm_init(struct drm_device *dev); int omap_dmm_remove(void);
+#ifdef CONFIG_DEBUG_FS +int tiler_map_show(struct seq_file *s, void *arg); +#endif + /* pin/unpin */ int tiler_pin(struct tiler_block *block, struct page **pages, uint32_t npages, uint32_t roll, bool wait); diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c index 7ecf578..602aa2d 100644 --- a/drivers/staging/omapdrm/omap_drv.c +++ b/drivers/staging/omapdrm/omap_drv.c @@ -726,6 +726,10 @@ static struct drm_driver omap_drm_driver = { .irq_uninstall = dev_irq_uninstall, .irq_handler = dev_irq_handler, .reclaim_buffers = drm_core_reclaim_buffers, +#ifdef CONFIG_DEBUG_FS + .debugfs_init = omap_debugfs_init, + .debugfs_cleanup = omap_debugfs_cleanup, +#endif .gem_init_object = omap_gem_init_object, .gem_free_object = omap_gem_free_object, .gem_vm_ops = &omap_gem_vm_ops, diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h index 263057a..76c4251 100644 --- a/drivers/staging/omapdrm/omap_drv.h +++ b/drivers/staging/omapdrm/omap_drv.h @@ -51,6 +51,11 @@ struct omap_drm_private { bool has_dmm; };
+#ifdef CONFIG_DEBUG_FS +int omap_debugfs_init(struct drm_minor *minor); +void omap_debugfs_cleanup(struct drm_minor *minor); +#endif + struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev); void omap_fbdev_free(struct drm_device *dev);
dri-devel@lists.freedesktop.org