mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
led: qcom-lpg: Fix sleeping in atomic
lpg_brighness_set() function can sleep, while led's brightness_set()
callback must be non-blocking. Change LPG driver to use
brightness_set_blocking() instead.
BUG: sleeping function called from invalid context at kernel/locking/mutex.c:580
in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 0, name: swapper/0
preempt_count: 101, expected: 0
INFO: lockdep is turned off.
CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 6.1.0-rc1-00014-gbe99b089c6fc-dirty #85
Hardware name: Qualcomm Technologies, Inc. DB820c (DT)
Call trace:
dump_backtrace.part.0+0xe4/0xf0
show_stack+0x18/0x40
dump_stack_lvl+0x88/0xb4
dump_stack+0x18/0x34
__might_resched+0x170/0x254
__might_sleep+0x48/0x9c
__mutex_lock+0x4c/0x400
mutex_lock_nested+0x2c/0x40
lpg_brightness_single_set+0x40/0x90
led_set_brightness_nosleep+0x34/0x60
led_heartbeat_function+0x80/0x170
call_timer_fn+0xb8/0x340
__run_timers.part.0+0x20c/0x254
run_timer_softirq+0x3c/0x7c
_stext+0x14c/0x578
____do_softirq+0x10/0x20
call_on_irq_stack+0x2c/0x5c
do_softirq_own_stack+0x1c/0x30
__irq_exit_rcu+0x164/0x170
irq_exit_rcu+0x10/0x40
el1_interrupt+0x38/0x50
el1h_64_irq_handler+0x18/0x2c
el1h_64_irq+0x64/0x68
cpuidle_enter_state+0xc8/0x380
cpuidle_enter+0x38/0x50
do_idle+0x244/0x2d0
cpu_startup_entry+0x24/0x30
rest_init+0x128/0x1a0
arch_post_acpi_subsys_init+0x0/0x18
start_kernel+0x6f4/0x734
__primary_switched+0xbc/0xc4
Fixes: 24e2d05d1b
("leds: Add driver for Qualcomm LPG")
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Pavel Machek <pavel@ucw.cz>
This commit is contained in:
parent
57d91e0390
commit
3031993b34
@ -602,8 +602,8 @@ static void lpg_brightness_set(struct lpg_led *led, struct led_classdev *cdev,
|
||||
lpg_lut_sync(lpg, lut_mask);
|
||||
}
|
||||
|
||||
static void lpg_brightness_single_set(struct led_classdev *cdev,
|
||||
enum led_brightness value)
|
||||
static int lpg_brightness_single_set(struct led_classdev *cdev,
|
||||
enum led_brightness value)
|
||||
{
|
||||
struct lpg_led *led = container_of(cdev, struct lpg_led, cdev);
|
||||
struct mc_subled info;
|
||||
@ -614,10 +614,12 @@ static void lpg_brightness_single_set(struct led_classdev *cdev,
|
||||
lpg_brightness_set(led, cdev, &info);
|
||||
|
||||
mutex_unlock(&led->lpg->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lpg_brightness_mc_set(struct led_classdev *cdev,
|
||||
enum led_brightness value)
|
||||
static int lpg_brightness_mc_set(struct led_classdev *cdev,
|
||||
enum led_brightness value)
|
||||
{
|
||||
struct led_classdev_mc *mc = lcdev_to_mccdev(cdev);
|
||||
struct lpg_led *led = container_of(mc, struct lpg_led, mcdev);
|
||||
@ -628,6 +630,8 @@ static void lpg_brightness_mc_set(struct led_classdev *cdev,
|
||||
lpg_brightness_set(led, cdev, mc->subled_info);
|
||||
|
||||
mutex_unlock(&led->lpg->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpg_blink_set(struct lpg_led *led,
|
||||
@ -1118,7 +1122,7 @@ static int lpg_add_led(struct lpg *lpg, struct device_node *np)
|
||||
led->mcdev.num_colors = num_channels;
|
||||
|
||||
cdev = &led->mcdev.led_cdev;
|
||||
cdev->brightness_set = lpg_brightness_mc_set;
|
||||
cdev->brightness_set_blocking = lpg_brightness_mc_set;
|
||||
cdev->blink_set = lpg_blink_mc_set;
|
||||
|
||||
/* Register pattern accessors only if we have a LUT block */
|
||||
@ -1132,7 +1136,7 @@ static int lpg_add_led(struct lpg *lpg, struct device_node *np)
|
||||
return ret;
|
||||
|
||||
cdev = &led->cdev;
|
||||
cdev->brightness_set = lpg_brightness_single_set;
|
||||
cdev->brightness_set_blocking = lpg_brightness_single_set;
|
||||
cdev->blink_set = lpg_blink_single_set;
|
||||
|
||||
/* Register pattern accessors only if we have a LUT block */
|
||||
@ -1151,7 +1155,7 @@ static int lpg_add_led(struct lpg *lpg, struct device_node *np)
|
||||
else
|
||||
cdev->brightness = LED_OFF;
|
||||
|
||||
cdev->brightness_set(cdev, cdev->brightness);
|
||||
cdev->brightness_set_blocking(cdev, cdev->brightness);
|
||||
|
||||
init_data.fwnode = of_fwnode_handle(np);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user