aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorFabio Estevam <fabio.estevam@freescale.com>2014-07-07 13:26:48 -0400
committerMark Brown <broonie@linaro.org>2014-07-09 04:12:37 -0400
commite42be7e1420389349400e990a3b13d23b9c60d39 (patch)
tree151b1e7ab0c8c5d136c34282a4cf550e1d837aec /sound/soc
parent7171511eaec5bf23fb06078f59784a3a0626b38f (diff)
ASoC: sgtl5000: Fix driver unbound
Using the sgtl5000 codec driver as a module and trying to remove it causes the followig kernel oops: root@freescale /$ rmmod snd-soc-imx-sgtl5000 [ 117.122920] ------------[ cut here ]------------ [ 117.127609] WARNING: CPU: 0 PID: 631 at drivers/regulator/core.c:3604 regula) [ 117.137046] Modules linked in: snd_soc_imx_sgtl5000(-) snd_soc_sgtl5000 evbug [ 117.144315] CPU: 0 PID: 631 Comm: rmmod Not tainted 3.16.0-rc3-next-201407043 [ 117.153366] Backtrace: [ 117.155865] [<80011e5c>] (dump_backtrace) from [<80011ff8>] (show_stack+0x18) [ 117.163484] r6:802fcc48 r5:00000000 r4:00000000 r3:00000000 [ 117.169228] [<80011fe0>] (show_stack) from [<80668cc0>] (dump_stack+0x88/0xa) [ 117.176508] [<80668c38>] (dump_stack) from [<80029a38>] (warn_slowpath_commo) [ 117.184696] r5:00000009 r4:00000000 [ 117.188322] [<800299c8>] (warn_slowpath_common) from [<80029a80>] (warn_slow) [ 117.197150] r8:dd60d600 r7:ddfa6d00 r6:dd5d9064 r5:dd5e0f90 r4:dd5d9400 [ 117.203983] [<80029a5c>] (warn_slowpath_null) from [<802fcc48>] (regulator_u) [ 117.212828] [<802fcb74>] (regulator_unregister) from [<7f0047c4>] (ldo_regul) [ 117.223475] r4:dd59e300 r3:dd5e0f90 [ 117.227100] [<7f00479c>] (ldo_regulator_remove [snd_soc_sgtl5000]) from [<7f) [ 117.238959] r4:dd5d8000 r3:ddd51420 [ 117.242623] [<7f0047dc>] (sgtl5000_remove [snd_soc_sgtl5000]) from [<804e5b1) [ 117.252489] r5:00000000 r4:dd5d8000 [ 117.256111] [<804e5af8>] (soc_remove_codec) from [<804e5ed4>] (soc_remove_da) [ 117.264933] r4:ddfb640c r3:00000000 [ 117.268555] [<804e5c10>] (soc_remove_dai_links) from [<804e5fbc>] (snd_soc_u) [ 117.277810] r10:80359e48 r9:dd684000 r8:dd5ca800 r7:dd685e60 r6:00000001 r5c [ 117.285761] r4:dd5d9064 [ 117.288329] [<804e5f28>] (snd_soc_unregister_card) from [<804f29f0>] (devm_c) [ 117.297324] r6:00000004 r5:ddd0fc10 r4:dd5a7980 r3:804f29dc [ 117.303095] [<804f29dc>] (devm_card_release) from [<8035a418>] (release_node) [ 117.311369] [<8035a2a8>] (release_nodes) from [<8035aab4>] (devres_release_a) [ 117.319583] r10:00000000 r9:dd684000 r8:8000ed64 r7:00000081 r6:ddd0fc44 r54 [ 117.327543] r4:ddd0fc10 [ 117.330108] [<8035aa7c>] (devres_release_all) from [<803571c8>] (__device_re) [ 117.339214] r4:ddd0fc10 r3:dd5d9010 [ 117.342989] [<80357148>] (__device_release_driver) from [<80357a48>] (driver) [ 117.351607] r5:7f00c9e4 r4:ddd0fc10 [ 117.355285] [<8035798c>] (driver_detach) from [<80357030>] (bus_remove_drive) [ 117.363454] r6:00000880 r5:00000000 r4:7f00c9e4 r3:dd6c3a80 [ 117.369195] [<80356fdc>] (bus_remove_driver) from [<803580b8>] (driver_unreg) [ 117.377683] r4:7f00c9e4 r3:dd60d480 [ 117.381305] [<80358088>] (driver_unregister) from [<80358bb4>] (platform_dri) [ 117.390642] r4:7f00ca28 r3:7f00c35c [ 117.394309] [<80358ba0>] (platform_driver_unregister) from [<7f00c370>] (imx) [ 117.406188] [<7f00c35c>] (imx_sgtl5000_driver_exit [snd_soc_imx_sgtl5000]) f) [ 117.417452] [<8008c2b8>] (SyS_delete_module) from [<8000eba0>] (ret_fast_sys) [ 117.425753] r6:5f636f73 r5:5f646e73 r4:00016f40 [ 117.430428] ---[ end trace 8fd8a5cb39e46d0e ]--- This problem is well explained by Russell King: "The sgtl5000 uses a two-stage initialisation process. The first stage is when the platform driver is probed, where some resources are found and initialised. The second stage is via the codec driver's probe function, where regulators are found and initialised using the managed resource support. The problem here is that this works fine until the codec driver is unbound. When this occurs, sgtl5000_remove() is called which is a no-op as far as the managed resource code is concerned. The regulators remain allocated, and their pointers in sgtl5000_priv remain valid. If the codec is now re-probed, it will again try and find the regulators, which will now be busy. This will fail. That's not the only problem - if using the LDO regulator, the regulator is unregistered from the regulator core code, but it still has a user. When the user is cleaned up (eg, by removing the module) it hits the free'd regulator, and this can oops the kernel. This bug was originally introduced by 63e54cd9caa3ce ("ASoC: sgtl5000: Use devm_regulator_bulk_get()")." This reverts commit 63e54cd9caa3ce. Tested on a imx53-qsb board. Reported-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com> Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/codecs/sgtl5000.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 3d39f0b5b4a8..8f4c73d17c87 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -1277,7 +1277,7 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
1277 return ret; 1277 return ret;
1278 } 1278 }
1279 1279
1280 ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies), 1280 ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies),
1281 sgtl5000->supplies); 1281 sgtl5000->supplies);
1282 if (ret) 1282 if (ret)
1283 goto err_ldo_remove; 1283 goto err_ldo_remove;
@@ -1285,13 +1285,16 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
1285 ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies), 1285 ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies),
1286 sgtl5000->supplies); 1286 sgtl5000->supplies);
1287 if (ret) 1287 if (ret)
1288 goto err_ldo_remove; 1288 goto err_regulator_free;
1289 1289
1290 /* wait for all power rails bring up */ 1290 /* wait for all power rails bring up */
1291 udelay(10); 1291 udelay(10);
1292 1292
1293 return 0; 1293 return 0;
1294 1294
1295err_regulator_free:
1296 regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
1297 sgtl5000->supplies);
1295err_ldo_remove: 1298err_ldo_remove:
1296 if (!external_vddd) 1299 if (!external_vddd)
1297 ldo_regulator_remove(codec); 1300 ldo_regulator_remove(codec);
@@ -1361,6 +1364,8 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
1361err: 1364err:
1362 regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), 1365 regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
1363 sgtl5000->supplies); 1366 sgtl5000->supplies);
1367 regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
1368 sgtl5000->supplies);
1364 ldo_regulator_remove(codec); 1369 ldo_regulator_remove(codec);
1365 1370
1366 return ret; 1371 return ret;
@@ -1374,6 +1379,8 @@ static int sgtl5000_remove(struct snd_soc_codec *codec)
1374 1379
1375 regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), 1380 regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
1376 sgtl5000->supplies); 1381 sgtl5000->supplies);
1382 regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
1383 sgtl5000->supplies);
1377 ldo_regulator_remove(codec); 1384 ldo_regulator_remove(codec);
1378 1385
1379 return 0; 1386 return 0;