Commit 430571d5 authored by Ville Syrjälä's avatar Ville Syrjälä Committed by Tomi Valkeinen

OMAP: DSS2: OMAPFB: Add locking for memory regions

Add locking to the memory regions to make sure the memory region size
won't be changed while some other piece of code is performing some
checks or setup based on that information.
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@nokia.com>
Signed-off-by: default avatarTomi Valkeinen <tomi.valkeinen@nokia.com>
parent 078ff546
...@@ -55,7 +55,7 @@ static struct omapfb2_mem_region *get_mem_region(struct omapfb_info *ofbi, ...@@ -55,7 +55,7 @@ static struct omapfb2_mem_region *get_mem_region(struct omapfb_info *ofbi,
if (mem_idx >= fbdev->num_fbs) if (mem_idx >= fbdev->num_fbs)
return NULL; 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) 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) ...@@ -77,11 +77,11 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
/* XXX uses only the first overlay */ /* XXX uses only the first overlay */
ovl = ofbi->overlays[0]; 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); new_rg = get_mem_region(ofbi, pi->mem_idx);
if (!new_rg) { if (!new_rg) {
r = -EINVAL; r = -EINVAL;
goto out; goto put_old;
} }
if (pi->enabled && !new_rg->size) { if (pi->enabled && !new_rg->size) {
...@@ -90,7 +90,7 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) ...@@ -90,7 +90,7 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
* until it's reallocated. * until it's reallocated.
*/ */
r = -EINVAL; r = -EINVAL;
goto out; goto put_new;
} }
ovl->get_overlay_info(ovl, &old_info); 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) ...@@ -135,6 +135,9 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
if (ovl->manager) if (ovl->manager)
ovl->manager->apply(ovl->manager); ovl->manager->apply(ovl->manager);
omapfb_put_mem_region(new_rg);
omapfb_put_mem_region(old_rg);
return 0; return 0;
undo: undo:
...@@ -144,6 +147,10 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) ...@@ -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); ovl->set_overlay_info(ovl, &old_info);
put_new:
omapfb_put_mem_region(new_rg);
put_old:
omapfb_put_mem_region(old_rg);
out: out:
dev_err(fbdev->dev, "setup_plane failed\n"); 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) ...@@ -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 omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev; struct omapfb2_device *fbdev = ofbi->fbdev;
struct omapfb2_mem_region *rg; struct omapfb2_mem_region *rg;
int r, i; int r = 0, i;
size_t size; size_t size;
if (mi->type > OMAPFB_MEMTYPE_MAX) if (mi->type > OMAPFB_MEMTYPE_MAX)
...@@ -191,8 +198,18 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) ...@@ -191,8 +198,18 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
rg = ofbi->region; rg = ofbi->region;
if (atomic_read(&rg->map_count)) /* FIXME probably should be a rwsem ... */
return -EBUSY; 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++) { for (i = 0; i < fbdev->num_fbs; i++) {
struct omapfb_info *ofbi2 = FB2OFB(fbdev->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) ...@@ -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++) { for (j = 0; j < ofbi2->num_overlays; j++) {
if (ofbi2->overlays[j]->info.enabled) { if (ofbi2->overlays[j]->info.enabled) {
r = -EBUSY; r = -EBUSY;
return r; goto out;
} }
} }
} }
...@@ -213,11 +230,14 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) ...@@ -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); r = omapfb_realloc_fbmem(fbi, size, mi->type);
if (r) { if (r) {
dev_err(fbdev->dev, "realloc fbmem failed\n"); 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) 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) ...@@ -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 omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_mem_region *rg; struct omapfb2_mem_region *rg;
rg = ofbi->region; rg = omapfb_get_mem_region(ofbi->region);
memset(mi, 0, sizeof(*mi)); memset(mi, 0, sizeof(*mi));
mi->size = rg->size; mi->size = rg->size;
mi->type = rg->type; mi->type = rg->type;
omapfb_put_mem_region(rg);
return 0; return 0;
} }
......
...@@ -1019,36 +1019,48 @@ int omapfb_apply_changes(struct fb_info *fbi, int init) ...@@ -1019,36 +1019,48 @@ int omapfb_apply_changes(struct fb_info *fbi, int init)
* DO NOT MODIFY PAR */ * DO NOT MODIFY PAR */
static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi) static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
{ {
struct omapfb_info *ofbi = FB2OFB(fbi);
int r; int r;
DBG("check_var(%d)\n", FB2OFB(fbi)->id); DBG("check_var(%d)\n", FB2OFB(fbi)->id);
omapfb_get_mem_region(ofbi->region);
r = check_fb_var(fbi, var); r = check_fb_var(fbi, var);
omapfb_put_mem_region(ofbi->region);
return r; return r;
} }
/* set the video mode according to info->var */ /* set the video mode according to info->var */
static int omapfb_set_par(struct fb_info *fbi) static int omapfb_set_par(struct fb_info *fbi)
{ {
struct omapfb_info *ofbi = FB2OFB(fbi);
int r; int r;
DBG("set_par(%d)\n", FB2OFB(fbi)->id); DBG("set_par(%d)\n", FB2OFB(fbi)->id);
omapfb_get_mem_region(ofbi->region);
set_fb_fix(fbi); set_fb_fix(fbi);
r = setup_vrfb_rotation(fbi); r = setup_vrfb_rotation(fbi);
if (r) if (r)
return r; goto out;
r = omapfb_apply_changes(fbi, 0); r = omapfb_apply_changes(fbi, 0);
out:
omapfb_put_mem_region(ofbi->region);
return r; return r;
} }
static int omapfb_pan_display(struct fb_var_screeninfo *var, static int omapfb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *fbi) struct fb_info *fbi)
{ {
struct omapfb_info *ofbi = FB2OFB(fbi);
struct fb_var_screeninfo new_var; struct fb_var_screeninfo new_var;
int r; int r;
...@@ -1064,8 +1076,12 @@ static int omapfb_pan_display(struct fb_var_screeninfo *var, ...@@ -1064,8 +1076,12 @@ static int omapfb_pan_display(struct fb_var_screeninfo *var,
fbi->var = new_var; fbi->var = new_var;
omapfb_get_mem_region(ofbi->region);
r = omapfb_apply_changes(fbi, 0); r = omapfb_apply_changes(fbi, 0);
omapfb_put_mem_region(ofbi->region);
return r; return r;
} }
...@@ -1073,14 +1089,18 @@ static void mmap_user_open(struct vm_area_struct *vma) ...@@ -1073,14 +1089,18 @@ static void mmap_user_open(struct vm_area_struct *vma)
{ {
struct omapfb2_mem_region *rg = vma->vm_private_data; struct omapfb2_mem_region *rg = vma->vm_private_data;
omapfb_get_mem_region(rg);
atomic_inc(&rg->map_count); atomic_inc(&rg->map_count);
omapfb_put_mem_region(rg);
} }
static void mmap_user_close(struct vm_area_struct *vma) static void mmap_user_close(struct vm_area_struct *vma)
{ {
struct omapfb2_mem_region *rg = vma->vm_private_data; struct omapfb2_mem_region *rg = vma->vm_private_data;
omapfb_get_mem_region(rg);
atomic_dec(&rg->map_count); atomic_dec(&rg->map_count);
omapfb_put_mem_region(rg);
} }
static struct vm_operations_struct mmap_user_ops = { static struct vm_operations_struct mmap_user_ops = {
...@@ -1096,6 +1116,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) ...@@ -1096,6 +1116,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
unsigned long off; unsigned long off;
unsigned long start; unsigned long start;
u32 len; u32 len;
int r = -EINVAL;
if (vma->vm_end - vma->vm_start == 0) if (vma->vm_end - vma->vm_start == 0)
return 0; return 0;
...@@ -1103,14 +1124,14 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) ...@@ -1103,14 +1124,14 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
return -EINVAL; return -EINVAL;
off = vma->vm_pgoff << PAGE_SHIFT; off = vma->vm_pgoff << PAGE_SHIFT;
rg = ofbi->region; rg = omapfb_get_mem_region(ofbi->region);
start = omapfb_get_region_paddr(ofbi); start = omapfb_get_region_paddr(ofbi);
len = fix->smem_len; len = fix->smem_len;
if (off >= len) if (off >= len)
return -EINVAL; goto error;
if ((vma->vm_end - vma->vm_start + off) > len) if ((vma->vm_end - vma->vm_start + off) > len)
return -EINVAL; goto error;
off += start; off += start;
...@@ -1122,11 +1143,23 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) ...@@ -1122,11 +1143,23 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
vma->vm_ops = &mmap_user_ops; vma->vm_ops = &mmap_user_ops;
vma->vm_private_data = rg; vma->vm_private_data = rg;
if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_page_prot)) vma->vm_end - vma->vm_start,
return -EAGAIN; vma->vm_page_prot)) {
r = -EAGAIN;
goto error;
}
/* vm_ops.open won't be called for mmap itself. */ /* vm_ops.open won't be called for mmap itself. */
atomic_inc(&rg->map_count); atomic_inc(&rg->map_count);
omapfb_put_mem_region(rg);
return 0; return 0;
error:
omapfb_put_mem_region(ofbi->region);
return r;
} }
/* Store a single color palette entry into a pseudo palette or the hardware /* Store a single color palette entry into a pseudo palette or the hardware
...@@ -1897,6 +1930,7 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) ...@@ -1897,6 +1930,7 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
ofbi->region = &fbdev->regions[i]; ofbi->region = &fbdev->regions[i];
ofbi->region->id = i; ofbi->region->id = i;
mutex_init(&ofbi->region->mtx);
/* assign these early, so that fb alloc can use them */ /* assign these early, so that fb alloc can use them */
ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB : ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
...@@ -1927,7 +1961,13 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) ...@@ -1927,7 +1961,13 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
/* setup fb_infos */ /* setup fb_infos */
for (i = 0; i < fbdev->num_fbs; i++) { 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) { if (r) {
dev_err(fbdev->dev, "failed to setup fb_info\n"); dev_err(fbdev->dev, "failed to setup fb_info\n");
return r; return r;
...@@ -1948,7 +1988,13 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) ...@@ -1948,7 +1988,13 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
DBG("framebuffers registered\n"); DBG("framebuffers registered\n");
for (i = 0; i < fbdev->num_fbs; i++) { 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) { if (r) {
dev_err(fbdev->dev, "failed to change mode\n"); dev_err(fbdev->dev, "failed to change mode\n");
return r; return r;
......
...@@ -49,6 +49,7 @@ static ssize_t store_rotate_type(struct device *dev, ...@@ -49,6 +49,7 @@ static ssize_t store_rotate_type(struct device *dev,
{ {
struct fb_info *fbi = dev_get_drvdata(dev); struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_mem_region *rg;
enum omap_dss_rotation_type rot_type; enum omap_dss_rotation_type rot_type;
int r; int r;
...@@ -64,9 +65,11 @@ static ssize_t store_rotate_type(struct device *dev, ...@@ -64,9 +65,11 @@ static ssize_t store_rotate_type(struct device *dev,
if (rot_type == ofbi->rotation_type) if (rot_type == ofbi->rotation_type)
goto out; goto out;
if (ofbi->region->size) { rg = omapfb_get_mem_region(ofbi->region);
if (rg->size) {
r = -EBUSY; r = -EBUSY;
goto out; goto put_region;
} }
ofbi->rotation_type = rot_type; ofbi->rotation_type = rot_type;
...@@ -75,6 +78,8 @@ static ssize_t store_rotate_type(struct device *dev, ...@@ -75,6 +78,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 * 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. * need to do any further parameter checking at this point.
*/ */
put_region:
omapfb_put_mem_region(rg);
out: out:
unlock_fb_info(fbi); unlock_fb_info(fbi);
...@@ -111,6 +116,8 @@ static ssize_t store_mirror(struct device *dev, ...@@ -111,6 +116,8 @@ static ssize_t store_mirror(struct device *dev,
ofbi->mirror = mirror; ofbi->mirror = mirror;
omapfb_get_mem_region(ofbi->region);
memcpy(&new_var, &fbi->var, sizeof(new_var)); memcpy(&new_var, &fbi->var, sizeof(new_var));
r = check_fb_var(fbi, &new_var); r = check_fb_var(fbi, &new_var);
if (r) if (r)
...@@ -125,6 +132,8 @@ static ssize_t store_mirror(struct device *dev, ...@@ -125,6 +132,8 @@ static ssize_t store_mirror(struct device *dev,
r = count; r = count;
out: out:
omapfb_put_mem_region(ofbi->region);
unlock_fb_info(fbi); unlock_fb_info(fbi);
return r; return r;
...@@ -263,11 +272,15 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr, ...@@ -263,11 +272,15 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
DBG("detaching %d\n", ofbi->overlays[i]->id); DBG("detaching %d\n", ofbi->overlays[i]->id);
omapfb_get_mem_region(ofbi->region);
omapfb_overlay_enable(ovl, 0); omapfb_overlay_enable(ovl, 0);
if (ovl->manager) if (ovl->manager)
ovl->manager->apply(ovl->manager); ovl->manager->apply(ovl->manager);
omapfb_put_mem_region(ofbi->region);
for (t = i + 1; t < ofbi->num_overlays; t++) { for (t = i + 1; t < ofbi->num_overlays; t++) {
ofbi->rotation[t-1] = ofbi->rotation[t]; ofbi->rotation[t-1] = ofbi->rotation[t];
ofbi->overlays[t-1] = ofbi->overlays[t]; ofbi->overlays[t-1] = ofbi->overlays[t];
...@@ -300,7 +313,12 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr, ...@@ -300,7 +313,12 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
} }
if (added) { if (added) {
omapfb_get_mem_region(ofbi->region);
r = omapfb_apply_changes(fbi, 0); r = omapfb_apply_changes(fbi, 0);
omapfb_put_mem_region(ofbi->region);
if (r) if (r)
goto out; goto out;
} }
...@@ -388,7 +406,12 @@ static ssize_t store_overlays_rotate(struct device *dev, ...@@ -388,7 +406,12 @@ static ssize_t store_overlays_rotate(struct device *dev,
for (i = 0; i < num_ovls; ++i) for (i = 0; i < num_ovls; ++i)
ofbi->rotation[i] = rotation[i]; ofbi->rotation[i] = rotation[i];
omapfb_get_mem_region(ofbi->region);
r = omapfb_apply_changes(fbi, 0); r = omapfb_apply_changes(fbi, 0);
omapfb_put_mem_region(ofbi->region);
if (r) if (r)
goto out; goto out;
...@@ -429,6 +452,14 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, ...@@ -429,6 +452,14 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
rg = ofbi->region; 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)) { if (atomic_read(&rg->map_count)) {
r = -EBUSY; r = -EBUSY;
goto out; goto out;
...@@ -459,6 +490,8 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, ...@@ -459,6 +490,8 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
r = count; r = count;
out: out:
mutex_unlock(&rg->mtx);
unlock_fb_info(fbi); unlock_fb_info(fbi);
return r; return r;
......
...@@ -52,6 +52,8 @@ struct omapfb2_mem_region { ...@@ -52,6 +52,8 @@ struct omapfb2_mem_region {
u8 type; /* OMAPFB_PLANE_MEM_* */ u8 type; /* OMAPFB_PLANE_MEM_* */
bool alloc; /* allocated by the driver */ bool alloc; /* allocated by the driver */
bool map; /* kernel mapped by the driver */ bool map; /* kernel mapped by the driver */
struct mutex mtx;
unsigned int ref;
atomic_t map_count; atomic_t map_count;
}; };
...@@ -159,4 +161,20 @@ static inline int omapfb_overlay_enable(struct omap_overlay *ovl, ...@@ -159,4 +161,20 @@ static inline int omapfb_overlay_enable(struct omap_overlay *ovl,
return ovl->set_overlay_info(ovl, &info); 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 #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment