Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

backlight: Fix external uses of backlight internal semaphore

backlight_device->sem has a very specific use as documented in the
header file. The external users of this are using it for a different
reason, to serialise access to the update_status() method.

backlight users were supposed to implement their own internal
serialisation of update_status() if needed but everyone is doing
things differently and incorrectly. Therefore add a global mutex to
take care of serialisation for everyone, once and for all.

Locking for get_brightness remains optional since most users don't
need it.

Also update the lcd class in a similar way.

Signed-off-by: Richard Purdie <rpurdie@rpsys.net>

+76 -76
+1 -3
arch/powerpc/kernel/traps.c
··· 107 107 if (machine_is(powermac) && pmac_backlight) { 108 108 struct backlight_properties *props; 109 109 110 - down(&pmac_backlight->sem); 111 110 props = pmac_backlight->props; 112 111 props->brightness = props->max_brightness; 113 112 props->power = FB_BLANK_UNBLANK; 114 - props->update_status(pmac_backlight); 115 - up(&pmac_backlight->sem); 113 + backlight_update_status(pmac_backlight); 116 114 } 117 115 mutex_unlock(&pmac_backlight_mutex); 118 116 #endif
+5 -14
arch/powerpc/platforms/powermac/backlight.c
··· 37 37 */ 38 38 static atomic_t kernel_backlight_disabled = ATOMIC_INIT(0); 39 39 40 - /* Protect the pmac_backlight variable */ 40 + /* Protect the pmac_backlight variable below. 41 + You should hold this lock when using the pmac_backlight pointer to 42 + prevent its potential removal. */ 41 43 DEFINE_MUTEX(pmac_backlight_mutex); 42 44 43 45 /* Main backlight storage ··· 51 49 * internal display, it doesn't matter. Other backlight drivers can be used 52 50 * independently. 53 51 * 54 - * Lock ordering: 55 - * pmac_backlight_mutex (global, main backlight) 56 - * pmac_backlight->sem (backlight class) 57 52 */ 58 53 struct backlight_device *pmac_backlight; 59 54 ··· 103 104 struct backlight_properties *props; 104 105 int brightness; 105 106 106 - down(&pmac_backlight->sem); 107 107 props = pmac_backlight->props; 108 108 109 109 brightness = props->brightness + ··· 115 117 brightness = props->max_brightness; 116 118 117 119 props->brightness = brightness; 118 - props->update_status(pmac_backlight); 119 - 120 - up(&pmac_backlight->sem); 120 + backlight_update_status(pmac_backlight); 121 121 } 122 122 mutex_unlock(&pmac_backlight_mutex); 123 123 } ··· 141 145 if (pmac_backlight) { 142 146 struct backlight_properties *props; 143 147 144 - down(&pmac_backlight->sem); 145 148 props = pmac_backlight->props; 146 149 props->brightness = brightness * 147 150 (props->max_brightness + 1) / ··· 151 156 else if (props->brightness < 0) 152 157 props->brightness = 0; 153 158 154 - props->update_status(pmac_backlight); 155 - up(&pmac_backlight->sem); 159 + backlight_update_status(pmac_backlight); 156 160 157 161 error = 0; 158 162 } ··· 190 196 if (pmac_backlight) { 191 197 struct backlight_properties *props; 192 198 193 - down(&pmac_backlight->sem); 194 199 props = pmac_backlight->props; 195 200 196 201 result = props->brightness * 197 202 (OLD_BACKLIGHT_MAX + 1) / 198 203 (props->max_brightness + 1); 199 - 200 - up(&pmac_backlight->sem); 201 204 } 202 205 mutex_unlock(&pmac_backlight_mutex); 203 206
+1 -3
drivers/macintosh/via-pmu-backlight.c
··· 166 166 pmu_backlight_data.max_brightness / 15); 167 167 } 168 168 169 - down(&bd->sem); 170 169 bd->props->brightness = level; 171 170 bd->props->power = FB_BLANK_UNBLANK; 172 - bd->props->update_status(bd); 173 - up(&bd->sem); 171 + backlight_update_status(bd); 174 172 175 173 mutex_lock(&pmac_backlight_mutex); 176 174 if (!pmac_backlight)
+5 -15
drivers/misc/asus-laptop.c
··· 348 348 struct backlight_device *bd = asus_backlight_device; 349 349 350 350 if (bd) { 351 - down(&bd->sem); 352 - if (likely(bd->props)) { 353 - bd->props->power = blank; 354 - if (likely(bd->props->update_status)) 355 - bd->props->update_status(bd); 356 - } 357 - up(&bd->sem); 351 + bd->props->power = blank; 352 + backlight_update_status(bd); 358 353 } 359 354 } 360 355 ··· 1023 1028 1024 1029 asus_backlight_device = bd; 1025 1030 1026 - down(&bd->sem); 1027 - if (likely(bd->props)) { 1028 - bd->props->brightness = read_brightness(NULL); 1029 - bd->props->power = FB_BLANK_UNBLANK; 1030 - if (likely(bd->props->update_status)) 1031 - bd->props->update_status(bd); 1032 - } 1033 - up(&bd->sem); 1031 + bd->props->brightness = read_brightness(NULL); 1032 + bd->props->power = FB_BLANK_UNBLANK; 1033 + backlight_update_status(bd); 1034 1034 } 1035 1035 return 0; 1036 1036 }
-6
drivers/usb/misc/appledisplay.c
··· 189 189 container_of(work, struct appledisplay, work.work); 190 190 int retval; 191 191 192 - up(&pdata->bd->sem); 193 192 retval = appledisplay_bl_get_brightness(pdata->bd); 194 193 if (retval >= 0) 195 194 pdata->bd->props->brightness = retval; 196 - down(&pdata->bd->sem); 197 195 198 196 /* Poll again in about 125ms if there's still a button pressed */ 199 197 if (pdata->button_pressed) ··· 286 288 } 287 289 288 290 /* Try to get brightness */ 289 - up(&pdata->bd->sem); 290 291 brightness = appledisplay_bl_get_brightness(pdata->bd); 291 - down(&pdata->bd->sem); 292 292 293 293 if (brightness < 0) { 294 294 retval = brightness; ··· 295 299 } 296 300 297 301 /* Set brightness in backlight device */ 298 - up(&pdata->bd->sem); 299 302 pdata->bd->props->brightness = brightness; 300 - down(&pdata->bd->sem); 301 303 302 304 /* save our data pointer in the interface device */ 303 305 usb_set_intfdata(iface, pdata);
+1 -5
drivers/video/aty/aty128fb.c
··· 1807 1807 mutex_lock(&info->bl_mutex); 1808 1808 1809 1809 if (info->bl_dev) { 1810 - down(&info->bl_dev->sem); 1811 1810 info->bl_dev->props->power = power; 1812 1811 __aty128_bl_update_status(info->bl_dev); 1813 - up(&info->bl_dev->sem); 1814 1812 } 1815 1813 1816 1814 mutex_unlock(&info->bl_mutex); ··· 1845 1847 219 * FB_BACKLIGHT_MAX / MAX_LEVEL); 1846 1848 mutex_unlock(&info->bl_mutex); 1847 1849 1848 - down(&bd->sem); 1849 1850 bd->props->brightness = aty128_bl_data.max_brightness; 1850 1851 bd->props->power = FB_BLANK_UNBLANK; 1851 - bd->props->update_status(bd); 1852 - up(&bd->sem); 1852 + backlight_update_status(bd); 1853 1853 1854 1854 #ifdef CONFIG_PMAC_BACKLIGHT 1855 1855 mutex_lock(&pmac_backlight_mutex);
+1 -5
drivers/video/aty/atyfb_base.c
··· 2188 2188 mutex_lock(&info->bl_mutex); 2189 2189 2190 2190 if (info->bl_dev) { 2191 - down(&info->bl_dev->sem); 2192 2191 info->bl_dev->props->power = power; 2193 2192 __aty_bl_update_status(info->bl_dev); 2194 - up(&info->bl_dev->sem); 2195 2193 } 2196 2194 2197 2195 mutex_unlock(&info->bl_mutex); ··· 2222 2224 0xFF * FB_BACKLIGHT_MAX / MAX_LEVEL); 2223 2225 mutex_unlock(&info->bl_mutex); 2224 2226 2225 - down(&bd->sem); 2226 2227 bd->props->brightness = aty_bl_data.max_brightness; 2227 2228 bd->props->power = FB_BLANK_UNBLANK; 2228 - bd->props->update_status(bd); 2229 - up(&bd->sem); 2229 + backlight_update_status(bd); 2230 2230 2231 2231 #ifdef CONFIG_PMAC_BACKLIGHT 2232 2232 mutex_lock(&pmac_backlight_mutex);
+1 -3
drivers/video/aty/radeon_backlight.c
··· 194 194 217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL); 195 195 mutex_unlock(&rinfo->info->bl_mutex); 196 196 197 - down(&bd->sem); 198 197 bd->props->brightness = radeon_bl_data.max_brightness; 199 198 bd->props->power = FB_BLANK_UNBLANK; 200 - bd->props->update_status(bd); 201 - up(&bd->sem); 199 + backlight_update_status(bd); 202 200 203 201 #ifdef CONFIG_PMAC_BACKLIGHT 204 202 mutex_lock(&pmac_backlight_mutex);
+4 -6
drivers/video/backlight/backlight.c
··· 37 37 if (!bd->props->check_fb || 38 38 bd->props->check_fb(evdata->info)) { 39 39 bd->props->fb_blank = *(int *)evdata->data; 40 - if (bd->props && bd->props->update_status) 41 - bd->props->update_status(bd); 40 + backlight_update_status(bd); 42 41 } 43 42 up(&bd->sem); 44 43 return 0; ··· 96 97 if (bd->props) { 97 98 pr_debug("backlight: set power to %d\n", power); 98 99 bd->props->power = power; 99 - if (bd->props->update_status) 100 - bd->props->update_status(bd); 100 + backlight_update_status(bd); 101 101 rc = count; 102 102 } 103 103 up(&bd->sem); ··· 138 140 pr_debug("backlight: set brightness to %d\n", 139 141 brightness); 140 142 bd->props->brightness = brightness; 141 - if (bd->props->update_status) 142 - bd->props->update_status(bd); 143 + backlight_update_status(bd); 143 144 rc = count; 144 145 } 145 146 } ··· 227 230 if (!new_bd) 228 231 return ERR_PTR(-ENOMEM); 229 232 233 + mutex_init(&new_bd->update_lock); 230 234 init_MUTEX(&new_bd->sem); 231 235 new_bd->props = bp; 232 236 memset(&new_bd->class_dev, 0, sizeof(new_bd->class_dev));
+1
drivers/video/backlight/lcd.c
··· 198 198 return ERR_PTR(-ENOMEM); 199 199 200 200 init_MUTEX(&new_ld->sem); 201 + mutex_init(&new_ld->update_lock); 201 202 new_ld->props = lp; 202 203 memset(&new_ld->class_dev, 0, sizeof(new_ld->class_dev)); 203 204 new_ld->class_dev.class = &lcd_class;
+2 -6
drivers/video/chipsfb.c
··· 153 153 * useful at blank = 1 too (saves battery, extends backlight 154 154 * life) 155 155 */ 156 - down(&pmac_backlight->sem); 157 156 if (blank) 158 157 pmac_backlight->props->power = FB_BLANK_POWERDOWN; 159 158 else 160 159 pmac_backlight->props->power = FB_BLANK_UNBLANK; 161 - pmac_backlight->props->update_status(pmac_backlight); 162 - up(&pmac_backlight->sem); 160 + backlight_update_status(pmac_backlight); 163 161 } 164 162 165 163 mutex_unlock(&pmac_backlight_mutex); ··· 413 415 /* turn on the backlight */ 414 416 mutex_lock(&pmac_backlight_mutex); 415 417 if (pmac_backlight) { 416 - down(&pmac_backlight->sem); 417 418 pmac_backlight->props->power = FB_BLANK_UNBLANK; 418 - pmac_backlight->props->update_status(pmac_backlight); 419 - up(&pmac_backlight->sem); 419 + backlight_update_status(pmac_backlight); 420 420 } 421 421 mutex_unlock(&pmac_backlight_mutex); 422 422 #endif /* CONFIG_PMAC_BACKLIGHT */
+1 -5
drivers/video/nvidia/nv_backlight.c
··· 114 114 mutex_lock(&info->bl_mutex); 115 115 116 116 if (info->bl_dev) { 117 - down(&info->bl_dev->sem); 118 117 info->bl_dev->props->power = power; 119 118 __nvidia_bl_update_status(info->bl_dev); 120 - up(&info->bl_dev->sem); 121 119 } 122 120 123 121 mutex_unlock(&info->bl_mutex); ··· 152 154 0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL); 153 155 mutex_unlock(&info->bl_mutex); 154 156 155 - down(&bd->sem); 156 157 bd->props->brightness = nvidia_bl_data.max_brightness; 157 158 bd->props->power = FB_BLANK_UNBLANK; 158 - bd->props->update_status(bd); 159 - up(&bd->sem); 159 + backlight_update_status(bd); 160 160 161 161 #ifdef CONFIG_PMAC_BACKLIGHT 162 162 mutex_lock(&pmac_backlight_mutex);
+1 -5
drivers/video/riva/fbdev.c
··· 357 357 mutex_lock(&info->bl_mutex); 358 358 359 359 if (info->bl_dev) { 360 - down(&info->bl_dev->sem); 361 360 info->bl_dev->props->power = power; 362 361 __riva_bl_update_status(info->bl_dev); 363 - up(&info->bl_dev->sem); 364 362 } 365 363 366 364 mutex_unlock(&info->bl_mutex); ··· 395 397 FB_BACKLIGHT_MAX); 396 398 mutex_unlock(&info->bl_mutex); 397 399 398 - down(&bd->sem); 399 400 bd->props->brightness = riva_bl_data.max_brightness; 400 401 bd->props->power = FB_BLANK_UNBLANK; 401 - bd->props->update_status(bd); 402 - up(&bd->sem); 402 + backlight_update_status(bd); 403 403 404 404 #ifdef CONFIG_PMAC_BACKLIGHT 405 405 mutex_lock(&pmac_backlight_mutex);
+26
include/linux/backlight.h
··· 9 9 #define _LINUX_BACKLIGHT_H 10 10 11 11 #include <linux/device.h> 12 + #include <linux/mutex.h> 12 13 #include <linux/notifier.h> 14 + 15 + /* Notes on locking: 16 + * 17 + * backlight_device->sem is an internal backlight lock protecting the props 18 + * field and no code outside the core should need to touch it. 19 + * 20 + * Access to update_status() is serialised by the update_lock mutex since 21 + * most drivers seem to need this and historically get it wrong. 22 + * 23 + * Most drivers don't need locking on their get_brightness() method. 24 + * If yours does, you need to implement it in the driver. You can use the 25 + * update_lock mutex if appropriate. 26 + * 27 + * Any other use of the locks below is probably wrong. 28 + */ 13 29 14 30 struct backlight_device; 15 31 struct fb_info; ··· 60 44 struct semaphore sem; 61 45 /* If this is NULL, the backing module is unloaded */ 62 46 struct backlight_properties *props; 47 + /* Serialise access to update_status method */ 48 + struct mutex update_lock; 63 49 /* The framebuffer notifier block */ 64 50 struct notifier_block fb_notif; 65 51 /* The class device structure */ 66 52 struct class_device class_dev; 67 53 }; 54 + 55 + static inline void backlight_update_status(struct backlight_device *bd) 56 + { 57 + mutex_lock(&bd->update_lock); 58 + if (bd->props && bd->props->update_status) 59 + bd->props->update_status(bd); 60 + mutex_unlock(&bd->update_lock); 61 + } 68 62 69 63 extern struct backlight_device *backlight_device_register(const char *name, 70 64 struct device *dev,void *devdata,struct backlight_properties *bp);
+26
include/linux/lcd.h
··· 9 9 #define _LINUX_LCD_H 10 10 11 11 #include <linux/device.h> 12 + #include <linux/mutex.h> 12 13 #include <linux/notifier.h> 14 + 15 + /* Notes on locking: 16 + * 17 + * lcd_device->sem is an internal backlight lock protecting the props 18 + * field and no code outside the core should need to touch it. 19 + * 20 + * Access to set_power() is serialised by the update_lock mutex since 21 + * most drivers seem to need this and historically get it wrong. 22 + * 23 + * Most drivers don't need locking on their get_power() method. 24 + * If yours does, you need to implement it in the driver. You can use the 25 + * update_lock mutex if appropriate. 26 + * 27 + * Any other use of the locks below is probably wrong. 28 + */ 13 29 14 30 struct lcd_device; 15 31 struct fb_info; ··· 55 39 struct semaphore sem; 56 40 /* If this is NULL, the backing module is unloaded */ 57 41 struct lcd_properties *props; 42 + /* Serialise access to set_power method */ 43 + struct mutex update_lock; 58 44 /* The framebuffer notifier block */ 59 45 struct notifier_block fb_notif; 60 46 /* The class device structure */ 61 47 struct class_device class_dev; 62 48 }; 49 + 50 + static inline void lcd_set_power(struct lcd_device *ld, int power) 51 + { 52 + mutex_lock(&ld->update_lock); 53 + if (ld->props && ld->props->set_power) 54 + ld->props->set_power(ld, power); 55 + mutex_unlock(&ld->update_lock); 56 + } 63 57 64 58 extern struct lcd_device *lcd_device_register(const char *name, 65 59 void *devdata, struct lcd_properties *lp);