Skip to content

Commit

Permalink
OMAP: DSS2: OMAPFB: Add locking for memory regions
Browse files Browse the repository at this point in the history
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: Ville Syrjälä <ville.syrjala@nokia.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>
  • Loading branch information
Ville Syrjälä authored and Tomi Valkeinen committed Aug 3, 2010
1 parent 078ff54 commit 430571d
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 21 deletions.
44 changes: 33 additions & 11 deletions drivers/video/omap2/omapfb/omapfb-ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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) {
Expand All @@ -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);
Expand Down Expand Up @@ -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:
Expand All @@ -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");

Expand Down Expand Up @@ -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)
Expand All @@ -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]);
Expand All @@ -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;
}
}
}
Expand All @@ -213,24 +230,29 @@ 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)
{
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;
}

Expand Down
62 changes: 54 additions & 8 deletions drivers/video/omap2/omapfb/omapfb-main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1019,36 +1019,48 @@ int omapfb_apply_changes(struct fb_info *fbi, int init)
* 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;

Expand All @@ -1064,23 +1076,31 @@ 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;
}

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 = {
Expand All @@ -1096,21 +1116,22 @@ 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;
if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
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;

Expand All @@ -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_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
Expand Down Expand Up @@ -1897,6 +1930,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 :
Expand Down Expand Up @@ -1927,7 +1961,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;
Expand All @@ -1948,7 +1988,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;
Expand Down
Loading

0 comments on commit 430571d

Please sign in to comment.