From 4b1ff08dbb2d07172cd5b2943d52089e96e7c977 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 27 Mar 2011 12:26:10 +0100 Subject: [PATCH] drm/i915: Accelerate fbdev using the BLT engine Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 9 + drivers/gpu/drm/i915/i915_gem.c | 10 +- drivers/gpu/drm/i915/i915_reg.h | 12 - drivers/gpu/drm/i915/intel_fb.c | 366 ++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_ringbuffer.c | 124 ++++++++--- drivers/gpu/drm/i915/intel_ringbuffer.h | 17 ++- drivers/video/cfbimgblt.c | 5 +- drivers/video/console/bitblit.c | 90 ++++---- drivers/video/console/fbcon_ccw.c | 25 +-- drivers/video/console/fbcon_cw.c | 25 +-- drivers/video/console/fbcon_ud.c | 29 ++-- drivers/video/console/softcursor.c | 11 +- drivers/video/fbmem.c | 2 +- include/linux/fb.h | 1 + 14 files changed, 557 insertions(+), 169 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 47fceeb..d1987b8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1329,6 +1329,15 @@ extern void intel_display_print_error_state(struct seq_file *m, #define ADVANCE_LP_RING() \ intel_ring_advance(LP_RING(dev_priv)) +static inline void intel_ring_queue_flush(struct intel_ring_buffer *ring) +{ + if (ring->pending_flush == 0) { + struct drm_i915_private *dev_priv = ring->dev->dev_private; + queue_delayed_work(dev_priv->wq, &ring->flush_work, HZ / 60); + ring->pending_flush = 1; + } +} + /** * Lock test for when it's just for synchronization of ring access. * diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a657734..098b3cc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2229,14 +2229,6 @@ i915_wait_request(struct intel_ring_buffer *ring, __func__, ret, seqno, ring->get_seqno(ring), dev_priv->next_seqno); - /* Directly dispatch request retiring. While we have the work queue - * to handle this, the waiter on a request often wants an associated - * buffer to have made it to the inactive list, and we would need - * a separate wait queue to handle that. - */ - if (ret == 0) - i915_gem_retire_requests_ring(ring); - return ret; } @@ -2262,6 +2254,8 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj) ret = i915_wait_request(obj->ring, obj->last_rendering_seqno); if (ret) return ret; + + i915_gem_retire_requests_ring(obj->ring); } return 0; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5194499..f68b890 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -211,18 +211,6 @@ #define GFX_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1) #define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3)) #define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2) -#define SRC_COPY_BLT_CMD ((2<<29)|(0x43<<22)|4) -#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) -#define XY_MONO_SRC_COPY_IMM_BLT ((2<<29)|(0x71<<22)|5) -#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21) -#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20) -#define BLT_DEPTH_8 (0<<24) -#define BLT_DEPTH_16_565 (1<<24) -#define BLT_DEPTH_16_1555 (2<<24) -#define BLT_DEPTH_32 (3<<24) -#define BLT_ROP_GXCOPY (0xcc<<16) -#define XY_SRC_COPY_BLT_SRC_TILED (1<<15) /* 965+ only */ -#define XY_SRC_COPY_BLT_DST_TILED (1<<11) /* 965+ only */ #define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2) #define ASYNC_FLIP (1<<22) #define DISPLAY_PLANE_A (0<<20) diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index ec49bae..f7dae92 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -44,13 +44,353 @@ #include "i915_drm.h" #include "i915_drv.h" +/* 2D Commands */ +#define COLOR_BLT_CMD ((2 << 29) | (0x40 << 22) | 3) +#define XY_COLOR_BLT_CMD ((2 << 29) | (0x50 << 22) | 4) +#define XY_SETUP_CLIP_BLT_CMD ((2 << 29) | (0x03 << 22) | 1) +#define XY_SRC_COPY_BLT_CMD ((2 << 29) | (0x53 << 22) | 6) +#define SRC_COPY_BLT_CMD ((2 << 29) | (0x43 << 22) | 4) +#define XY_MONO_PAT_BLT_CMD ((2 << 29) | (0x52 << 22) | 7) +#define XY_MONO_SRC_BLT_CMD ((2 << 29) | (0x54 << 22) | 6) +#define XY_MONO_SRC_IMM_BLT_CMD ((2 << 29) | (0x71 << 22) | 5) +#define TXT_IMM_BLT_CMD ((2 << 29) | (0x30 << 22) | 2) +#define SETUP_BLT_CMD ((2 << 29) | (0x00 << 22) | 6) + +#define DW_LENGTH_MASK 0xff + +#define WRITE_ALPHA (1 << 21) +#define WRITE_RGB (1 << 20) + +#define ROP_SHIFT 16 +#define SRC_ROP_COPY (0xcc << ROP_SHIFT) +#define PAT_ROP_COPY (0xf0 << ROP_SHIFT) +#define PAT_ROP_XOR (0x5a << ROP_SHIFT) + +#define WIDTH_SHIFT 0 +#define HEIGHT_SHIFT 16 + +#define MAX_MONO_IMM_SIZE 128 /* in bytes */ + +static struct intel_ring_buffer *blt_ring(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + return &dev_priv->ring[INTEL_INFO(dev)->gen >= 6 ? BCS : RCS]; +} + +static struct intel_fbdev *intel_fbdev(struct fb_info *info) +{ + return container_of(info->par, struct intel_fbdev, helper); +} + +static u32 color_to_pixel(struct fb_info *info, u32 index) +{ + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) + return ((u32 *)info->pseudo_palette)[index]; + else + return index; +} + +/* fbdev accelerated ops */ +static int intelfb_do_fill(struct intel_fbdev *ifbdev, + const struct fb_fillrect *rect) +{ + struct drm_device *dev = ifbdev->helper.dev; + struct intel_ring_buffer *ring = blt_ring(dev); + struct drm_i915_gem_object *obj = ifbdev->ifb.obj; + u32 bpp = ifbdev->ifb.base.bits_per_pixel; + u32 cmd; + int ret; + + ret = intel_ring_begin(ring, 6); + if (ret) + return ret; + + cmd = XY_COLOR_BLT_CMD; + if (bpp == 32) + cmd |= WRITE_ALPHA | WRITE_RGB; + intel_ring_emit(ring, cmd); + + cmd = rect->rop == ROP_COPY ? PAT_ROP_COPY : PAT_ROP_XOR; + cmd |= ifbdev->ifb.base.pitch; + switch (bpp) { + case 32: cmd |= 1 << 25; + case 16: cmd |= 1 << 24; + case 8: break; + } + intel_ring_emit(ring, cmd); + intel_ring_emit(ring, rect->dy << HEIGHT_SHIFT | rect->dx << WIDTH_SHIFT); + intel_ring_emit(ring, (rect->dy+rect->height) << HEIGHT_SHIFT | (rect->dx+rect->width) << WIDTH_SHIFT); + intel_ring_emit(ring, obj->gtt_offset); + intel_ring_emit(ring, color_to_pixel(ifbdev->helper.fbdev, rect->color)); + intel_ring_queue_flush(ring); + intel_ring_advance(ring); + return 0; +} + +static int +intelfb_do_copy(struct intel_fbdev *ifbdev, + const struct fb_copyarea *region) +{ + struct drm_device *dev = ifbdev->helper.dev; + struct intel_ring_buffer *ring = blt_ring(dev); + struct drm_i915_gem_object *obj = ifbdev->ifb.obj; + u32 bpp = ifbdev->ifb.base.bits_per_pixel; + u32 pitch = ifbdev->ifb.base.pitch; + u32 cmd; + int ret; + + ret = intel_ring_begin(ring, 8); + if (ret) + return ret; + + cmd = XY_SRC_COPY_BLT_CMD; + if (bpp == 32) + cmd |= WRITE_ALPHA | WRITE_RGB; + intel_ring_emit(ring, cmd); + + cmd = SRC_ROP_COPY | pitch; + switch (bpp) { + case 32: cmd |= 1 << 25; + case 16: cmd |= 1 << 24; + case 8: break; + } + intel_ring_emit(ring, cmd); + intel_ring_emit(ring, obj->gtt_offset); + intel_ring_emit(ring, + region->dx << WIDTH_SHIFT | + region->dy << HEIGHT_SHIFT); + intel_ring_emit(ring, + (region->dx + region->width) << WIDTH_SHIFT | + (region->dy + region->height) << HEIGHT_SHIFT); + intel_ring_emit(ring, obj->gtt_offset); + intel_ring_emit(ring, + region->sx << WIDTH_SHIFT | + region->sy << HEIGHT_SHIFT); + intel_ring_emit(ring, pitch); + intel_ring_queue_flush(ring); + intel_ring_advance(ring); + return 0; +} + +static int intelfb_do_mono(struct intel_fbdev *ifbdev, + const struct fb_image *image) +{ + struct intel_ring_buffer *ring = blt_ring(ifbdev->helper.dev); + u32 fg = color_to_pixel(ifbdev->helper.fbdev, image->fg_color); + u32 bg = color_to_pixel(ifbdev->helper.fbdev, image->bg_color); + u32 x = image->dx, y = image->dy; + u32 w = image->width, h = image->height; + const char *data = image->data; + int n, pad, lines, ret; + u32 cmd, pitch; + + lines = MAX_MONO_IMM_SIZE / image->pitch; + if (lines == 0) + return -EINVAL; /* XXX */ + + cmd = XY_MONO_SRC_IMM_BLT_CMD & ~DW_LENGTH_MASK; + pitch = SRC_ROP_COPY | ifbdev->ifb.base.pitch; + switch (ifbdev->ifb.base.bits_per_pixel) { + case 32: cmd |= WRITE_ALPHA | WRITE_RGB; + pitch |= 1 << 25; + case 16: pitch |= 1 << 24; + case 8: break; + } + + do { + if (lines > h) + lines = h; + + n = DIV_ROUND_UP(lines * image->pitch, 4); + pad = (n & 1) == 0; + + ret = intel_ring_begin(ring, 7 + n + pad); + if (ret) + return ret; + + intel_ring_emit(ring, cmd | ((XY_MONO_SRC_IMM_BLT_CMD & DW_LENGTH_MASK) + n)); + intel_ring_emit(ring, pitch); + intel_ring_emit(ring, x << WIDTH_SHIFT | y << HEIGHT_SHIFT); + intel_ring_emit(ring, (x + w) << WIDTH_SHIFT | (y + lines) << HEIGHT_SHIFT); + intel_ring_emit(ring, ifbdev->ifb.obj->gtt_offset); + intel_ring_emit(ring, bg); + intel_ring_emit(ring, fg); + intel_ring_emit_many(ring, (u32*)data, n); + if (pad) + intel_ring_emit(ring, MI_NOOP); + intel_ring_queue_flush(ring); + intel_ring_advance(ring); + + data += lines * image->pitch; + y += lines; + h -= lines; + } while (h); + + return 0; +} + +/* fbdev interface */ +static void intelfb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect) +{ + struct intel_fbdev *ifbdev = intel_fbdev(info); + struct drm_device *dev = ifbdev->helper.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (info->state != FBINFO_STATE_RUNNING) + return; + + if (info->flags & FBINFO_HWACCEL_DISABLED || in_interrupt()) + goto fallback; + if (atomic_read(&dev_priv->mm.wedged)) { + info->flags |= FBINFO_HWACCEL_DISABLED; + goto fallback; + } + + if (intelfb_do_fill(ifbdev, rect) == 0) + return; + +fallback: + cfb_fillrect(info, rect); +} + +static void intelfb_copyarea(struct fb_info *info, + const struct fb_copyarea *region) +{ + struct intel_fbdev *ifbdev = intel_fbdev(info); + struct drm_device *dev = ifbdev->helper.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (info->state != FBINFO_STATE_RUNNING) + return; + + if (info->flags & FBINFO_HWACCEL_DISABLED || in_interrupt()) + goto fallback; + if (atomic_read(&dev_priv->mm.wedged)) { + info->flags |= FBINFO_HWACCEL_DISABLED; + goto fallback; + } + + if (intelfb_do_copy(ifbdev, region) == 0) + return; + +fallback: + cfb_copyarea(info, region); +} + +static void intelfb_imageblit(struct fb_info *info, + const struct fb_image *image) +{ + struct intel_fbdev *ifbdev = intel_fbdev(info); + struct drm_device *dev = ifbdev->helper.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (info->state != FBINFO_STATE_RUNNING) + return; + + if (image->depth != 1) + goto fallback; + + if (info->flags & FBINFO_HWACCEL_DISABLED || in_interrupt()) + goto fallback; + if (atomic_read(&dev_priv->mm.wedged)) { + info->flags |= FBINFO_HWACCEL_DISABLED; + goto fallback; + } + + if (intelfb_do_mono(ifbdev, image) == 0) + return; + +fallback: + cfb_imageblit(info, image); +} + +static int +intelfb_sync(struct fb_info *info) +{ + struct intel_fbdev *ifbdev = intel_fbdev(info); + struct drm_device *dev = ifbdev->helper.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = blt_ring(dev); + + if (info->state != FBINFO_STATE_RUNNING) + return 0; + + if (atomic_read(&dev_priv->mm.wedged) || in_interrupt()) + return 0; + + if (ring->pending_flush) { + u32 flush = I915_GEM_GPU_DOMAINS; + u32 invalidate = 0; + int ret = ring->flush(ring, &invalidate, &flush); + if (ret) + return ret; + } + + return intel_wait_ring_buffer(ring, ring->size - 8); +} + +#if 0 +static int intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + + if (cursor->set & FB_CUR_SETSIZE) { + if (cursor->image.width != 64 || cursor->image.height != 64) + return -ENXIO; + } + + if (cursor->set & FB_CUR_SETPOS) { + intel_crtc->cursor_x = cursor->image.dx - info->var.xoffset; + intel_crtc->cursor_y = cursor->image.dy - info->var.yoffset; + } + + if (cursor->set & FB_CUR_SETCMAP) { + u32 fg = color_to_pixel(info, cursor->image.fg_color); + u32 bg = color_to_pixel(info, cursor->image.bg_color); + + /* XXX */ + } + + if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { + u32 size = cursor->image.pitch * cursor->image.height; + u8 *dat = (u8 *)cursor->image.data; + u8 *msk = (u8 *)cursor->mask; + u8 src[64]; + u32 i; + + if (cursor->image.depth != 1) + return -ENXIO; + + switch (cursor->rop) { + case ROP_XOR: + for (i = 0; i < size; i++) + src[i] = dat[i] ^ msk[i]; + break; + case ROP_COPY: + default: + for (i = 0; i < size; i++) + src[i] = dat[i] & msk[i]; + break; + } + + /* XXX expose intel_crtc_cursor_set() */ + } + + intel_crtc_update_cursor(crtc, cursor->enable); + + return 0; +} +#endif + static struct fb_ops intelfb_ops = { .owner = THIS_MODULE, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, + .fb_fillrect = intelfb_fillrect, + .fb_copyarea = intelfb_copyarea, + .fb_imageblit = intelfb_imageblit, + .fb_sync = intelfb_sync, .fb_pan_display = drm_fb_helper_pan_display, .fb_blank = drm_fb_helper_blank, .fb_setcmap = drm_fb_helper_setcmap, @@ -118,7 +458,13 @@ static int intelfb_create(struct intel_fbdev *ifbdev, strcpy(info->fix.id, "inteldrmfb"); - info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT; + info->flags = + FBINFO_DEFAULT | + FBINFO_CAN_FORCE_OUTPUT | + FBINFO_HWACCEL_COPYAREA | + FBINFO_HWACCEL_FILLRECT | + FBINFO_HWACCEL_IMAGEBLIT; + info->fbops = &intelfb_ops; ret = fb_alloc_cmap(&info->cmap, 256, 0); @@ -146,22 +492,20 @@ static int intelfb_create(struct intel_fbdev *ifbdev, } info->screen_size = size; -// memset(info->screen_base, 0, size); - drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height); - info->pixmap.size = 64*1024; - info->pixmap.buf_align = 8; - info->pixmap.access_align = 32; info->pixmap.flags = FB_PIXMAP_SYSTEM; - info->pixmap.scan_align = 1; + info->pixmap.size = 4096; + info->pixmap.buf_align = 4; + info->pixmap.access_align = 32; + info->pixmap.scan_align = 2; + info->pixmap.addr = (void*)__get_free_page(GFP_KERNEL); DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n", fb->width, fb->height, obj->gtt_offset, obj); - mutex_unlock(&dev->struct_mutex); vga_switcheroo_client_fb_set(dev->pdev, info); return 0; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 64a4fc5..fb7f664 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -118,6 +118,7 @@ render_ring_flush(struct intel_ring_buffer *ring, intel_ring_emit(ring, cmd); intel_ring_emit(ring, MI_NOOP); + ring->pending_flush = 0; intel_ring_advance(ring); return 0; @@ -139,6 +140,25 @@ u32 intel_ring_get_active_head(struct intel_ring_buffer *ring) return I915_READ(acthd_reg); } + +static void +intel_ring_flush_work_handler(struct work_struct *work) +{ + struct intel_ring_buffer *ring; + u32 flush = I915_GEM_GPU_DOMAINS; + u32 invalidate = 0; + + ring = container_of(work, struct intel_ring_buffer, flush_work.work); + if (ring->pending_flush == 0) + return; + + /* Come back later if the device is busy... */ + if (ring->flush(ring, &invalidate, &flush)) { + struct drm_i915_private *dev_priv = ring->dev->dev_private; + queue_delayed_work(dev_priv->wq, &ring->flush_work, HZ/60); + } +} + static int init_ring_common(struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = ring->dev->dev_private; @@ -573,6 +593,7 @@ bsd_ring_flush(struct intel_ring_buffer *ring, intel_ring_emit(ring, MI_FLUSH); intel_ring_emit(ring, MI_NOOP); + ring->pending_flush = 0; intel_ring_advance(ring); return 0; } @@ -802,10 +823,13 @@ int intel_init_ring_buffer(struct drm_device *dev, INIT_LIST_HEAD(&ring->request_list); INIT_LIST_HEAD(&ring->gpu_write_list); - init_waitqueue_head(&ring->irq_queue); + spin_lock_init(&ring->lock); spin_lock_init(&ring->irq_lock); + init_waitqueue_head(&ring->irq_queue); ring->irq_mask = ~0; + INIT_DELAYED_WORK(&ring->flush_work, intel_ring_flush_work_handler); + if (I915_NEED_GFX_HWS(dev)) { ret = init_status_page(ring); if (ret) @@ -873,6 +897,8 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) if (ring->obj == NULL) return; + cancel_delayed_work_sync(&ring->flush_work); + /* Disable the ring buffer. The ring must be idle at this point */ dev_priv = ring->dev->dev_private; ret = intel_wait_ring_idle(ring); @@ -892,38 +918,16 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) ring->cleanup(ring); cleanup_status_page(ring); -} -static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring) -{ - unsigned int *virt; - int rem = ring->size - ring->tail; - - if (ring->space < rem) { - int ret = intel_wait_ring_buffer(ring, rem); - if (ret) - return ret; - } - - virt = (unsigned int *)(ring->virtual_start + ring->tail); - rem /= 8; - while (rem--) { - *virt++ = MI_NOOP; - *virt++ = MI_NOOP; - } - - ring->tail = 0; - ring->space = ring_space(ring); - - return 0; } -int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) +static int _intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n, bool is_atomic) { struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; unsigned long end; u32 head; + int ret; /* If the reported head position has wrapped or hasn't advanced, * fallback to the slow and accurate path. @@ -936,28 +940,68 @@ int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) return 0; } + ret = -EBUSY; trace_i915_ring_wait_begin(ring); end = jiffies + 3 * HZ; do { ring->head = I915_READ_HEAD(ring); ring->space = ring_space(ring); if (ring->space >= n) { - trace_i915_ring_wait_end(ring); - return 0; + ret = 0; + break; } + if (is_atomic) + break; + if (dev->primary->master) { struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; if (master_priv->sarea_priv) master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; } + spin_unlock(&ring->lock); msleep(1); - if (atomic_read(&dev_priv->mm.wedged)) - return -EAGAIN; + spin_lock(&ring->lock); + + if (atomic_read(&dev_priv->mm.wedged)) { + ret = -EAGAIN; + break; + } } while (!time_after(jiffies, end)); trace_i915_ring_wait_end(ring); - return -EBUSY; + return ret; +} + +int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) +{ + bool is_atomic = in_atomic(); + int ret = -EBUSY; + + if (spin_trylock(&ring->lock)) { + ret = _intel_wait_ring_buffer(ring, n, is_atomic); + spin_unlock(&ring->lock); + } + + return ret; +} + +static int _intel_wrap_ring_buffer(struct intel_ring_buffer *ring, + bool is_atomic) +{ + int rem = ring->size - ring->tail; + + if (ring->space < rem) { + int ret = _intel_wait_ring_buffer(ring, rem, is_atomic); + if (ret) + return ret; + } + + memset_io(ring->virtual_start + ring->tail, 0, rem); + + ring->tail = 0; + ring->space = ring_space(ring); + return 0; } int intel_ring_begin(struct intel_ring_buffer *ring, @@ -965,31 +1009,39 @@ int intel_ring_begin(struct intel_ring_buffer *ring, { struct drm_i915_private *dev_priv = ring->dev->dev_private; int n = 4*num_dwords; + bool is_atomic = in_atomic(); int ret; if (unlikely(atomic_read(&dev_priv->mm.wedged))) return -EIO; + if (!spin_trylock(&ring->lock)) + return -EBUSY; + if (unlikely(ring->tail + n > ring->effective_size)) { - ret = intel_wrap_ring_buffer(ring); + ret = _intel_wrap_ring_buffer(ring, is_atomic); if (unlikely(ret)) - return ret; + goto err; } if (unlikely(ring->space < n)) { - ret = intel_wait_ring_buffer(ring, n); + ret = _intel_wait_ring_buffer(ring, n, is_atomic); if (unlikely(ret)) - return ret; + goto err; } ring->space -= n; return 0; +err: + spin_unlock(&ring->lock); + return ret; } void intel_ring_advance(struct intel_ring_buffer *ring) { ring->tail &= ring->size - 1; ring->write_tail(ring, ring->tail); + spin_unlock(&ring->lock); } static const struct intel_ring_buffer render_ring = { @@ -1065,6 +1117,7 @@ static int gen6_ring_flush(struct intel_ring_buffer *ring, intel_ring_emit(ring, 0); intel_ring_emit(ring, 0); intel_ring_emit(ring, MI_NOOP); + ring->pending_flush = 0; intel_ring_advance(ring); return 0; } @@ -1216,7 +1269,7 @@ static int blt_ring_begin(struct intel_ring_buffer *ring, return 0; } else - return intel_ring_begin(ring, 4); + return intel_ring_begin(ring, num_dwords); } static int blt_ring_flush(struct intel_ring_buffer *ring, @@ -1236,6 +1289,7 @@ static int blt_ring_flush(struct intel_ring_buffer *ring, intel_ring_emit(ring, 0); intel_ring_emit(ring, 0); intel_ring_emit(ring, MI_NOOP); + ring->pending_flush = 0; intel_ring_advance(ring); return 0; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 16cb125..624b4d1 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -44,10 +44,13 @@ struct intel_ring_buffer { RING_BLT = 0x4, } id; u32 mmio_base; - void __iomem *virtual_start; struct drm_device *dev; struct drm_i915_gem_object *obj; + spinlock_t lock; + void __iomem *virtual_start; + struct delayed_work flush_work; + u32 head; u32 tail; int space; @@ -111,6 +114,8 @@ struct intel_ring_buffer { */ u32 outstanding_lazy_request; + unsigned int pending_flush : 1; + wait_queue_head_t irq_queue; drm_local_map_t map; @@ -177,7 +182,15 @@ static inline void intel_ring_emit(struct intel_ring_buffer *ring, u32 data) { iowrite32(data, ring->virtual_start + ring->tail); - ring->tail += 4; + ring->tail += sizeof(u32); +} + +static inline void intel_ring_emit_many(struct intel_ring_buffer *ring, + const u32 *data, int n) +{ + n *= sizeof(u32); + memcpy_toio(ring->virtual_start + ring->tail, data, n); + ring->tail += n; } void intel_ring_advance(struct intel_ring_buffer *ring); diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c index baed57d..b560e68 100644 --- a/drivers/video/cfbimgblt.c +++ b/drivers/video/cfbimgblt.c @@ -144,7 +144,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * u32 __iomem *dst, *dst2; u32 val, pitch = p->fix.line_length; u32 null_bits = 32 - bpp; - u32 spitch = (image->width+7)/8; + u32 spitch = image->pitch; const u8 *src = image->data, *s; u32 i, j, l; u32 bswapmask = fb_compute_bswapmask(p); @@ -217,7 +217,8 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info * u32 bgcolor) { u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel; - u32 ppw = 32/bpp, spitch = (image->width + 7)/8; + u32 ppw = 32/bpp; + u32 spitch = image->pitch; u32 bit_mask, end_mask, eorx, shift; const char *s = image->data, *src; u32 __iomem *dst; diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c index 28b1a83..06a1cf0 100644 --- a/drivers/video/console/bitblit.c +++ b/drivers/video/console/bitblit.c @@ -19,11 +19,16 @@ #include #include "fbcon.h" +static inline int fb_pitch_for_width(struct fb_info *info, int width) +{ + return DIV_ROUND_UP(width, info->pixmap.scan_align * 8) * info->pixmap.scan_align; +} + /* * Accelerated handlers. */ -static void update_attr(u8 *dst, u8 *src, int attribute, - struct vc_data *vc) +static u8 *update_attr(u8 *dst, u8 *src, int attribute, + struct vc_data *vc) { int i, offset = (vc->vc_font.height < 10) ? 1 : 2; int width = DIV_ROUND_UP(vc->vc_font.width, 8); @@ -41,6 +46,8 @@ static void update_attr(u8 *dst, u8 *src, int attribute, c = ~c; dst[i] = c; } + + return dst; } static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy, @@ -74,60 +81,53 @@ static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy, info->fbops->fb_fillrect(info, ®ion); } -static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info, +static inline void bit_putcs_aligned(struct vc_data *vc, const u16 *s, u32 attr, u32 cnt, - u32 d_pitch, u32 s_pitch, u32 cellsize, - struct fb_image *image, u8 *buf, u8 *dst) + u32 s_pitch, u32 cellsize, + const struct fb_image *image, u8 *buf) { u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; u32 idx = vc->vc_font.width >> 3; - u8 *src; + u8 *dst = (u8 *)image->data; while (cnt--) { - src = vc->vc_font.data + (scr_readw(s++)& - charmask)*cellsize; + u8 *src = vc->vc_font.data + (scr_readw(s++)& + charmask)*cellsize; - if (attr) { - update_attr(buf, src, attr, vc); - src = buf; - } + if (attr) + src = update_attr(buf, src, attr, vc); if (likely(idx == 1)) - __fb_pad_aligned_buffer(dst, d_pitch, src, idx, + __fb_pad_aligned_buffer(dst, image->pitch, src, idx, image->height); else - fb_pad_aligned_buffer(dst, d_pitch, src, idx, + fb_pad_aligned_buffer(dst, image->pitch, src, idx, image->height); dst += s_pitch; } - - info->fbops->fb_imageblit(info, image); } static inline void bit_putcs_unaligned(struct vc_data *vc, - struct fb_info *info, const u16 *s, - u32 attr, u32 cnt, u32 d_pitch, + const u16 *s, + u32 attr, u32 cnt, u32 s_pitch, u32 cellsize, - struct fb_image *image, u8 *buf, - u8 *dst) + const struct fb_image *image, u8 *buf) { u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; u32 shift_low = 0, mod = vc->vc_font.width % 8; u32 shift_high = 8; u32 idx = vc->vc_font.width >> 3; - u8 *src; + u8 *dst = (u8 *)image->data; while (cnt--) { - src = vc->vc_font.data + (scr_readw(s++)& - charmask)*cellsize; + u8 *src = vc->vc_font.data + (scr_readw(s++)& + charmask)*cellsize; - if (attr) { - update_attr(buf, src, attr, vc); - src = buf; - } + if (attr) + src = update_attr(buf, src, attr, vc); - fb_pad_unaligned_buffer(dst, d_pitch, src, idx, + fb_pad_unaligned_buffer(dst, image->pitch, src, idx, image->height, shift_high, shift_low, mod); shift_low += mod; @@ -135,9 +135,6 @@ static inline void bit_putcs_unaligned(struct vc_data *vc, shift_low &= 7; shift_high = 8 - shift_low; } - - info->fbops->fb_imageblit(info, image); - } static void bit_putcs(struct vc_data *vc, struct fb_info *info, @@ -147,12 +144,11 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info, struct fb_image image; u32 width = DIV_ROUND_UP(vc->vc_font.width, 8); u32 cellsize = width * vc->vc_font.height; - u32 maxcnt = info->pixmap.size/cellsize; u32 scan_align = info->pixmap.scan_align - 1; - u32 buf_align = info->pixmap.buf_align - 1; - u32 mod = vc->vc_font.width % 8, cnt, pitch, size; + u32 maxcnt = info->pixmap.size/vc->vc_font.height*8/ALIGN(vc->vc_font.width, 8*info->pixmap.scan_align); + u32 mod = vc->vc_font.width % 8, cnt; u32 attribute = get_attribute(info, scr_readw(s)); - u8 *dst, *buf = NULL; + u8 *buf = NULL; image.fg_color = fg; image.bg_color = bg; @@ -174,20 +170,18 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info, cnt = count; image.width = vc->vc_font.width * cnt; - pitch = DIV_ROUND_UP(image.width, 8) + scan_align; - pitch &= ~scan_align; - size = pitch * image.height + buf_align; - size &= ~buf_align; - dst = fb_get_buffer_offset(info, &info->pixmap, size); - image.data = dst; + image.pitch = DIV_ROUND_UP(image.width, 8) + scan_align; + image.pitch &= ~scan_align; + image.data = fb_get_buffer_offset(info, &info->pixmap, + image.pitch * image.height); if (!mod) - bit_putcs_aligned(vc, info, s, attribute, cnt, pitch, - width, cellsize, &image, buf, dst); + bit_putcs_aligned(vc, s, attribute, cnt, + width, cellsize, &image, buf); else - bit_putcs_unaligned(vc, info, s, attribute, cnt, - pitch, width, cellsize, &image, - buf, dst); + bit_putcs_unaligned(vc, s, attribute, cnt, + width, cellsize, &image, buf); + info->fbops->fb_imageblit(info, &image); image.dx += cnt * vc->vc_font.width; count -= cnt; @@ -275,8 +269,7 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode, return; kfree(ops->cursor_data); ops->cursor_data = dst; - update_attr(dst, src, attribute, vc); - src = dst; + src = update_attr(dst, src, attribute, vc); } if (ops->cursor_state.image.fg_color != fg || @@ -373,6 +366,7 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode, cursor.image.dy = ops->cursor_state.image.dy; cursor.image.height = ops->cursor_state.image.height; cursor.image.width = ops->cursor_state.image.width; + cursor.image.pitch = w; cursor.hot.x = ops->cursor_state.hot.x; cursor.hot.y = ops->cursor_state.hot.y; cursor.mask = ops->cursor_state.mask; diff --git a/drivers/video/console/fbcon_ccw.c b/drivers/video/console/fbcon_ccw.c index 41b32ae..272a117 100644 --- a/drivers/video/console/fbcon_ccw.c +++ b/drivers/video/console/fbcon_ccw.c @@ -97,7 +97,7 @@ static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy, static inline void ccw_putcs_aligned(struct vc_data *vc, struct fb_info *info, const u16 *s, u32 attr, u32 cnt, - u32 d_pitch, u32 s_pitch, u32 cellsize, + u32 s_pitch, u32 cellsize, struct fb_image *image, u8 *buf, u8 *dst) { struct fbcon_ops *ops = info->fbcon_par; @@ -114,13 +114,13 @@ static inline void ccw_putcs_aligned(struct vc_data *vc, struct fb_info *info, } if (likely(idx == 1)) - __fb_pad_aligned_buffer(dst, d_pitch, src, idx, + __fb_pad_aligned_buffer(dst, image->pitch, src, idx, vc->vc_font.width); else - fb_pad_aligned_buffer(dst, d_pitch, src, idx, + fb_pad_aligned_buffer(dst, image->pitch, src, idx, vc->vc_font.width); - dst += d_pitch * vc->vc_font.width; + dst += image->pitch * vc->vc_font.width; } info->fbops->fb_imageblit(info, image); @@ -132,12 +132,10 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info, { struct fb_image image; struct fbcon_ops *ops = info->fbcon_par; - u32 width = (vc->vc_font.height + 7)/8; + u32 width = DIV_ROUND_UP(vc->vc_font.height, 8); u32 cellsize = width * vc->vc_font.width; u32 maxcnt = info->pixmap.size/cellsize; - u32 scan_align = info->pixmap.scan_align - 1; - u32 buf_align = info->pixmap.buf_align - 1; - u32 cnt, pitch, size; + u32 cnt; u32 attribute = get_attribute(info, scr_readw(s)); u8 *dst, *buf = NULL; u32 vyres = GETVYRES(ops->p->scrollmode, info); @@ -150,6 +148,7 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info, image.dx = yy * vc->vc_font.height; image.dy = vyres - ((xx + count) * vc->vc_font.width); image.width = vc->vc_font.height; + image.pitch = ALIGN(width, info->pixmap.scan_align); image.depth = 1; if (attribute) { @@ -167,13 +166,10 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info, cnt = count; image.height = vc->vc_font.width * cnt; - pitch = ((image.width + 7) >> 3) + scan_align; - pitch &= ~scan_align; - size = pitch * image.height + buf_align; - size &= ~buf_align; - dst = fb_get_buffer_offset(info, &info->pixmap, size); + dst = fb_get_buffer_offset(info, &info->pixmap, + image.pitch*image.height); image.data = dst; - ccw_putcs_aligned(vc, info, s, attribute, cnt, pitch, + ccw_putcs_aligned(vc, info, s, attribute, cnt, width, cellsize, &image, buf, dst); image.dy += image.height; count -= cnt; @@ -376,6 +372,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode, cursor.image.dy = ops->cursor_state.image.dy; cursor.image.height = ops->cursor_state.image.height; cursor.image.width = ops->cursor_state.image.width; + cursor.image.pitch = w; cursor.hot.x = ops->cursor_state.hot.x; cursor.hot.y = ops->cursor_state.hot.y; cursor.mask = ops->cursor_state.mask; diff --git a/drivers/video/console/fbcon_cw.c b/drivers/video/console/fbcon_cw.c index 6a73782..adcfc08 100644 --- a/drivers/video/console/fbcon_cw.c +++ b/drivers/video/console/fbcon_cw.c @@ -83,7 +83,7 @@ static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy, static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info, const u16 *s, u32 attr, u32 cnt, - u32 d_pitch, u32 s_pitch, u32 cellsize, + u32 s_pitch, u32 cellsize, struct fb_image *image, u8 *buf, u8 *dst) { struct fbcon_ops *ops = info->fbcon_par; @@ -100,13 +100,13 @@ static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info, } if (likely(idx == 1)) - __fb_pad_aligned_buffer(dst, d_pitch, src, idx, + __fb_pad_aligned_buffer(dst, image->pitch, src, idx, vc->vc_font.width); else - fb_pad_aligned_buffer(dst, d_pitch, src, idx, + fb_pad_aligned_buffer(dst, image->pitch, src, idx, vc->vc_font.width); - dst += d_pitch * vc->vc_font.width; + dst += image->pitch * vc->vc_font.width; } info->fbops->fb_imageblit(info, image); @@ -118,12 +118,10 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info, { struct fb_image image; struct fbcon_ops *ops = info->fbcon_par; - u32 width = (vc->vc_font.height + 7)/8; + u32 width = DIV_ROUND_UP(vc->vc_font.height, 8); u32 cellsize = width * vc->vc_font.width; u32 maxcnt = info->pixmap.size/cellsize; - u32 scan_align = info->pixmap.scan_align - 1; - u32 buf_align = info->pixmap.buf_align - 1; - u32 cnt, pitch, size; + u32 cnt; u32 attribute = get_attribute(info, scr_readw(s)); u8 *dst, *buf = NULL; u32 vxres = GETVXRES(ops->p->scrollmode, info); @@ -136,6 +134,7 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info, image.dx = vxres - ((yy + 1) * vc->vc_font.height); image.dy = xx * vc->vc_font.width; image.width = vc->vc_font.height; + image.pitch = ALIGN(width, info->pixmap.scan_align); image.depth = 1; if (attribute) { @@ -151,13 +150,10 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info, cnt = count; image.height = vc->vc_font.width * cnt; - pitch = ((image.width + 7) >> 3) + scan_align; - pitch &= ~scan_align; - size = pitch * image.height + buf_align; - size &= ~buf_align; - dst = fb_get_buffer_offset(info, &info->pixmap, size); + dst = fb_get_buffer_offset(info, &info->pixmap, + image.pitch * image.height); image.data = dst; - cw_putcs_aligned(vc, info, s, attribute, cnt, pitch, + cw_putcs_aligned(vc, info, s, attribute, cnt, width, cellsize, &image, buf, dst); image.dy += image.height; count -= cnt; @@ -360,6 +356,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode, cursor.image.dy = ops->cursor_state.image.dy; cursor.image.height = ops->cursor_state.image.height; cursor.image.width = ops->cursor_state.image.width; + cursor.image.pitch = w; cursor.hot.x = ops->cursor_state.hot.x; cursor.hot.y = ops->cursor_state.hot.y; cursor.mask = ops->cursor_state.mask; diff --git a/drivers/video/console/fbcon_ud.c b/drivers/video/console/fbcon_ud.c index ff0872c..8092652 100644 --- a/drivers/video/console/fbcon_ud.c +++ b/drivers/video/console/fbcon_ud.c @@ -84,7 +84,7 @@ static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy, static inline void ud_putcs_aligned(struct vc_data *vc, struct fb_info *info, const u16 *s, u32 attr, u32 cnt, - u32 d_pitch, u32 s_pitch, u32 cellsize, + u32 s_pitch, u32 cellsize, struct fb_image *image, u8 *buf, u8 *dst) { struct fbcon_ops *ops = info->fbcon_par; @@ -101,10 +101,10 @@ static inline void ud_putcs_aligned(struct vc_data *vc, struct fb_info *info, } if (likely(idx == 1)) - __fb_pad_aligned_buffer(dst, d_pitch, src, idx, + __fb_pad_aligned_buffer(dst, image->pitch, src, idx, image->height); else - fb_pad_aligned_buffer(dst, d_pitch, src, idx, + fb_pad_aligned_buffer(dst, image->pitch, src, idx, image->height); dst += s_pitch; @@ -115,7 +115,7 @@ static inline void ud_putcs_aligned(struct vc_data *vc, struct fb_info *info, static inline void ud_putcs_unaligned(struct vc_data *vc, struct fb_info *info, const u16 *s, - u32 attr, u32 cnt, u32 d_pitch, + u32 attr, u32 cnt, u32 s_pitch, u32 cellsize, struct fb_image *image, u8 *buf, u8 *dst) @@ -135,7 +135,7 @@ static inline void ud_putcs_unaligned(struct vc_data *vc, src = buf; } - fb_pad_unaligned_buffer(dst, d_pitch, src, idx, + fb_pad_unaligned_buffer(dst, image->pitch, src, idx, image->height, shift_high, shift_low, mod); shift_low += mod; @@ -154,12 +154,11 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info, { struct fb_image image; struct fbcon_ops *ops = info->fbcon_par; - u32 width = (vc->vc_font.width + 7)/8; + u32 width = DIV_ROUND_UP(vc->vc_font.width, 8); u32 cellsize = width * vc->vc_font.height; u32 maxcnt = info->pixmap.size/cellsize; u32 scan_align = info->pixmap.scan_align - 1; - u32 buf_align = info->pixmap.buf_align - 1; - u32 mod = vc->vc_font.width % 8, cnt, pitch, size; + u32 mod = vc->vc_font.width % 8, cnt; u32 attribute = get_attribute(info, scr_readw(s)); u8 *dst, *buf = NULL; u32 vyres = GETVYRES(ops->p->scrollmode, info); @@ -190,18 +189,17 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info, cnt = count; image.width = vc->vc_font.width * cnt; - pitch = ((image.width + 7) >> 3) + scan_align; - pitch &= ~scan_align; - size = pitch * image.height + buf_align; - size &= ~buf_align; - dst = fb_get_buffer_offset(info, &info->pixmap, size); + image.pitch = DIV_ROUND_UP(image.width, 8) + scan_align; + image.pitch &= ~scan_align; + dst = fb_get_buffer_offset(info, &info->pixmap, + image.pitch * image.height); image.data = dst; if (!mod) - ud_putcs_aligned(vc, info, s, attribute, cnt, pitch, + ud_putcs_aligned(vc, info, s, attribute, cnt, width, cellsize, &image, buf, dst); else - ud_putcs_unaligned(vc, info, s, attribute, cnt, pitch, + ud_putcs_unaligned(vc, info, s, attribute, cnt, width, cellsize, &image, buf, dst); @@ -400,6 +398,7 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode, cursor.image.dy = ops->cursor_state.image.dy; cursor.image.height = ops->cursor_state.image.height; cursor.image.width = ops->cursor_state.image.width; + cursor.image.pitch = w; cursor.hot.x = ops->cursor_state.hot.x; cursor.hot.y = ops->cursor_state.hot.y; cursor.mask = ops->cursor_state.mask; diff --git a/drivers/video/console/softcursor.c b/drivers/video/console/softcursor.c index 25f835b..1032088 100644 --- a/drivers/video/console/softcursor.c +++ b/drivers/video/console/softcursor.c @@ -23,8 +23,7 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) { struct fbcon_ops *ops = info->fbcon_par; unsigned int scan_align = info->pixmap.scan_align - 1; - unsigned int buf_align = info->pixmap.buf_align - 1; - unsigned int i, size, dsize, s_pitch, d_pitch; + unsigned int i, dsize, s_pitch; struct fb_image *image; u8 *src, *dst; @@ -49,11 +48,9 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) src = ops->cursor_src + sizeof(struct fb_image); image = (struct fb_image *)ops->cursor_src; *image = cursor->image; - d_pitch = (s_pitch + scan_align) & ~scan_align; + image->pitch = (s_pitch + scan_align) & ~scan_align; - size = d_pitch * image->height + buf_align; - size &= ~buf_align; - dst = fb_get_buffer_offset(info, &info->pixmap, size); + dst = fb_get_buffer_offset(info, &info->pixmap, image->pitch*image->height); if (cursor->enable) { switch (cursor->rop) { @@ -70,7 +67,7 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) } else memcpy(src, image->data, dsize); - fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, image->height); + fb_pad_aligned_buffer(dst, image->pitch, src, s_pitch, image->height); image->data = dst; info->fbops->fb_imageblit(info, image); return 0; diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index e0c2284..7fbce77 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -470,7 +470,7 @@ static int fb_show_logo_line(struct fb_info *info, int rotate, image.dx = 0; image.dy = y; - image.width = logo->width; + image.pitch = image.width = logo->width; image.height = logo->height; if (rotate) { diff --git a/include/linux/fb.h b/include/linux/fb.h index df728c1..46a4cd6 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -358,6 +358,7 @@ struct fb_image { __u32 dx; /* Where to place image */ __u32 dy; __u32 width; /* Size of image */ + __u32 pitch; /* Bytes between the start of each row */ __u32 height; __u32 fg_color; /* Only used when a mono bitmap */ __u32 bg_color; -- 1.7.5.4