From: 黄涛 Date: Fri, 6 Jun 2014 10:50:11 +0000 (+0800) Subject: rk808: fix deadlock when shutown or reboot X-Git-Tag: firefly_0821_release~5164 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=66bd82550fdc356e455adba8466455a50dd17518;p=firefly-linux-kernel-4.4.55.git rk808: fix deadlock when shutown or reboot When shutdown, rk808 driver shutdown first, so io_lock mutex is locked. At same time, gpu change freq by runtime pm, will locked on rk808_reg_read. Finally, gpu device shutdown, call pm_runtime_barrier. Deadlock happens. Fix this bug by make rk808 shutdown later. task PC stack pid father init D c06e9a14 0 1 0 0x00000000 [] (__schedule+0x48c/0x554) from [] (__pm_runtime_barrier+0x114/0x138) [] (__pm_runtime_barrier+0x114/0x138) from [] (pm_runtime_barrier+0x68/0xb8) [] (pm_runtime_barrier+0x68/0xb8) from [] (device_shutdown+0xa0/0x190) [] (device_shutdown+0xa0/0x190) from [] (kernel_restart+0xc/0x50) [] (kernel_restart+0xc/0x50) from [] (SyS_reboot+0x150/0x1b0) [] (SyS_reboot+0x150/0x1b0) from [] (ret_fast_syscall+0x0/0x30) kworker/2:1 D c06e9a14 0 32 2 0x00000000 Workqueue: pm pm_runtime_work [] (__schedule+0x48c/0x554) from [] (schedule_preempt_disabled+0x24/0x34) [] (schedule_preempt_disabled+0x24/0x34) from [] (__mutex_lock_slowpath+0x1c0/0x22c) [] (__mutex_lock_slowpath+0x1c0/0x22c) from [] (mutex_lock+0x30/0x48) [] (mutex_lock+0x30/0x48) from [] (rk808_reg_read+0x24/0x5c) [] (rk808_reg_read+0x24/0x5c) from [] (rk808_dcdc_is_enabled+0x28/0x38) [] (rk808_dcdc_is_enabled+0x28/0x38) from [] (_regulator_is_enabled+0x34/0x40) [] (_regulator_is_enabled+0x34/0x40) from [] (_regulator_do_set_voltage+0xbc/0x3e4) [] (_regulator_do_set_voltage+0xbc/0x3e4) from [] (regulator_set_voltage+0xc0/0xe0) [] (regulator_set_voltage+0xc0/0xe0) from [] (dvfs_regulator_set_voltage_readback.isra.6+0x14/0x8c) [] (dvfs_regulator_set_voltage_readback.isra.6+0x14/0x8c) from [] (dvfs_scale_volt_direct+0xa0/0xc4) [] (dvfs_scale_volt_direct+0xa0/0xc4) from [] (dvfs_target+0x1a4/0x1d4) [] (dvfs_target+0x1a4/0x1d4) from [] (dvfs_clk_set_rate+0x44/0x80) [] (dvfs_clk_set_rate+0x44/0x80) from [] (mali_dvfs_clk_set+0x28/0x48) [] (mali_dvfs_clk_set+0x28/0x48) from [] (kbase_platform_dvfs_set_level+0x9c/0xe0) [] (kbase_platform_dvfs_set_level+0x9c/0xe0) from [] (kbase_platform_dvfs_enable+0xf4/0x110) [] (kbase_platform_dvfs_enable+0xf4/0x110) from [] (pm_callback_runtime_off+0x3c/0x58) [] (pm_callback_runtime_off+0x3c/0x58) from [] (kbase_device_runtime_suspend+0x24/0x34) [] (kbase_device_runtime_suspend+0x24/0x34) from [] (pm_generic_runtime_suspend+0x2c/0x40) [] (pm_generic_runtime_suspend+0x2c/0x40) from [] (__rpm_callback+0x38/0x68) [] (__rpm_callback+0x38/0x68) from [] (rpm_callback+0x64/0x7c) [] (rpm_callback+0x64/0x7c) from [] (rpm_suspend+0x2d8/0x534) [] (rpm_suspend+0x2d8/0x534) from [] (pm_runtime_work+0x7c/0x94) [] (pm_runtime_work+0x7c/0x94) from [] (process_one_work+0x29c/0x458) [] (process_one_work+0x29c/0x458) from [] (worker_thread+0x194/0x2d4) [] (worker_thread+0x194/0x2d4) from [] (kthread+0xa0/0xac) [] (kthread+0xa0/0xac) from [] (ret_from_fork+0x14/0x3c) --- diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index 9c964533a148..b2852acb86c7 100755 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -32,6 +32,7 @@ #include #include #include +#include #if 0 #define DBG(x...) printk(KERN_INFO x) @@ -1138,7 +1139,7 @@ static struct rk808_board *rk808_parse_dt(struct i2c_client *i2c) return NULL; } #endif -static int rk808_shutdown(struct i2c_client *i2c) +static void rk808_shutdown(void) { int ret,i,val; u16 reg = 0; @@ -1157,9 +1158,11 @@ static int rk808_shutdown(struct i2c_client *i2c) ret = rk808_clear_bits(rk808, RK808_RTC_INT_REG,(0x3<<2)); //close rtc int when power off mutex_lock(&rk808->io_lock); msleep(100); - return 0; } -EXPORT_SYMBOL_GPL(rk808_shutdown); + +static struct syscore_ops rk808_syscore_ops = { + .shutdown = rk808_shutdown, +}; static void rk808_device_shutdown(void) { @@ -1503,6 +1506,8 @@ static int rk808_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i } } #endif + + register_syscore_ops(&rk808_syscore_ops); return 0; @@ -1517,12 +1522,12 @@ static int rk808_i2c_remove(struct i2c_client *i2c) struct rk808 *rk808 = i2c_get_clientdata(i2c); int i; + unregister_syscore_ops(&rk808_syscore_ops); for (i = 0; i < rk808->num_regulators; i++) if (rk808->rdev[i]) regulator_unregister(rk808->rdev[i]); kfree(rk808->rdev); i2c_set_clientdata(i2c, NULL); - kfree(rk808); return 0; } @@ -1551,7 +1556,6 @@ static struct i2c_driver rk808_i2c_driver = { .probe = rk808_i2c_probe, .remove = rk808_i2c_remove, .id_table = rk808_i2c_id, - .shutdown = rk808_shutdown, }; static int __init rk808_module_init(void)