Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 537a1bf0 authored by Krzysztof Helt's avatar Krzysztof Helt Committed by Linus Torvalds
Browse files

fbdev: add mutex for fb_mmap locking



Add a mutex to avoid a circular locking problem between the mm layer
semaphore and fbdev ioctl mutex through the fb_mmap() call.

Also, add mutex to all places where smem_start and smem_len fields change
so the mutex inside the fb_mmap() is actually used.  Changing of these
fields before calling the framebuffer_register() are not mutexed.

This is 2.6.31 material.  It removes one lockdep (fb_mmap() and
register_framebuffer()) but there is still another one (fb_release() and
register_framebuffer()).  It also cleans up handling of the smem_start and
smem_len fields used by mutexed section of the fb_mmap().

Signed-off-by: default avatarKrzysztof Helt <krzysztof.h1@wp.pl>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
Cc: <stable@kernel.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 70d6027f
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -2414,7 +2414,10 @@ static int atafb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
	if (err)
		return err;
	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
	return fbhw->encode_fix(fix, &par);
	mutex_lock(&info->mm_lock);
	err = fbhw->encode_fix(fix, &par);
	mutex_unlock(&info->mm_lock);
	return err;
}

static int atafb_get_var(struct fb_var_screeninfo *var, struct fb_info *info)
@@ -2743,7 +2746,9 @@ static int atafb_set_par(struct fb_info *info)

	/* Decode wanted screen parameters */
	fbhw->decode_var(&info->var, par);
	mutex_lock(&info->mm_lock);
	fbhw->encode_fix(&info->fix, par);
	mutex_unlock(&info->mm_lock);

	/* Set new videomode */
	ata_set_par(par);
+2 −0
Original line number Diff line number Diff line
@@ -270,7 +270,9 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)

	smem_len = (var->xres_virtual * var->yres_virtual
		    * ((var->bits_per_pixel + 7) / 8));
	mutex_lock(&info->mm_lock);
	info->fix.smem_len = max(smem_len, sinfo->smem_len);
	mutex_unlock(&info->mm_lock);

	info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len,
					(dma_addr_t *)&info->fix.smem_start, GFP_KERNEL);
+5 −8
Original line number Diff line number Diff line
@@ -1310,8 +1310,6 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd,

static int
fb_mmap(struct file *file, struct vm_area_struct * vma)
__acquires(&info->lock)
__releases(&info->lock)
{
	int fbidx = iminor(file->f_path.dentry->d_inode);
	struct fb_info *info = registered_fb[fbidx];
@@ -1325,16 +1323,14 @@ __releases(&info->lock)
	off = vma->vm_pgoff << PAGE_SHIFT;
	if (!fb)
		return -ENODEV;
	mutex_lock(&info->mm_lock);
	if (fb->fb_mmap) {
		int res;
		mutex_lock(&info->lock);
		res = fb->fb_mmap(info, vma);
		mutex_unlock(&info->lock);
		mutex_unlock(&info->mm_lock);
		return res;
	}

	mutex_lock(&info->lock);

	/* frame buffer memory */
	start = info->fix.smem_start;
	len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
@@ -1342,13 +1338,13 @@ __releases(&info->lock)
		/* memory mapped io */
		off -= len;
		if (info->var.accel_flags) {
			mutex_unlock(&info->lock);
			mutex_unlock(&info->mm_lock);
			return -EINVAL;
		}
		start = info->fix.mmio_start;
		len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
	}
	mutex_unlock(&info->lock);
	mutex_unlock(&info->mm_lock);
	start &= PAGE_MASK;
	if ((vma->vm_end - vma->vm_start + off) > len)
		return -EINVAL;
@@ -1518,6 +1514,7 @@ register_framebuffer(struct fb_info *fb_info)
			break;
	fb_info->node = i;
	mutex_init(&fb_info->lock);
	mutex_init(&fb_info->mm_lock);

	fb_info->dev = device_create(fb_class, fb_info->device,
				     MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
+9 −5
Original line number Diff line number Diff line
@@ -750,24 +750,26 @@ static void update_lcdc(struct fb_info *info)
static int map_video_memory(struct fb_info *info)
{
	phys_addr_t phys;
	u32 smem_len = info->fix.line_length * info->var.yres_virtual;

	pr_debug("info->var.xres_virtual = %d\n", info->var.xres_virtual);
	pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
	pr_debug("info->fix.line_length  = %d\n", info->fix.line_length);
	pr_debug("MAP_VIDEO_MEMORY: smem_len = %u\n", smem_len);

	info->fix.smem_len = info->fix.line_length * info->var.yres_virtual;
	pr_debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->fix.smem_len);
	info->screen_base = fsl_diu_alloc(info->fix.smem_len, &phys);
	info->screen_base = fsl_diu_alloc(smem_len, &phys);
	if (info->screen_base == NULL) {
		printk(KERN_ERR "Unable to allocate fb memory\n");
		return -ENOMEM;
	}
	mutex_lock(&info->mm_lock);
	info->fix.smem_start = (unsigned long) phys;
	info->fix.smem_len = smem_len;
	mutex_unlock(&info->mm_lock);
	info->screen_size = info->fix.smem_len;

	pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n",
				info->fix.smem_start,
		info->fix.smem_len);
		 info->fix.smem_start, info->fix.smem_len);
	pr_debug("screen base %p\n", info->screen_base);

	return 0;
@@ -776,9 +778,11 @@ static int map_video_memory(struct fb_info *info)
static void unmap_video_memory(struct fb_info *info)
{
	fsl_diu_free(info->screen_base, info->fix.smem_len);
	mutex_lock(&info->mm_lock);
	info->screen_base = NULL;
	info->fix.smem_start = 0;
	info->fix.smem_len = 0;
	mutex_unlock(&info->mm_lock);
}

/*
+2 −0
Original line number Diff line number Diff line
@@ -1090,8 +1090,10 @@ static int encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
    	memset(fix, 0, sizeof(struct fb_fix_screeninfo));

    	strcpy(fix->id, "I810");
	mutex_lock(&info->mm_lock);
    	fix->smem_start = par->fb.physical;
    	fix->smem_len = par->fb.size;
	mutex_unlock(&info->mm_lock);
    	fix->type = FB_TYPE_PACKED_PIXELS;
    	fix->type_aux = 0;
	fix->xpanstep = 8;
Loading