This solution keeps the virtual clock in place and enable the child clocks before enable the virtual clock. So, any comments ? Stanley. On Thu, 2008-11-06 at 20:44 +0800, Stanley.Miao wrote: > 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); -- 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