[v4,5/8] DSS2: OMAPFB: Add locking for memory regions
diff mbox

Message ID 1268865983-16270-6-git-send-email-ville.syrjala@nokia.com
State New, archived
Delegated to: Tomi Valkeinen
Headers show

Commit Message

ville.syrjala@nokia.com March 17, 2010, 10:46 p.m. UTC
None

Patch
diff mbox

diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c
index a160a3e..f02b1b0 100644
--- a/drivers/video/omap2/omapfb/omapfb-ioctl.c
+++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
@@ -55,7 +55,7 @@  static struct omapfb2_mem_region *get_mem_region(struct omapfb_info *ofbi,
 	if (mem_idx >= fbdev->num_fbs)
 		return NULL;
 
-	return &fbdev->regions[mem_idx];
+	return omapfb_get_mem_region(&fbdev->regions[mem_idx]);
 }
 
 static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
@@ -77,11 +77,11 @@  static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
 	/* XXX uses only the first overlay */
 	ovl = ofbi->overlays[0];
 
-	old_rg = ofbi->region;
+	old_rg = omapfb_get_mem_region(ofbi->region);
 	new_rg = get_mem_region(ofbi, pi->mem_idx);
 	if (!new_rg) {
 		r = -EINVAL;
-		goto out;
+		goto put_old;
 	}
 
 	if (pi->enabled && !new_rg->size) {
@@ -90,7 +90,7 @@  static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
 		 * until it's reallocated.
 		 */
 		r = -EINVAL;
-		goto out;
+		goto put_new;
 	}
 
 	ovl->get_overlay_info(ovl, &old_info);
@@ -135,6 +135,9 @@  static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
 	if (ovl->manager)
 		ovl->manager->apply(ovl->manager);
 
+	omapfb_put_mem_region(new_rg);
+	omapfb_put_mem_region(old_rg);
+
 	return 0;
 
  undo:
@@ -144,6 +147,10 @@  static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
 	}
 
 	ovl->set_overlay_info(ovl, &old_info);
+ put_new:
+	omapfb_put_mem_region(new_rg);
+ put_old:
+	omapfb_put_mem_region(old_rg);
  out:
 	dev_err(fbdev->dev, "setup_plane failed\n");
 
@@ -181,7 +188,7 @@  static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
 	struct omapfb_info *ofbi = FB2OFB(fbi);
 	struct omapfb2_device *fbdev = ofbi->fbdev;
 	struct omapfb2_mem_region *rg;
-	int r, i;
+	int r = 0, i;
 	size_t size;
 
 	if (mi->type > OMAPFB_MEMTYPE_MAX)
@@ -191,8 +198,18 @@  static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
 
 	rg = ofbi->region;
 
-	if (atomic_read(&rg->map_count))
-		return -EBUSY;
+	/* FIXME probably should be a rwsem ... */
+	mutex_lock(&rg->mtx);
+	while (rg->ref) {
+		mutex_unlock(&rg->mtx);
+		schedule();
+		mutex_lock(&rg->mtx);
+	}
+
+	if (atomic_read(&rg->map_count)) {
+		r = -EBUSY;
+		goto out;
+	}
 
 	for (i = 0; i < fbdev->num_fbs; i++) {
 		struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
@@ -204,7 +221,7 @@  static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
 		for (j = 0; j < ofbi2->num_overlays; j++) {
 			if (ofbi2->overlays[j]->info.enabled) {
 				r = -EBUSY;
-				return r;
+				goto out;
 			}
 		}
 	}
@@ -213,11 +230,14 @@  static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
 		r = omapfb_realloc_fbmem(fbi, size, mi->type);
 		if (r) {
 			dev_err(fbdev->dev, "realloc fbmem failed\n");
-			return r;
+			goto out;
 		}
 	}
 
-	return 0;
+ out:
+	mutex_unlock(&rg->mtx);
+
+	return r;
 }
 
 static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
@@ -225,12 +245,14 @@  static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
 	struct omapfb_info *ofbi = FB2OFB(fbi);
 	struct omapfb2_mem_region *rg;
 
-	rg = ofbi->region;
+	rg = omapfb_get_mem_region(ofbi->region);
 	memset(mi, 0, sizeof(*mi));
 
 	mi->size = rg->size;
 	mi->type = rg->type;
 
+	omapfb_put_mem_region(rg);
+
 	return 0;
 }
 
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index ceb7d92..d330032 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -1018,36 +1018,48 @@  err:
  * DO NOT MODIFY PAR */
 static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
 {
+	struct omapfb_info *ofbi = FB2OFB(fbi);
 	int r;
 
 	DBG("check_var(%d)\n", FB2OFB(fbi)->id);
 
+	omapfb_get_mem_region(ofbi->region);
+
 	r = check_fb_var(fbi, var);
 
+	omapfb_put_mem_region(ofbi->region);
+
 	return r;
 }
 
 /* set the video mode according to info->var */
 static int omapfb_set_par(struct fb_info *fbi)
 {
+	struct omapfb_info *ofbi = FB2OFB(fbi);
 	int r;
 
 	DBG("set_par(%d)\n", FB2OFB(fbi)->id);
 
+	omapfb_get_mem_region(ofbi->region);
+
 	set_fb_fix(fbi);
 
 	r = setup_vrfb_rotation(fbi);
 	if (r)
-		return r;
+		goto out;
 
 	r = omapfb_apply_changes(fbi, 0);
 
+ out:
+	omapfb_put_mem_region(ofbi->region);
+
 	return r;
 }
 
 static int omapfb_pan_display(struct fb_var_screeninfo *var,
 		struct fb_info *fbi)
 {
+	struct omapfb_info *ofbi = FB2OFB(fbi);
 	struct fb_var_screeninfo new_var;
 	int r;
 
@@ -1063,8 +1075,12 @@  static int omapfb_pan_display(struct fb_var_screeninfo *var,
 
 	fbi->var = new_var;
 
+	omapfb_get_mem_region(ofbi->region);
+
 	r = omapfb_apply_changes(fbi, 0);
 
+	omapfb_put_mem_region(ofbi->region);
+
 	return r;
 }
 
@@ -1072,14 +1088,18 @@  static void mmap_user_open(struct vm_area_struct *vma)
 {
 	struct omapfb2_mem_region *rg = vma->vm_private_data;
 
+	omapfb_get_mem_region(rg);
 	atomic_inc(&rg->map_count);
+	omapfb_put_mem_region(rg);
 }
 
 static void mmap_user_close(struct vm_area_struct *vma)
 {
 	struct omapfb2_mem_region *rg = vma->vm_private_data;
 
+	omapfb_get_mem_region(rg);
 	atomic_dec(&rg->map_count);
+	omapfb_put_mem_region(rg);
 }
 
 static struct vm_operations_struct mmap_user_ops = {
@@ -1095,6 +1115,7 @@  static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
 	unsigned long off;
 	unsigned long start;
 	u32 len;
+	int r = -EINVAL;
 
 	if (vma->vm_end - vma->vm_start == 0)
 		return 0;
@@ -1102,14 +1123,14 @@  static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
 		return -EINVAL;
 	off = vma->vm_pgoff << PAGE_SHIFT;
 
-	rg = ofbi->region;
+	rg = omapfb_get_mem_region(ofbi->region);
 
 	start = omapfb_get_region_paddr(ofbi);
 	len = fix->smem_len;
 	if (off >= len)
-		return -EINVAL;
+		goto error;
 	if ((vma->vm_end - vma->vm_start + off) > len)
-		return -EINVAL;
+		goto error;
 
 	off += start;
 
@@ -1121,11 +1142,23 @@  static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
 	vma->vm_ops = &mmap_user_ops;
 	vma->vm_private_data = rg;
 	if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
-			     vma->vm_end - vma->vm_start, vma->vm_page_prot))
-		return -EAGAIN;
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot)) {
+		r = -EAGAIN;
+		goto error;
+	}
+
 	/* vm_ops.open won't be called for mmap itself. */
 	atomic_inc(&rg->map_count);
+
+	omapfb_put_mem_region(rg);
+
 	return 0;
+
+ error:
+	omapfb_put_mem_region(ofbi->region);
+
+	return r;
 }
 
 /* Store a single color palette entry into a pseudo palette or the hardware
@@ -1896,6 +1929,7 @@  static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
 
 		ofbi->region = &fbdev->regions[i];
 		ofbi->region->id = i;
+		mutex_init(&ofbi->region->mtx);
 
 		/* assign these early, so that fb alloc can use them */
 		ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
@@ -1926,7 +1960,13 @@  static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
 
 	/* setup fb_infos */
 	for (i = 0; i < fbdev->num_fbs; i++) {
-		r = omapfb_fb_init(fbdev, fbdev->fbs[i]);
+		struct fb_info *fbi = fbdev->fbs[i];
+		struct omapfb_info *ofbi = FB2OFB(fbi);
+
+		omapfb_get_mem_region(ofbi->region);
+		r = omapfb_fb_init(fbdev, fbi);
+		omapfb_put_mem_region(ofbi->region);
+
 		if (r) {
 			dev_err(fbdev->dev, "failed to setup fb_info\n");
 			return r;
@@ -1947,7 +1987,13 @@  static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
 	DBG("framebuffers registered\n");
 
 	for (i = 0; i < fbdev->num_fbs; i++) {
-		r = omapfb_apply_changes(fbdev->fbs[i], 1);
+		struct fb_info *fbi = fbdev->fbs[i];
+		struct omapfb_info *ofbi = FB2OFB(fbi);
+
+		omapfb_get_mem_region(ofbi->region);
+		r = omapfb_apply_changes(fbi, 1);
+		omapfb_put_mem_region(ofbi->region);
+
 		if (r) {
 			dev_err(fbdev->dev, "failed to change mode\n");
 			return r;
diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c
index 6fbe39a..6aee279 100644
--- a/drivers/video/omap2/omapfb/omapfb-sysfs.c
+++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c
@@ -49,6 +49,7 @@  static ssize_t store_rotate_type(struct device *dev,
 {
 	struct fb_info *fbi = dev_get_drvdata(dev);
 	struct omapfb_info *ofbi = FB2OFB(fbi);
+	struct omapfb2_mem_region *rg;
 	enum omap_dss_rotation_type rot_type;
 	int r;
 
@@ -63,9 +64,11 @@  static ssize_t store_rotate_type(struct device *dev,
 	if (rot_type == ofbi->rotation_type)
 		goto out;
 
-	if (ofbi->region->size) {
+	rg = omapfb_get_mem_region(ofbi->region);
+
+	if (rg->size) {
 		r = -EBUSY;
-		goto out;
+		goto put_region;
 	}
 
 	ofbi->rotation_type = rot_type;
@@ -74,6 +77,8 @@  static ssize_t store_rotate_type(struct device *dev,
 	 * Since the VRAM for this FB is not allocated at the moment we don't
 	 * need to do any further parameter checking at this point.
 	 */
+put_region:
+	omapfb_put_mem_region(rg);
 out:
 	unlock_fb_info(fbi);
 
@@ -109,6 +114,8 @@  static ssize_t store_mirror(struct device *dev,
 
 	ofbi->mirror = mirror;
 
+	omapfb_get_mem_region(ofbi->region);
+
 	memcpy(&new_var, &fbi->var, sizeof(new_var));
 	r = check_fb_var(fbi, &new_var);
 	if (r)
@@ -123,6 +130,8 @@  static ssize_t store_mirror(struct device *dev,
 
 	r = count;
 out:
+	omapfb_put_mem_region(ofbi->region);
+
 	unlock_fb_info(fbi);
 
 	return r;
@@ -259,11 +268,15 @@  static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
 
 		DBG("detaching %d\n", ofbi->overlays[i]->id);
 
+		omapfb_get_mem_region(ofbi->region);
+
 		omapfb_overlay_enable(ovl, 0);
 
 		if (ovl->manager)
 			ovl->manager->apply(ovl->manager);
 
+		omapfb_put_mem_region(ofbi->region);
+
 		for (t = i + 1; t < ofbi->num_overlays; t++) {
 			ofbi->rotation[t-1] = ofbi->rotation[t];
 			ofbi->overlays[t-1] = ofbi->overlays[t];
@@ -296,7 +309,12 @@  static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
 	}
 
 	if (added) {
+		omapfb_get_mem_region(ofbi->region);
+
 		r = omapfb_apply_changes(fbi, 0);
+
+		omapfb_put_mem_region(ofbi->region);
+
 		if (r)
 			goto out;
 	}
@@ -382,7 +400,12 @@  static ssize_t store_overlays_rotate(struct device *dev,
 		for (i = 0; i < num_ovls; ++i)
 			ofbi->rotation[i] = rotation[i];
 
+		omapfb_get_mem_region(ofbi->region);
+
 		r = omapfb_apply_changes(fbi, 0);
+
+		omapfb_put_mem_region(ofbi->region);
+
 		if (r)
 			goto out;
 
@@ -422,6 +445,14 @@  static ssize_t store_size(struct device *dev, struct device_attribute *attr,
 
 	rg = ofbi->region;
 
+	/* FIXME probably should be a rwsem ... */
+	mutex_lock(&rg->mtx);
+	while (rg->ref) {
+		mutex_unlock(&rg->mtx);
+		schedule();
+		mutex_lock(&rg->mtx);
+	}
+
 	if (atomic_read(&rg->map_count)) {
 		r = -EBUSY;
 		goto out;
@@ -452,6 +483,8 @@  static ssize_t store_size(struct device *dev, struct device_attribute *attr,
 
 	r = count;
 out:
+	mutex_unlock(&rg->mtx);
+
 	unlock_fb_info(fbi);
 
 	return r;
diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h
index 02f1ba9..db3aef5 100644
--- a/drivers/video/omap2/omapfb/omapfb.h
+++ b/drivers/video/omap2/omapfb/omapfb.h
@@ -52,6 +52,8 @@  struct omapfb2_mem_region {
 	u8		type;		/* OMAPFB_PLANE_MEM_* */
 	bool		alloc;		/* allocated by the driver */
 	bool		map;		/* kernel mapped by the driver */
+	struct mutex    mtx;
+	unsigned int    ref;
 	atomic_t	map_count;
 };
 
@@ -159,4 +161,20 @@  static inline int omapfb_overlay_enable(struct omap_overlay *ovl,
 	return ovl->set_overlay_info(ovl, &info);
 }
 
+static inline struct omapfb2_mem_region *
+omapfb_get_mem_region(struct omapfb2_mem_region *rg)
+{
+	mutex_lock(&rg->mtx);
+	rg->ref++;
+	mutex_unlock(&rg->mtx);
+	return rg;
+}
+
+static inline void omapfb_put_mem_region(struct omapfb2_mem_region *rg)
+{
+	mutex_lock(&rg->mtx);
+	rg->ref--;
+	mutex_unlock(&rg->mtx);
+}
+
 #endif