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: Krzysztof 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: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
					parent
					
						
							
								70d6027ff2
							
						
					
				
			
			
				commit
				
					
						537a1bf059
					
				
			
		
					 16 changed files with 74 additions and 42 deletions
				
			
		|  | @ -2414,7 +2414,10 @@ static int atafb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info) | ||||||
| 	if (err) | 	if (err) | ||||||
| 		return err; | 		return err; | ||||||
| 	memset(fix, 0, sizeof(struct fb_fix_screeninfo)); | 	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) | 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 */ | 	/* Decode wanted screen parameters */ | ||||||
| 	fbhw->decode_var(&info->var, par); | 	fbhw->decode_var(&info->var, par); | ||||||
|  | 	mutex_lock(&info->mm_lock); | ||||||
| 	fbhw->encode_fix(&info->fix, par); | 	fbhw->encode_fix(&info->fix, par); | ||||||
|  | 	mutex_unlock(&info->mm_lock); | ||||||
| 
 | 
 | ||||||
| 	/* Set new videomode */ | 	/* Set new videomode */ | ||||||
| 	ata_set_par(par); | 	ata_set_par(par); | ||||||
|  |  | ||||||
|  | @ -270,7 +270,9 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo) | ||||||
| 
 | 
 | ||||||
| 	smem_len = (var->xres_virtual * var->yres_virtual | 	smem_len = (var->xres_virtual * var->yres_virtual | ||||||
| 		    * ((var->bits_per_pixel + 7) / 8)); | 		    * ((var->bits_per_pixel + 7) / 8)); | ||||||
|  | 	mutex_lock(&info->mm_lock); | ||||||
| 	info->fix.smem_len = max(smem_len, sinfo->smem_len); | 	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, | 	info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len, | ||||||
| 					(dma_addr_t *)&info->fix.smem_start, GFP_KERNEL); | 					(dma_addr_t *)&info->fix.smem_start, GFP_KERNEL); | ||||||
|  |  | ||||||
|  | @ -1310,8 +1310,6 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd, | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
| fb_mmap(struct file *file, struct vm_area_struct * vma) | 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); | 	int fbidx = iminor(file->f_path.dentry->d_inode); | ||||||
| 	struct fb_info *info = registered_fb[fbidx]; | 	struct fb_info *info = registered_fb[fbidx]; | ||||||
|  | @ -1325,16 +1323,14 @@ __releases(&info->lock) | ||||||
| 	off = vma->vm_pgoff << PAGE_SHIFT; | 	off = vma->vm_pgoff << PAGE_SHIFT; | ||||||
| 	if (!fb) | 	if (!fb) | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
|  | 	mutex_lock(&info->mm_lock); | ||||||
| 	if (fb->fb_mmap) { | 	if (fb->fb_mmap) { | ||||||
| 		int res; | 		int res; | ||||||
| 		mutex_lock(&info->lock); |  | ||||||
| 		res = fb->fb_mmap(info, vma); | 		res = fb->fb_mmap(info, vma); | ||||||
| 		mutex_unlock(&info->lock); | 		mutex_unlock(&info->mm_lock); | ||||||
| 		return res; | 		return res; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&info->lock); |  | ||||||
| 
 |  | ||||||
| 	/* frame buffer memory */ | 	/* frame buffer memory */ | ||||||
| 	start = info->fix.smem_start; | 	start = info->fix.smem_start; | ||||||
| 	len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len); | 	len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len); | ||||||
|  | @ -1342,13 +1338,13 @@ __releases(&info->lock) | ||||||
| 		/* memory mapped io */ | 		/* memory mapped io */ | ||||||
| 		off -= len; | 		off -= len; | ||||||
| 		if (info->var.accel_flags) { | 		if (info->var.accel_flags) { | ||||||
| 			mutex_unlock(&info->lock); | 			mutex_unlock(&info->mm_lock); | ||||||
| 			return -EINVAL; | 			return -EINVAL; | ||||||
| 		} | 		} | ||||||
| 		start = info->fix.mmio_start; | 		start = info->fix.mmio_start; | ||||||
| 		len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len); | 		len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len); | ||||||
| 	} | 	} | ||||||
| 	mutex_unlock(&info->lock); | 	mutex_unlock(&info->mm_lock); | ||||||
| 	start &= PAGE_MASK; | 	start &= PAGE_MASK; | ||||||
| 	if ((vma->vm_end - vma->vm_start + off) > len) | 	if ((vma->vm_end - vma->vm_start + off) > len) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
|  | @ -1518,6 +1514,7 @@ register_framebuffer(struct fb_info *fb_info) | ||||||
| 			break; | 			break; | ||||||
| 	fb_info->node = i; | 	fb_info->node = i; | ||||||
| 	mutex_init(&fb_info->lock); | 	mutex_init(&fb_info->lock); | ||||||
|  | 	mutex_init(&fb_info->mm_lock); | ||||||
| 
 | 
 | ||||||
| 	fb_info->dev = device_create(fb_class, fb_info->device, | 	fb_info->dev = device_create(fb_class, fb_info->device, | ||||||
| 				     MKDEV(FB_MAJOR, i), NULL, "fb%d", i); | 				     MKDEV(FB_MAJOR, i), NULL, "fb%d", i); | ||||||
|  |  | ||||||
|  | @ -750,24 +750,26 @@ static void update_lcdc(struct fb_info *info) | ||||||
| static int map_video_memory(struct fb_info *info) | static int map_video_memory(struct fb_info *info) | ||||||
| { | { | ||||||
| 	phys_addr_t phys; | 	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.xres_virtual = %d\n", info->var.xres_virtual); | ||||||
| 	pr_debug("info->var.yres_virtual = %d\n", info->var.yres_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("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; | 	info->screen_base = fsl_diu_alloc(smem_len, &phys); | ||||||
| 	pr_debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->fix.smem_len); |  | ||||||
| 	info->screen_base = fsl_diu_alloc(info->fix.smem_len, &phys); |  | ||||||
| 	if (info->screen_base == NULL) { | 	if (info->screen_base == NULL) { | ||||||
| 		printk(KERN_ERR "Unable to allocate fb memory\n"); | 		printk(KERN_ERR "Unable to allocate fb memory\n"); | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 	} | 	} | ||||||
|  | 	mutex_lock(&info->mm_lock); | ||||||
| 	info->fix.smem_start = (unsigned long) phys; | 	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; | 	info->screen_size = info->fix.smem_len; | ||||||
| 
 | 
 | ||||||
| 	pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n", | 	pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n", | ||||||
| 				info->fix.smem_start, | 		 info->fix.smem_start, info->fix.smem_len); | ||||||
| 		info->fix.smem_len); |  | ||||||
| 	pr_debug("screen base %p\n", info->screen_base); | 	pr_debug("screen base %p\n", info->screen_base); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -776,9 +778,11 @@ static int map_video_memory(struct fb_info *info) | ||||||
| static void unmap_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); | 	fsl_diu_free(info->screen_base, info->fix.smem_len); | ||||||
|  | 	mutex_lock(&info->mm_lock); | ||||||
| 	info->screen_base = NULL; | 	info->screen_base = NULL; | ||||||
| 	info->fix.smem_start = 0; | 	info->fix.smem_start = 0; | ||||||
| 	info->fix.smem_len = 0; | 	info->fix.smem_len = 0; | ||||||
|  | 	mutex_unlock(&info->mm_lock); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  |  | ||||||
|  | @ -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)); |     	memset(fix, 0, sizeof(struct fb_fix_screeninfo)); | ||||||
| 
 | 
 | ||||||
|     	strcpy(fix->id, "I810"); |     	strcpy(fix->id, "I810"); | ||||||
|  | 	mutex_lock(&info->mm_lock); | ||||||
|     	fix->smem_start = par->fb.physical; |     	fix->smem_start = par->fb.physical; | ||||||
|     	fix->smem_len = par->fb.size; |     	fix->smem_len = par->fb.size; | ||||||
|  | 	mutex_unlock(&info->mm_lock); | ||||||
|     	fix->type = FB_TYPE_PACKED_PIXELS; |     	fix->type = FB_TYPE_PACKED_PIXELS; | ||||||
|     	fix->type_aux = 0; |     	fix->type_aux = 0; | ||||||
| 	fix->xpanstep = 8; | 	fix->xpanstep = 8; | ||||||
|  |  | ||||||
|  | @ -724,8 +724,10 @@ static void matroxfb_update_fix(WPMINFO2) | ||||||
| 	struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix; | 	struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix; | ||||||
| 	DBG(__func__) | 	DBG(__func__) | ||||||
| 
 | 
 | ||||||
|  | 	mutex_lock(&ACCESS_FBINFO(fbcon).mm_lock); | ||||||
| 	fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes); | 	fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes); | ||||||
| 	fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes); | 	fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes); | ||||||
|  | 	mutex_unlock(&ACCESS_FBINFO(fbcon).mm_lock); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int matroxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | static int matroxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | ||||||
|  | @ -2081,6 +2083,7 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm | ||||||
| 	spin_lock_init(&ACCESS_FBINFO(lock.accel)); | 	spin_lock_init(&ACCESS_FBINFO(lock.accel)); | ||||||
| 	init_rwsem(&ACCESS_FBINFO(crtc2.lock)); | 	init_rwsem(&ACCESS_FBINFO(crtc2.lock)); | ||||||
| 	init_rwsem(&ACCESS_FBINFO(altout.lock)); | 	init_rwsem(&ACCESS_FBINFO(altout.lock)); | ||||||
|  | 	mutex_init(&ACCESS_FBINFO(fbcon).mm_lock); | ||||||
| 	ACCESS_FBINFO(irq_flags) = 0; | 	ACCESS_FBINFO(irq_flags) = 0; | ||||||
| 	init_waitqueue_head(&ACCESS_FBINFO(crtc1.vsync.wait)); | 	init_waitqueue_head(&ACCESS_FBINFO(crtc1.vsync.wait)); | ||||||
| 	init_waitqueue_head(&ACCESS_FBINFO(crtc2.vsync.wait)); | 	init_waitqueue_head(&ACCESS_FBINFO(crtc2.vsync.wait)); | ||||||
|  |  | ||||||
|  | @ -289,13 +289,16 @@ static int matroxfb_dh_release(struct fb_info* info, int user) { | ||||||
| #undef m2info | #undef m2info | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void matroxfb_dh_init_fix(struct matroxfb_dh_fb_info *m2info) { | static void matroxfb_dh_init_fix(struct matroxfb_dh_fb_info *m2info) | ||||||
|  | { | ||||||
| 	struct fb_fix_screeninfo *fix = &m2info->fbcon.fix; | 	struct fb_fix_screeninfo *fix = &m2info->fbcon.fix; | ||||||
| 
 | 
 | ||||||
| 	strcpy(fix->id, "MATROX DH"); | 	strcpy(fix->id, "MATROX DH"); | ||||||
| 
 | 
 | ||||||
|  | 	mutex_lock(&m2info->fbcon.mm_lock); | ||||||
| 	fix->smem_start = m2info->video.base; | 	fix->smem_start = m2info->video.base; | ||||||
| 	fix->smem_len = m2info->video.len_usable; | 	fix->smem_len = m2info->video.len_usable; | ||||||
|  | 	mutex_unlock(&m2info->fbcon.mm_lock); | ||||||
| 	fix->ypanstep = 1; | 	fix->ypanstep = 1; | ||||||
| 	fix->ywrapstep = 0; | 	fix->ywrapstep = 0; | ||||||
| 	fix->xpanstep = 8;	/* TBD */ | 	fix->xpanstep = 8;	/* TBD */ | ||||||
|  |  | ||||||
|  | @ -669,7 +669,7 @@ static uint32_t bpp_to_pixfmt(int bpp) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int mx3fb_blank(int blank, struct fb_info *fbi); | static int mx3fb_blank(int blank, struct fb_info *fbi); | ||||||
| static int mx3fb_map_video_memory(struct fb_info *fbi); | static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len); | ||||||
| static int mx3fb_unmap_video_memory(struct fb_info *fbi); | static int mx3fb_unmap_video_memory(struct fb_info *fbi); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -742,8 +742,7 @@ static int mx3fb_set_par(struct fb_info *fbi) | ||||||
| 		if (fbi->fix.smem_start) | 		if (fbi->fix.smem_start) | ||||||
| 			mx3fb_unmap_video_memory(fbi); | 			mx3fb_unmap_video_memory(fbi); | ||||||
| 
 | 
 | ||||||
| 		fbi->fix.smem_len = mem_len; | 		if (mx3fb_map_video_memory(fbi, mem_len) < 0) { | ||||||
| 		if (mx3fb_map_video_memory(fbi) < 0) { |  | ||||||
| 			mutex_unlock(&mx3_fbi->mutex); | 			mutex_unlock(&mx3_fbi->mutex); | ||||||
| 			return -ENOMEM; | 			return -ENOMEM; | ||||||
| 		} | 		} | ||||||
|  | @ -1198,6 +1197,7 @@ static int mx3fb_resume(struct platform_device *pdev) | ||||||
| /**
 | /**
 | ||||||
|  * mx3fb_map_video_memory() - allocates the DRAM memory for the frame buffer. |  * mx3fb_map_video_memory() - allocates the DRAM memory for the frame buffer. | ||||||
|  * @fbi:	framebuffer information pointer |  * @fbi:	framebuffer information pointer | ||||||
|  |  * @mem_len:	length of mapped memory | ||||||
|  * @return:	Error code indicating success or failure |  * @return:	Error code indicating success or failure | ||||||
|  * |  * | ||||||
|  * This buffer is remapped into a non-cached, non-buffered, memory region to |  * This buffer is remapped into a non-cached, non-buffered, memory region to | ||||||
|  | @ -1205,23 +1205,26 @@ static int mx3fb_resume(struct platform_device *pdev) | ||||||
|  * area is remapped, all virtual memory access to the video memory should occur |  * area is remapped, all virtual memory access to the video memory should occur | ||||||
|  * at the new region. |  * at the new region. | ||||||
|  */ |  */ | ||||||
| static int mx3fb_map_video_memory(struct fb_info *fbi) | static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len) | ||||||
| { | { | ||||||
| 	int retval = 0; | 	int retval = 0; | ||||||
| 	dma_addr_t addr; | 	dma_addr_t addr; | ||||||
| 
 | 
 | ||||||
| 	fbi->screen_base = dma_alloc_writecombine(fbi->device, | 	fbi->screen_base = dma_alloc_writecombine(fbi->device, | ||||||
| 						  fbi->fix.smem_len, | 						  mem_len, | ||||||
| 						  &addr, GFP_DMA); | 						  &addr, GFP_DMA); | ||||||
| 
 | 
 | ||||||
| 	if (!fbi->screen_base) { | 	if (!fbi->screen_base) { | ||||||
| 		dev_err(fbi->device, "Cannot allocate %u bytes framebuffer memory\n", | 		dev_err(fbi->device, "Cannot allocate %u bytes framebuffer memory\n", | ||||||
| 			fbi->fix.smem_len); | 			mem_len); | ||||||
| 		retval = -EBUSY; | 		retval = -EBUSY; | ||||||
| 		goto err0; | 		goto err0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	mutex_lock(&fbi->mm_lock); | ||||||
| 	fbi->fix.smem_start = addr; | 	fbi->fix.smem_start = addr; | ||||||
|  | 	fbi->fix.smem_len = mem_len; | ||||||
|  | 	mutex_unlock(&fbi->mm_lock); | ||||||
| 
 | 
 | ||||||
| 	dev_dbg(fbi->device, "allocated fb @ p=0x%08x, v=0x%p, size=%d.\n", | 	dev_dbg(fbi->device, "allocated fb @ p=0x%08x, v=0x%p, size=%d.\n", | ||||||
| 		(uint32_t) fbi->fix.smem_start, fbi->screen_base, fbi->fix.smem_len); | 		(uint32_t) fbi->fix.smem_start, fbi->screen_base, fbi->fix.smem_len); | ||||||
|  | @ -1251,8 +1254,10 @@ static int mx3fb_unmap_video_memory(struct fb_info *fbi) | ||||||
| 			      fbi->screen_base, fbi->fix.smem_start); | 			      fbi->screen_base, fbi->fix.smem_start); | ||||||
| 
 | 
 | ||||||
| 	fbi->screen_base = 0; | 	fbi->screen_base = 0; | ||||||
|  | 	mutex_lock(&fbi->mm_lock); | ||||||
| 	fbi->fix.smem_start = 0; | 	fbi->fix.smem_start = 0; | ||||||
| 	fbi->fix.smem_len = 0; | 	fbi->fix.smem_len = 0; | ||||||
|  | 	mutex_unlock(&fbi->mm_lock); | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -393,8 +393,10 @@ static void set_fb_fix(struct fb_info *fbi) | ||||||
| 
 | 
 | ||||||
| 	rg = &plane->fbdev->mem_desc.region[plane->idx]; | 	rg = &plane->fbdev->mem_desc.region[plane->idx]; | ||||||
| 	fbi->screen_base	= rg->vaddr; | 	fbi->screen_base	= rg->vaddr; | ||||||
|  | 	mutex_lock(&fbi->mm_lock); | ||||||
| 	fix->smem_start		= rg->paddr; | 	fix->smem_start		= rg->paddr; | ||||||
| 	fix->smem_len		= rg->size; | 	fix->smem_len		= rg->size; | ||||||
|  | 	mutex_unlock(&fbi->mm_lock); | ||||||
| 
 | 
 | ||||||
| 	fix->type = FB_TYPE_PACKED_PIXELS; | 	fix->type = FB_TYPE_PACKED_PIXELS; | ||||||
| 	bpp = var->bits_per_pixel; | 	bpp = var->bits_per_pixel; | ||||||
|  | @ -886,8 +888,10 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | ||||||
| 				 * plane memory is dealloce'd, the other | 				 * plane memory is dealloce'd, the other | ||||||
| 				 * screen parameters in var / fix are invalid. | 				 * screen parameters in var / fix are invalid. | ||||||
| 				 */ | 				 */ | ||||||
|  | 				mutex_lock(&fbi->mm_lock); | ||||||
| 				fbi->fix.smem_start = 0; | 				fbi->fix.smem_start = 0; | ||||||
| 				fbi->fix.smem_len = 0; | 				fbi->fix.smem_len = 0; | ||||||
|  | 				mutex_unlock(&fbi->mm_lock); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -141,7 +141,9 @@ static int platinumfb_set_par (struct fb_info *info) | ||||||
|   		offset = 0x10; |   		offset = 0x10; | ||||||
| 
 | 
 | ||||||
| 	info->screen_base = pinfo->frame_buffer + init->fb_offset + offset; | 	info->screen_base = pinfo->frame_buffer + init->fb_offset + offset; | ||||||
|  | 	mutex_lock(&info->mm_lock); | ||||||
| 	info->fix.smem_start = (pinfo->frame_buffer_phys) + init->fb_offset + offset; | 	info->fix.smem_start = (pinfo->frame_buffer_phys) + init->fb_offset + offset; | ||||||
|  | 	mutex_unlock(&info->mm_lock); | ||||||
| 	info->fix.visual = (pinfo->cmode == CMODE_8) ? | 	info->fix.visual = (pinfo->cmode == CMODE_8) ? | ||||||
| 		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; | 		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; | ||||||
|  	info->fix.line_length = vmode_attrs[pinfo->vmode-1].hres * (1<<pinfo->cmode) |  	info->fix.line_length = vmode_attrs[pinfo->vmode-1].hres * (1<<pinfo->cmode) | ||||||
|  |  | ||||||
|  | @ -815,8 +815,10 @@ static int overlayfb_map_video_memory(struct pxafb_layer *ofb) | ||||||
| 	ofb->video_mem_phys = virt_to_phys(ofb->video_mem); | 	ofb->video_mem_phys = virt_to_phys(ofb->video_mem); | ||||||
| 	ofb->video_mem_size = size; | 	ofb->video_mem_size = size; | ||||||
| 
 | 
 | ||||||
|  | 	mutex_lock(&ofb->fb.mm_lock); | ||||||
| 	ofb->fb.fix.smem_start	= ofb->video_mem_phys; | 	ofb->fb.fix.smem_start	= ofb->video_mem_phys; | ||||||
| 	ofb->fb.fix.smem_len	= ofb->fb.fix.line_length * var->yres_virtual; | 	ofb->fb.fix.smem_len	= ofb->fb.fix.line_length * var->yres_virtual; | ||||||
|  | 	mutex_unlock(&ofb->fb.mm_lock); | ||||||
| 	ofb->fb.screen_base	= ofb->video_mem; | 	ofb->fb.screen_base	= ofb->video_mem; | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -120,18 +120,6 @@ static int sh7760_setcolreg (u_int regno, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info, |  | ||||||
| 		       unsigned long stride) |  | ||||||
| { |  | ||||||
| 	memset(fix, 0, sizeof(struct fb_fix_screeninfo)); |  | ||||||
| 	strcpy(fix->id, "sh7760-lcdc"); |  | ||||||
| 
 |  | ||||||
| 	fix->smem_start = (unsigned long)info->screen_base; |  | ||||||
| 	fix->smem_len = info->screen_size; |  | ||||||
| 
 |  | ||||||
| 	fix->line_length = stride; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int sh7760fb_get_color_info(struct device *dev, | static int sh7760fb_get_color_info(struct device *dev, | ||||||
| 				   u16 lddfr, int *bpp, int *gray) | 				   u16 lddfr, int *bpp, int *gray) | ||||||
| { | { | ||||||
|  | @ -334,7 +322,8 @@ static int sh7760fb_set_par(struct fb_info *info) | ||||||
| 
 | 
 | ||||||
| 	iowrite32(ldsarl, par->base + LDSARL);	/* mem for lower half of DSTN */ | 	iowrite32(ldsarl, par->base + LDSARL);	/* mem for lower half of DSTN */ | ||||||
| 
 | 
 | ||||||
| 	encode_fix(&info->fix, info, stride); | 	info->fix.line_length = stride; | ||||||
|  | 
 | ||||||
| 	sh7760fb_check_var(&info->var, info); | 	sh7760fb_check_var(&info->var, info); | ||||||
| 
 | 
 | ||||||
| 	sh7760fb_blank(FB_BLANK_UNBLANK, info);	/* panel on! */ | 	sh7760fb_blank(FB_BLANK_UNBLANK, info);	/* panel on! */ | ||||||
|  | @ -435,6 +424,8 @@ static int sh7760fb_alloc_mem(struct fb_info *info) | ||||||
| 
 | 
 | ||||||
| 	info->screen_base = fbmem; | 	info->screen_base = fbmem; | ||||||
| 	info->screen_size = vram; | 	info->screen_size = vram; | ||||||
|  | 	info->fix.smem_start = (unsigned long)info->screen_base; | ||||||
|  | 	info->fix.smem_len = info->screen_size; | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | @ -520,6 +511,8 @@ static int __devinit sh7760fb_probe(struct platform_device *pdev) | ||||||
| 	info->var.transp.length = 0; | 	info->var.transp.length = 0; | ||||||
| 	info->var.transp.msb_right = 0; | 	info->var.transp.msb_right = 0; | ||||||
| 
 | 
 | ||||||
|  | 	strcpy(info->fix.id, "sh7760-lcdc"); | ||||||
|  | 
 | ||||||
| 	/* set the DON2 bit now, before cmap allocation, as it will randomize
 | 	/* set the DON2 bit now, before cmap allocation, as it will randomize
 | ||||||
| 	 * palette memory. | 	 * palette memory. | ||||||
| 	 */ | 	 */ | ||||||
|  |  | ||||||
|  | @ -1847,8 +1847,10 @@ sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) | ||||||
| 
 | 
 | ||||||
| 	strcpy(fix->id, ivideo->myid); | 	strcpy(fix->id, ivideo->myid); | ||||||
| 
 | 
 | ||||||
|  | 	mutex_lock(&info->mm_lock); | ||||||
| 	fix->smem_start  = ivideo->video_base + ivideo->video_offset; | 	fix->smem_start  = ivideo->video_base + ivideo->video_offset; | ||||||
| 	fix->smem_len    = ivideo->sisfb_mem; | 	fix->smem_len    = ivideo->sisfb_mem; | ||||||
|  | 	mutex_unlock(&info->mm_lock); | ||||||
| 	fix->type        = FB_TYPE_PACKED_PIXELS; | 	fix->type        = FB_TYPE_PACKED_PIXELS; | ||||||
| 	fix->type_aux    = 0; | 	fix->type_aux    = 0; | ||||||
| 	fix->visual      = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; | 	fix->visual      = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; | ||||||
|  |  | ||||||
|  | @ -145,7 +145,7 @@ static inline void sm501fb_sync_regs(struct sm501fb_info *info) | ||||||
| #define SM501_MEMF_ACCEL		(8) | #define SM501_MEMF_ACCEL		(8) | ||||||
| 
 | 
 | ||||||
| static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, | static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, | ||||||
| 			   unsigned int why, size_t size) | 			   unsigned int why, size_t size, u32 smem_len) | ||||||
| { | { | ||||||
| 	struct sm501fb_par *par; | 	struct sm501fb_par *par; | ||||||
| 	struct fb_info *fbi; | 	struct fb_info *fbi; | ||||||
|  | @ -172,7 +172,7 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, | ||||||
| 		if (ptr > 0) | 		if (ptr > 0) | ||||||
| 			ptr &= ~(PAGE_SIZE - 1); | 			ptr &= ~(PAGE_SIZE - 1); | ||||||
| 
 | 
 | ||||||
| 		if (fbi && ptr < fbi->fix.smem_len) | 		if (fbi && ptr < smem_len) | ||||||
| 			return -ENOMEM; | 			return -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 		break; | 		break; | ||||||
|  | @ -197,7 +197,7 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, | ||||||
| 
 | 
 | ||||||
| 	case SM501_MEMF_ACCEL: | 	case SM501_MEMF_ACCEL: | ||||||
| 		fbi = inf->fb[HEAD_CRT]; | 		fbi = inf->fb[HEAD_CRT]; | ||||||
| 		ptr = fbi ? fbi->fix.smem_len : 0; | 		ptr = fbi ? smem_len : 0; | ||||||
| 
 | 
 | ||||||
| 		fbi = inf->fb[HEAD_PANEL]; | 		fbi = inf->fb[HEAD_PANEL]; | ||||||
| 		if (fbi) { | 		if (fbi) { | ||||||
|  | @ -413,6 +413,7 @@ static int sm501fb_set_par_common(struct fb_info *info, | ||||||
| 	unsigned int mem_type; | 	unsigned int mem_type; | ||||||
| 	unsigned int clock_type; | 	unsigned int clock_type; | ||||||
| 	unsigned int head_addr; | 	unsigned int head_addr; | ||||||
|  | 	unsigned int smem_len; | ||||||
| 
 | 
 | ||||||
| 	dev_dbg(fbi->dev, "%s: %dx%d, bpp = %d, virtual %dx%d\n", | 	dev_dbg(fbi->dev, "%s: %dx%d, bpp = %d, virtual %dx%d\n", | ||||||
| 		__func__, var->xres, var->yres, var->bits_per_pixel, | 		__func__, var->xres, var->yres, var->bits_per_pixel, | ||||||
|  | @ -453,18 +454,20 @@ static int sm501fb_set_par_common(struct fb_info *info, | ||||||
| 
 | 
 | ||||||
| 	/* allocate fb memory within 501 */ | 	/* allocate fb memory within 501 */ | ||||||
| 	info->fix.line_length = (var->xres_virtual * var->bits_per_pixel)/8; | 	info->fix.line_length = (var->xres_virtual * var->bits_per_pixel)/8; | ||||||
| 	info->fix.smem_len    = info->fix.line_length * var->yres_virtual; | 	smem_len = info->fix.line_length * var->yres_virtual; | ||||||
| 
 | 
 | ||||||
| 	dev_dbg(fbi->dev, "%s: line length = %u\n", __func__, | 	dev_dbg(fbi->dev, "%s: line length = %u\n", __func__, | ||||||
| 		info->fix.line_length); | 		info->fix.line_length); | ||||||
| 
 | 
 | ||||||
| 	if (sm501_alloc_mem(fbi, &par->screen, mem_type, | 	if (sm501_alloc_mem(fbi, &par->screen, mem_type, smem_len, smem_len)) { | ||||||
| 			    info->fix.smem_len)) { |  | ||||||
| 		dev_err(fbi->dev, "no memory available\n"); | 		dev_err(fbi->dev, "no memory available\n"); | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	mutex_lock(&info->mm_lock); | ||||||
| 	info->fix.smem_start = fbi->fbmem_res->start + par->screen.sm_addr; | 	info->fix.smem_start = fbi->fbmem_res->start + par->screen.sm_addr; | ||||||
|  | 	info->fix.smem_len   = smem_len; | ||||||
|  | 	mutex_unlock(&info->mm_lock); | ||||||
| 
 | 
 | ||||||
| 	info->screen_base = fbi->fbmem + par->screen.sm_addr; | 	info->screen_base = fbi->fbmem + par->screen.sm_addr; | ||||||
| 	info->screen_size = info->fix.smem_len; | 	info->screen_size = info->fix.smem_len; | ||||||
|  | @ -637,7 +640,8 @@ static int sm501fb_set_par_crt(struct fb_info *info) | ||||||
| 	if ((control & SM501_DC_CRT_CONTROL_SEL) == 0) { | 	if ((control & SM501_DC_CRT_CONTROL_SEL) == 0) { | ||||||
| 		/* the head is displaying panel data... */ | 		/* the head is displaying panel data... */ | ||||||
| 
 | 
 | ||||||
| 		sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0); | 		sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0, | ||||||
|  | 				info->fix.smem_len); | ||||||
| 		goto out_update; | 		goto out_update; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -1289,7 +1293,8 @@ static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base) | ||||||
| 
 | 
 | ||||||
| 	par->cursor_regs = info->regs + reg_base; | 	par->cursor_regs = info->regs + reg_base; | ||||||
| 
 | 
 | ||||||
| 	ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024); | 	ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024, | ||||||
|  | 			      fbi->fix.smem_len); | ||||||
| 	if (ret < 0) | 	if (ret < 0) | ||||||
| 		return ret; | 		return ret; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -523,6 +523,7 @@ static int w100fb_set_par(struct fb_info *info) | ||||||
| 		info->fix.ywrapstep = 0; | 		info->fix.ywrapstep = 0; | ||||||
| 		info->fix.line_length = par->xres * BITS_PER_PIXEL / 8; | 		info->fix.line_length = par->xres * BITS_PER_PIXEL / 8; | ||||||
| 
 | 
 | ||||||
|  | 		mutex_lock(&info->mm_lock); | ||||||
| 		if ((par->xres*par->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)) { | 		if ((par->xres*par->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)) { | ||||||
| 			par->extmem_active = 1; | 			par->extmem_active = 1; | ||||||
| 			info->fix.smem_len = par->mach->mem->size+1; | 			info->fix.smem_len = par->mach->mem->size+1; | ||||||
|  | @ -530,6 +531,7 @@ static int w100fb_set_par(struct fb_info *info) | ||||||
| 			par->extmem_active = 0; | 			par->extmem_active = 0; | ||||||
| 			info->fix.smem_len = MEM_INT_SIZE+1; | 			info->fix.smem_len = MEM_INT_SIZE+1; | ||||||
| 		} | 		} | ||||||
|  | 		mutex_unlock(&info->mm_lock); | ||||||
| 
 | 
 | ||||||
| 		w100fb_activate_var(par); | 		w100fb_activate_var(par); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -819,6 +819,7 @@ struct fb_info { | ||||||
| 	int node; | 	int node; | ||||||
| 	int flags; | 	int flags; | ||||||
| 	struct mutex lock;		/* Lock for open/release/ioctl funcs */ | 	struct mutex lock;		/* Lock for open/release/ioctl funcs */ | ||||||
|  | 	struct mutex mm_lock;		/* Lock for fb_mmap and smem_* fields */ | ||||||
| 	struct fb_var_screeninfo var;	/* Current var */ | 	struct fb_var_screeninfo var;	/* Current var */ | ||||||
| 	struct fb_fix_screeninfo fix;	/* Current fix */ | 	struct fb_fix_screeninfo fix;	/* Current fix */ | ||||||
| 	struct fb_monspecs monspecs;	/* Current Monitor specs */ | 	struct fb_monspecs monspecs;	/* Current Monitor specs */ | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Krzysztof Helt
				Krzysztof Helt