All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] OMAP clock: implement clock rate/parent change notifiers
@ 2009-03-25 16:09 Paul Walmsley
  2009-03-25 16:09 ` [PATCH 1/2] OMAP clock: add clk_round_rate_parent (with OMAP2/3 implementation) Paul Walmsley
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Paul Walmsley @ 2009-03-25 16:09 UTC (permalink / raw)
  To: linux-omap

Hello,

This series allows core code and driver code to register for
notification when a clock's rate or parent changes.  This is currently
used by driver code that must be notified whenever power management
code (e.g., CPUFreq) causes system rate changes that affect the driver's
clock.

There are three notifier messages: 

1. a pre-change notifier, called before the change; 

2. a post-change notifier, called after the change; and

3. an abort notifier, called if the change fails for any reason after
   the pre-change notifier callbacks have run.

Since the implementation uses a blocking notifier, notifier code may
block waiting for devices to quiesce; but long delays here will reduce
the effectiveness of DVFS.  Since notifier callbacks are called with
clocks_mutex held, callback code must not re-enter the clock framework.

Pre-change notifiers are passed the current clock rate and the desired
clock rate, so drivers can adjust any internal dividers appropriately.
(To minimize performance and memory usage impact, post-change
notifiers are passed only the desired clock rate, i.e., the clock rate
after the rate change.)  The notifiers are called even if the clock
rate is the same before and after the change.  This is because
reprogramming a clock's parent or rate may briefly disrupt the clock.

The interface to the notifiers is via:

int clk_notifier_register(struct clk *clk, struct notifier_block *nb);
int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);

Until prototypes for these functions are made available in
include/linux/clk.h, drivers should pass function pointers to
clk_notifier_register() and clk_notifier_unregister() via their
platform_data struct.

This series is a collaboration between Tero Kristo
<tero.kristo@nokia.com> and Paul Walmsley <paul@pwsan.com> and several
others. Hiroshi Doyu <Hiroshi.DOYU@nokia.com> tracked down and fixed a
bug where blocking_notifier_chain_*() were called while interrupts
were disabled.  Nishanth Menon <nm@ti.com> found and fixed a bug in
the clk_notifier_unregister() path, where a list_del() was missing.
And thanks to Jouni Högander <jouni.hogander@nokia.com> for comments
and review during the evolution of these patches.

Registration and callbacks on rate change and parent change tested on
BeagleBoard (OMAP3530 ES2.1).

Comments welcomed.

---

   text    data     bss     dec     hex filename
3439981  175136  111800 3726917  38de45 vmlinux.beagle.orig
3441545  176000  111800 3729345  38e7c1 vmlinux.beagle


 arch/arm/mach-omap2/clock.c             |   30 ++++
 arch/arm/mach-omap2/clock.h             |    1 
 arch/arm/mach-omap2/clock24xx.c         |    1 
 arch/arm/mach-omap2/clock34xx.c         |    1 
 arch/arm/plat-omap/clock.c              |  256 +++++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/mach/clock.h |   68 ++++++++
 6 files changed, 357 insertions(+), 0 deletions(-)


--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/2] OMAP clock: add clk_round_rate_parent (with OMAP2/3 implementation)
  2009-03-25 16:09 [PATCH 0/2] OMAP clock: implement clock rate/parent change notifiers Paul Walmsley
@ 2009-03-25 16:09 ` Paul Walmsley
  2009-03-25 16:09 ` [PATCH 2/2] OMAP2/3 clock: implement clock rate/parent change notifiers Paul Walmsley
  2009-03-25 17:54 ` [PATCH 0/2] OMAP " Kevin Hilman
  2 siblings, 0 replies; 7+ messages in thread
From: Paul Walmsley @ 2009-03-25 16:09 UTC (permalink / raw)
  To: linux-omap; +Cc: Paul Walmsley

This patch adds clk_round_rate_parent(), a means for internal clock
code to determine what a clock's rate would be if its parent changed.
This is needed by the pre-change clock notifier, which passes the
current clock rate and the desired clock rate to its callbacks.

An implementation is provided for the OMAP2/3 architecture
(omap2_clk_round_rate_parent)..

Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
 arch/arm/mach-omap2/clock.c             |   30 ++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/clock.h             |    1 +
 arch/arm/mach-omap2/clock24xx.c         |    1 +
 arch/arm/mach-omap2/clock34xx.c         |    1 +
 arch/arm/plat-omap/include/mach/clock.h |    2 ++
 5 files changed, 35 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index 41662fd..65391ba 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -871,6 +871,36 @@ struct clk *omap2_clk_get_parent(struct clk *clk)
 	return clk->parent;
 }
 
+/**
+ * omap2_clk_round_rate_parent - return the rate for @clk if parent were changed
+ * @clk: struct clk that may change parents
+ * @new_parent: the struct clk that @clk may be reparented under
+ *
+ * Given a struct clk @clk and a new parent struct clk @new_parent,
+ * determine what @clk's rate would be after the reparent operation.
+ * Returns the new clock rate or -EINVAL upon error.
+ */
+long omap2_clk_round_rate_parent(struct clk *clk, struct clk *new_parent)
+{
+	u32 field_val, parent_div;
+	long rate;
+
+	if (!clk->clksel || !new_parent)
+		return -EINVAL;
+
+	parent_div = _omap2_clksel_get_src_field(new_parent, clk, &field_val);
+	if (!parent_div)
+		return -EINVAL;
+
+	/* CLKSEL clocks follow their parents' rates, divided by a divisor */
+	rate = new_parent->rate;
+	if (parent_div > 0)
+		rate /= parent_div;
+
+	return rate;
+}
+
+
 /* DPLL rate rounding code */
 
 /**
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
index f4d489f..af350ed 100644
--- a/arch/arm/mach-omap2/clock.h
+++ b/arch/arm/mach-omap2/clock.h
@@ -41,6 +41,7 @@ int omap2_clk_register(struct clk *clk);
 int omap2_clk_enable(struct clk *clk);
 void omap2_clk_disable(struct clk *clk);
 long omap2_clk_round_rate(struct clk *clk, unsigned long rate);
+long omap2_clk_round_rate_parent(struct clk *clk, struct clk *new_parent);
 int omap2_clk_set_rate(struct clk *clk, unsigned long rate);
 int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent);
 int omap2_dpll_set_rate_tolerance(struct clk *clk, unsigned int tolerance);
diff --git a/arch/arm/mach-omap2/clock24xx.c b/arch/arm/mach-omap2/clock24xx.c
index 53864c0..3f75524 100644
--- a/arch/arm/mach-omap2/clock24xx.c
+++ b/arch/arm/mach-omap2/clock24xx.c
@@ -448,6 +448,7 @@ static struct clk_functions omap2_clk_functions = {
 	.clk_enable		= omap2_clk_enable,
 	.clk_disable		= omap2_clk_disable,
 	.clk_round_rate		= omap2_clk_round_rate,
+	.clk_round_rate_parent	= omap2_clk_round_rate_parent,
 	.clk_set_rate		= omap2_clk_set_rate,
 	.clk_set_parent		= omap2_clk_set_parent,
 	.clk_get_parent		= omap2_clk_get_parent,
diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c
index f7ac5c1..12ff39f 100644
--- a/arch/arm/mach-omap2/clock34xx.c
+++ b/arch/arm/mach-omap2/clock34xx.c
@@ -635,6 +635,7 @@ static struct clk_functions omap2_clk_functions = {
 	.clk_enable		= omap2_clk_enable,
 	.clk_disable		= omap2_clk_disable,
 	.clk_round_rate		= omap2_clk_round_rate,
+	.clk_round_rate_parent	= omap2_clk_round_rate_parent,
 	.clk_set_rate		= omap2_clk_set_rate,
 	.clk_set_parent		= omap2_clk_set_parent,
 	.clk_get_parent		= omap2_clk_get_parent,
diff --git a/arch/arm/plat-omap/include/mach/clock.h b/arch/arm/plat-omap/include/mach/clock.h
index db57b71..89a2662 100644
--- a/arch/arm/plat-omap/include/mach/clock.h
+++ b/arch/arm/plat-omap/include/mach/clock.h
@@ -121,6 +121,8 @@ struct clk_functions {
 	int		(*clk_enable)(struct clk *clk);
 	void		(*clk_disable)(struct clk *clk);
 	long		(*clk_round_rate)(struct clk *clk, unsigned long rate);
+	long		(*clk_round_rate_parent)(struct clk *clk,
+						 struct clk *parent);
 	int		(*clk_set_rate)(struct clk *clk, unsigned long rate);
 	int		(*clk_set_parent)(struct clk *clk, struct clk *parent);
 	struct clk *	(*clk_get_parent)(struct clk *clk);



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] OMAP2/3 clock: implement clock rate/parent change notifiers
  2009-03-25 16:09 [PATCH 0/2] OMAP clock: implement clock rate/parent change notifiers Paul Walmsley
  2009-03-25 16:09 ` [PATCH 1/2] OMAP clock: add clk_round_rate_parent (with OMAP2/3 implementation) Paul Walmsley
@ 2009-03-25 16:09 ` Paul Walmsley
  2009-03-25 17:54 ` [PATCH 0/2] OMAP " Kevin Hilman
  2 siblings, 0 replies; 7+ messages in thread
From: Paul Walmsley @ 2009-03-25 16:09 UTC (permalink / raw)
  To: linux-omap
  Cc: Tero Kristo, Paul Walmsley, Hiroshi DOYU, Nishanth Menon,
	Jouni Högander

This patch allows core code and driver code to register for
notification when a clock's rate or parent changes.  These are useful
because drivers don't have exclusive control over a clock's rate:
power management code (e.g., CPUFreq) may cause rate changes across
large parts of the clock tree.

There are three notifier messages:

1. a pre-change notifier, called before the change;

2. a post-change notifier, called after the change; and

3. an abort notifier, called if the change fails for any reason after
   the pre-change notifier callbacks have run.

Since the implementation uses a blocking notifier, notifier code may
block waiting for devices to quiesce; but long delays here will reduce
the effectiveness of DVFS.  Since notifier callbacks are called with
clocks_mutex held, callback code must not re-enter the clock framework.

Pre-change notifiers are passed the current clock rate and the
desired clock rate.  (To minimize performance and memory usage impact,
post-change notifiers are passed only the desired clock rate, i.e.,
the clock rate after the rate change.)  The notifiers are called even
if the clock rate is the same before and after the change.  This is
because reprogramming a clock's parent or rate may briefly disrupt the
clock.

There are likely to be few users of these notifiers, compared to the
total number of clocks.  So, rather than storing one notifier per
struct clk, notifiers are stored in a separate, dynamically allocated
list, effectively trading execution speed (in terms of a sequential
scan of the notifier list) for memory savings.  The implementation is
completely hidden from the callbacks and can be easily changed.

Until prototypes for these functions are made available in
include/linux/clk.h, drivers should pass function pointers to
clk_notifier_register() and clk_notifier_unregister() via their
platform_data struct.

This patch is a collaboration between Tero Kristo
<tero.kristo@nokia.com> and Paul Walmsley <paul@pwsan.com> and several
others. Hiroshi Doyu <Hiroshi.DOYU@nokia.com> tracked down and fixed a
bug where blocking_notifier_chain_*() were called while interrupts
were disabled.  Nishanth Menon <nm@ti.com> found and fixed a bug in
the clk_notifier_unregister() path, where a list_del() was missing.
And thanks to Jouni Högander <jouni.hogander@nokia.com> for comments
and review during the evolution of these patches.

Signed-off-by: Tero Kristo <tero.kristo@nokia.com>
Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
Cc: Nishanth Menon <nm@ti.com>
Cc: Jouni Högander <jouni.hogander@nokia.com>
---
 arch/arm/plat-omap/clock.c              |  256 +++++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/mach/clock.h |   66 ++++++++
 2 files changed, 322 insertions(+), 0 deletions(-)

diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index bdf2cd4..eb354ec 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -21,6 +21,7 @@
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
 #include <linux/cpufreq.h>
+#include <linux/notifier.h>
 #include <linux/debugfs.h>
 #include <linux/io.h>
 #include <linux/bootmem.h>
@@ -34,6 +35,8 @@ static DEFINE_SPINLOCK(clockfw_lock);
 
 static struct clk_functions *arch_clock;
 
+static LIST_HEAD(clk_notifier_list);
+
 /**
  * omap_clk_for_each_child - call callback on each child clock of clk
  * @clk: struct clk * to use as the "parent"
@@ -95,6 +98,19 @@ static int _do_propagate_rate(struct clk *clk, unsigned long parent_rate,
 }
 
 /**
+ * _clk_free_notifier_chain - safely remove struct clk_notifier
+ * @cn: struct clk_notifier *
+ *
+ * Removes the struct clk_notifier @cn from the clk_notifier_list and
+ * frees it.
+ */
+static void _clk_free_notifier_chain(struct clk_notifier *cn)
+{
+	list_del(&cn->node);
+	kfree(cn);
+}
+
+/**
  * omap_clk_add_child - add a child clock @clk2 to @clk
  * @clk: parent struct clk *
  * @clk2: new child struct clk *
@@ -170,6 +186,101 @@ void omap_clk_del_child(struct clk *clk, struct clk *clk2)
 	}
 }
 
+/**
+ * omap_clk_notify - call clk notifier chain
+ * @clk: struct clk * that is changing rate
+ * @msg: clk notifier type (i.e., CLK_POST_RATE_CHANGE; see mach/clock.h)
+ * @old_rate: old rate
+ * @new_rate: new rate
+ *
+ * Triggers a notifier call chain on the post-clk-rate-change notifier
+ * for clock 'clk'.  Passes a pointer to the struct clk and the
+ * previous and current rates to the notifier callback.  Intended to be
+ * called by internal clock code only.  No return value.
+ */
+static void omap_clk_notify(struct clk *clk, unsigned long msg,
+			    unsigned long old_rate, unsigned long new_rate)
+{
+	struct clk_notifier *cn;
+	struct clk_notifier_data cnd;
+
+	cnd.clk = clk;
+	cnd.old_rate = old_rate;
+	cnd.new_rate = new_rate;
+
+	list_for_each_entry(cn, &clk_notifier_list, node) {
+		if (cn->clk == clk) {
+			blocking_notifier_call_chain(&cn->notifier_head, msg,
+						     &cnd);
+			break;
+		}
+	}
+}
+
+/**
+ * omap_clk_notify_downstream - trigger clock change notifications
+ * @clk: struct clk * to start the notifications with
+ * @msg: notifier msg - see "Clk notifier callback types" in mach/clock.h
+ * @param2: (not used - any u8 will do)
+ *
+ * Call clock change notifiers on clocks starting with @clk and including
+ * all of @clk's downstream children clocks.  Returns NOTIFY_DONE.
+ */
+static int omap_clk_notify_downstream(struct clk *clk, unsigned long msg,
+				      u8 param2)
+{
+	if (!clk->notifier_count)
+		return NOTIFY_DONE;
+
+	omap_clk_notify(clk, msg, clk->rate, clk->temp_rate);
+
+	if (!omap_clk_has_children(clk))
+		return NOTIFY_DONE;
+
+	return omap_clk_for_each_child(clk, msg, 0, omap_clk_notify_downstream);
+}
+
+
+/**
+ * _clk_pre_notify_set_parent - handle pre-notification for clk_set_parent()
+ * @clk: struct clk * changing parent
+ *
+ * When @clk is ready to change its parent, handle pre-notification.
+ * If the architecture does not have an
+ * arch_clock->clk_round_rate_parent() defined, this code will be unable
+ * to verify that the selected parent is valid, and also unable to pass the
+ * post-parent-change clock rate to the notifier.  Returns any error from
+ * clk_round_rate_parent() or 0 upon success.
+ */
+static int _clk_pre_notify_set_parent(struct clk *clk, struct clk *parent)
+{
+	long rate;
+
+	if (!clk->notifier_count)
+		return 0;
+
+	if (!arch_clock->clk_round_rate_parent) {
+		pr_warning("clock: clk_set_parent(): WARNING: "
+			   "clk_round_rate_parent() undefined: pre-notifiers "
+			   "will get bogus rate\n");
+
+		rate = 0;
+	} else {
+		rate = arch_clock->clk_round_rate_parent(clk, parent);
+	};
+
+	if (IS_ERR_VALUE(rate))
+		return rate;
+
+	clk->temp_rate = rate;
+	propagate_rate(clk, TEMP_RATE);
+
+	omap_clk_notify_downstream(clk, CLK_PRE_RATE_CHANGE, 0);
+
+	return 0;
+}
+
+
 /*-------------------------------------------------------------------------
  * Standard clock functions defined in include/linux/clk.h
  *-------------------------------------------------------------------------*/
@@ -306,10 +417,20 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
 {
 	unsigned long flags;
 	int ret = -EINVAL;
+	int msg;
 
 	if (clk == NULL || IS_ERR(clk))
 		return ret;
 
+	mutex_lock(&clocks_mutex);
+
+	if (clk->notifier_count) {
+		clk->temp_rate = rate;
+		propagate_rate(clk, TEMP_RATE);
+
+		omap_clk_notify_downstream(clk, CLK_PRE_RATE_CHANGE, 0);
+	}
+
 	spin_lock_irqsave(&clockfw_lock, flags);
 
 	if (arch_clock->clk_set_rate) {
@@ -321,6 +442,12 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
 
 	spin_unlock_irqrestore(&clockfw_lock, flags);
 
+	msg = (ret) ? CLK_ABORT_RATE_CHANGE : CLK_POST_RATE_CHANGE;
+
+	omap_clk_notify_downstream(clk, msg, 0);
+
+	mutex_unlock(&clocks_mutex);
+
 	return ret;
 }
 EXPORT_SYMBOL(clk_set_rate);
@@ -330,10 +457,17 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
 	unsigned long flags;
 	struct clk *prev_parent;
 	int ret = -EINVAL;
+	int msg;
 
 	if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
 		return ret;
 
+	mutex_lock(&clocks_mutex);
+
+	ret = _clk_pre_notify_set_parent(clk, parent);
+	if (IS_ERR_VALUE(ret))
+		goto csp_out;
+
 	spin_lock_irqsave(&clockfw_lock, flags);
 
 	if (arch_clock->clk_set_parent) {
@@ -349,6 +483,13 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
 
 	spin_unlock_irqrestore(&clockfw_lock, flags);
 
+	msg = (ret) ? CLK_ABORT_RATE_CHANGE : CLK_POST_RATE_CHANGE;
+
+	omap_clk_notify_downstream(clk, msg, 0);
+
+csp_out:
+	mutex_unlock(&clocks_mutex);
+
 	return ret;
 }
 EXPORT_SYMBOL(clk_set_parent);
@@ -535,6 +676,121 @@ void clk_init_cpufreq_table(struct cpufreq_frequency_table **table)
 EXPORT_SYMBOL(clk_init_cpufreq_table);
 #endif
 
+/* Clk notifier implementation */
+
+/**
+ * clk_notifier_register - add a clock parameter change notifier
+ * @clk: struct clk * to watch
+ * @nb: struct notifier_block * with callback info
+ *
+ * Request notification for changes to the clock 'clk'.  This uses a
+ * blocking notifier.  Callback code must not call into the clock
+ * framework, as clocks_mutex is held.  Pre-notifier callbacks will be
+ * passed the previous and new rate of the clock.
+ *
+ * clk_notifier_register() must be called from process
+ * context.  Returns -EINVAL if called with null arguments, -ENOMEM
+ * upon allocation failure; otherwise, passes along the return value
+ * of blocking_notifier_chain_register().
+ */
+int clk_notifier_register(struct clk *clk, struct notifier_block *nb)
+{
+	struct clk_notifier *cn = NULL, *cn_new = NULL;
+	int r;
+	struct clk *clkp;
+
+	if (!clk || !nb)
+		return -EINVAL;
+
+	mutex_lock(&clocks_mutex);
+
+	list_for_each_entry(cn, &clk_notifier_list, node)
+		if (cn->clk == clk)
+			break;
+
+	if (cn->clk != clk) {
+		cn_new = kzalloc(sizeof(struct clk_notifier), GFP_KERNEL);
+		if (!cn_new) {
+			r = -ENOMEM;
+			goto cnr_out;
+		};
+
+		cn_new->clk = clk;
+		BLOCKING_INIT_NOTIFIER_HEAD(&cn_new->notifier_head);
+
+		list_add(&cn_new->node, &clk_notifier_list);
+		cn = cn_new;
+	}
+
+	r = blocking_notifier_chain_register(&cn->notifier_head, nb);
+	if (!IS_ERR_VALUE(r)) {
+		clkp = clk;
+		do {
+			clkp->notifier_count++;
+		} while ((clkp = clkp->parent));
+	} else {
+		if (cn_new)
+			_clk_free_notifier_chain(cn);
+	}
+
+cnr_out:
+	mutex_unlock(&clocks_mutex);
+
+	return r;
+}
+
+/**
+ * clk_notifier_unregister - remove a clock change notifier
+ * @clk: struct clk *
+ * @nb: struct notifier_block * with callback info
+ *
+ * Request no further notification for changes to clock 'clk'.
+ * Returns -EINVAL if called with null arguments; otherwise, passes
+ * along the return value of blocking_notifier_chain_unregister().
+ */
+int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
+{
+	struct clk_notifier *cn = NULL;
+	struct clk *clkp;
+	int r = -EINVAL;
+
+	if (!clk || !nb)
+		return -EINVAL;
+
+	mutex_lock(&clocks_mutex);
+
+	list_for_each_entry(cn, &clk_notifier_list, node)
+		if (cn->clk == clk)
+			break;
+
+	if (cn->clk != clk) {
+		r = -ENOENT;
+		goto cnu_out;
+	};
+
+	r = blocking_notifier_chain_unregister(&cn->notifier_head, nb);
+	if (!IS_ERR_VALUE(r)) {
+		clkp = clk;
+		do {
+			clkp->notifier_count--;
+		} while ((clkp = clkp->parent));
+	}
+
+	/*
+	 * XXX ugh, layering violation.  There should be some
+	 * support in the notifier code for this.
+	 */
+	if (!cn->notifier_head.head)
+		_clk_free_notifier_chain(cn);
+
+cnu_out:
+	mutex_unlock(&clocks_mutex);
+
+	return r;
+}
+
+
+
 /*-------------------------------------------------------------------------*/
 
 #ifdef CONFIG_OMAP_RESET_CLOCKS
diff --git a/arch/arm/plat-omap/include/mach/clock.h b/arch/arm/plat-omap/include/mach/clock.h
index 89a2662..3927781 100644
--- a/arch/arm/plat-omap/include/mach/clock.h
+++ b/arch/arm/plat-omap/include/mach/clock.h
@@ -10,6 +10,8 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/notifier.h>
+
 #ifndef __ARCH_ARM_OMAP_CLOCK_H
 #define __ARCH_ARM_OMAP_CLOCK_H
 
@@ -75,6 +77,40 @@ struct clk_child {
 	u8			flags;
 };
 
+/**
+ * struct clk_notifier - associate a clk with a notifier
+ * @clk: struct clk * to associate the notifier with
+ * @notifier_head: a blocking_notifier_head for this clk
+ * @node: linked list pointers
+ *
+ * A list of struct clk_notifier is maintained by the notifier code.
+ * An entry is created whenever code registers the first notifier on a
+ * particular @clk.  Future notifiers on that @clk are added to the
+ * @notifier_head.
+ */
+struct clk_notifier {
+	struct clk			*clk;
+	struct blocking_notifier_head	notifier_head;
+	struct list_head		node;
+};
+
+/**
+ * struct clk_notifier_data - rate data to pass to the notifier callback
+ * @clk: struct clk * being changed
+ * @old_rate: previous rate of this clock
+ * @new_rate: new rate of this clock
+ *
+ * For a pre-notifier, old_rate is the clock's rate before this rate
+ * change, and new_rate is what the rate will be in the future.  For a
+ * post-notifier, old_rate and new_rate are both set to the clock's
+ * current rate (this was done to optimize the implementation).
+ */
+struct clk_notifier_data {
+	struct clk		*clk;
+	unsigned long		old_rate;
+	unsigned long		new_rate;
+};
+
 struct clk {
 	struct list_head	node;
 	const char		*name;
@@ -91,6 +127,7 @@ struct clk {
 	void			(*init)(struct clk *);
 	int			(*enable)(struct clk *);
 	void			(*disable)(struct clk *);
+	u16			notifier_count;
 	__u8			enable_bit;
 	__s8			usecount;
 	u8			idlest_bit;
@@ -146,6 +183,8 @@ extern void followparent_recalc(struct clk *clk, unsigned long parent_rate,
 extern void clk_allow_idle(struct clk *clk);
 extern void clk_deny_idle(struct clk *clk);
 extern void clk_enable_init_clocks(void);
+extern int clk_notifier_register(struct clk *clk, struct notifier_block *nb);
+extern int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);
 #ifdef CONFIG_CPU_FREQ
 extern void clk_init_cpufreq_table(struct cpufreq_frequency_table **table);
 #endif
@@ -203,4 +242,31 @@ void omap_clk_del_child(struct clk *clk, struct clk *clk2);
 #define CLK_REG_IN_PRM		(1 << 0)
 #define CLK_REG_IN_SCM		(1 << 1)
 
+/*
+ * Clk notifier callback types
+ *
+ * Since the notifier is called with interrupts disabled, any actions
+ * taken by callbacks must be extremely fast and lightweight.
+ *
+ * CLK_PRE_RATE_CHANGE - called after all callbacks have approved the
+ *     rate change, immediately before the clock rate is changed, to
+ *     indicate that the rate change will proceed.  Drivers must
+ *     immediately terminate any operations that will be affected by
+ *     the rate change.  Callbacks must always return NOTIFY_DONE.
+ *
+ * CLK_ABORT_RATE_CHANGE: called if the rate change failed for some
+ *     reason after CLK_PRE_RATE_CHANGE.  In this case, all registered
+ *     notifiers on the clock will be called with
+ *     CLK_ABORT_RATE_CHANGE. Callbacks must always return
+ *     NOTIFY_DONE.
+ *
+ * CLK_POST_RATE_CHANGE - called after the clock rate change has
+ *     successfully completed.  Callbacks must always return
+ *     NOTIFY_DONE.
+ *
+ */
+#define CLK_PRE_RATE_CHANGE		1
+#define CLK_ABORT_RATE_CHANGE		2
+#define CLK_POST_RATE_CHANGE		3
+
 #endif


--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/2] OMAP clock: implement clock rate/parent change notifiers
  2009-03-25 16:09 [PATCH 0/2] OMAP clock: implement clock rate/parent change notifiers Paul Walmsley
  2009-03-25 16:09 ` [PATCH 1/2] OMAP clock: add clk_round_rate_parent (with OMAP2/3 implementation) Paul Walmsley
  2009-03-25 16:09 ` [PATCH 2/2] OMAP2/3 clock: implement clock rate/parent change notifiers Paul Walmsley
@ 2009-03-25 17:54 ` Kevin Hilman
  2011-08-14  7:39   ` Felipe Contreras
  2 siblings, 1 reply; 7+ messages in thread
From: Kevin Hilman @ 2009-03-25 17:54 UTC (permalink / raw)
  To: Paul Walmsley; +Cc: linux-omap

Paul Walmsley <paul@pwsan.com> writes:

> Hello,
>
> This series allows core code and driver code to register for
> notification when a clock's rate or parent changes.  This is currently
> used by driver code that must be notified whenever power management
> code (e.g., CPUFreq) causes system rate changes that affect the driver's
> clock.

I will be re-basing the PM branch onto today's linux-omap HEAD which
is v2.6.29 based.  As I do this, I'll be dropping all the previous
notifier patches and replacing them with this series.

Kevin

> There are three notifier messages: 
>
> 1. a pre-change notifier, called before the change; 
>
> 2. a post-change notifier, called after the change; and
>
> 3. an abort notifier, called if the change fails for any reason after
>    the pre-change notifier callbacks have run.
>
> Since the implementation uses a blocking notifier, notifier code may
> block waiting for devices to quiesce; but long delays here will reduce
> the effectiveness of DVFS.  Since notifier callbacks are called with
> clocks_mutex held, callback code must not re-enter the clock framework.
>
> Pre-change notifiers are passed the current clock rate and the desired
> clock rate, so drivers can adjust any internal dividers appropriately.
> (To minimize performance and memory usage impact, post-change
> notifiers are passed only the desired clock rate, i.e., the clock rate
> after the rate change.)  The notifiers are called even if the clock
> rate is the same before and after the change.  This is because
> reprogramming a clock's parent or rate may briefly disrupt the clock.
>
> The interface to the notifiers is via:
>
> int clk_notifier_register(struct clk *clk, struct notifier_block *nb);
> int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);
>
> Until prototypes for these functions are made available in
> include/linux/clk.h, drivers should pass function pointers to
> clk_notifier_register() and clk_notifier_unregister() via their
> platform_data struct.
>
> This series is a collaboration between Tero Kristo
> <tero.kristo@nokia.com> and Paul Walmsley <paul@pwsan.com> and several
> others. Hiroshi Doyu <Hiroshi.DOYU@nokia.com> tracked down and fixed a
> bug where blocking_notifier_chain_*() were called while interrupts
> were disabled.  Nishanth Menon <nm@ti.com> found and fixed a bug in
> the clk_notifier_unregister() path, where a list_del() was missing.
> And thanks to Jouni Högander <jouni.hogander@nokia.com> for comments
> and review during the evolution of these patches.
>
> Registration and callbacks on rate change and parent change tested on
> BeagleBoard (OMAP3530 ES2.1).
>
> Comments welcomed.
>
> ---
>
>    text    data     bss     dec     hex filename
> 3439981  175136  111800 3726917  38de45 vmlinux.beagle.orig
> 3441545  176000  111800 3729345  38e7c1 vmlinux.beagle
>
>
>  arch/arm/mach-omap2/clock.c             |   30 ++++
>  arch/arm/mach-omap2/clock.h             |    1 
>  arch/arm/mach-omap2/clock24xx.c         |    1 
>  arch/arm/mach-omap2/clock34xx.c         |    1 
>  arch/arm/plat-omap/clock.c              |  256 +++++++++++++++++++++++++++++++
>  arch/arm/plat-omap/include/mach/clock.h |   68 ++++++++
>  6 files changed, 357 insertions(+), 0 deletions(-)
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/2] OMAP clock: implement clock rate/parent change notifiers
  2009-03-25 17:54 ` [PATCH 0/2] OMAP " Kevin Hilman
@ 2011-08-14  7:39   ` Felipe Contreras
  2011-12-08 19:26     ` Paul Walmsley
  0 siblings, 1 reply; 7+ messages in thread
From: Felipe Contreras @ 2011-08-14  7:39 UTC (permalink / raw)
  To: Kevin Hilman; +Cc: Paul Walmsley, linux-omap

Hi,

On Wed, Mar 25, 2009 at 7:54 PM, Kevin Hilman
<khilman@deeprootsystems.com> wrote:
> Paul Walmsley <paul@pwsan.com> writes:
>> This series allows core code and driver code to register for
>> notification when a clock's rate or parent changes.  This is currently
>> used by driver code that must be notified whenever power management
>> code (e.g., CPUFreq) causes system rate changes that affect the driver's
>> clock.
>
> I will be re-basing the PM branch onto today's linux-omap HEAD which
> is v2.6.29 based.  As I do this, I'll be dropping all the previous
> notifier patches and replacing them with this series.

What happened to this series? I don't see it anywhere.

-- 
Felipe Contreras
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/2] OMAP clock: implement clock rate/parent change notifiers
  2011-08-14  7:39   ` Felipe Contreras
@ 2011-12-08 19:26     ` Paul Walmsley
  2011-12-08 19:56       ` Felipe Contreras
  0 siblings, 1 reply; 7+ messages in thread
From: Paul Walmsley @ 2011-12-08 19:26 UTC (permalink / raw)
  To: Felipe Contreras; +Cc: Kevin Hilman, linux-omap

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1238 bytes --]

Hi Felipe,

I'm really sorry about the long delay in responding,

On Sun, 14 Aug 2011, Felipe Contreras wrote:

> On Wed, Mar 25, 2009 at 7:54 PM, Kevin Hilman
> <khilman@deeprootsystems.com> wrote:
> > Paul Walmsley <paul@pwsan.com> writes:
> >> This series allows core code and driver code to register for
> >> notification when a clock's rate or parent changes.  This is currently
> >> used by driver code that must be notified whenever power management
> >> code (e.g., CPUFreq) causes system rate changes that affect the driver's
> >> clock.
> >
> > I will be re-basing the PM branch onto today's linux-omap HEAD which
> > is v2.6.29 based.  As I do this, I'll be dropping all the previous
> > notifier patches and replacing them with this series.
> 
> What happened to this series? I don't see it anywhere.

Unforunately It got postponed for a long time for a variety of reasons.  
The good news is that it seems that others are starting to realize that 
something like this is needed, so hopefully it will finally go in as 
part of the common clock stuff.

Just out of curiosity: you are interested in them from the DSPBridge 
perspective?  Or do you have another use-case in mind?

regards

- Paul

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/2] OMAP clock: implement clock rate/parent change notifiers
  2011-12-08 19:26     ` Paul Walmsley
@ 2011-12-08 19:56       ` Felipe Contreras
  0 siblings, 0 replies; 7+ messages in thread
From: Felipe Contreras @ 2011-12-08 19:56 UTC (permalink / raw)
  To: Paul Walmsley; +Cc: Kevin Hilman, linux-omap

On Thu, Dec 8, 2011 at 9:26 PM, Paul Walmsley <paul@pwsan.com> wrote:
> On Sun, 14 Aug 2011, Felipe Contreras wrote:
>> On Wed, Mar 25, 2009 at 7:54 PM, Kevin Hilman
>> <khilman@deeprootsystems.com> wrote:
>> > Paul Walmsley <paul@pwsan.com> writes:
>> >> This series allows core code and driver code to register for
>> >> notification when a clock's rate or parent changes.  This is currently
>> >> used by driver code that must be notified whenever power management
>> >> code (e.g., CPUFreq) causes system rate changes that affect the driver's
>> >> clock.
>> >
>> > I will be re-basing the PM branch onto today's linux-omap HEAD which
>> > is v2.6.29 based.  As I do this, I'll be dropping all the previous
>> > notifier patches and replacing them with this series.
>>
>> What happened to this series? I don't see it anywhere.
>
> Unforunately It got postponed for a long time for a variety of reasons.
> The good news is that it seems that others are starting to realize that
> something like this is needed, so hopefully it will finally go in as
> part of the common clock stuff.

Cool.

> Just out of curiosity: you are interested in them from the DSPBridge
> perspective?  Or do you have another use-case in mind?

I ported the latest tidspbridge to the N9 kernel, and I was hit by a
bug, but it was only triggered in that kernel because of this patch.
So I was wondering why it never made it to mainline. That's all :)

-- 
Felipe Contreras
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2011-12-08 19:56 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-03-25 16:09 [PATCH 0/2] OMAP clock: implement clock rate/parent change notifiers Paul Walmsley
2009-03-25 16:09 ` [PATCH 1/2] OMAP clock: add clk_round_rate_parent (with OMAP2/3 implementation) Paul Walmsley
2009-03-25 16:09 ` [PATCH 2/2] OMAP2/3 clock: implement clock rate/parent change notifiers Paul Walmsley
2009-03-25 17:54 ` [PATCH 0/2] OMAP " Kevin Hilman
2011-08-14  7:39   ` Felipe Contreras
2011-12-08 19:26     ` Paul Walmsley
2011-12-08 19:56       ` Felipe Contreras

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.