Commit c4f28e54 authored by Jiri Slaby's avatar Jiri Slaby Committed by Linus Torvalds

[PATCH] Video: fb, add true ref_count atomicity

Some of fb drivers uses atomic_t in bad manner, since there are still some
race-prone gaps.  Use mutexes to protect open/close code sections with
ref_count testing and finally use simple uint.
Signed-off-by: default avatarJiri Slaby <jirislaby@gmail.com>
Acked-by: default avatarDenis Oliver Kropp <dok@directfb.org>
Cc: James Simmons <jsimmons@infradead.org>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 52e7c922
...@@ -264,7 +264,8 @@ struct i810fb_par { ...@@ -264,7 +264,8 @@ struct i810fb_par {
struct heap_data cursor_heap; struct heap_data cursor_heap;
struct vgastate state; struct vgastate state;
struct i810fb_i2c_chan chan[3]; struct i810fb_i2c_chan chan[3];
atomic_t use_count; struct mutex open_lock;
unsigned int use_count;
u32 pseudo_palette[17]; u32 pseudo_palette[17];
unsigned long mmio_start_phys; unsigned long mmio_start_phys;
u8 __iomem *mmio_start_virtual; u8 __iomem *mmio_start_virtual;
......
...@@ -1235,9 +1235,9 @@ static int i810fb_getcolreg(u8 regno, u8 *red, u8 *green, u8 *blue, ...@@ -1235,9 +1235,9 @@ static int i810fb_getcolreg(u8 regno, u8 *red, u8 *green, u8 *blue,
static int i810fb_open(struct fb_info *info, int user) static int i810fb_open(struct fb_info *info, int user)
{ {
struct i810fb_par *par = info->par; struct i810fb_par *par = info->par;
u32 count = atomic_read(&par->use_count);
mutex_lock(&par->open_lock);
if (count == 0) { if (par->use_count == 0) {
memset(&par->state, 0, sizeof(struct vgastate)); memset(&par->state, 0, sizeof(struct vgastate));
par->state.flags = VGA_SAVE_CMAP; par->state.flags = VGA_SAVE_CMAP;
par->state.vgabase = par->mmio_start_virtual; par->state.vgabase = par->mmio_start_virtual;
...@@ -1246,7 +1246,8 @@ static int i810fb_open(struct fb_info *info, int user) ...@@ -1246,7 +1246,8 @@ static int i810fb_open(struct fb_info *info, int user)
i810_save_vga_state(par); i810_save_vga_state(par);
} }
atomic_inc(&par->use_count); par->use_count++;
mutex_unlock(&par->open_lock);
return 0; return 0;
} }
...@@ -1254,18 +1255,20 @@ static int i810fb_open(struct fb_info *info, int user) ...@@ -1254,18 +1255,20 @@ static int i810fb_open(struct fb_info *info, int user)
static int i810fb_release(struct fb_info *info, int user) static int i810fb_release(struct fb_info *info, int user)
{ {
struct i810fb_par *par = info->par; struct i810fb_par *par = info->par;
u32 count;
mutex_lock(&par->open_lock);
count = atomic_read(&par->use_count); if (par->use_count == 0) {
if (count == 0) mutex_unlock(&par->open_lock);
return -EINVAL; return -EINVAL;
}
if (count == 1) { if (par->use_count == 1) {
i810_restore_vga_state(par); i810_restore_vga_state(par);
restore_vga(&par->state); restore_vga(&par->state);
} }
atomic_dec(&par->use_count); par->use_count--;
mutex_unlock(&par->open_lock);
return 0; return 0;
} }
...@@ -1752,6 +1755,8 @@ static void __devinit i810_init_monspecs(struct fb_info *info) ...@@ -1752,6 +1755,8 @@ static void __devinit i810_init_monspecs(struct fb_info *info)
static void __devinit i810_init_defaults(struct i810fb_par *par, static void __devinit i810_init_defaults(struct i810fb_par *par,
struct fb_info *info) struct fb_info *info)
{ {
mutex_init(&par->open_lock);
if (voffset) if (voffset)
v_offset_default = voffset; v_offset_default = voffset;
else if (par->aperture.size > 32 * 1024 * 1024) else if (par->aperture.size > 32 * 1024 * 1024)
......
...@@ -556,14 +556,16 @@ static int ...@@ -556,14 +556,16 @@ static int
neofb_open(struct fb_info *info, int user) neofb_open(struct fb_info *info, int user)
{ {
struct neofb_par *par = info->par; struct neofb_par *par = info->par;
int cnt = atomic_read(&par->ref_count);
if (!cnt) { mutex_lock(&par->open_lock);
if (!par->ref_count) {
memset(&par->state, 0, sizeof(struct vgastate)); memset(&par->state, 0, sizeof(struct vgastate));
par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS; par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS;
save_vga(&par->state); save_vga(&par->state);
} }
atomic_inc(&par->ref_count); par->ref_count++;
mutex_unlock(&par->open_lock);
return 0; return 0;
} }
...@@ -571,14 +573,18 @@ static int ...@@ -571,14 +573,18 @@ static int
neofb_release(struct fb_info *info, int user) neofb_release(struct fb_info *info, int user)
{ {
struct neofb_par *par = info->par; struct neofb_par *par = info->par;
int cnt = atomic_read(&par->ref_count);
if (!cnt) mutex_lock(&par->open_lock);
if (!par->ref_count) {
mutex_unlock(&par->open_lock);
return -EINVAL; return -EINVAL;
if (cnt == 1) { }
if (par->ref_count == 1) {
restore_vga(&par->state); restore_vga(&par->state);
} }
atomic_dec(&par->ref_count); par->ref_count--;
mutex_unlock(&par->open_lock);
return 0; return 0;
} }
...@@ -2047,6 +2053,7 @@ static struct fb_info *__devinit neo_alloc_fb_info(struct pci_dev *dev, const st ...@@ -2047,6 +2053,7 @@ static struct fb_info *__devinit neo_alloc_fb_info(struct pci_dev *dev, const st
info->fix.accel = id->driver_data; info->fix.accel = id->driver_data;
mutex_init(&par->open_lock);
par->pci_burst = !nopciburst; par->pci_burst = !nopciburst;
par->lcd_stretch = !nostretch; par->lcd_stretch = !nostretch;
par->libretto = libretto; par->libretto = libretto;
......
...@@ -1101,10 +1101,10 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var) ...@@ -1101,10 +1101,10 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
static int rivafb_open(struct fb_info *info, int user) static int rivafb_open(struct fb_info *info, int user)
{ {
struct riva_par *par = info->par; struct riva_par *par = info->par;
int cnt = atomic_read(&par->ref_count);
NVTRACE_ENTER(); NVTRACE_ENTER();
if (!cnt) { mutex_lock(&par->open_lock);
if (!par->ref_count) {
#ifdef CONFIG_X86 #ifdef CONFIG_X86
memset(&par->state, 0, sizeof(struct vgastate)); memset(&par->state, 0, sizeof(struct vgastate));
par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS; par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS;
...@@ -1119,7 +1119,8 @@ static int rivafb_open(struct fb_info *info, int user) ...@@ -1119,7 +1119,8 @@ static int rivafb_open(struct fb_info *info, int user)
riva_save_state(par, &par->initial_state); riva_save_state(par, &par->initial_state);
} }
atomic_inc(&par->ref_count); par->ref_count++;
mutex_unlock(&par->open_lock);
NVTRACE_LEAVE(); NVTRACE_LEAVE();
return 0; return 0;
} }
...@@ -1127,12 +1128,14 @@ static int rivafb_open(struct fb_info *info, int user) ...@@ -1127,12 +1128,14 @@ static int rivafb_open(struct fb_info *info, int user)
static int rivafb_release(struct fb_info *info, int user) static int rivafb_release(struct fb_info *info, int user)
{ {
struct riva_par *par = info->par; struct riva_par *par = info->par;
int cnt = atomic_read(&par->ref_count);
NVTRACE_ENTER(); NVTRACE_ENTER();
if (!cnt) mutex_lock(&par->open_lock);
if (!par->ref_count) {
mutex_unlock(&par->open_lock);
return -EINVAL; return -EINVAL;
if (cnt == 1) { }
if (par->ref_count == 1) {
par->riva.LockUnlock(&par->riva, 0); par->riva.LockUnlock(&par->riva, 0);
par->riva.LoadStateExt(&par->riva, &par->initial_state.ext); par->riva.LoadStateExt(&par->riva, &par->initial_state.ext);
riva_load_state(par, &par->initial_state); riva_load_state(par, &par->initial_state);
...@@ -1141,7 +1144,8 @@ static int rivafb_release(struct fb_info *info, int user) ...@@ -1141,7 +1144,8 @@ static int rivafb_release(struct fb_info *info, int user)
#endif #endif
par->riva.LockUnlock(&par->riva, 1); par->riva.LockUnlock(&par->riva, 1);
} }
atomic_dec(&par->ref_count); par->ref_count--;
mutex_unlock(&par->open_lock);
NVTRACE_LEAVE(); NVTRACE_LEAVE();
return 0; return 0;
} }
...@@ -1999,6 +2003,7 @@ static int __devinit rivafb_probe(struct pci_dev *pd, ...@@ -1999,6 +2003,7 @@ static int __devinit rivafb_probe(struct pci_dev *pd,
goto err_disable_device; goto err_disable_device;
} }
mutex_init(&default_par->open_lock);
default_par->riva.Architecture = riva_get_arch(pd); default_par->riva.Architecture = riva_get_arch(pd);
default_par->Chipset = (pd->vendor << 16) | pd->device; default_par->Chipset = (pd->vendor << 16) | pd->device;
......
...@@ -53,7 +53,8 @@ struct riva_par { ...@@ -53,7 +53,8 @@ struct riva_par {
#ifdef CONFIG_X86 #ifdef CONFIG_X86
struct vgastate state; struct vgastate state;
#endif #endif
atomic_t ref_count; struct mutex open_lock;
unsigned int ref_count;
unsigned char *EDID; unsigned char *EDID;
unsigned int Chipset; unsigned int Chipset;
int forceCRTC; int forceCRTC;
......
...@@ -70,7 +70,8 @@ struct vga16fb_par { ...@@ -70,7 +70,8 @@ struct vga16fb_par {
unsigned char ClockingMode; /* Seq-Controller:01h */ unsigned char ClockingMode; /* Seq-Controller:01h */
} vga_state; } vga_state;
struct vgastate state; struct vgastate state;
atomic_t ref_count; struct mutex open_lock;
unsigned int ref_count;
int palette_blanked, vesa_blanked, mode, isVGA; int palette_blanked, vesa_blanked, mode, isVGA;
u8 misc, pel_msk, vss, clkdiv; u8 misc, pel_msk, vss, clkdiv;
u8 crtc[VGA_CRT_C]; u8 crtc[VGA_CRT_C];
...@@ -300,28 +301,33 @@ static void vga16fb_clock_chip(struct vga16fb_par *par, ...@@ -300,28 +301,33 @@ static void vga16fb_clock_chip(struct vga16fb_par *par,
static int vga16fb_open(struct fb_info *info, int user) static int vga16fb_open(struct fb_info *info, int user)
{ {
struct vga16fb_par *par = info->par; struct vga16fb_par *par = info->par;
int cnt = atomic_read(&par->ref_count);
if (!cnt) { mutex_lock(&par->open_lock);
if (!par->ref_count) {
memset(&par->state, 0, sizeof(struct vgastate)); memset(&par->state, 0, sizeof(struct vgastate));
par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE | par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE |
VGA_SAVE_CMAP; VGA_SAVE_CMAP;
save_vga(&par->state); save_vga(&par->state);
} }
atomic_inc(&par->ref_count); par->ref_count++;
mutex_unlock(&par->open_lock);
return 0; return 0;
} }
static int vga16fb_release(struct fb_info *info, int user) static int vga16fb_release(struct fb_info *info, int user)
{ {
struct vga16fb_par *par = info->par; struct vga16fb_par *par = info->par;
int cnt = atomic_read(&par->ref_count);
if (!cnt) mutex_lock(&par->open_lock);
if (!par->ref_count) {
mutex_unlock(&par->open_lock);
return -EINVAL; return -EINVAL;
if (cnt == 1) }
if (par->ref_count == 1)
restore_vga(&par->state); restore_vga(&par->state);
atomic_dec(&par->ref_count); par->ref_count--;
mutex_unlock(&par->open_lock);
return 0; return 0;
} }
...@@ -1357,6 +1363,7 @@ static int __init vga16fb_probe(struct platform_device *dev) ...@@ -1357,6 +1363,7 @@ static int __init vga16fb_probe(struct platform_device *dev)
printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base); printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base);
par = info->par; par = info->par;
mutex_init(&par->open_lock);
par->isVGA = ORIG_VIDEO_ISVGA; par->isVGA = ORIG_VIDEO_ISVGA;
par->palette_blanked = 0; par->palette_blanked = 0;
par->vesa_blanked = 0; par->vesa_blanked = 0;
......
...@@ -140,7 +140,8 @@ typedef volatile struct { ...@@ -140,7 +140,8 @@ typedef volatile struct {
struct neofb_par { struct neofb_par {
struct vgastate state; struct vgastate state;
atomic_t ref_count; struct mutex open_lock;
unsigned int ref_count;
unsigned char MiscOutReg; /* Misc */ unsigned char MiscOutReg; /* Misc */
unsigned char CRTC[25]; /* Crtc Controller */ unsigned char CRTC[25]; /* Crtc Controller */
......
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