Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933477AbcJ0Djo (ORCPT ); Wed, 26 Oct 2016 23:39:44 -0400 Received: from mail-pf0-f178.google.com ([209.85.192.178]:34902 "EHLO mail-pf0-f178.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932506AbcJ0Djk (ORCPT ); Wed, 26 Oct 2016 23:39:40 -0400 From: Viresh Kumar To: Lee Jones Cc: linaro-kernel@lists.linaro.org, broonie@kernel.org, ckeepax@opensource.wolfsonmicro.com, Viresh Kumar , patches@opensource.wolfsonmicro.com, linux-kernel@vger.kernel.org Subject: [PATCH V3] mfd: wm8994-core: Don't use managed regulator bulk get API Date: Thu, 27 Oct 2016 09:09:30 +0530 Message-Id: X-Mailer: git-send-email 2.7.1.410.g6faf27b Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 21573 Lines: 348 The kernel WARNs and then crashes today if wm8994_device_init() fails after calling devm_regulator_bulk_get(). That happens because there are multiple devices involved here and the order in which resources are freed isn't correct. The regulators are added as children of wm8994->dev. devm_regulator_bulk_get() receives wm8994->dev as the device, though it gets the same regulators which were added as children of wm8994->dev earlier. During failures, the children are removed first and the core eventually calls regulator_unregister() for them. As regulator_put() was never done for them (opposite of devm_regulator_bulk_get()), the kernel WARNs at WARN_ON(rdev->open_count); And eventually it crashes from debugfs_remove_recursive(). --------x------------------x---------------- wm8994 3-001a: Device is not a WM8994, ID is 0 ------------[ cut here ]------------ WARNING: CPU: 0 PID: 1 at /mnt/ssd/all/work/repos/devel/linux/drivers/regulator/core.c:4072 regulator_unregister+0xc8/0xd0 Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.8.0-rc6-00154-g54fe84cbd50b #41 Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0x88/0x9c) [] (dump_stack) from [] (__warn+0xe8/0x100) [] (__warn) from [] (warn_slowpath_null+0x20/0x28) [] (warn_slowpath_null) from [] (regulator_unregister+0xc8/0xd0) [] (regulator_unregister) from [] (release_nodes+0x16c/0x1dc) [] (release_nodes) from [] (__device_release_driver+0x8c/0x110) [] (__device_release_driver) from [] (device_release_driver+0x1c/0x28) [] (device_release_driver) from [] (bus_remove_device+0xd8/0x104) [] (bus_remove_device) from [] (device_del+0x10c/0x218) [] (device_del) from [] (platform_device_del+0x1c/0x88) [] (platform_device_del) from [] (platform_device_unregister+0xc/0x20) [] (platform_device_unregister) from [] (mfd_remove_devices_fn+0x5c/0x64) [] (mfd_remove_devices_fn) from [] (device_for_each_child_reverse+0x4c/0x78) [] (device_for_each_child_reverse) from [] (mfd_remove_devices+0x20/0x30) [] (mfd_remove_devices) from [] (wm8994_device_init+0x2ac/0x7f0) [] (wm8994_device_init) from [] (i2c_device_probe+0x178/0x1fc) [] (i2c_device_probe) from [] (driver_probe_device+0x214/0x2c0) [] (driver_probe_device) from [] (__driver_attach+0xac/0xb0) [] (__driver_attach) from [] (bus_for_each_dev+0x68/0x9c) [] (bus_for_each_dev) from [] (bus_add_driver+0x1a0/0x218) [] (bus_add_driver) from [] (driver_register+0x78/0xf8) [] (driver_register) from [] (i2c_register_driver+0x34/0x84) [] (i2c_register_driver) from [] (do_one_initcall+0x40/0x170) [] (do_one_initcall) from [] (kernel_init_freeable+0x15c/0x1fc) [] (kernel_init_freeable) from [] (kernel_init+0x8/0x114) [] (kernel_init) from [] (ret_from_fork+0x14/0x3c) ---[ end trace 0919d3d0bc998260 ]--- ------------[ cut here ]------------ WARNING: CPU: 0 PID: 1 at /mnt/ssd/all/work/repos/devel/linux/drivers/regulator/core.c:4072 regulator_unregister+0xc8/0xd0 Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Tainted: G W 4.8.0-rc6-00154-g54fe84cbd50b #41 Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0x88/0x9c) [] (dump_stack) from [] (__warn+0xe8/0x100) [] (__warn) from [] (warn_slowpath_null+0x20/0x28) [] (warn_slowpath_null) from [] (regulator_unregister+0xc8/0xd0) [] (regulator_unregister) from [] (release_nodes+0x16c/0x1dc) [] (release_nodes) from [] (__device_release_driver+0x8c/0x110) [] (__device_release_driver) from [] (device_release_driver+0x1c/0x28) [] (device_release_driver) from [] (bus_remove_device+0xd8/0x104) [] (bus_remove_device) from [] (device_del+0x10c/0x218) [] (device_del) from [] (platform_device_del+0x1c/0x88) wm8994 3-001a: Device is not a WM8994, ID is 0 ------------[ cut here ]------------ WARNING: CPU: 0 PID: 1 at /mnt/ssd/all/work/repos/devel/linux/drivers/regulator/core.c:4072 regulator_unregister+0xc8/0xd0 Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.8.0-rc6-00154-g54fe84cbd50b #41 Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0x88/0x9c) [] (dump_stack) from [] (__warn+0xe8/0x100) [] (__warn) from [] (warn_slowpath_null+0x20/0x28) [] (warn_slowpath_null) from [] (regulator_unregister+0xc8/0xd0) [] (regulator_unregister) from [] (release_nodes+0x16c/0x1dc) [] (release_nodes) from [] (__device_release_driver+0x8c/0x110) [] (__device_release_driver) from [] (device_release_driver+0x1c/0x28) [] (device_release_driver) from [] (bus_remove_device+0xd8/0x104) [] (bus_remove_device) from [] (device_del+0x10c/0x218) [] (device_del) from [] (platform_device_del+0x1c/0x88) [] (platform_device_del) from [] (platform_device_unregister+0xc/0x20) [] (platform_device_unregister) from [] (mfd_remove_devices_fn+0x5c/0x64) [] (mfd_remove_devices_fn) from [] (device_for_each_child_reverse+0x4c/0x78) [] (device_for_each_child_reverse) from [] (mfd_remove_devices+0x20/0x30) [] (mfd_remove_devices) from [] (wm8994_device_init+0x2ac/0x7f0) [] (wm8994_device_init) from [] (i2c_device_probe+0x178/0x1fc) [] (i2c_device_probe) from [] (driver_probe_device+0x214/0x2c0) [] (driver_probe_device) from [] (__driver_attach+0xac/0xb0) [] (__driver_attach) from [] (bus_for_each_dev+0x68/0x9c) [] (bus_for_each_dev) from [] (bus_add_driver+0x1a0/0x218) [] (bus_add_driver) from [] (driver_register+0x78/0xf8) [] (driver_register) from [] (i2c_register_driver+0x34/0x84) [] (i2c_register_driver) from [] (do_one_initcall+0x40/0x170) [] (do_one_initcall) from [] (kernel_init_freeable+0x15c/0x1fc) [] (kernel_init_freeable) from [] (kernel_init+0x8/0x114) [] (kernel_init) from [] (ret_from_fork+0x14/0x3c) ---[ end trace 0919d3d0bc998260 ]--- ------------[ cut here ]------------ WARNING: CPU: 0 PID: 1 at /mnt/ssd/all/work/repos/devel/linux/drivers/regulator/core.c:4072 regulator_unregister+0xc8/0xd0 Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Tainted: G W 4.8.0-rc6-00154-g54fe84cbd50b #41 Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0x88/0x9c) [] (dump_stack) from [] (__warn+0xe8/0x100) [] (__warn) from [] (warn_slowpath_null+0x20/0x28) [] (warn_slowpath_null) from [] (regulator_unregister+0xc8/0xd0) [] (regulator_unregister) from [] (release_nodes+0x16c/0x1dc) [] (release_nodes) from [] (__device_release_driver+0x8c/0x110) [] (__device_release_driver) from [] (device_release_driver+0x1c/0x28) [] (device_release_driver) from [] (bus_remove_device+0xd8/0x104) [] (bus_remove_device) from [] (device_del+0x10c/0x218) [] (device_del) from [] (platform_device_del+0x1c/0x88) [] (platform_device_del) from [] (platform_device_unregister+0xc/0x20) [] (platform_device_unregister) from [] (mfd_remove_devices_fn+0x5c/0x64) [] (mfd_remove_devices_fn) from [] (device_for_each_child_reverse+0x4c/0x78) [] (device_for_each_child_reverse) from [] (mfd_remove_devices+0x20/0x30) [] (mfd_remove_devices) from [] (wm8994_device_init+0x2ac/0x7f0) [] (wm8994_device_init) from [] (i2c_device_probe+0x178/0x1fc) [] (i2c_device_probe) from [] (driver_probe_device+0x214/0x2c0) [] (driver_probe_device) from [] (__driver_attach+0xac/0xb0) [] (__driver_attach) from [] (bus_for_each_dev+0x68/0x9c) [] (bus_for_each_dev) from [] (bus_add_driver+0x1a0/0x218) [] (bus_add_driver) from [] (driver_register+0x78/0xf8) [] (driver_register) from [] (i2c_register_driver+0x34/0x84) [] (i2c_register_driver) from [] (do_one_initcall+0x40/0x170) [] (do_one_initcall) from [] (kernel_init_freeable+0x15c/0x1fc) [] (kernel_init_freeable) from [] (kernel_init+0x8/0x114) [] (kernel_init) from [] (ret_from_fork+0x14/0x3c) ---[ end trace 0919d3d0bc998261 ]--- Unable to handle kernel NULL pointer dereference at virtual address 00000078 pgd = c0004000 [00000078] *pgd=00000000 Internal error: Oops: 5 [#1] PREEMPT SMP ARM Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Tainted: G W 4.8.0-rc6-00154-g54fe84cbd50b #41 Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) task: ee874000 task.stack: ee878000 PC is at down_write+0x14/0x54 LR is at debugfs_remove_recursive+0x30/0x150 pc : [] lr : [] psr: 80000013 sp : ee879e18 ip : 2e575000 fp : 00000000 r10: 00000000 r9 : c0406004 r8 : ee46f428 r7 : ee46f4ac r6 : ee46f478 r5 : ee46f428 r4 : 00000078 r3 : ffff0001 r2 : 00000000 r1 : 00000001 r0 : 00000078 Flags: Nzcv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none Control: 10c5387d Table: 4000406a DAC: 00000051 Process swapper/0 (pid: 1, stack limit = 0xee878210) Stack: (0xee879e18 to 0xee87a000) 9e00: ee216340 c02e9954 9e20: ee216340 ee12bc00 0000000d eea22220 ee879e58 c0382b78 c0b1505c ee216340 9e40: 0000000d c0382c1c ee216300 ee216200 0000000d c0406434 ee1e7c00 ee216700 9e60: eea22220 c0b81c0c c0b81c14 c0b22320 ffffffea 00000000 00000000 c04035d4 9e80: eea22220 c0b22320 eea22254 c0b2a950 c0b44000 000000d8 00000000 c0403854 9ea0: 00000000 c0b22320 c04037a8 c0401a74 ee97be74 eea153c0 c0b22320 ee16f480 9ec0: 00000000 c0402cf0 c08a5174 c0a1d3cc c0a34840 c0b22320 c0a1d3cc c0a34840 9ee0: c0b44000 c040406c c0b22304 c0a1d3cc c0a34840 c04f20a0 c0a5ff58 c0a1d3cc 9f00: c0a34840 c01017d0 c0b0ac18 ee879f18 c0b45fe8 c06e3f40 60000000 c0b095a0 9f20: 00000000 c0b095a0 efffca46 c0716b00 efffca42 c01350dc 0000cccd 00000000 9f40: c08cdb2c 00000000 00000006 00000006 c0b0957c efffc940 c0a5ff58 00000006 9f60: c0a34840 c0b44000 c0b44000 000000d8 c0a34848 c0a00dbc 00000006 00000006 9f80: 00000000 c0a005a0 00000000 c06e07a8 00000000 00000000 00000000 00000000 9fa0: 00000000 c06e07b0 00000000 c0107978 00000000 00000000 00000000 00000000 9fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 9fe0: 00000000 00000000 00000000 00000000 00000013 00000000 ffffffff ffffffff [] (down_write) from [] (debugfs_remove_recursive+0x30/0x150) [] (debugfs_remove_recursive) from [] (_regulator_put+0x24/0xac) [] (_regulator_put) from [] (regulator_put+0x1c/0x2c) [] (regulator_put) from [] (release_nodes+0x16c/0x1dc) [] (release_nodes) from [] (driver_probe_device+0xec/0x2c0) [] (driver_probe_device) from [] (__driver_attach+0xac/0xb0) [] (__driver_attach) from [] (bus_for_each_dev+0x68/0x9c) [] (bus_for_each_dev) from [] (bus_add_driver+0x1a0/0x218) [] (bus_add_driver) from [] (driver_register+0x78/0xf8) [] (driver_register) from [] (i2c_register_driver+0x34/0x84) [] (i2c_register_driver) from [] (do_one_initcall+0x40/0x170) [] (do_one_initcall) from [] (kernel_init_freeable+0x15c/0x1fc) [] (kernel_init_freeable) from [] (kernel_init+0x8/0x114) [] (kernel_init) from [] (ret_from_fork+0x14/0x3c) Code: e1a04000 f590f000 e3a03001 e34f3fff (e1902f9f) ---[ end trace 0919d3d0bc998262 ]--- Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b CPU1: stopping CPU: 1 PID: 0 Comm: swapper/1 Tainted: G D W 4.8.0-rc6-00154-g54fe84cbd50b #41 Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0x88/0x9c) [] (dump_stack) from [] (handle_IPI+0x198/0x1ac) [] (handle_IPI) from [] (gic_handle_irq+0x94/0x98) [] (gic_handle_irq) from [] (__irq_svc+0x6c/0xa8) Exception stack(0xee89ff88 to 0xee89ffd0) ff80: 00000001 00000000 00000000 c0113f40 ee89e000 c0b02454 ffa0: 00000002 00000000 00000000 c0a65f88 c0b024c0 c0b024b8 00000000 ee89ffd8 ffc0: c01083b8 c01083bc 60000013 ffffffff [] (__irq_svc) from [] (arch_cpu_idle+0x38/0x3c) [] (arch_cpu_idle) from [] (cpu_startup_entry+0x1cc/0x250) [] (cpu_startup_entry) from [<4010158c>] (0x4010158c) ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [] (platform_device_del) from [] (platform_device_unregister+0xc/0x20) [] (platform_device_unregister) from [] (mfd_remove_devices_fn+0x5c/0x64) [] (mfd_remove_devices_fn) from [] (device_for_each_child_reverse+0x4c/0x78) [] (device_for_each_child_reverse) from [] (mfd_remove_devices+0x20/0x30) [] (mfd_remove_devices) from [] (wm8994_device_init+0x2ac/0x7f0) [] (wm8994_device_init) from [] (i2c_device_probe+0x178/0x1fc) [] (i2c_device_probe) from [] (driver_probe_device+0x214/0x2c0) [] (driver_probe_device) from [] (__driver_attach+0xac/0xb0) [] (__driver_attach) from [] (bus_for_each_dev+0x68/0x9c) [] (bus_for_each_dev) from [] (bus_add_driver+0x1a0/0x218) [] (bus_add_driver) from [] (driver_register+0x78/0xf8) [] (driver_register) from [] (i2c_register_driver+0x34/0x84) [] (i2c_register_driver) from [] (do_one_initcall+0x40/0x170) [] (do_one_initcall) from [] (kernel_init_freeable+0x15c/0x1fc) [] (kernel_init_freeable) from [] (kernel_init+0x8/0x114) [] (kernel_init) from [] (ret_from_fork+0x14/0x3c) ---[ end trace 0919d3d0bc998261 ]--- Unable to handle kernel NULL pointer dereference at virtual address 00000078 pgd = c0004000 [00000078] *pgd=00000000 Internal error: Oops: 5 [#1] PREEMPT SMP ARM Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Tainted: G W 4.8.0-rc6-00154-g54fe84cbd50b #41 Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) task: ee874000 task.stack: ee878000 PC is at down_write+0x14/0x54 LR is at debugfs_remove_recursive+0x30/0x150 pc : [] lr : [] psr: 80000013 sp : ee879e18 ip : 2e575000 fp : 00000000 r10: 00000000 r9 : c0406004 r8 : ee46f428 r7 : ee46f4ac r6 : ee46f478 r5 : ee46f428 r4 : 00000078 r3 : ffff0001 r2 : 00000000 r1 : 00000001 r0 : 00000078 Flags: Nzcv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none Control: 10c5387d Table: 4000406a DAC: 00000051 Process swapper/0 (pid: 1, stack limit = 0xee878210) Stack: (0xee879e18 to 0xee87a000) 9e00: ee216340 c02e9954 9e20: ee216340 ee12bc00 0000000d eea22220 ee879e58 c0382b78 c0b1505c ee216340 9e40: 0000000d c0382c1c ee216300 ee216200 0000000d c0406434 ee1e7c00 ee216700 9e60: eea22220 c0b81c0c c0b81c14 c0b22320 ffffffea 00000000 00000000 c04035d4 9e80: eea22220 c0b22320 eea22254 c0b2a950 c0b44000 000000d8 00000000 c0403854 9ea0: 00000000 c0b22320 c04037a8 c0401a74 ee97be74 eea153c0 c0b22320 ee16f480 9ec0: 00000000 c0402cf0 c08a5174 c0a1d3cc c0a34840 c0b22320 c0a1d3cc c0a34840 9ee0: c0b44000 c040406c c0b22304 c0a1d3cc c0a34840 c04f20a0 c0a5ff58 c0a1d3cc 9f00: c0a34840 c01017d0 c0b0ac18 ee879f18 c0b45fe8 c06e3f40 60000000 c0b095a0 9f20: 00000000 c0b095a0 efffca46 c0716b00 efffca42 c01350dc 0000cccd 00000000 9f40: c08cdb2c 00000000 00000006 00000006 c0b0957c efffc940 c0a5ff58 00000006 9f60: c0a34840 c0b44000 c0b44000 000000d8 c0a34848 c0a00dbc 00000006 00000006 9f80: 00000000 c0a005a0 00000000 c06e07a8 00000000 00000000 00000000 00000000 9fa0: 00000000 c06e07b0 00000000 c0107978 00000000 00000000 00000000 00000000 9fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 9fe0: 00000000 00000000 00000000 00000000 00000013 00000000 ffffffff ffffffff [] (down_write) from [] (debugfs_remove_recursive+0x30/0x150) [] (debugfs_remove_recursive) from [] (_regulator_put+0x24/0xac) [] (_regulator_put) from [] (regulator_put+0x1c/0x2c) [] (regulator_put) from [] (release_nodes+0x16c/0x1dc) [] (release_nodes) from [] (driver_probe_device+0xec/0x2c0) [] (driver_probe_device) from [] (__driver_attach+0xac/0xb0) [] (__driver_attach) from [] (bus_for_each_dev+0x68/0x9c) [] (bus_for_each_dev) from [] (bus_add_driver+0x1a0/0x218) [] (bus_add_driver) from [] (driver_register+0x78/0xf8) [] (driver_register) from [] (i2c_register_driver+0x34/0x84) [] (i2c_register_driver) from [] (do_one_initcall+0x40/0x170) [] (do_one_initcall) from [] (kernel_init_freeable+0x15c/0x1fc) [] (kernel_init_freeable) from [] (kernel_init+0x8/0x114) [] (kernel_init) from [] (ret_from_fork+0x14/0x3c) Code: e1a04000 f590f000 e3a03001 e34f3fff (e1902f9f) ---[ end trace 0919d3d0bc998262 ]--- Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b --------x------------------x---------------- Fix the kernel warnings and crashes by moving away from managed regulator bulk get API by using regulator_bulk_get() and explicitly calling regulator_put() for all the supplies in exit paths. Tested on Exynos 5250, dual core ARM A15 machine. Signed-off-by: Viresh Kumar Acked-by: Charles Keepax --- V2->V3: - Fixed a rebase conflict - sending only one patch with Charles Ack V1->V2: - Use regulator_bulk_free() instead of open coding it. - Shorter backtrace - Reworded the last paragraph to make it more clear - Added a comment in code drivers/mfd/wm8994-core.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 95e6bc55adbb..87e9309c5f92 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -394,7 +394,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) goto err; } - ret = devm_regulator_bulk_get(wm8994->dev, wm8994->num_supplies, + ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies, wm8994->supplies); if (ret != 0) { dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret); @@ -404,7 +404,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) ret = regulator_bulk_enable(wm8994->num_supplies, wm8994->supplies); if (ret != 0) { dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret); - goto err; + goto err_regulator_put; } ret = wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET); @@ -595,6 +595,9 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) err_enable: regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies); +err_regulator_put: + for (i = wm8994->num_supplies - 1; i >= 0; i--) + regulator_put(wm8994->supplies[i].consumer); err: mfd_remove_devices(wm8994->dev); return ret; @@ -602,9 +605,12 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) static void wm8994_device_exit(struct wm8994 *wm8994) { + int i; pm_runtime_disable(wm8994->dev); wm8994_irq_exit(wm8994); regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies); + for (i = wm8994->num_supplies - 1; i >= 0; i--) + regulator_put(wm8994->supplies[i].consumer); mfd_remove_devices(wm8994->dev); } -- 2.7.1.410.g6faf27b