diff options
author | Stanley.Miao <stanley.miao@windriver.com> | 2009-01-29 11:57:12 -0500 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2009-01-29 11:57:12 -0500 |
commit | 06151158f2da4764479b4ec01688dc4bade6ce9d (patch) | |
tree | b78b3f2ccde6e3d49e9f35bad3352fbfd9a3eca2 /arch/arm/plat-omap | |
parent | 18e352e4a73465349711a9324767e1b2453383e2 (diff) |
ARM: OMAP: Fix McBSP spin_lock deadlock
A spin_lock deadlock will occur when omap_mcbsp_request() is invoked.
omap_mcbsp_request()
\- clk_enable(mcbsp->clk) [takes and holds clockfw_lock]
\- omap2_clk_enable()
\- _omap2_clk_enable()
\- omap_mcbsp_clk_enable()
\- clk_enable(child clock) [tries for clockfw_lock again]
mcbsp_clk is a virtual clock and it comprises several child clocks. when
enable mcbsp_clk in omap_mcbsp_request(), the enable function of mcbsp_clk
will enable its child clocks, then the deadlock occurs.
The solution is to remove the virtual clock and enable these child clocks in
omap_mcbsp_request() directly.
Signed-off-by: Stanley.Miao <stanley.miao@windriver.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/plat-omap')
-rw-r--r-- | arch/arm/plat-omap/include/mach/mcbsp.h | 6 | ||||
-rw-r--r-- | arch/arm/plat-omap/mcbsp.c | 52 |
2 files changed, 43 insertions, 15 deletions
diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h b/arch/arm/plat-omap/include/mach/mcbsp.h index eef873db3d48..113c2466c86a 100644 --- a/arch/arm/plat-omap/include/mach/mcbsp.h +++ b/arch/arm/plat-omap/include/mach/mcbsp.h | |||
@@ -344,7 +344,8 @@ struct omap_mcbsp_platform_data { | |||
344 | u8 dma_rx_sync, dma_tx_sync; | 344 | u8 dma_rx_sync, dma_tx_sync; |
345 | u16 rx_irq, tx_irq; | 345 | u16 rx_irq, tx_irq; |
346 | struct omap_mcbsp_ops *ops; | 346 | struct omap_mcbsp_ops *ops; |
347 | char const *clk_name; | 347 | char const **clk_names; |
348 | int num_clks; | ||
348 | }; | 349 | }; |
349 | 350 | ||
350 | struct omap_mcbsp { | 351 | struct omap_mcbsp { |
@@ -376,7 +377,8 @@ struct omap_mcbsp { | |||
376 | /* Protect the field .free, while checking if the mcbsp is in use */ | 377 | /* Protect the field .free, while checking if the mcbsp is in use */ |
377 | spinlock_t lock; | 378 | spinlock_t lock; |
378 | struct omap_mcbsp_platform_data *pdata; | 379 | struct omap_mcbsp_platform_data *pdata; |
379 | struct clk *clk; | 380 | struct clk **clks; |
381 | int num_clks; | ||
380 | }; | 382 | }; |
381 | extern struct omap_mcbsp **mcbsp_ptr; | 383 | extern struct omap_mcbsp **mcbsp_ptr; |
382 | extern int omap_mcbsp_count; | 384 | extern int omap_mcbsp_count; |
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index f2401a831f99..e5842e30e534 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c | |||
@@ -214,6 +214,7 @@ EXPORT_SYMBOL(omap_mcbsp_set_io_type); | |||
214 | int omap_mcbsp_request(unsigned int id) | 214 | int omap_mcbsp_request(unsigned int id) |
215 | { | 215 | { |
216 | struct omap_mcbsp *mcbsp; | 216 | struct omap_mcbsp *mcbsp; |
217 | int i; | ||
217 | int err; | 218 | int err; |
218 | 219 | ||
219 | if (!omap_mcbsp_check_valid_id(id)) { | 220 | if (!omap_mcbsp_check_valid_id(id)) { |
@@ -225,7 +226,8 @@ int omap_mcbsp_request(unsigned int id) | |||
225 | if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request) | 226 | if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request) |
226 | mcbsp->pdata->ops->request(id); | 227 | mcbsp->pdata->ops->request(id); |
227 | 228 | ||
228 | clk_enable(mcbsp->clk); | 229 | for (i = 0; i < mcbsp->num_clks; i++) |
230 | clk_enable(mcbsp->clks[i]); | ||
229 | 231 | ||
230 | spin_lock(&mcbsp->lock); | 232 | spin_lock(&mcbsp->lock); |
231 | if (!mcbsp->free) { | 233 | if (!mcbsp->free) { |
@@ -276,6 +278,7 @@ EXPORT_SYMBOL(omap_mcbsp_request); | |||
276 | void omap_mcbsp_free(unsigned int id) | 278 | void omap_mcbsp_free(unsigned int id) |
277 | { | 279 | { |
278 | struct omap_mcbsp *mcbsp; | 280 | struct omap_mcbsp *mcbsp; |
281 | int i; | ||
279 | 282 | ||
280 | if (!omap_mcbsp_check_valid_id(id)) { | 283 | if (!omap_mcbsp_check_valid_id(id)) { |
281 | printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); | 284 | printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); |
@@ -286,7 +289,8 @@ void omap_mcbsp_free(unsigned int id) | |||
286 | if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free) | 289 | if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free) |
287 | mcbsp->pdata->ops->free(id); | 290 | mcbsp->pdata->ops->free(id); |
288 | 291 | ||
289 | clk_disable(mcbsp->clk); | 292 | for (i = mcbsp->num_clks - 1; i >= 0; i--) |
293 | clk_disable(mcbsp->clks[i]); | ||
290 | 294 | ||
291 | spin_lock(&mcbsp->lock); | 295 | spin_lock(&mcbsp->lock); |
292 | if (mcbsp->free) { | 296 | if (mcbsp->free) { |
@@ -872,6 +876,7 @@ static int __devinit omap_mcbsp_probe(struct platform_device *pdev) | |||
872 | struct omap_mcbsp_platform_data *pdata = pdev->dev.platform_data; | 876 | struct omap_mcbsp_platform_data *pdata = pdev->dev.platform_data; |
873 | struct omap_mcbsp *mcbsp; | 877 | struct omap_mcbsp *mcbsp; |
874 | int id = pdev->id - 1; | 878 | int id = pdev->id - 1; |
879 | int i; | ||
875 | int ret = 0; | 880 | int ret = 0; |
876 | 881 | ||
877 | if (!pdata) { | 882 | if (!pdata) { |
@@ -916,14 +921,25 @@ static int __devinit omap_mcbsp_probe(struct platform_device *pdev) | |||
916 | mcbsp->dma_rx_sync = pdata->dma_rx_sync; | 921 | mcbsp->dma_rx_sync = pdata->dma_rx_sync; |
917 | mcbsp->dma_tx_sync = pdata->dma_tx_sync; | 922 | mcbsp->dma_tx_sync = pdata->dma_tx_sync; |
918 | 923 | ||
919 | if (pdata->clk_name) | 924 | if (pdata->num_clks) { |
920 | mcbsp->clk = clk_get(&pdev->dev, pdata->clk_name); | 925 | mcbsp->num_clks = pdata->num_clks; |
921 | if (IS_ERR(mcbsp->clk)) { | 926 | mcbsp->clks = kzalloc(mcbsp->num_clks * sizeof(struct clk *), |
922 | dev_err(&pdev->dev, | 927 | GFP_KERNEL); |
923 | "Invalid clock configuration for McBSP%d.\n", | 928 | if (!mcbsp->clks) { |
924 | mcbsp->id); | 929 | ret = -ENOMEM; |
925 | ret = PTR_ERR(mcbsp->clk); | 930 | goto exit; |
926 | goto err_clk; | 931 | } |
932 | for (i = 0; i < mcbsp->num_clks; i++) { | ||
933 | mcbsp->clks[i] = clk_get(&pdev->dev, pdata->clk_names[i]); | ||
934 | if (IS_ERR(mcbsp->clks[i])) { | ||
935 | dev_err(&pdev->dev, | ||
936 | "Invalid %s configuration for McBSP%d.\n", | ||
937 | pdata->clk_names[i], mcbsp->id); | ||
938 | ret = PTR_ERR(mcbsp->clks[i]); | ||
939 | goto err_clk; | ||
940 | } | ||
941 | } | ||
942 | |||
927 | } | 943 | } |
928 | 944 | ||
929 | mcbsp->pdata = pdata; | 945 | mcbsp->pdata = pdata; |
@@ -932,6 +948,9 @@ static int __devinit omap_mcbsp_probe(struct platform_device *pdev) | |||
932 | return 0; | 948 | return 0; |
933 | 949 | ||
934 | err_clk: | 950 | err_clk: |
951 | while (i--) | ||
952 | clk_put(mcbsp->clks[i]); | ||
953 | kfree(mcbsp->clks); | ||
935 | iounmap(mcbsp->io_base); | 954 | iounmap(mcbsp->io_base); |
936 | err_ioremap: | 955 | err_ioremap: |
937 | mcbsp->free = 0; | 956 | mcbsp->free = 0; |
@@ -942,6 +961,7 @@ exit: | |||
942 | static int __devexit omap_mcbsp_remove(struct platform_device *pdev) | 961 | static int __devexit omap_mcbsp_remove(struct platform_device *pdev) |
943 | { | 962 | { |
944 | struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); | 963 | struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); |
964 | int i; | ||
945 | 965 | ||
946 | platform_set_drvdata(pdev, NULL); | 966 | platform_set_drvdata(pdev, NULL); |
947 | if (mcbsp) { | 967 | if (mcbsp) { |
@@ -950,12 +970,18 @@ static int __devexit omap_mcbsp_remove(struct platform_device *pdev) | |||
950 | mcbsp->pdata->ops->free) | 970 | mcbsp->pdata->ops->free) |
951 | mcbsp->pdata->ops->free(mcbsp->id); | 971 | mcbsp->pdata->ops->free(mcbsp->id); |
952 | 972 | ||
953 | clk_disable(mcbsp->clk); | 973 | for (i = mcbsp->num_clks - 1; i >= 0; i--) { |
954 | clk_put(mcbsp->clk); | 974 | clk_disable(mcbsp->clks[i]); |
975 | clk_put(mcbsp->clks[i]); | ||
976 | } | ||
955 | 977 | ||
956 | iounmap(mcbsp->io_base); | 978 | iounmap(mcbsp->io_base); |
957 | 979 | ||
958 | mcbsp->clk = NULL; | 980 | if (mcbsp->num_clks) { |
981 | kfree(mcbsp->clks); | ||
982 | mcbsp->clks = NULL; | ||
983 | mcbsp->num_clks = 0; | ||
984 | } | ||
959 | mcbsp->free = 0; | 985 | mcbsp->free = 0; |
960 | mcbsp->dev = NULL; | 986 | mcbsp->dev = NULL; |
961 | } | 987 | } |