A spin_lock deadlock will occur when omap_mcbsp_request() is invoked. omap_mcbsp_request() --> clk_enable(mcbsp->clk) --> clk_enable get clockfw_lock, then call -> omap2_clk_enable() --> _omap2_clk_enable() --> omap_mcbsp_clk_enable() --> clk_enable(mcbsp_ick) --> now clk_enable acquire clockfw_lock again. The solution: If a alias clock has some relative clocks, enable relative clocks before enable the alias clock. Signed-off-by: Stanley.Miao <stanley.miao@xxxxxxxxxxxxx> --- arch/arm/mach-omap1/mcbsp.c | 67 ++++++------------------ arch/arm/mach-omap2/mcbsp.c | 88 +++++++----------------------- arch/arm/plat-omap/clock.c | 9 +++- arch/arm/plat-omap/include/mach/clock.h | 2 + 4 files changed, 47 insertions(+), 119 deletions(-) diff --git a/arch/arm/mach-omap1/mcbsp.c b/arch/arm/mach-omap1/mcbsp.c index 7de7c69..cf220be 100644 --- a/arch/arm/mach-omap1/mcbsp.c +++ b/arch/arm/mach-omap1/mcbsp.c @@ -26,80 +26,45 @@ #define DPS_RSTCT2_PER_EN (1 << 0) #define DSP_RSTCT2_WD_PER_EN (1 << 1) -struct mcbsp_internal_clk { - struct clk clk; - struct clk **childs; - int n_childs; -}; - #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) -static void omap_mcbsp_clk_init(struct mcbsp_internal_clk *mclk) +static void omap_mcbsp_clk_init(struct clk *mclk) { const char *clk_names[] = { "dsp_ck", "api_ck", "dspxor_ck" }; int i; - mclk->n_childs = ARRAY_SIZE(clk_names); - mclk->childs = kzalloc(mclk->n_childs * sizeof(struct clk *), + mclk->n_relatives = ARRAY_SIZE(clk_names); + mclk->relatives = kzalloc(mclk->n_relatives * sizeof(struct clk *), GFP_KERNEL); - for (i = 0; i < mclk->n_childs; i++) { + for (i = 0; i < mclk->n_relatives; i++) { /* We fake a platform device to get correct device id */ struct platform_device pdev; pdev.dev.bus = &platform_bus_type; - pdev.id = mclk->clk.id; - mclk->childs[i] = clk_get(&pdev.dev, clk_names[i]); - if (IS_ERR(mclk->childs[i])) + pdev.id = mclk->id; + mclk->relatives[i] = clk_get(&pdev.dev, clk_names[i]); + if (IS_ERR(mclk->relatives[i])) printk(KERN_ERR "Could not get clock %s (%d).\n", - clk_names[i], mclk->clk.id); + clk_names[i], mclk->id); } } -static int omap_mcbsp_clk_enable(struct clk *clk) -{ - struct mcbsp_internal_clk *mclk = container_of(clk, - struct mcbsp_internal_clk, clk); - int i; - - for (i = 0; i < mclk->n_childs; i++) - clk_enable(mclk->childs[i]); - return 0; -} - -static void omap_mcbsp_clk_disable(struct clk *clk) -{ - struct mcbsp_internal_clk *mclk = container_of(clk, - struct mcbsp_internal_clk, clk); - int i; - - for (i = 0; i < mclk->n_childs; i++) - clk_disable(mclk->childs[i]); -} - -static struct mcbsp_internal_clk omap_mcbsp_clks[] = { +static struct clk omap_mcbsp_clks[] = { { - .clk = { - .name = "mcbsp_clk", - .id = 1, - .enable = omap_mcbsp_clk_enable, - .disable = omap_mcbsp_clk_disable, - }, + .name = "mcbsp_clk", + .id = 1, }, { - .clk = { - .name = "mcbsp_clk", - .id = 3, - .enable = omap_mcbsp_clk_enable, - .disable = omap_mcbsp_clk_disable, - }, + .name = "mcbsp_clk", + .id = 3, }, }; #define omap_mcbsp_clks_size ARRAY_SIZE(omap_mcbsp_clks) #else #define omap_mcbsp_clks_size 0 -static struct mcbsp_internal_clk __initdata *omap_mcbsp_clks; -static inline void omap_mcbsp_clk_init(struct mcbsp_internal_clk *mclk) +static struct clk __initdata *omap_mcbsp_clks; +static inline void omap_mcbsp_clk_init(struct clk *mclk) { } #endif @@ -233,7 +198,7 @@ int __init omap1_mcbsp_init(void) for (i = 0; i < omap_mcbsp_clks_size; i++) { if (cpu_is_omap15xx() || cpu_is_omap16xx()) { omap_mcbsp_clk_init(&omap_mcbsp_clks[i]); - clk_register(&omap_mcbsp_clks[i].clk); + clk_register(&omap_mcbsp_clks[i]); } } diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c index cae3ebe..20663e1 100644 --- a/arch/arm/mach-omap2/mcbsp.c +++ b/arch/arm/mach-omap2/mcbsp.c @@ -22,103 +22,57 @@ #include <mach/cpu.h> #include <mach/mcbsp.h> -struct mcbsp_internal_clk { - struct clk clk; - struct clk **childs; - int n_childs; -}; - #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) -static void omap_mcbsp_clk_init(struct mcbsp_internal_clk *mclk) +static void omap_mcbsp_clk_init(struct clk *mclk) { const char *clk_names[] = { "mcbsp_ick", "mcbsp_fck" }; int i; - mclk->n_childs = ARRAY_SIZE(clk_names); - mclk->childs = kzalloc(mclk->n_childs * sizeof(struct clk *), + mclk->n_relatives = ARRAY_SIZE(clk_names); + mclk->relatives = kzalloc(mclk->n_relatives * sizeof(struct clk *), GFP_KERNEL); - for (i = 0; i < mclk->n_childs; i++) { + for (i = 0; i < mclk->n_relatives; i++) { /* We fake a platform device to get correct device id */ struct platform_device pdev; pdev.dev.bus = &platform_bus_type; - pdev.id = mclk->clk.id; - mclk->childs[i] = clk_get(&pdev.dev, clk_names[i]); - if (IS_ERR(mclk->childs[i])) + pdev.id = mclk->id; + mclk->relatives[i] = clk_get(&pdev.dev, clk_names[i]); + if (IS_ERR(mclk->relatives[i])) printk(KERN_ERR "Could not get clock %s (%d).\n", - clk_names[i], mclk->clk.id); + clk_names[i], mclk->id); } } -static int omap_mcbsp_clk_enable(struct clk *clk) -{ - struct mcbsp_internal_clk *mclk = container_of(clk, - struct mcbsp_internal_clk, clk); - int i; - - for (i = 0; i < mclk->n_childs; i++) - clk_enable(mclk->childs[i]); - return 0; -} - -static void omap_mcbsp_clk_disable(struct clk *clk) -{ - struct mcbsp_internal_clk *mclk = container_of(clk, - struct mcbsp_internal_clk, clk); - int i; - - for (i = 0; i < mclk->n_childs; i++) - clk_disable(mclk->childs[i]); -} -static struct mcbsp_internal_clk omap_mcbsp_clks[] = { +static struct clk omap_mcbsp_clks[] = { { - .clk = { - .name = "mcbsp_clk", - .id = 1, - .enable = omap_mcbsp_clk_enable, - .disable = omap_mcbsp_clk_disable, - }, + .name = "mcbsp_clk", + .id = 1, }, { - .clk = { - .name = "mcbsp_clk", - .id = 2, - .enable = omap_mcbsp_clk_enable, - .disable = omap_mcbsp_clk_disable, - }, + .name = "mcbsp_clk", + .id = 2, }, { - .clk = { - .name = "mcbsp_clk", - .id = 3, - .enable = omap_mcbsp_clk_enable, - .disable = omap_mcbsp_clk_disable, - }, + .name = "mcbsp_clk", + .id = 3, }, { - .clk = { - .name = "mcbsp_clk", - .id = 4, - .enable = omap_mcbsp_clk_enable, - .disable = omap_mcbsp_clk_disable, - }, + .name = "mcbsp_clk", + .id = 4, }, { - .clk = { - .name = "mcbsp_clk", - .id = 5, - .enable = omap_mcbsp_clk_enable, - .disable = omap_mcbsp_clk_disable, - }, + .name = "mcbsp_clk", + .id = 5, }, }; #define omap_mcbsp_clks_size ARRAY_SIZE(omap_mcbsp_clks) #else #define omap_mcbsp_clks_size 0 -static struct mcbsp_internal_clk __initdata *omap_mcbsp_clks; +static struct clk __initdata *omap_mcbsp_clks; static inline void omap_mcbsp_clk_init(struct clk *clk) { } #endif @@ -287,7 +241,7 @@ static int __init omap2_mcbsp_init(void) for (i = 0; i < omap_mcbsp_clks_size; i++) { /* Once we call clk_get inside init, we do not register it */ omap_mcbsp_clk_init(&omap_mcbsp_clks[i]); - clk_register(&omap_mcbsp_clks[i].clk); + clk_register(&omap_mcbsp_clks[i]); } if (cpu_is_omap2420()) diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c index d13acd2..1c4f877 100644 --- a/arch/arm/plat-omap/clock.c +++ b/arch/arm/plat-omap/clock.c @@ -77,11 +77,14 @@ EXPORT_SYMBOL(clk_get); int clk_enable(struct clk *clk) { unsigned long flags; - int ret = 0; + int i, ret = 0; if (clk == NULL || IS_ERR(clk)) return -EINVAL; + for (i = 0; i < clk->n_relatives; i++) + clk_enable(clk->relatives[i]); + spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_enable) ret = arch_clock->clk_enable(clk); @@ -94,10 +97,14 @@ EXPORT_SYMBOL(clk_enable); void clk_disable(struct clk *clk) { unsigned long flags; + int i; if (clk == NULL || IS_ERR(clk)) return; + for (i = 0; i < clk->n_relatives; i++) + clk_disable(clk->relatives[i]); + spin_lock_irqsave(&clockfw_lock, flags); if (clk->usecount == 0) { printk(KERN_ERR "Trying disable clock %s with 0 usecount\n", diff --git a/arch/arm/plat-omap/include/mach/clock.h b/arch/arm/plat-omap/include/mach/clock.h index 9088925..2760bcf 100644 --- a/arch/arm/plat-omap/include/mach/clock.h +++ b/arch/arm/plat-omap/include/mach/clock.h @@ -71,6 +71,8 @@ struct clk { __u8 enable_bit; __s8 usecount; u8 idlest_bit; + struct clk **relatives; + int n_relatives; void (*recalc)(struct clk *); int (*set_rate)(struct clk *, unsigned long); long (*round_rate)(struct clk *, unsigned long); -- 1.5.6.3 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html