On Thu, Jan 29, 2009 at 03:14:01PM +0000, Russell King - ARM Linux wrote:
> On Wed, Jan 28, 2009 at 12:27:59PM -0700, Paul Walmsley wrote:
> > The price paid is additional runtime memory consumption - 8 bytes per
> > clock and 16 bytes per child clock - roughly 4.5KiB on OMAP3.
> 
> For OMAP3, that's 222 struct clks of which 182 are children, and indeed
> 222 * 8 + 182 * 16 gives about 4.5K.  On OMAP2, it's 140 and 136,
> giving 140 * 8 + 136 * 16 = 3.3K.
> 
> Moving struct clk_child into struct clk means that its clk and flags
> members can be deleted, making it 8 bytes in size - effectively just
> the list_head.  We need a list_head for the 'children' as you have it.
> So, that works out as 16 bytes per clock.  That gives 3.5K on OMAP3
> and 2.2K on OMAP2.
> 
> So, by taking that alternative approach, not only do you end up using
> less memory, but you also don't have to have the overhead of your
> custom memory bookkeeping.
> 
> The other change I'd suggest is that you have one function which deals
> with setting the parent of a clock:
> 
> void clk_reparent(struct clk *child, struct clk *parent)
> {
>       list_del_init(&child->sibling);
>       if (parent)
>               list_add(&child->sibling, &parent->children);
>       child->parent = parent;
> 
>       /* now do the debugfs renaming to reattach the child
>          to the proper parent */
> }
> 
> which is a lot simpler than your omap_clk_add_child() and 
> omap_clk_del_child().
> 
> These should be in the _core_ OMAP clock code, not just in the OMAP2
> clock code.  OMAP1 has child clocks as well as OMAP2.

And here is my version of this patch:

 arch/arm/mach-omap2/clock.c             |    4 +-
 arch/arm/plat-omap/clock.c              |   49 +++++++++++++++++++------------
 arch/arm/plat-omap/include/mach/clock.h |    3 ++
 3 files changed, 35 insertions(+), 21 deletions(-)

diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index 56d9ea4..14bf566 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -175,7 +175,7 @@ void omap2_init_clksel_parent(struct clk *clk)
                                                 clk->name, clks->parent->name,
                                                 ((clk->parent) ?
                                                  clk->parent->name : "NULL"));
-                                       clk->parent = clks->parent;
+                                       clk_reparent(clk, clks->parent);
                                };
                                found = 1;
                        }
@@ -780,7 +780,7 @@ int omap2_clk_set_parent(struct clk *clk, struct clk 
*new_parent)
        if (clk->usecount > 0)
                _omap2_clk_enable(clk);
 
-       clk->parent = new_parent;
+       clk_reparent(clk, new_parent);
 
        /* CLKSEL clocks follow their parents' rates, divided by a divisor */
        clk->rate = new_parent->rate;
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index 3688400..58e42b1 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -127,8 +127,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
        if (ret == 0) {
                if (clk->recalc)
                        clk->recalc(clk);
-               if (clk->flags & RATE_PROPAGATES)
-                       propagate_rate(clk);
+               propagate_rate(clk);
        }
        spin_unlock_irqrestore(&clockfw_lock, flags);
 
@@ -150,8 +149,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
        if (ret == 0) {
                if (clk->recalc)
                        clk->recalc(clk);
-               if (clk->flags & RATE_PROPAGATES)
-                       propagate_rate(clk);
+               propagate_rate(clk);
        }
        spin_unlock_irqrestore(&clockfw_lock, flags);
 
@@ -192,27 +190,34 @@ void followparent_recalc(struct clk *clk)
        clk->rate = clk->parent->rate;
 }
 
+void clk_reparent(struct clk *child, struct clk *parent)
+{
+       list_del_init(&child->sibling);
+       if (parent)
+               list_add(&child->sibling, &parent->children);
+       child->parent = parent;
+
+       /* now do the debugfs renaming to reattach the child
+          to the proper parent */
+}
+
 /* Propagate rate to children */
 void propagate_rate(struct clk * tclk)
 {
        struct clk *clkp;
 
-       if (tclk == NULL || IS_ERR(tclk))
-               return;
-
-       list_for_each_entry(clkp, &clocks, node) {
-               if (likely(clkp->parent != tclk))
-                       continue;
+       list_for_each_entry(clkp, &tclk->children, sibling) {
                if (clkp->recalc) {
                        unsigned long old_rate = clkp->rate;
                        clkp->recalc(clkp);
-                       if (clkp->rate != old_rate &&
-                           (clkp->flags & RATE_PROPAGATES))
+                       if (clkp->rate != old_rate)
                                propagate_rate(clkp);
                }
        }
 }
 
+static LIST_HEAD(root_clks);
+
 /**
  * recalculate_root_clocks - recalculate and propagate all root clocks
  *
@@ -224,13 +229,10 @@ void recalculate_root_clocks(void)
 {
        struct clk *clkp;
 
-       list_for_each_entry(clkp, &clocks, node) {
-               if (!clkp->parent) {
-                       if (clkp->recalc)
-                               clkp->recalc(clkp);
-                       if (clkp->flags & RATE_PROPAGATES)
-                               propagate_rate(clkp);
-               }
+       list_for_each_entry(clkp, &root_clks, sibling) {
+               if (clkp->recalc)
+                       clkp->recalc(clkp);
+               propagate_rate(clkp);
        }
 }
 
@@ -246,6 +248,15 @@ int clk_register(struct clk *clk)
                return 0;
 
        mutex_lock(&clocks_mutex);
+       if (!clk->children.next)
+               INIT_LIST_HEAD(&clk->children);
+       if (clk->parent && !clk->parent->children.next)
+               INIT_LIST_HEAD(&clk->parent->children);
+       if (clk->parent)
+               list_add(&clk->sibling, &clk->parent->children);
+       else
+               list_add(&clk->sibling, &root_clks);
+
        list_add(&clk->node, &clocks);
        if (clk->init)
                clk->init(clk);
diff --git a/arch/arm/plat-omap/include/mach/clock.h 
b/arch/arm/plat-omap/include/mach/clock.h
index ad0345f..3504c2b 100644
--- a/arch/arm/plat-omap/include/mach/clock.h
+++ b/arch/arm/plat-omap/include/mach/clock.h
@@ -70,6 +70,8 @@ struct clk {
        const char              *name;
        int                     id;
        struct clk              *parent;
+       struct list_head        children;
+       struct list_head        sibling;        /* node for children */
        unsigned long           rate;
        __u32                   flags;
        void __iomem            *enable_reg;
@@ -116,6 +118,7 @@ extern unsigned int mpurate;
 
 extern int clk_init(struct clk_functions *custom_clocks);
 extern int clk_register(struct clk *clk);
+extern void clk_reparent(struct clk *child, struct clk *parent);
 extern void clk_unregister(struct clk *clk);
 extern void propagate_rate(struct clk *clk);
 extern void recalculate_root_clocks(void);
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to