diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2016-03-09 14:41:27 +0100 |
---|---|---|
committer | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2016-03-09 14:41:27 +0100 |
commit | 3300e9f53a238b533ecbd8857d4c93f65132bafc (patch) | |
tree | 2a7910f591b99a35d98e7aa92d8b6c327e315270 | |
parent | ee504eaedb9779b0e95b5925f3bbc9e0ead0282a (diff) | |
download | 4.12-rt-patches-3300e9f53a238b533ecbd8857d4c93f65132bafc.tar.gz |
[ANNOUNCE] 4.4.4-rt11
Dear RT folks!
I'm pleased to announce the v4.4.4-rt11 patch set.
Changes since v4.4.4-rt10:
- A compile error has been fixed in conjunction with the latency
tracer.
- AT91 got a little better. A larger patch series by Boris Brezillon has
been merged. That means SAMA5 boots now. There is one warning left
about invoking free_irq() twice. I would be glad about some feedback
from pre-SAMA5 SoC. Those which share UART and timer interrupt. It
seems that that one I have here does not do this anymore.
- A patch on top the AT91 series to avoid two warning while switching
from period to oneshow mode.
- Daniel Wagner refurbished the swait patches. This relase contains now
what is queued for v4.6 in the TIP tree. Only RT uses `completion'
based on swait. Based on the current implementation you will see a
warning if complete_all() in invoked on more than two waiters. Please
report if see this.
Known issues:
- CPU hotplug got a little better but can deadlock.
The delta patch against 4.4.4-rt10 is appended below and can be found here:
https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.4/incr/patch-4.4.4-rt10-rt11.patch.xz
You can get this release via the git tree at:
git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git v4.4.4-rt11
The RT patch against 4.4.4 can be found here:
https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.4/patch-4.4.4-rt11.patch.xz
The split quilt queue is available at:
https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.4/patches-4.4.4-rt11.tar.xz
Sebastian
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
36 files changed, 6578 insertions, 691 deletions
diff --git a/patches/0001-clk-at91-make-use-of-syscon-to-share-PMC-registers-i.patch b/patches/0001-clk-at91-make-use-of-syscon-to-share-PMC-registers-i.patch new file mode 100644 index 00000000000000..62ad706a6aba34 --- /dev/null +++ b/patches/0001-clk-at91-make-use-of-syscon-to-share-PMC-registers-i.patch @@ -0,0 +1,121 @@ +From: Boris Brezillon <boris.brezillon@free-electrons.com> +Date: Fri, 5 Sep 2014 09:54:13 +0200 +Subject: [PATCH 01/13] clk: at91: make use of syscon to share PMC registers in + several drivers + +The PMC block is providing several functionnalities: + - system clk management + - cpuidle + - platform suspend + +Replace the void __iomem *regs field by a regmap (retrieved using syscon) +so that we can later share the regmap across several drivers without +exporting a new specific API or a global void __iomem * variable. + +Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com> +Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Acked-by: Stephen Boyd <sboyd@codeaurora.org> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + arch/arm/mach-at91/Kconfig | 1 + + drivers/clk/at91/pmc.c | 12 ++++++++---- + drivers/clk/at91/pmc.h | 11 ++++++++--- + 3 files changed, 17 insertions(+), 7 deletions(-) + +--- a/arch/arm/mach-at91/Kconfig ++++ b/arch/arm/mach-at91/Kconfig +@@ -99,6 +99,7 @@ config HAVE_AT91_USB_CLK + config COMMON_CLK_AT91 + bool + select COMMON_CLK ++ select MFD_SYSCON + + config HAVE_AT91_SMD + bool +--- a/drivers/clk/at91/pmc.c ++++ b/drivers/clk/at91/pmc.c +@@ -19,6 +19,7 @@ + #include <linux/irqchip/chained_irq.h> + #include <linux/irqdomain.h> + #include <linux/of_irq.h> ++#include <linux/mfd/syscon.h> + + #include <asm/proc-fns.h> + +@@ -223,6 +224,7 @@ static const struct at91_pmc_caps sama5d + }; + + static struct at91_pmc *__init at91_pmc_init(struct device_node *np, ++ struct regmap *regmap, + void __iomem *regbase, int virq, + const struct at91_pmc_caps *caps) + { +@@ -238,7 +240,7 @@ static struct at91_pmc *__init at91_pmc_ + return NULL; + + spin_lock_init(&pmc->lock); +- pmc->regbase = regbase; ++ pmc->regmap = regmap; + pmc->virq = virq; + pmc->caps = caps; + +@@ -394,16 +396,18 @@ static void __init of_at91_pmc_setup(str + void (*clk_setup)(struct device_node *, struct at91_pmc *); + const struct of_device_id *clk_id; + void __iomem *regbase = of_iomap(np, 0); ++ struct regmap *regmap; + int virq; + +- if (!regbase) +- return; ++ regmap = syscon_node_to_regmap(np); ++ if (IS_ERR(regmap)) ++ panic("Could not retrieve syscon regmap"); + + virq = irq_of_parse_and_map(np, 0); + if (!virq) + return; + +- pmc = at91_pmc_init(np, regbase, virq, caps); ++ pmc = at91_pmc_init(np, regmap, regbase, virq, caps); + if (!pmc) + return; + for_each_child_of_node(np, childnp) { +--- a/drivers/clk/at91/pmc.h ++++ b/drivers/clk/at91/pmc.h +@@ -14,6 +14,7 @@ + + #include <linux/io.h> + #include <linux/irqdomain.h> ++#include <linux/regmap.h> + #include <linux/spinlock.h> + + struct clk_range { +@@ -28,7 +29,7 @@ struct at91_pmc_caps { + }; + + struct at91_pmc { +- void __iomem *regbase; ++ struct regmap *regmap; + int virq; + spinlock_t lock; + const struct at91_pmc_caps *caps; +@@ -48,12 +49,16 @@ static inline void pmc_unlock(struct at9 + + static inline u32 pmc_read(struct at91_pmc *pmc, int offset) + { +- return readl(pmc->regbase + offset); ++ unsigned int ret = 0; ++ ++ regmap_read(pmc->regmap, offset, &ret); ++ ++ return ret; + } + + static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 value) + { +- writel(value, pmc->regbase + offset); ++ regmap_write(pmc->regmap, offset, value); + } + + int of_at91_get_clk_range(struct device_node *np, const char *propname, diff --git a/patches/0001-wait.-ch-Introduce-the-simple-waitqueue-swait-implem.patch b/patches/0001-wait.-ch-Introduce-the-simple-waitqueue-swait-implem.patch new file mode 100644 index 00000000000000..d0dade7f816510 --- /dev/null +++ b/patches/0001-wait.-ch-Introduce-the-simple-waitqueue-swait-implem.patch @@ -0,0 +1,360 @@ +From: "Peter Zijlstra (Intel)" <peterz@infradead.org> +Date: Fri, 19 Feb 2016 09:46:37 +0100 +Subject: [PATCH 1/5] wait.[ch]: Introduce the simple waitqueue (swait) + implementation + +The existing wait queue support has support for custom wake up call +backs, wake flags, wake key (passed to call back) and exclusive +flags that allow wakers to be tagged as exclusive, for limiting +the number of wakers. + +In a lot of cases, none of these features are used, and hence we +can benefit from a slimmed down version that lowers memory overhead +and reduces runtime overhead. + +The concept originated from -rt, where waitqueues are a constant +source of trouble, as we can't convert the head lock to a raw +spinlock due to fancy and long lasting callbacks. + +With the removal of custom callbacks, we can use a raw lock for +queue list manipulations, hence allowing the simple wait support +to be used in -rt. + +[Patch is from PeterZ which is based on Thomas version. Commit message is + written by Paul G. + Daniel: - Fixed some compile issues + - Added non-lazy implementation of swake_up_locked as suggested + by Boqun Feng.] + +Originally-by: Thomas Gleixner <tglx@linutronix.de> +Signed-off-by: Daniel Wagner <daniel.wagner@bmw-carit.de> +Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> +Cc: linux-rt-users@vger.kernel.org +Cc: Boqun Feng <boqun.feng@gmail.com> +Cc: Marcelo Tosatti <mtosatti@redhat.com> +Cc: Steven Rostedt <rostedt@goodmis.org> +Cc: Paul Gortmaker <paul.gortmaker@windriver.com> +Cc: Paolo Bonzini <pbonzini@redhat.com> +Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> +Link: http://lkml.kernel.org/r/1455871601-27484-2-git-send-email-wagi@monom.org +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +--- + include/linux/swait.h | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++ + kernel/sched/Makefile | 2 + kernel/sched/swait.c | 123 +++++++++++++++++++++++++++++++++++ + 3 files changed, 296 insertions(+), 1 deletion(-) + create mode 100644 include/linux/swait.h + create mode 100644 kernel/sched/swait.c + +--- /dev/null ++++ b/include/linux/swait.h +@@ -0,0 +1,172 @@ ++#ifndef _LINUX_SWAIT_H ++#define _LINUX_SWAIT_H ++ ++#include <linux/list.h> ++#include <linux/stddef.h> ++#include <linux/spinlock.h> ++#include <asm/current.h> ++ ++/* ++ * Simple wait queues ++ * ++ * While these are very similar to the other/complex wait queues (wait.h) the ++ * most important difference is that the simple waitqueue allows for ++ * deterministic behaviour -- IOW it has strictly bounded IRQ and lock hold ++ * times. ++ * ++ * In order to make this so, we had to drop a fair number of features of the ++ * other waitqueue code; notably: ++ * ++ * - mixing INTERRUPTIBLE and UNINTERRUPTIBLE sleeps on the same waitqueue; ++ * all wakeups are TASK_NORMAL in order to avoid O(n) lookups for the right ++ * sleeper state. ++ * ++ * - the exclusive mode; because this requires preserving the list order ++ * and this is hard. ++ * ++ * - custom wake functions; because you cannot give any guarantees about ++ * random code. ++ * ++ * As a side effect of this; the data structures are slimmer. ++ * ++ * One would recommend using this wait queue where possible. ++ */ ++ ++struct task_struct; ++ ++struct swait_queue_head { ++ raw_spinlock_t lock; ++ struct list_head task_list; ++}; ++ ++struct swait_queue { ++ struct task_struct *task; ++ struct list_head task_list; ++}; ++ ++#define __SWAITQUEUE_INITIALIZER(name) { \ ++ .task = current, \ ++ .task_list = LIST_HEAD_INIT((name).task_list), \ ++} ++ ++#define DECLARE_SWAITQUEUE(name) \ ++ struct swait_queue name = __SWAITQUEUE_INITIALIZER(name) ++ ++#define __SWAIT_QUEUE_HEAD_INITIALIZER(name) { \ ++ .lock = __RAW_SPIN_LOCK_UNLOCKED(name.lock), \ ++ .task_list = LIST_HEAD_INIT((name).task_list), \ ++} ++ ++#define DECLARE_SWAIT_QUEUE_HEAD(name) \ ++ struct swait_queue_head name = __SWAIT_QUEUE_HEAD_INITIALIZER(name) ++ ++extern void __init_swait_queue_head(struct swait_queue_head *q, const char *name, ++ struct lock_class_key *key); ++ ++#define init_swait_queue_head(q) \ ++ do { \ ++ static struct lock_class_key __key; \ ++ __init_swait_queue_head((q), #q, &__key); \ ++ } while (0) ++ ++#ifdef CONFIG_LOCKDEP ++# define __SWAIT_QUEUE_HEAD_INIT_ONSTACK(name) \ ++ ({ init_swait_queue_head(&name); name; }) ++# define DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(name) \ ++ struct swait_queue_head name = __SWAIT_QUEUE_HEAD_INIT_ONSTACK(name) ++#else ++# define DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(name) \ ++ DECLARE_SWAIT_QUEUE_HEAD(name) ++#endif ++ ++static inline int swait_active(struct swait_queue_head *q) ++{ ++ return !list_empty(&q->task_list); ++} ++ ++extern void swake_up(struct swait_queue_head *q); ++extern void swake_up_all(struct swait_queue_head *q); ++extern void swake_up_locked(struct swait_queue_head *q); ++ ++extern void __prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait); ++extern void prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait, int state); ++extern long prepare_to_swait_event(struct swait_queue_head *q, struct swait_queue *wait, int state); ++ ++extern void __finish_swait(struct swait_queue_head *q, struct swait_queue *wait); ++extern void finish_swait(struct swait_queue_head *q, struct swait_queue *wait); ++ ++/* as per ___wait_event() but for swait, therefore "exclusive == 0" */ ++#define ___swait_event(wq, condition, state, ret, cmd) \ ++({ \ ++ struct swait_queue __wait; \ ++ long __ret = ret; \ ++ \ ++ INIT_LIST_HEAD(&__wait.task_list); \ ++ for (;;) { \ ++ long __int = prepare_to_swait_event(&wq, &__wait, state);\ ++ \ ++ if (condition) \ ++ break; \ ++ \ ++ if (___wait_is_interruptible(state) && __int) { \ ++ __ret = __int; \ ++ break; \ ++ } \ ++ \ ++ cmd; \ ++ } \ ++ finish_swait(&wq, &__wait); \ ++ __ret; \ ++}) ++ ++#define __swait_event(wq, condition) \ ++ (void)___swait_event(wq, condition, TASK_UNINTERRUPTIBLE, 0, \ ++ schedule()) ++ ++#define swait_event(wq, condition) \ ++do { \ ++ if (condition) \ ++ break; \ ++ __swait_event(wq, condition); \ ++} while (0) ++ ++#define __swait_event_timeout(wq, condition, timeout) \ ++ ___swait_event(wq, ___wait_cond_timeout(condition), \ ++ TASK_UNINTERRUPTIBLE, timeout, \ ++ __ret = schedule_timeout(__ret)) ++ ++#define swait_event_timeout(wq, condition, timeout) \ ++({ \ ++ long __ret = timeout; \ ++ if (!___wait_cond_timeout(condition)) \ ++ __ret = __swait_event_timeout(wq, condition, timeout); \ ++ __ret; \ ++}) ++ ++#define __swait_event_interruptible(wq, condition) \ ++ ___swait_event(wq, condition, TASK_INTERRUPTIBLE, 0, \ ++ schedule()) ++ ++#define swait_event_interruptible(wq, condition) \ ++({ \ ++ int __ret = 0; \ ++ if (!(condition)) \ ++ __ret = __swait_event_interruptible(wq, condition); \ ++ __ret; \ ++}) ++ ++#define __swait_event_interruptible_timeout(wq, condition, timeout) \ ++ ___swait_event(wq, ___wait_cond_timeout(condition), \ ++ TASK_INTERRUPTIBLE, timeout, \ ++ __ret = schedule_timeout(__ret)) ++ ++#define swait_event_interruptible_timeout(wq, condition, timeout) \ ++({ \ ++ long __ret = timeout; \ ++ if (!___wait_cond_timeout(condition)) \ ++ __ret = __swait_event_interruptible_timeout(wq, \ ++ condition, timeout); \ ++ __ret; \ ++}) ++ ++#endif /* _LINUX_SWAIT_H */ +--- a/kernel/sched/Makefile ++++ b/kernel/sched/Makefile +@@ -13,7 +13,7 @@ endif + + obj-y += core.o loadavg.o clock.o cputime.o + obj-y += idle_task.o fair.o rt.o deadline.o stop_task.o +-obj-y += wait.o completion.o idle.o ++obj-y += wait.o swait.o completion.o idle.o + obj-$(CONFIG_SMP) += cpupri.o cpudeadline.o + obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o + obj-$(CONFIG_SCHEDSTATS) += stats.o +--- /dev/null ++++ b/kernel/sched/swait.c +@@ -0,0 +1,123 @@ ++#include <linux/sched.h> ++#include <linux/swait.h> ++ ++void __init_swait_queue_head(struct swait_queue_head *q, const char *name, ++ struct lock_class_key *key) ++{ ++ raw_spin_lock_init(&q->lock); ++ lockdep_set_class_and_name(&q->lock, key, name); ++ INIT_LIST_HEAD(&q->task_list); ++} ++EXPORT_SYMBOL(__init_swait_queue_head); ++ ++/* ++ * The thing about the wake_up_state() return value; I think we can ignore it. ++ * ++ * If for some reason it would return 0, that means the previously waiting ++ * task is already running, so it will observe condition true (or has already). ++ */ ++void swake_up_locked(struct swait_queue_head *q) ++{ ++ struct swait_queue *curr; ++ ++ if (list_empty(&q->task_list)) ++ return; ++ ++ curr = list_first_entry(&q->task_list, typeof(*curr), task_list); ++ wake_up_process(curr->task); ++ list_del_init(&curr->task_list); ++} ++EXPORT_SYMBOL(swake_up_locked); ++ ++void swake_up(struct swait_queue_head *q) ++{ ++ unsigned long flags; ++ ++ if (!swait_active(q)) ++ return; ++ ++ raw_spin_lock_irqsave(&q->lock, flags); ++ swake_up_locked(q); ++ raw_spin_unlock_irqrestore(&q->lock, flags); ++} ++EXPORT_SYMBOL(swake_up); ++ ++/* ++ * Does not allow usage from IRQ disabled, since we must be able to ++ * release IRQs to guarantee bounded hold time. ++ */ ++void swake_up_all(struct swait_queue_head *q) ++{ ++ struct swait_queue *curr; ++ LIST_HEAD(tmp); ++ ++ if (!swait_active(q)) ++ return; ++ ++ raw_spin_lock_irq(&q->lock); ++ list_splice_init(&q->task_list, &tmp); ++ while (!list_empty(&tmp)) { ++ curr = list_first_entry(&tmp, typeof(*curr), task_list); ++ ++ wake_up_state(curr->task, TASK_NORMAL); ++ list_del_init(&curr->task_list); ++ ++ if (list_empty(&tmp)) ++ break; ++ ++ raw_spin_unlock_irq(&q->lock); ++ raw_spin_lock_irq(&q->lock); ++ } ++ raw_spin_unlock_irq(&q->lock); ++} ++EXPORT_SYMBOL(swake_up_all); ++ ++void __prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait) ++{ ++ wait->task = current; ++ if (list_empty(&wait->task_list)) ++ list_add(&wait->task_list, &q->task_list); ++} ++ ++void prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait, int state) ++{ ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&q->lock, flags); ++ __prepare_to_swait(q, wait); ++ set_current_state(state); ++ raw_spin_unlock_irqrestore(&q->lock, flags); ++} ++EXPORT_SYMBOL(prepare_to_swait); ++ ++long prepare_to_swait_event(struct swait_queue_head *q, struct swait_queue *wait, int state) ++{ ++ if (signal_pending_state(state, current)) ++ return -ERESTARTSYS; ++ ++ prepare_to_swait(q, wait, state); ++ ++ return 0; ++} ++EXPORT_SYMBOL(prepare_to_swait_event); ++ ++void __finish_swait(struct swait_queue_head *q, struct swait_queue *wait) ++{ ++ __set_current_state(TASK_RUNNING); ++ if (!list_empty(&wait->task_list)) ++ list_del_init(&wait->task_list); ++} ++ ++void finish_swait(struct swait_queue_head *q, struct swait_queue *wait) ++{ ++ unsigned long flags; ++ ++ __set_current_state(TASK_RUNNING); ++ ++ if (!list_empty_careful(&wait->task_list)) { ++ raw_spin_lock_irqsave(&q->lock, flags); ++ list_del_init(&wait->task_list); ++ raw_spin_unlock_irqrestore(&q->lock, flags); ++ } ++} ++EXPORT_SYMBOL(finish_swait); diff --git a/patches/0002-clk-at91-make-use-of-syscon-regmap-internally.patch b/patches/0002-clk-at91-make-use-of-syscon-regmap-internally.patch new file mode 100644 index 00000000000000..ab73e058c4d1d8 --- /dev/null +++ b/patches/0002-clk-at91-make-use-of-syscon-regmap-internally.patch @@ -0,0 +1,3252 @@ +From: Boris Brezillon <boris.brezillon@free-electrons.com> +Date: Sun, 7 Sep 2014 08:14:29 +0200 +Subject: [PATCH 02/13] clk: at91: make use of syscon/regmap internally + +Use the regmap coming from syscon to access the registers instead of using +pmc_read/pmc_write. This allows to avoid passing the at91_pmc structure to +the child nodes of the PMC. + +The final benefit is to have each clock register itself instead of having +to iterate over the children. + +Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com> +Acked-by: Stephen Boyd <sboyd@codeaurora.org> +Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + drivers/clk/at91/clk-generated.c | 91 +++++++------ + drivers/clk/at91/clk-h32mx.c | 32 ++-- + drivers/clk/at91/clk-main.c | 248 +++++++++++++++++++++++------------- + drivers/clk/at91/clk-master.c | 68 ++++++--- + drivers/clk/at91/clk-peripheral.c | 134 +++++++++++-------- + drivers/clk/at91/clk-pll.c | 119 ++++++++++------- + drivers/clk/at91/clk-plldiv.c | 42 ++---- + drivers/clk/at91/clk-programmable.c | 92 +++++++------ + drivers/clk/at91/clk-slow.c | 26 ++- + drivers/clk/at91/clk-smd.c | 54 ++++--- + drivers/clk/at91/clk-system.c | 60 +++++--- + drivers/clk/at91/clk-usb.c | 121 +++++++++-------- + drivers/clk/at91/clk-utmi.c | 53 ++++--- + drivers/clk/at91/pmc.c | 155 +--------------------- + drivers/clk/at91/pmc.h | 89 ------------ + 15 files changed, 691 insertions(+), 693 deletions(-) + +--- a/drivers/clk/at91/clk-generated.c ++++ b/drivers/clk/at91/clk-generated.c +@@ -17,6 +17,8 @@ + #include <linux/of.h> + #include <linux/of_address.h> + #include <linux/io.h> ++#include <linux/mfd/syscon.h> ++#include <linux/regmap.h> + + #include "pmc.h" + +@@ -28,8 +30,9 @@ + + struct clk_generated { + struct clk_hw hw; +- struct at91_pmc *pmc; ++ struct regmap *regmap; + struct clk_range range; ++ spinlock_t *lock; + u32 id; + u32 gckdiv; + u8 parent_id; +@@ -41,49 +44,52 @@ struct clk_generated { + static int clk_generated_enable(struct clk_hw *hw) + { + struct clk_generated *gck = to_clk_generated(hw); +- struct at91_pmc *pmc = gck->pmc; +- u32 tmp; ++ unsigned long flags; + + pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n", + __func__, gck->gckdiv, gck->parent_id); + +- pmc_lock(pmc); +- pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK)); +- tmp = pmc_read(pmc, AT91_PMC_PCR) & +- ~(AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK); +- pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_GCKCSS(gck->parent_id) +- | AT91_PMC_PCR_CMD +- | AT91_PMC_PCR_GCKDIV(gck->gckdiv) +- | AT91_PMC_PCR_GCKEN); +- pmc_unlock(pmc); ++ spin_lock_irqsave(gck->lock, flags); ++ regmap_write(gck->regmap, AT91_PMC_PCR, ++ (gck->id & AT91_PMC_PCR_PID_MASK)); ++ regmap_update_bits(gck->regmap, AT91_PMC_PCR, ++ AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK | ++ AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN, ++ AT91_PMC_PCR_GCKCSS(gck->parent_id) | ++ AT91_PMC_PCR_CMD | ++ AT91_PMC_PCR_GCKDIV(gck->gckdiv) | ++ AT91_PMC_PCR_GCKEN); ++ spin_unlock_irqrestore(gck->lock, flags); + return 0; + } + + static void clk_generated_disable(struct clk_hw *hw) + { + struct clk_generated *gck = to_clk_generated(hw); +- struct at91_pmc *pmc = gck->pmc; +- u32 tmp; ++ unsigned long flags; + +- pmc_lock(pmc); +- pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK)); +- tmp = pmc_read(pmc, AT91_PMC_PCR) & ~AT91_PMC_PCR_GCKEN; +- pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_CMD); +- pmc_unlock(pmc); ++ spin_lock_irqsave(gck->lock, flags); ++ regmap_write(gck->regmap, AT91_PMC_PCR, ++ (gck->id & AT91_PMC_PCR_PID_MASK)); ++ regmap_update_bits(gck->regmap, AT91_PMC_PCR, ++ AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN, ++ AT91_PMC_PCR_CMD); ++ spin_unlock_irqrestore(gck->lock, flags); + } + + static int clk_generated_is_enabled(struct clk_hw *hw) + { + struct clk_generated *gck = to_clk_generated(hw); +- struct at91_pmc *pmc = gck->pmc; +- int ret; ++ unsigned long flags; ++ unsigned int status; + +- pmc_lock(pmc); +- pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK)); +- ret = !!(pmc_read(pmc, AT91_PMC_PCR) & AT91_PMC_PCR_GCKEN); +- pmc_unlock(pmc); ++ spin_lock_irqsave(gck->lock, flags); ++ regmap_write(gck->regmap, AT91_PMC_PCR, ++ (gck->id & AT91_PMC_PCR_PID_MASK)); ++ regmap_read(gck->regmap, AT91_PMC_PCR, &status); ++ spin_unlock_irqrestore(gck->lock, flags); + +- return ret; ++ return status & AT91_PMC_PCR_GCKEN ? 1 : 0; + } + + static unsigned long +@@ -214,13 +220,14 @@ static const struct clk_ops generated_op + */ + static void clk_generated_startup(struct clk_generated *gck) + { +- struct at91_pmc *pmc = gck->pmc; + u32 tmp; ++ unsigned long flags; + +- pmc_lock(pmc); +- pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK)); +- tmp = pmc_read(pmc, AT91_PMC_PCR); +- pmc_unlock(pmc); ++ spin_lock_irqsave(gck->lock, flags); ++ regmap_write(gck->regmap, AT91_PMC_PCR, ++ (gck->id & AT91_PMC_PCR_PID_MASK)); ++ regmap_read(gck->regmap, AT91_PMC_PCR, &tmp); ++ spin_unlock_irqrestore(gck->lock, flags); + + gck->parent_id = (tmp & AT91_PMC_PCR_GCKCSS_MASK) + >> AT91_PMC_PCR_GCKCSS_OFFSET; +@@ -229,8 +236,8 @@ static void clk_generated_startup(struct + } + + static struct clk * __init +-at91_clk_register_generated(struct at91_pmc *pmc, const char *name, +- const char **parent_names, u8 num_parents, ++at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, const char ++ *name, const char **parent_names, u8 num_parents, + u8 id, const struct clk_range *range) + { + struct clk_generated *gck; +@@ -249,7 +256,8 @@ at91_clk_register_generated(struct at91_ + + gck->id = id; + gck->hw.init = &init; +- gck->pmc = pmc; ++ gck->regmap = regmap; ++ gck->lock = lock; + gck->range = *range; + + clk = clk_register(NULL, &gck->hw); +@@ -261,8 +269,7 @@ at91_clk_register_generated(struct at91_ + return clk; + } + +-void __init of_sama5d2_clk_generated_setup(struct device_node *np, +- struct at91_pmc *pmc) ++void __init of_sama5d2_clk_generated_setup(struct device_node *np) + { + int num; + u32 id; +@@ -272,6 +279,7 @@ void __init of_sama5d2_clk_generated_set + const char *parent_names[GENERATED_SOURCE_MAX]; + struct device_node *gcknp; + struct clk_range range = CLK_RANGE(0, 0); ++ struct regmap *regmap; + + num_parents = of_clk_get_parent_count(np); + if (num_parents <= 0 || num_parents > GENERATED_SOURCE_MAX) +@@ -283,6 +291,10 @@ void __init of_sama5d2_clk_generated_set + if (!num || num > PERIPHERAL_MAX) + return; + ++ regmap = syscon_node_to_regmap(of_get_parent(np)); ++ if (IS_ERR(regmap)) ++ return; ++ + for_each_child_of_node(np, gcknp) { + if (of_property_read_u32(gcknp, "reg", &id)) + continue; +@@ -296,11 +308,14 @@ void __init of_sama5d2_clk_generated_set + of_at91_get_clk_range(gcknp, "atmel,clk-output-range", + &range); + +- clk = at91_clk_register_generated(pmc, name, parent_names, +- num_parents, id, &range); ++ clk = at91_clk_register_generated(regmap, &pmc_pcr_lock, name, ++ parent_names, num_parents, ++ id, &range); + if (IS_ERR(clk)) + continue; + + of_clk_add_provider(gcknp, of_clk_src_simple_get, clk); + } + } ++CLK_OF_DECLARE(of_sama5d2_clk_generated_setup, "atmel,sama5d2-clk-generated", ++ of_sama5d2_clk_generated_setup); +--- a/drivers/clk/at91/clk-h32mx.c ++++ b/drivers/clk/at91/clk-h32mx.c +@@ -24,6 +24,8 @@ + #include <linux/irq.h> + #include <linux/sched.h> + #include <linux/wait.h> ++#include <linux/regmap.h> ++#include <linux/mfd/syscon.h> + + #include "pmc.h" + +@@ -31,7 +33,7 @@ + + struct clk_sama5d4_h32mx { + struct clk_hw hw; +- struct at91_pmc *pmc; ++ struct regmap *regmap; + }; + + #define to_clk_sama5d4_h32mx(hw) container_of(hw, struct clk_sama5d4_h32mx, hw) +@@ -40,8 +42,10 @@ static unsigned long clk_sama5d4_h32mx_r + unsigned long parent_rate) + { + struct clk_sama5d4_h32mx *h32mxclk = to_clk_sama5d4_h32mx(hw); ++ unsigned int mckr; + +- if (pmc_read(h32mxclk->pmc, AT91_PMC_MCKR) & AT91_PMC_H32MXDIV) ++ regmap_read(h32mxclk->regmap, AT91_PMC_MCKR, &mckr); ++ if (mckr & AT91_PMC_H32MXDIV) + return parent_rate / 2; + + if (parent_rate > H32MX_MAX_FREQ) +@@ -70,18 +74,16 @@ static int clk_sama5d4_h32mx_set_rate(st + unsigned long parent_rate) + { + struct clk_sama5d4_h32mx *h32mxclk = to_clk_sama5d4_h32mx(hw); +- struct at91_pmc *pmc = h32mxclk->pmc; +- u32 tmp; ++ u32 mckr = 0; + + if (parent_rate != rate && (parent_rate / 2) != rate) + return -EINVAL; + +- pmc_lock(pmc); +- tmp = pmc_read(pmc, AT91_PMC_MCKR) & ~AT91_PMC_H32MXDIV; + if ((parent_rate / 2) == rate) +- tmp |= AT91_PMC_H32MXDIV; +- pmc_write(pmc, AT91_PMC_MCKR, tmp); +- pmc_unlock(pmc); ++ mckr = AT91_PMC_H32MXDIV; ++ ++ regmap_update_bits(h32mxclk->regmap, AT91_PMC_MCKR, ++ AT91_PMC_H32MXDIV, mckr); + + return 0; + } +@@ -92,14 +94,18 @@ static const struct clk_ops h32mx_ops = + .set_rate = clk_sama5d4_h32mx_set_rate, + }; + +-void __init of_sama5d4_clk_h32mx_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np) + { + struct clk_sama5d4_h32mx *h32mxclk; + struct clk_init_data init; + const char *parent_name; ++ struct regmap *regmap; + struct clk *clk; + ++ regmap = syscon_node_to_regmap(of_get_parent(np)); ++ if (IS_ERR(regmap)) ++ return; ++ + h32mxclk = kzalloc(sizeof(*h32mxclk), GFP_KERNEL); + if (!h32mxclk) + return; +@@ -113,7 +119,7 @@ void __init of_sama5d4_clk_h32mx_setup(s + init.flags = CLK_SET_RATE_GATE; + + h32mxclk->hw.init = &init; +- h32mxclk->pmc = pmc; ++ h32mxclk->regmap = regmap; + + clk = clk_register(NULL, &h32mxclk->hw); + if (!clk) { +@@ -123,3 +129,5 @@ void __init of_sama5d4_clk_h32mx_setup(s + + of_clk_add_provider(np, of_clk_src_simple_get, clk); + } ++CLK_OF_DECLARE(of_sama5d4_clk_h32mx_setup, "atmel,sama5d4-clk-h32mx", ++ of_sama5d4_clk_h32mx_setup); +--- a/drivers/clk/at91/clk-main.c ++++ b/drivers/clk/at91/clk-main.c +@@ -18,6 +18,8 @@ + #include <linux/io.h> + #include <linux/interrupt.h> + #include <linux/irq.h> ++#include <linux/mfd/syscon.h> ++#include <linux/regmap.h> + #include <linux/sched.h> + #include <linux/wait.h> + +@@ -34,7 +36,7 @@ + + struct clk_main_osc { + struct clk_hw hw; +- struct at91_pmc *pmc; ++ struct regmap *regmap; + unsigned int irq; + wait_queue_head_t wait; + }; +@@ -43,7 +45,7 @@ struct clk_main_osc { + + struct clk_main_rc_osc { + struct clk_hw hw; +- struct at91_pmc *pmc; ++ struct regmap *regmap; + unsigned int irq; + wait_queue_head_t wait; + unsigned long frequency; +@@ -54,14 +56,14 @@ struct clk_main_rc_osc { + + struct clk_rm9200_main { + struct clk_hw hw; +- struct at91_pmc *pmc; ++ struct regmap *regmap; + }; + + #define to_clk_rm9200_main(hw) container_of(hw, struct clk_rm9200_main, hw) + + struct clk_sam9x5_main { + struct clk_hw hw; +- struct at91_pmc *pmc; ++ struct regmap *regmap; + unsigned int irq; + wait_queue_head_t wait; + u8 parent; +@@ -79,25 +81,36 @@ static irqreturn_t clk_main_osc_irq_hand + return IRQ_HANDLED; + } + ++static inline bool clk_main_osc_ready(struct regmap *regmap) ++{ ++ unsigned int status; ++ ++ regmap_read(regmap, AT91_PMC_SR, &status); ++ ++ return status & AT91_PMC_MOSCS; ++} ++ + static int clk_main_osc_prepare(struct clk_hw *hw) + { + struct clk_main_osc *osc = to_clk_main_osc(hw); +- struct at91_pmc *pmc = osc->pmc; ++ struct regmap *regmap = osc->regmap; + u32 tmp; + +- tmp = pmc_read(pmc, AT91_CKGR_MOR) & ~MOR_KEY_MASK; ++ regmap_read(regmap, AT91_CKGR_MOR, &tmp); ++ tmp &= ~MOR_KEY_MASK; ++ + if (tmp & AT91_PMC_OSCBYPASS) + return 0; + + if (!(tmp & AT91_PMC_MOSCEN)) { + tmp |= AT91_PMC_MOSCEN | AT91_PMC_KEY; +- pmc_write(pmc, AT91_CKGR_MOR, tmp); ++ regmap_write(regmap, AT91_CKGR_MOR, tmp); + } + +- while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS)) { ++ while (!clk_main_osc_ready(regmap)) { + enable_irq(osc->irq); + wait_event(osc->wait, +- pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS); ++ clk_main_osc_ready(regmap)); + } + + return 0; +@@ -106,9 +119,10 @@ static int clk_main_osc_prepare(struct c + static void clk_main_osc_unprepare(struct clk_hw *hw) + { + struct clk_main_osc *osc = to_clk_main_osc(hw); +- struct at91_pmc *pmc = osc->pmc; +- u32 tmp = pmc_read(pmc, AT91_CKGR_MOR); ++ struct regmap *regmap = osc->regmap; ++ u32 tmp; + ++ regmap_read(regmap, AT91_CKGR_MOR, &tmp); + if (tmp & AT91_PMC_OSCBYPASS) + return; + +@@ -116,20 +130,22 @@ static void clk_main_osc_unprepare(struc + return; + + tmp &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN); +- pmc_write(pmc, AT91_CKGR_MOR, tmp | AT91_PMC_KEY); ++ regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_KEY); + } + + static int clk_main_osc_is_prepared(struct clk_hw *hw) + { + struct clk_main_osc *osc = to_clk_main_osc(hw); +- struct at91_pmc *pmc = osc->pmc; +- u32 tmp = pmc_read(pmc, AT91_CKGR_MOR); ++ struct regmap *regmap = osc->regmap; ++ u32 tmp, status; + ++ regmap_read(regmap, AT91_CKGR_MOR, &tmp); + if (tmp & AT91_PMC_OSCBYPASS) + return 1; + +- return !!((pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS) && +- (pmc_read(pmc, AT91_CKGR_MOR) & AT91_PMC_MOSCEN)); ++ regmap_read(regmap, AT91_PMC_SR, &status); ++ ++ return (status & AT91_PMC_MOSCS) && (tmp & AT91_PMC_MOSCEN); + } + + static const struct clk_ops main_osc_ops = { +@@ -139,7 +155,7 @@ static const struct clk_ops main_osc_ops + }; + + static struct clk * __init +-at91_clk_register_main_osc(struct at91_pmc *pmc, ++at91_clk_register_main_osc(struct regmap *regmap, + unsigned int irq, + const char *name, + const char *parent_name, +@@ -150,7 +166,7 @@ at91_clk_register_main_osc(struct at91_p + struct clk *clk = NULL; + struct clk_init_data init; + +- if (!pmc || !irq || !name || !parent_name) ++ if (!irq || !name || !parent_name) + return ERR_PTR(-EINVAL); + + osc = kzalloc(sizeof(*osc), GFP_KERNEL); +@@ -164,7 +180,7 @@ at91_clk_register_main_osc(struct at91_p + init.flags = CLK_IGNORE_UNUSED; + + osc->hw.init = &init; +- osc->pmc = pmc; ++ osc->regmap = regmap; + osc->irq = irq; + + init_waitqueue_head(&osc->wait); +@@ -177,10 +193,10 @@ at91_clk_register_main_osc(struct at91_p + } + + if (bypass) +- pmc_write(pmc, AT91_CKGR_MOR, +- (pmc_read(pmc, AT91_CKGR_MOR) & +- ~(MOR_KEY_MASK | AT91_PMC_MOSCEN)) | +- AT91_PMC_OSCBYPASS | AT91_PMC_KEY); ++ regmap_update_bits(regmap, ++ AT91_CKGR_MOR, MOR_KEY_MASK | ++ AT91_PMC_MOSCEN, ++ AT91_PMC_OSCBYPASS | AT91_PMC_KEY); + + clk = clk_register(NULL, &osc->hw); + if (IS_ERR(clk)) { +@@ -191,29 +207,35 @@ at91_clk_register_main_osc(struct at91_p + return clk; + } + +-void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np) + { + struct clk *clk; + unsigned int irq; + const char *name = np->name; + const char *parent_name; ++ struct regmap *regmap; + bool bypass; + + of_property_read_string(np, "clock-output-names", &name); + bypass = of_property_read_bool(np, "atmel,osc-bypass"); + parent_name = of_clk_get_parent_name(np, 0); + ++ regmap = syscon_node_to_regmap(of_get_parent(np)); ++ if (IS_ERR(regmap)) ++ return; ++ + irq = irq_of_parse_and_map(np, 0); + if (!irq) + return; + +- clk = at91_clk_register_main_osc(pmc, irq, name, parent_name, bypass); ++ clk = at91_clk_register_main_osc(regmap, irq, name, parent_name, bypass); + if (IS_ERR(clk)) + return; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); + } ++CLK_OF_DECLARE(at91rm9200_clk_main_osc, "atmel,at91rm9200-clk-main-osc", ++ of_at91rm9200_clk_main_osc_setup); + + static irqreturn_t clk_main_rc_osc_irq_handler(int irq, void *dev_id) + { +@@ -225,23 +247,32 @@ static irqreturn_t clk_main_rc_osc_irq_h + return IRQ_HANDLED; + } + ++static bool clk_main_rc_osc_ready(struct regmap *regmap) ++{ ++ unsigned int status; ++ ++ regmap_read(regmap, AT91_PMC_SR, &status); ++ ++ return status & AT91_PMC_MOSCRCS; ++} ++ + static int clk_main_rc_osc_prepare(struct clk_hw *hw) + { + struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw); +- struct at91_pmc *pmc = osc->pmc; +- u32 tmp; ++ struct regmap *regmap = osc->regmap; ++ unsigned int mor; + +- tmp = pmc_read(pmc, AT91_CKGR_MOR) & ~MOR_KEY_MASK; ++ regmap_read(regmap, AT91_CKGR_MOR, &mor); + +- if (!(tmp & AT91_PMC_MOSCRCEN)) { +- tmp |= AT91_PMC_MOSCRCEN | AT91_PMC_KEY; +- pmc_write(pmc, AT91_CKGR_MOR, tmp); +- } ++ if (!(mor & AT91_PMC_MOSCRCEN)) ++ regmap_update_bits(regmap, AT91_CKGR_MOR, ++ MOR_KEY_MASK | AT91_PMC_MOSCRCEN, ++ AT91_PMC_MOSCRCEN | AT91_PMC_KEY); + +- while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCRCS)) { ++ while (!clk_main_rc_osc_ready(regmap)) { + enable_irq(osc->irq); + wait_event(osc->wait, +- pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCRCS); ++ clk_main_rc_osc_ready(regmap)); + } + + return 0; +@@ -250,23 +281,28 @@ static int clk_main_rc_osc_prepare(struc + static void clk_main_rc_osc_unprepare(struct clk_hw *hw) + { + struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw); +- struct at91_pmc *pmc = osc->pmc; +- u32 tmp = pmc_read(pmc, AT91_CKGR_MOR); ++ struct regmap *regmap = osc->regmap; ++ unsigned int mor; + +- if (!(tmp & AT91_PMC_MOSCRCEN)) ++ regmap_read(regmap, AT91_CKGR_MOR, &mor); ++ ++ if (!(mor & AT91_PMC_MOSCRCEN)) + return; + +- tmp &= ~(MOR_KEY_MASK | AT91_PMC_MOSCRCEN); +- pmc_write(pmc, AT91_CKGR_MOR, tmp | AT91_PMC_KEY); ++ regmap_update_bits(regmap, AT91_CKGR_MOR, ++ MOR_KEY_MASK | AT91_PMC_MOSCRCEN, AT91_PMC_KEY); + } + + static int clk_main_rc_osc_is_prepared(struct clk_hw *hw) + { + struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw); +- struct at91_pmc *pmc = osc->pmc; ++ struct regmap *regmap = osc->regmap; ++ unsigned int mor, status; ++ ++ regmap_read(regmap, AT91_CKGR_MOR, &mor); ++ regmap_read(regmap, AT91_PMC_SR, &status); + +- return !!((pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCRCS) && +- (pmc_read(pmc, AT91_CKGR_MOR) & AT91_PMC_MOSCRCEN)); ++ return (mor & AT91_PMC_MOSCRCEN) && (status & AT91_PMC_MOSCRCS); + } + + static unsigned long clk_main_rc_osc_recalc_rate(struct clk_hw *hw, +@@ -294,7 +330,7 @@ static const struct clk_ops main_rc_osc_ + }; + + static struct clk * __init +-at91_clk_register_main_rc_osc(struct at91_pmc *pmc, ++at91_clk_register_main_rc_osc(struct regmap *regmap, + unsigned int irq, + const char *name, + u32 frequency, u32 accuracy) +@@ -304,7 +340,7 @@ at91_clk_register_main_rc_osc(struct at9 + struct clk *clk = NULL; + struct clk_init_data init; + +- if (!pmc || !irq || !name || !frequency) ++ if (!name || !frequency) + return ERR_PTR(-EINVAL); + + osc = kzalloc(sizeof(*osc), GFP_KERNEL); +@@ -318,7 +354,7 @@ at91_clk_register_main_rc_osc(struct at9 + init.flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED; + + osc->hw.init = &init; +- osc->pmc = pmc; ++ osc->regmap = regmap; + osc->irq = irq; + osc->frequency = frequency; + osc->accuracy = accuracy; +@@ -339,14 +375,14 @@ at91_clk_register_main_rc_osc(struct at9 + return clk; + } + +-void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np) + { + struct clk *clk; + unsigned int irq; + u32 frequency = 0; + u32 accuracy = 0; + const char *name = np->name; ++ struct regmap *regmap; + + of_property_read_string(np, "clock-output-names", &name); + of_property_read_u32(np, "clock-frequency", &frequency); +@@ -356,25 +392,31 @@ void __init of_at91sam9x5_clk_main_rc_os + if (!irq) + return; + +- clk = at91_clk_register_main_rc_osc(pmc, irq, name, frequency, ++ regmap = syscon_node_to_regmap(of_get_parent(np)); ++ if (IS_ERR(regmap)) ++ return; ++ ++ clk = at91_clk_register_main_rc_osc(regmap, irq, name, frequency, + accuracy); + if (IS_ERR(clk)) + return; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); + } ++CLK_OF_DECLARE(at91sam9x5_clk_main_rc_osc, "atmel,at91sam9x5-clk-main-rc-osc", ++ of_at91sam9x5_clk_main_rc_osc_setup); + + +-static int clk_main_probe_frequency(struct at91_pmc *pmc) ++static int clk_main_probe_frequency(struct regmap *regmap) + { + unsigned long prep_time, timeout; +- u32 tmp; ++ unsigned int mcfr; + + timeout = jiffies + usecs_to_jiffies(MAINFRDY_TIMEOUT); + do { + prep_time = jiffies; +- tmp = pmc_read(pmc, AT91_CKGR_MCFR); +- if (tmp & AT91_PMC_MAINRDY) ++ regmap_read(regmap, AT91_CKGR_MCFR, &mcfr); ++ if (mcfr & AT91_PMC_MAINRDY) + return 0; + usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT); + } while (time_before(prep_time, timeout)); +@@ -382,34 +424,37 @@ static int clk_main_probe_frequency(stru + return -ETIMEDOUT; + } + +-static unsigned long clk_main_recalc_rate(struct at91_pmc *pmc, ++static unsigned long clk_main_recalc_rate(struct regmap *regmap, + unsigned long parent_rate) + { +- u32 tmp; ++ unsigned int mcfr; + + if (parent_rate) + return parent_rate; + + pr_warn("Main crystal frequency not set, using approximate value\n"); +- tmp = pmc_read(pmc, AT91_CKGR_MCFR); +- if (!(tmp & AT91_PMC_MAINRDY)) ++ regmap_read(regmap, AT91_CKGR_MCFR, &mcfr); ++ if (!(mcfr & AT91_PMC_MAINRDY)) + return 0; + +- return ((tmp & AT91_PMC_MAINF) * SLOW_CLOCK_FREQ) / MAINF_DIV; ++ return ((mcfr & AT91_PMC_MAINF) * SLOW_CLOCK_FREQ) / MAINF_DIV; + } + + static int clk_rm9200_main_prepare(struct clk_hw *hw) + { + struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw); + +- return clk_main_probe_frequency(clkmain->pmc); ++ return clk_main_probe_frequency(clkmain->regmap); + } + + static int clk_rm9200_main_is_prepared(struct clk_hw *hw) + { + struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw); ++ unsigned int status; ++ ++ regmap_read(clkmain->regmap, AT91_CKGR_MCFR, &status); + +- return !!(pmc_read(clkmain->pmc, AT91_CKGR_MCFR) & AT91_PMC_MAINRDY); ++ return status & AT91_PMC_MAINRDY ? 1 : 0; + } + + static unsigned long clk_rm9200_main_recalc_rate(struct clk_hw *hw, +@@ -417,7 +462,7 @@ static unsigned long clk_rm9200_main_rec + { + struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw); + +- return clk_main_recalc_rate(clkmain->pmc, parent_rate); ++ return clk_main_recalc_rate(clkmain->regmap, parent_rate); + } + + static const struct clk_ops rm9200_main_ops = { +@@ -427,7 +472,7 @@ static const struct clk_ops rm9200_main_ + }; + + static struct clk * __init +-at91_clk_register_rm9200_main(struct at91_pmc *pmc, ++at91_clk_register_rm9200_main(struct regmap *regmap, + const char *name, + const char *parent_name) + { +@@ -435,7 +480,7 @@ at91_clk_register_rm9200_main(struct at9 + struct clk *clk = NULL; + struct clk_init_data init; + +- if (!pmc || !name) ++ if (!name) + return ERR_PTR(-EINVAL); + + if (!parent_name) +@@ -452,7 +497,7 @@ at91_clk_register_rm9200_main(struct at9 + init.flags = 0; + + clkmain->hw.init = &init; +- clkmain->pmc = pmc; ++ clkmain->regmap = regmap; + + clk = clk_register(NULL, &clkmain->hw); + if (IS_ERR(clk)) +@@ -461,22 +506,28 @@ at91_clk_register_rm9200_main(struct at9 + return clk; + } + +-void __init of_at91rm9200_clk_main_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_at91rm9200_clk_main_setup(struct device_node *np) + { + struct clk *clk; + const char *parent_name; + const char *name = np->name; ++ struct regmap *regmap; + + parent_name = of_clk_get_parent_name(np, 0); + of_property_read_string(np, "clock-output-names", &name); + +- clk = at91_clk_register_rm9200_main(pmc, name, parent_name); ++ regmap = syscon_node_to_regmap(of_get_parent(np)); ++ if (IS_ERR(regmap)) ++ return; ++ ++ clk = at91_clk_register_rm9200_main(regmap, name, parent_name); + if (IS_ERR(clk)) + return; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); + } ++CLK_OF_DECLARE(at91rm9200_clk_main, "atmel,at91rm9200-clk-main", ++ of_at91rm9200_clk_main_setup); + + static irqreturn_t clk_sam9x5_main_irq_handler(int irq, void *dev_id) + { +@@ -488,25 +539,34 @@ static irqreturn_t clk_sam9x5_main_irq_h + return IRQ_HANDLED; + } + ++static inline bool clk_sam9x5_main_ready(struct regmap *regmap) ++{ ++ unsigned int status; ++ ++ regmap_read(regmap, AT91_PMC_SR, &status); ++ ++ return status & AT91_PMC_MOSCSELS ? 1 : 0; ++} ++ + static int clk_sam9x5_main_prepare(struct clk_hw *hw) + { + struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw); +- struct at91_pmc *pmc = clkmain->pmc; ++ struct regmap *regmap = clkmain->regmap; + +- while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS)) { ++ while (!clk_sam9x5_main_ready(regmap)) { + enable_irq(clkmain->irq); + wait_event(clkmain->wait, +- pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS); ++ clk_sam9x5_main_ready(regmap)); + } + +- return clk_main_probe_frequency(pmc); ++ return clk_main_probe_frequency(regmap); + } + + static int clk_sam9x5_main_is_prepared(struct clk_hw *hw) + { + struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw); + +- return !!(pmc_read(clkmain->pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS); ++ return clk_sam9x5_main_ready(clkmain->regmap); + } + + static unsigned long clk_sam9x5_main_recalc_rate(struct clk_hw *hw, +@@ -514,29 +574,30 @@ static unsigned long clk_sam9x5_main_rec + { + struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw); + +- return clk_main_recalc_rate(clkmain->pmc, parent_rate); ++ return clk_main_recalc_rate(clkmain->regmap, parent_rate); + } + + static int clk_sam9x5_main_set_parent(struct clk_hw *hw, u8 index) + { + struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw); +- struct at91_pmc *pmc = clkmain->pmc; +- u32 tmp; ++ struct regmap *regmap = clkmain->regmap; ++ unsigned int tmp; + + if (index > 1) + return -EINVAL; + +- tmp = pmc_read(pmc, AT91_CKGR_MOR) & ~MOR_KEY_MASK; ++ regmap_read(regmap, AT91_CKGR_MOR, &tmp); ++ tmp &= ~MOR_KEY_MASK; + + if (index && !(tmp & AT91_PMC_MOSCSEL)) +- pmc_write(pmc, AT91_CKGR_MOR, tmp | AT91_PMC_MOSCSEL); ++ regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_MOSCSEL); + else if (!index && (tmp & AT91_PMC_MOSCSEL)) +- pmc_write(pmc, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL); ++ regmap_write(regmap, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL); + +- while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS)) { ++ while (!clk_sam9x5_main_ready(regmap)) { + enable_irq(clkmain->irq); + wait_event(clkmain->wait, +- pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS); ++ clk_sam9x5_main_ready(regmap)); + } + + return 0; +@@ -545,8 +606,11 @@ static int clk_sam9x5_main_set_parent(st + static u8 clk_sam9x5_main_get_parent(struct clk_hw *hw) + { + struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw); ++ unsigned int status; + +- return !!(pmc_read(clkmain->pmc, AT91_CKGR_MOR) & AT91_PMC_MOSCEN); ++ regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status); ++ ++ return status & AT91_PMC_MOSCEN ? 1 : 0; + } + + static const struct clk_ops sam9x5_main_ops = { +@@ -558,7 +622,7 @@ static const struct clk_ops sam9x5_main_ + }; + + static struct clk * __init +-at91_clk_register_sam9x5_main(struct at91_pmc *pmc, ++at91_clk_register_sam9x5_main(struct regmap *regmap, + unsigned int irq, + const char *name, + const char **parent_names, +@@ -568,8 +632,9 @@ at91_clk_register_sam9x5_main(struct at9 + struct clk_sam9x5_main *clkmain; + struct clk *clk = NULL; + struct clk_init_data init; ++ unsigned int status; + +- if (!pmc || !irq || !name) ++ if (!name) + return ERR_PTR(-EINVAL); + + if (!parent_names || !num_parents) +@@ -586,10 +651,10 @@ at91_clk_register_sam9x5_main(struct at9 + init.flags = CLK_SET_PARENT_GATE; + + clkmain->hw.init = &init; +- clkmain->pmc = pmc; ++ clkmain->regmap = regmap; + clkmain->irq = irq; +- clkmain->parent = !!(pmc_read(clkmain->pmc, AT91_CKGR_MOR) & +- AT91_PMC_MOSCEN); ++ regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status); ++ clkmain->parent = status & AT91_PMC_MOSCEN ? 1 : 0; + init_waitqueue_head(&clkmain->wait); + irq_set_status_flags(clkmain->irq, IRQ_NOAUTOEN); + ret = request_irq(clkmain->irq, clk_sam9x5_main_irq_handler, +@@ -606,20 +671,23 @@ at91_clk_register_sam9x5_main(struct at9 + return clk; + } + +-void __init of_at91sam9x5_clk_main_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_at91sam9x5_clk_main_setup(struct device_node *np) + { + struct clk *clk; + const char *parent_names[2]; + int num_parents; + unsigned int irq; + const char *name = np->name; ++ struct regmap *regmap; + + num_parents = of_clk_get_parent_count(np); + if (num_parents <= 0 || num_parents > 2) + return; + + of_clk_parent_fill(np, parent_names, num_parents); ++ regmap = syscon_node_to_regmap(of_get_parent(np)); ++ if (IS_ERR(regmap)) ++ return; + + of_property_read_string(np, "clock-output-names", &name); + +@@ -627,10 +695,12 @@ void __init of_at91sam9x5_clk_main_setup + if (!irq) + return; + +- clk = at91_clk_register_sam9x5_main(pmc, irq, name, parent_names, ++ clk = at91_clk_register_sam9x5_main(regmap, irq, name, parent_names, + num_parents); + if (IS_ERR(clk)) + return; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); + } ++CLK_OF_DECLARE(at91sam9x5_clk_main, "atmel,at91sam9x5-clk-main", ++ of_at91sam9x5_clk_main_setup); +--- a/drivers/clk/at91/clk-master.c ++++ b/drivers/clk/at91/clk-master.c +@@ -19,6 +19,8 @@ + #include <linux/sched.h> + #include <linux/interrupt.h> + #include <linux/irq.h> ++#include <linux/mfd/syscon.h> ++#include <linux/regmap.h> + + #include "pmc.h" + +@@ -44,7 +46,7 @@ struct clk_master_layout { + + struct clk_master { + struct clk_hw hw; +- struct at91_pmc *pmc; ++ struct regmap *regmap; + unsigned int irq; + wait_queue_head_t wait; + const struct clk_master_layout *layout; +@@ -60,15 +62,24 @@ static irqreturn_t clk_master_irq_handle + + return IRQ_HANDLED; + } ++ ++static inline bool clk_master_ready(struct regmap *regmap) ++{ ++ unsigned int status; ++ ++ regmap_read(regmap, AT91_PMC_SR, &status); ++ ++ return status & AT91_PMC_MCKRDY ? 1 : 0; ++} ++ + static int clk_master_prepare(struct clk_hw *hw) + { + struct clk_master *master = to_clk_master(hw); +- struct at91_pmc *pmc = master->pmc; + +- while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY)) { ++ while (!clk_master_ready(master->regmap)) { + enable_irq(master->irq); + wait_event(master->wait, +- pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY); ++ clk_master_ready(master->regmap)); + } + + return 0; +@@ -78,7 +89,7 @@ static int clk_master_is_prepared(struct + { + struct clk_master *master = to_clk_master(hw); + +- return !!(pmc_read(master->pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY); ++ return clk_master_ready(master->regmap); + } + + static unsigned long clk_master_recalc_rate(struct clk_hw *hw, +@@ -88,18 +99,16 @@ static unsigned long clk_master_recalc_r + u8 div; + unsigned long rate = parent_rate; + struct clk_master *master = to_clk_master(hw); +- struct at91_pmc *pmc = master->pmc; + const struct clk_master_layout *layout = master->layout; + const struct clk_master_characteristics *characteristics = + master->characteristics; +- u32 tmp; ++ unsigned int mckr; + +- pmc_lock(pmc); +- tmp = pmc_read(pmc, AT91_PMC_MCKR) & layout->mask; +- pmc_unlock(pmc); ++ regmap_read(master->regmap, AT91_PMC_MCKR, &mckr); ++ mckr &= layout->mask; + +- pres = (tmp >> layout->pres_shift) & MASTER_PRES_MASK; +- div = (tmp >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK; ++ pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK; ++ div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK; + + if (characteristics->have_div3_pres && pres == MASTER_PRES_MAX) + rate /= 3; +@@ -119,9 +128,11 @@ static unsigned long clk_master_recalc_r + static u8 clk_master_get_parent(struct clk_hw *hw) + { + struct clk_master *master = to_clk_master(hw); +- struct at91_pmc *pmc = master->pmc; ++ unsigned int mckr; ++ ++ regmap_read(master->regmap, AT91_PMC_MCKR, &mckr); + +- return pmc_read(pmc, AT91_PMC_MCKR) & AT91_PMC_CSS; ++ return mckr & AT91_PMC_CSS; + } + + static const struct clk_ops master_ops = { +@@ -132,7 +143,7 @@ static const struct clk_ops master_ops = + }; + + static struct clk * __init +-at91_clk_register_master(struct at91_pmc *pmc, unsigned int irq, ++at91_clk_register_master(struct regmap *regmap, unsigned int irq, + const char *name, int num_parents, + const char **parent_names, + const struct clk_master_layout *layout, +@@ -143,7 +154,7 @@ at91_clk_register_master(struct at91_pmc + struct clk *clk = NULL; + struct clk_init_data init; + +- if (!pmc || !irq || !name || !num_parents || !parent_names) ++ if (!name || !num_parents || !parent_names) + return ERR_PTR(-EINVAL); + + master = kzalloc(sizeof(*master), GFP_KERNEL); +@@ -159,7 +170,7 @@ at91_clk_register_master(struct at91_pmc + master->hw.init = &init; + master->layout = layout; + master->characteristics = characteristics; +- master->pmc = pmc; ++ master->regmap = regmap; + master->irq = irq; + init_waitqueue_head(&master->wait); + irq_set_status_flags(master->irq, IRQ_NOAUTOEN); +@@ -217,7 +228,7 @@ of_at91_clk_master_get_characteristics(s + } + + static void __init +-of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc, ++of_at91_clk_master_setup(struct device_node *np, + const struct clk_master_layout *layout) + { + struct clk *clk; +@@ -226,6 +237,7 @@ of_at91_clk_master_setup(struct device_n + const char *parent_names[MASTER_SOURCE_MAX]; + const char *name = np->name; + struct clk_master_characteristics *characteristics; ++ struct regmap *regmap; + + num_parents = of_clk_get_parent_count(np); + if (num_parents <= 0 || num_parents > MASTER_SOURCE_MAX) +@@ -239,11 +251,15 @@ of_at91_clk_master_setup(struct device_n + if (!characteristics) + return; + ++ regmap = syscon_node_to_regmap(of_get_parent(np)); ++ if (IS_ERR(regmap)) ++ return; ++ + irq = irq_of_parse_and_map(np, 0); + if (!irq) + goto out_free_characteristics; + +- clk = at91_clk_register_master(pmc, irq, name, num_parents, ++ clk = at91_clk_register_master(regmap, irq, name, num_parents, + parent_names, layout, + characteristics); + if (IS_ERR(clk)) +@@ -256,14 +272,16 @@ of_at91_clk_master_setup(struct device_n + kfree(characteristics); + } + +-void __init of_at91rm9200_clk_master_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_at91rm9200_clk_master_setup(struct device_node *np) + { +- of_at91_clk_master_setup(np, pmc, &at91rm9200_master_layout); ++ of_at91_clk_master_setup(np, &at91rm9200_master_layout); + } ++CLK_OF_DECLARE(at91rm9200_clk_master, "atmel,at91rm9200-clk-master", ++ of_at91rm9200_clk_master_setup); + +-void __init of_at91sam9x5_clk_master_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_at91sam9x5_clk_master_setup(struct device_node *np) + { +- of_at91_clk_master_setup(np, pmc, &at91sam9x5_master_layout); ++ of_at91_clk_master_setup(np, &at91sam9x5_master_layout); + } ++CLK_OF_DECLARE(at91sam9x5_clk_master, "atmel,at91sam9x5-clk-master", ++ of_at91sam9x5_clk_master_setup); +--- a/drivers/clk/at91/clk-peripheral.c ++++ b/drivers/clk/at91/clk-peripheral.c +@@ -14,9 +14,13 @@ + #include <linux/of.h> + #include <linux/of_address.h> + #include <linux/io.h> ++#include <linux/mfd/syscon.h> ++#include <linux/regmap.h> + + #include "pmc.h" + ++DEFINE_SPINLOCK(pmc_pcr_lock); ++ + #define PERIPHERAL_MAX 64 + + #define PERIPHERAL_AT91RM9200 0 +@@ -33,7 +37,7 @@ + + struct clk_peripheral { + struct clk_hw hw; +- struct at91_pmc *pmc; ++ struct regmap *regmap; + u32 id; + }; + +@@ -41,8 +45,9 @@ struct clk_peripheral { + + struct clk_sam9x5_peripheral { + struct clk_hw hw; +- struct at91_pmc *pmc; ++ struct regmap *regmap; + struct clk_range range; ++ spinlock_t *lock; + u32 id; + u32 div; + bool auto_div; +@@ -54,7 +59,6 @@ struct clk_sam9x5_peripheral { + static int clk_peripheral_enable(struct clk_hw *hw) + { + struct clk_peripheral *periph = to_clk_peripheral(hw); +- struct at91_pmc *pmc = periph->pmc; + int offset = AT91_PMC_PCER; + u32 id = periph->id; + +@@ -62,14 +66,14 @@ static int clk_peripheral_enable(struct + return 0; + if (id > PERIPHERAL_ID_MAX) + offset = AT91_PMC_PCER1; +- pmc_write(pmc, offset, PERIPHERAL_MASK(id)); ++ regmap_write(periph->regmap, offset, PERIPHERAL_MASK(id)); ++ + return 0; + } + + static void clk_peripheral_disable(struct clk_hw *hw) + { + struct clk_peripheral *periph = to_clk_peripheral(hw); +- struct at91_pmc *pmc = periph->pmc; + int offset = AT91_PMC_PCDR; + u32 id = periph->id; + +@@ -77,21 +81,23 @@ static void clk_peripheral_disable(struc + return; + if (id > PERIPHERAL_ID_MAX) + offset = AT91_PMC_PCDR1; +- pmc_write(pmc, offset, PERIPHERAL_MASK(id)); ++ regmap_write(periph->regmap, offset, PERIPHERAL_MASK(id)); + } + + static int clk_peripheral_is_enabled(struct clk_hw *hw) + { + struct clk_peripheral *periph = to_clk_peripheral(hw); +- struct at91_pmc *pmc = periph->pmc; + int offset = AT91_PMC_PCSR; ++ unsigned int status; + u32 id = periph->id; + + if (id < PERIPHERAL_ID_MIN) + return 1; + if (id > PERIPHERAL_ID_MAX) + offset = AT91_PMC_PCSR1; +- return !!(pmc_read(pmc, offset) & PERIPHERAL_MASK(id)); ++ regmap_read(periph->regmap, offset, &status); ++ ++ return status & PERIPHERAL_MASK(id) ? 1 : 0; + } + + static const struct clk_ops peripheral_ops = { +@@ -101,14 +107,14 @@ static const struct clk_ops peripheral_o + }; + + static struct clk * __init +-at91_clk_register_peripheral(struct at91_pmc *pmc, const char *name, ++at91_clk_register_peripheral(struct regmap *regmap, const char *name, + const char *parent_name, u32 id) + { + struct clk_peripheral *periph; + struct clk *clk = NULL; + struct clk_init_data init; + +- if (!pmc || !name || !parent_name || id > PERIPHERAL_ID_MAX) ++ if (!name || !parent_name || id > PERIPHERAL_ID_MAX) + return ERR_PTR(-EINVAL); + + periph = kzalloc(sizeof(*periph), GFP_KERNEL); +@@ -123,7 +129,7 @@ at91_clk_register_peripheral(struct at91 + + periph->id = id; + periph->hw.init = &init; +- periph->pmc = pmc; ++ periph->regmap = regmap; + + clk = clk_register(NULL, &periph->hw); + if (IS_ERR(clk)) +@@ -160,53 +166,58 @@ static void clk_sam9x5_peripheral_autodi + static int clk_sam9x5_peripheral_enable(struct clk_hw *hw) + { + struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); +- struct at91_pmc *pmc = periph->pmc; +- u32 tmp; ++ unsigned long flags; + + if (periph->id < PERIPHERAL_ID_MIN) + return 0; + +- pmc_lock(pmc); +- pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK)); +- tmp = pmc_read(pmc, AT91_PMC_PCR) & ~AT91_PMC_PCR_DIV_MASK; +- pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_DIV(periph->div) +- | AT91_PMC_PCR_CMD +- | AT91_PMC_PCR_EN); +- pmc_unlock(pmc); ++ spin_lock_irqsave(periph->lock, flags); ++ regmap_write(periph->regmap, AT91_PMC_PCR, ++ (periph->id & AT91_PMC_PCR_PID_MASK)); ++ regmap_update_bits(periph->regmap, AT91_PMC_PCR, ++ AT91_PMC_PCR_DIV_MASK | AT91_PMC_PCR_CMD | ++ AT91_PMC_PCR_EN, ++ AT91_PMC_PCR_DIV(periph->div) | ++ AT91_PMC_PCR_CMD | ++ AT91_PMC_PCR_EN); ++ spin_unlock_irqrestore(periph->lock, flags); ++ + return 0; + } + + static void clk_sam9x5_peripheral_disable(struct clk_hw *hw) + { + struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); +- struct at91_pmc *pmc = periph->pmc; +- u32 tmp; ++ unsigned long flags; + + if (periph->id < PERIPHERAL_ID_MIN) + return; + +- pmc_lock(pmc); +- pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK)); +- tmp = pmc_read(pmc, AT91_PMC_PCR) & ~AT91_PMC_PCR_EN; +- pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_CMD); +- pmc_unlock(pmc); ++ spin_lock_irqsave(periph->lock, flags); ++ regmap_write(periph->regmap, AT91_PMC_PCR, ++ (periph->id & AT91_PMC_PCR_PID_MASK)); ++ regmap_update_bits(periph->regmap, AT91_PMC_PCR, ++ AT91_PMC_PCR_EN | AT91_PMC_PCR_CMD, ++ AT91_PMC_PCR_CMD); ++ spin_unlock_irqrestore(periph->lock, flags); + } + + static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw) + { + struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); +- struct at91_pmc *pmc = periph->pmc; +- int ret; ++ unsigned long flags; ++ unsigned int status; + + if (periph->id < PERIPHERAL_ID_MIN) + return 1; + +- pmc_lock(pmc); +- pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK)); +- ret = !!(pmc_read(pmc, AT91_PMC_PCR) & AT91_PMC_PCR_EN); +- pmc_unlock(pmc); ++ spin_lock_irqsave(periph->lock, flags); ++ regmap_write(periph->regmap, AT91_PMC_PCR, ++ (periph->id & AT91_PMC_PCR_PID_MASK)); ++ regmap_read(periph->regmap, AT91_PMC_PCR, &status); ++ spin_unlock_irqrestore(periph->lock, flags); + +- return ret; ++ return status & AT91_PMC_PCR_EN ? 1 : 0; + } + + static unsigned long +@@ -214,19 +225,20 @@ clk_sam9x5_peripheral_recalc_rate(struct + unsigned long parent_rate) + { + struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); +- struct at91_pmc *pmc = periph->pmc; +- u32 tmp; ++ unsigned long flags; ++ unsigned int status; + + if (periph->id < PERIPHERAL_ID_MIN) + return parent_rate; + +- pmc_lock(pmc); +- pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK)); +- tmp = pmc_read(pmc, AT91_PMC_PCR); +- pmc_unlock(pmc); ++ spin_lock_irqsave(periph->lock, flags); ++ regmap_write(periph->regmap, AT91_PMC_PCR, ++ (periph->id & AT91_PMC_PCR_PID_MASK)); ++ regmap_read(periph->regmap, AT91_PMC_PCR, &status); ++ spin_unlock_irqrestore(periph->lock, flags); + +- if (tmp & AT91_PMC_PCR_EN) { +- periph->div = PERIPHERAL_RSHIFT(tmp); ++ if (status & AT91_PMC_PCR_EN) { ++ periph->div = PERIPHERAL_RSHIFT(status); + periph->auto_div = false; + } else { + clk_sam9x5_peripheral_autodiv(periph); +@@ -318,15 +330,15 @@ static const struct clk_ops sam9x5_perip + }; + + static struct clk * __init +-at91_clk_register_sam9x5_peripheral(struct at91_pmc *pmc, const char *name, +- const char *parent_name, u32 id, +- const struct clk_range *range) ++at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, ++ const char *name, const char *parent_name, ++ u32 id, const struct clk_range *range) + { + struct clk_sam9x5_peripheral *periph; + struct clk *clk = NULL; + struct clk_init_data init; + +- if (!pmc || !name || !parent_name) ++ if (!name || !parent_name) + return ERR_PTR(-EINVAL); + + periph = kzalloc(sizeof(*periph), GFP_KERNEL); +@@ -342,7 +354,8 @@ at91_clk_register_sam9x5_peripheral(stru + periph->id = id; + periph->hw.init = &init; + periph->div = 0; +- periph->pmc = pmc; ++ periph->regmap = regmap; ++ periph->lock = lock; + periph->auto_div = true; + periph->range = *range; + +@@ -356,7 +369,7 @@ at91_clk_register_sam9x5_peripheral(stru + } + + static void __init +-of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type) ++of_at91_clk_periph_setup(struct device_node *np, u8 type) + { + int num; + u32 id; +@@ -364,6 +377,7 @@ of_at91_clk_periph_setup(struct device_n + const char *parent_name; + const char *name; + struct device_node *periphclknp; ++ struct regmap *regmap; + + parent_name = of_clk_get_parent_name(np, 0); + if (!parent_name) +@@ -373,6 +387,10 @@ of_at91_clk_periph_setup(struct device_n + if (!num || num > PERIPHERAL_MAX) + return; + ++ regmap = syscon_node_to_regmap(of_get_parent(np)); ++ if (IS_ERR(regmap)) ++ return; ++ + for_each_child_of_node(np, periphclknp) { + if (of_property_read_u32(periphclknp, "reg", &id)) + continue; +@@ -384,7 +402,7 @@ of_at91_clk_periph_setup(struct device_n + name = periphclknp->name; + + if (type == PERIPHERAL_AT91RM9200) { +- clk = at91_clk_register_peripheral(pmc, name, ++ clk = at91_clk_register_peripheral(regmap, name, + parent_name, id); + } else { + struct clk_range range = CLK_RANGE(0, 0); +@@ -393,7 +411,9 @@ of_at91_clk_periph_setup(struct device_n + "atmel,clk-output-range", + &range); + +- clk = at91_clk_register_sam9x5_peripheral(pmc, name, ++ clk = at91_clk_register_sam9x5_peripheral(regmap, ++ &pmc_pcr_lock, ++ name, + parent_name, + id, &range); + } +@@ -405,14 +425,16 @@ of_at91_clk_periph_setup(struct device_n + } + } + +-void __init of_at91rm9200_clk_periph_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_at91rm9200_clk_periph_setup(struct device_node *np) + { +- of_at91_clk_periph_setup(np, pmc, PERIPHERAL_AT91RM9200); ++ of_at91_clk_periph_setup(np, PERIPHERAL_AT91RM9200); + } ++CLK_OF_DECLARE(at91rm9200_clk_periph, "atmel,at91rm9200-clk-peripheral", ++ of_at91rm9200_clk_periph_setup); + +-void __init of_at91sam9x5_clk_periph_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_at91sam9x5_clk_periph_setup(struct device_node *np) + { +- of_at91_clk_periph_setup(np, pmc, PERIPHERAL_AT91SAM9X5); ++ of_at91_clk_periph_setup(np, PERIPHERAL_AT91SAM9X5); + } ++CLK_OF_DECLARE(at91sam9x5_clk_periph, "atmel,at91sam9x5-clk-peripheral", ++ of_at91sam9x5_clk_periph_setup); +--- a/drivers/clk/at91/clk-pll.c ++++ b/drivers/clk/at91/clk-pll.c +@@ -20,6 +20,8 @@ + #include <linux/sched.h> + #include <linux/interrupt.h> + #include <linux/irq.h> ++#include <linux/mfd/syscon.h> ++#include <linux/regmap.h> + + #include "pmc.h" + +@@ -58,7 +60,7 @@ struct clk_pll_layout { + + struct clk_pll { + struct clk_hw hw; +- struct at91_pmc *pmc; ++ struct regmap *regmap; + unsigned int irq; + wait_queue_head_t wait; + u8 id; +@@ -79,10 +81,19 @@ static irqreturn_t clk_pll_irq_handler(i + return IRQ_HANDLED; + } + ++static inline bool clk_pll_ready(struct regmap *regmap, int id) ++{ ++ unsigned int status; ++ ++ regmap_read(regmap, AT91_PMC_SR, &status); ++ ++ return status & PLL_STATUS_MASK(id) ? 1 : 0; ++} ++ + static int clk_pll_prepare(struct clk_hw *hw) + { + struct clk_pll *pll = to_clk_pll(hw); +- struct at91_pmc *pmc = pll->pmc; ++ struct regmap *regmap = pll->regmap; + const struct clk_pll_layout *layout = pll->layout; + const struct clk_pll_characteristics *characteristics = + pll->characteristics; +@@ -90,38 +101,36 @@ static int clk_pll_prepare(struct clk_hw + u32 mask = PLL_STATUS_MASK(id); + int offset = PLL_REG(id); + u8 out = 0; +- u32 pllr, icpr; ++ unsigned int pllr; ++ unsigned int status; + u8 div; + u16 mul; + +- pllr = pmc_read(pmc, offset); ++ regmap_read(regmap, offset, &pllr); + div = PLL_DIV(pllr); + mul = PLL_MUL(pllr, layout); + +- if ((pmc_read(pmc, AT91_PMC_SR) & mask) && ++ regmap_read(regmap, AT91_PMC_SR, &status); ++ if ((status & mask) && + (div == pll->div && mul == pll->mul)) + return 0; + + if (characteristics->out) + out = characteristics->out[pll->range]; +- if (characteristics->icpll) { +- icpr = pmc_read(pmc, AT91_PMC_PLLICPR) & ~PLL_ICPR_MASK(id); +- icpr |= (characteristics->icpll[pll->range] << +- PLL_ICPR_SHIFT(id)); +- pmc_write(pmc, AT91_PMC_PLLICPR, icpr); +- } + +- pllr &= ~layout->pllr_mask; +- pllr |= layout->pllr_mask & +- (pll->div | (PLL_MAX_COUNT << PLL_COUNT_SHIFT) | +- (out << PLL_OUT_SHIFT) | +- ((pll->mul & layout->mul_mask) << layout->mul_shift)); +- pmc_write(pmc, offset, pllr); ++ if (characteristics->icpll) ++ regmap_update_bits(regmap, AT91_PMC_PLLICPR, PLL_ICPR_MASK(id), ++ characteristics->icpll[pll->range] << PLL_ICPR_SHIFT(id)); ++ ++ regmap_update_bits(regmap, offset, layout->pllr_mask, ++ pll->div | (PLL_MAX_COUNT << PLL_COUNT_SHIFT) | ++ (out << PLL_OUT_SHIFT) | ++ ((pll->mul & layout->mul_mask) << layout->mul_shift)); + +- while (!(pmc_read(pmc, AT91_PMC_SR) & mask)) { ++ while (!clk_pll_ready(regmap, pll->id)) { + enable_irq(pll->irq); + wait_event(pll->wait, +- pmc_read(pmc, AT91_PMC_SR) & mask); ++ clk_pll_ready(regmap, pll->id)); + } + + return 0; +@@ -130,32 +139,35 @@ static int clk_pll_prepare(struct clk_hw + static int clk_pll_is_prepared(struct clk_hw *hw) + { + struct clk_pll *pll = to_clk_pll(hw); +- struct at91_pmc *pmc = pll->pmc; + +- return !!(pmc_read(pmc, AT91_PMC_SR) & +- PLL_STATUS_MASK(pll->id)); ++ return clk_pll_ready(pll->regmap, pll->id); + } + + static void clk_pll_unprepare(struct clk_hw *hw) + { + struct clk_pll *pll = to_clk_pll(hw); +- struct at91_pmc *pmc = pll->pmc; +- const struct clk_pll_layout *layout = pll->layout; +- int offset = PLL_REG(pll->id); +- u32 tmp = pmc_read(pmc, offset) & ~(layout->pllr_mask); ++ unsigned int mask = pll->layout->pllr_mask; + +- pmc_write(pmc, offset, tmp); ++ regmap_update_bits(pll->regmap, PLL_REG(pll->id), mask, ~mask); + } + + static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) + { + struct clk_pll *pll = to_clk_pll(hw); ++ unsigned int pllr; ++ u16 mul; ++ u8 div; ++ ++ regmap_read(pll->regmap, PLL_REG(pll->id), &pllr); ++ ++ div = PLL_DIV(pllr); ++ mul = PLL_MUL(pllr, pll->layout); + +- if (!pll->div || !pll->mul) ++ if (!div || !mul) + return 0; + +- return (parent_rate / pll->div) * (pll->mul + 1); ++ return (parent_rate / div) * (mul + 1); + } + + static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate, +@@ -308,7 +320,7 @@ static const struct clk_ops pll_ops = { + }; + + static struct clk * __init +-at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name, ++at91_clk_register_pll(struct regmap *regmap, unsigned int irq, const char *name, + const char *parent_name, u8 id, + const struct clk_pll_layout *layout, + const struct clk_pll_characteristics *characteristics) +@@ -318,7 +330,7 @@ at91_clk_register_pll(struct at91_pmc *p + struct clk_init_data init; + int ret; + int offset = PLL_REG(id); +- u32 tmp; ++ unsigned int pllr; + + if (id > PLL_MAX_ID) + return ERR_PTR(-EINVAL); +@@ -337,11 +349,11 @@ at91_clk_register_pll(struct at91_pmc *p + pll->hw.init = &init; + pll->layout = layout; + pll->characteristics = characteristics; +- pll->pmc = pmc; ++ pll->regmap = regmap; + pll->irq = irq; +- tmp = pmc_read(pmc, offset) & layout->pllr_mask; +- pll->div = PLL_DIV(tmp); +- pll->mul = PLL_MUL(tmp, layout); ++ regmap_read(regmap, offset, &pllr); ++ pll->div = PLL_DIV(pllr); ++ pll->mul = PLL_MUL(pllr, layout); + init_waitqueue_head(&pll->wait); + irq_set_status_flags(pll->irq, IRQ_NOAUTOEN); + ret = request_irq(pll->irq, clk_pll_irq_handler, IRQF_TRIGGER_HIGH, +@@ -483,12 +495,13 @@ of_at91_clk_pll_get_characteristics(stru + } + + static void __init +-of_at91_clk_pll_setup(struct device_node *np, struct at91_pmc *pmc, ++of_at91_clk_pll_setup(struct device_node *np, + const struct clk_pll_layout *layout) + { + u32 id; + unsigned int irq; + struct clk *clk; ++ struct regmap *regmap; + const char *parent_name; + const char *name = np->name; + struct clk_pll_characteristics *characteristics; +@@ -500,6 +513,10 @@ of_at91_clk_pll_setup(struct device_node + + of_property_read_string(np, "clock-output-names", &name); + ++ regmap = syscon_node_to_regmap(of_get_parent(np)); ++ if (IS_ERR(regmap)) ++ return; ++ + characteristics = of_at91_clk_pll_get_characteristics(np); + if (!characteristics) + return; +@@ -508,7 +525,7 @@ of_at91_clk_pll_setup(struct device_node + if (!irq) + return; + +- clk = at91_clk_register_pll(pmc, irq, name, parent_name, id, layout, ++ clk = at91_clk_register_pll(regmap, irq, name, parent_name, id, layout, + characteristics); + if (IS_ERR(clk)) + goto out_free_characteristics; +@@ -520,26 +537,30 @@ of_at91_clk_pll_setup(struct device_node + kfree(characteristics); + } + +-void __init of_at91rm9200_clk_pll_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_at91rm9200_clk_pll_setup(struct device_node *np) + { +- of_at91_clk_pll_setup(np, pmc, &at91rm9200_pll_layout); ++ of_at91_clk_pll_setup(np, &at91rm9200_pll_layout); + } ++CLK_OF_DECLARE(at91rm9200_clk_pll, "atmel,at91rm9200-clk-pll", ++ of_at91rm9200_clk_pll_setup); + +-void __init of_at91sam9g45_clk_pll_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_at91sam9g45_clk_pll_setup(struct device_node *np) + { +- of_at91_clk_pll_setup(np, pmc, &at91sam9g45_pll_layout); ++ of_at91_clk_pll_setup(np, &at91sam9g45_pll_layout); + } ++CLK_OF_DECLARE(at91sam9g45_clk_pll, "atmel,at91sam9g45-clk-pll", ++ of_at91sam9g45_clk_pll_setup); + +-void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np) + { +- of_at91_clk_pll_setup(np, pmc, &at91sam9g20_pllb_layout); ++ of_at91_clk_pll_setup(np, &at91sam9g20_pllb_layout); + } ++CLK_OF_DECLARE(at91sam9g20_clk_pllb, "atmel,at91sam9g20-clk-pllb", ++ of_at91sam9g20_clk_pllb_setup); + +-void __init of_sama5d3_clk_pll_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_sama5d3_clk_pll_setup(struct device_node *np) + { +- of_at91_clk_pll_setup(np, pmc, &sama5d3_pll_layout); ++ of_at91_clk_pll_setup(np, &sama5d3_pll_layout); + } ++CLK_OF_DECLARE(sama5d3_clk_pll, "atmel,sama5d3-clk-pll", ++ of_sama5d3_clk_pll_setup); +--- a/drivers/clk/at91/clk-plldiv.c ++++ b/drivers/clk/at91/clk-plldiv.c +@@ -14,6 +14,8 @@ + #include <linux/of.h> + #include <linux/of_address.h> + #include <linux/io.h> ++#include <linux/mfd/syscon.h> ++#include <linux/regmap.h> + + #include "pmc.h" + +@@ -21,16 +23,18 @@ + + struct clk_plldiv { + struct clk_hw hw; +- struct at91_pmc *pmc; ++ struct regmap *regmap; + }; + + static unsigned long clk_plldiv_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) + { + struct clk_plldiv *plldiv = to_clk_plldiv(hw); +- struct at91_pmc *pmc = plldiv->pmc; ++ unsigned int mckr; + +- if (pmc_read(pmc, AT91_PMC_MCKR) & AT91_PMC_PLLADIV2) ++ regmap_read(plldiv->regmap, AT91_PMC_MCKR, &mckr); ++ ++ if (mckr & AT91_PMC_PLLADIV2) + return parent_rate / 2; + + return parent_rate; +@@ -57,18 +61,12 @@ static int clk_plldiv_set_rate(struct cl + unsigned long parent_rate) + { + struct clk_plldiv *plldiv = to_clk_plldiv(hw); +- struct at91_pmc *pmc = plldiv->pmc; +- u32 tmp; + +- if (parent_rate != rate && (parent_rate / 2) != rate) ++ if ((parent_rate != rate) && (parent_rate / 2 != rate)) + return -EINVAL; + +- pmc_lock(pmc); +- tmp = pmc_read(pmc, AT91_PMC_MCKR) & ~AT91_PMC_PLLADIV2; +- if ((parent_rate / 2) == rate) +- tmp |= AT91_PMC_PLLADIV2; +- pmc_write(pmc, AT91_PMC_MCKR, tmp); +- pmc_unlock(pmc); ++ regmap_update_bits(plldiv->regmap, AT91_PMC_MCKR, AT91_PMC_PLLADIV2, ++ parent_rate != rate ? AT91_PMC_PLLADIV2 : 0); + + return 0; + } +@@ -80,7 +78,7 @@ static const struct clk_ops plldiv_ops = + }; + + static struct clk * __init +-at91_clk_register_plldiv(struct at91_pmc *pmc, const char *name, ++at91_clk_register_plldiv(struct regmap *regmap, const char *name, + const char *parent_name) + { + struct clk_plldiv *plldiv; +@@ -98,7 +96,7 @@ at91_clk_register_plldiv(struct at91_pmc + init.flags = CLK_SET_RATE_GATE; + + plldiv->hw.init = &init; +- plldiv->pmc = pmc; ++ plldiv->regmap = regmap; + + clk = clk_register(NULL, &plldiv->hw); + +@@ -109,27 +107,27 @@ at91_clk_register_plldiv(struct at91_pmc + } + + static void __init +-of_at91_clk_plldiv_setup(struct device_node *np, struct at91_pmc *pmc) ++of_at91sam9x5_clk_plldiv_setup(struct device_node *np) + { + struct clk *clk; + const char *parent_name; + const char *name = np->name; ++ struct regmap *regmap; + + parent_name = of_clk_get_parent_name(np, 0); + + of_property_read_string(np, "clock-output-names", &name); + +- clk = at91_clk_register_plldiv(pmc, name, parent_name); ++ regmap = syscon_node_to_regmap(of_get_parent(np)); ++ if (IS_ERR(regmap)) ++ return; + ++ clk = at91_clk_register_plldiv(regmap, name, parent_name); + if (IS_ERR(clk)) + return; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); + return; + } +- +-void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np, +- struct at91_pmc *pmc) +-{ +- of_at91_clk_plldiv_setup(np, pmc); +-} ++CLK_OF_DECLARE(at91sam9x5_clk_plldiv, "atmel,at91sam9x5-clk-plldiv", ++ of_at91sam9x5_clk_plldiv_setup); +--- a/drivers/clk/at91/clk-programmable.c ++++ b/drivers/clk/at91/clk-programmable.c +@@ -16,6 +16,8 @@ + #include <linux/io.h> + #include <linux/wait.h> + #include <linux/sched.h> ++#include <linux/mfd/syscon.h> ++#include <linux/regmap.h> + + #include "pmc.h" + +@@ -24,6 +26,7 @@ + + #define PROG_STATUS_MASK(id) (1 << ((id) + 8)) + #define PROG_PRES_MASK 0x7 ++#define PROG_PRES(layout, pckr) ((pckr >> layout->pres_shift) & PROG_PRES_MASK) + #define PROG_MAX_RM9200_CSS 3 + + struct clk_programmable_layout { +@@ -34,7 +37,7 @@ struct clk_programmable_layout { + + struct clk_programmable { + struct clk_hw hw; +- struct at91_pmc *pmc; ++ struct regmap *regmap; + u8 id; + const struct clk_programmable_layout *layout; + }; +@@ -44,14 +47,12 @@ struct clk_programmable { + static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) + { +- u32 pres; + struct clk_programmable *prog = to_clk_programmable(hw); +- struct at91_pmc *pmc = prog->pmc; +- const struct clk_programmable_layout *layout = prog->layout; ++ unsigned int pckr; ++ ++ regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr); + +- pres = (pmc_read(pmc, AT91_PMC_PCKR(prog->id)) >> layout->pres_shift) & +- PROG_PRES_MASK; +- return parent_rate >> pres; ++ return parent_rate >> PROG_PRES(prog->layout, pckr); + } + + static int clk_programmable_determine_rate(struct clk_hw *hw, +@@ -101,36 +102,36 @@ static int clk_programmable_set_parent(s + { + struct clk_programmable *prog = to_clk_programmable(hw); + const struct clk_programmable_layout *layout = prog->layout; +- struct at91_pmc *pmc = prog->pmc; +- u32 tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id)) & ~layout->css_mask; ++ unsigned int mask = layout->css_mask; ++ unsigned int pckr = 0; + + if (layout->have_slck_mck) +- tmp &= AT91_PMC_CSSMCK_MCK; ++ mask |= AT91_PMC_CSSMCK_MCK; + + if (index > layout->css_mask) { +- if (index > PROG_MAX_RM9200_CSS && layout->have_slck_mck) { +- tmp |= AT91_PMC_CSSMCK_MCK; +- return 0; +- } else { ++ if (index > PROG_MAX_RM9200_CSS && !layout->have_slck_mck) + return -EINVAL; +- } ++ ++ pckr |= AT91_PMC_CSSMCK_MCK; + } + +- pmc_write(pmc, AT91_PMC_PCKR(prog->id), tmp | index); ++ regmap_update_bits(prog->regmap, AT91_PMC_PCKR(prog->id), mask, pckr); ++ + return 0; + } + + static u8 clk_programmable_get_parent(struct clk_hw *hw) + { +- u32 tmp; +- u8 ret; + struct clk_programmable *prog = to_clk_programmable(hw); +- struct at91_pmc *pmc = prog->pmc; + const struct clk_programmable_layout *layout = prog->layout; ++ unsigned int pckr; ++ u8 ret; ++ ++ regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr); ++ ++ ret = pckr & layout->css_mask; + +- tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id)); +- ret = tmp & layout->css_mask; +- if (layout->have_slck_mck && (tmp & AT91_PMC_CSSMCK_MCK) && !ret) ++ if (layout->have_slck_mck && (pckr & AT91_PMC_CSSMCK_MCK) && !ret) + ret = PROG_MAX_RM9200_CSS + 1; + + return ret; +@@ -140,26 +141,27 @@ static int clk_programmable_set_rate(str + unsigned long parent_rate) + { + struct clk_programmable *prog = to_clk_programmable(hw); +- struct at91_pmc *pmc = prog->pmc; + const struct clk_programmable_layout *layout = prog->layout; + unsigned long div = parent_rate / rate; ++ unsigned int pckr; + int shift = 0; +- u32 tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id)) & +- ~(PROG_PRES_MASK << layout->pres_shift); ++ ++ regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr); + + if (!div) + return -EINVAL; + + shift = fls(div) - 1; + +- if (div != (1<<shift)) ++ if (div != (1 << shift)) + return -EINVAL; + + if (shift >= PROG_PRES_MASK) + return -EINVAL; + +- pmc_write(pmc, AT91_PMC_PCKR(prog->id), +- tmp | (shift << layout->pres_shift)); ++ regmap_update_bits(prog->regmap, AT91_PMC_PCKR(prog->id), ++ PROG_PRES_MASK << layout->pres_shift, ++ shift << layout->pres_shift); + + return 0; + } +@@ -173,7 +175,7 @@ static const struct clk_ops programmable + }; + + static struct clk * __init +-at91_clk_register_programmable(struct at91_pmc *pmc, ++at91_clk_register_programmable(struct regmap *regmap, + const char *name, const char **parent_names, + u8 num_parents, u8 id, + const struct clk_programmable_layout *layout) +@@ -198,7 +200,7 @@ at91_clk_register_programmable(struct at + prog->id = id; + prog->layout = layout; + prog->hw.init = &init; +- prog->pmc = pmc; ++ prog->regmap = regmap; + + clk = clk_register(NULL, &prog->hw); + if (IS_ERR(clk)) +@@ -226,7 +228,7 @@ static const struct clk_programmable_lay + }; + + static void __init +-of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc, ++of_at91_clk_prog_setup(struct device_node *np, + const struct clk_programmable_layout *layout) + { + int num; +@@ -236,6 +238,7 @@ of_at91_clk_prog_setup(struct device_nod + const char *parent_names[PROG_SOURCE_MAX]; + const char *name; + struct device_node *progclknp; ++ struct regmap *regmap; + + num_parents = of_clk_get_parent_count(np); + if (num_parents <= 0 || num_parents > PROG_SOURCE_MAX) +@@ -247,6 +250,10 @@ of_at91_clk_prog_setup(struct device_nod + if (!num || num > (PROG_ID_MAX + 1)) + return; + ++ regmap = syscon_node_to_regmap(of_get_parent(np)); ++ if (IS_ERR(regmap)) ++ return; ++ + for_each_child_of_node(np, progclknp) { + if (of_property_read_u32(progclknp, "reg", &id)) + continue; +@@ -254,7 +261,7 @@ of_at91_clk_prog_setup(struct device_nod + if (of_property_read_string(np, "clock-output-names", &name)) + name = progclknp->name; + +- clk = at91_clk_register_programmable(pmc, name, ++ clk = at91_clk_register_programmable(regmap, name, + parent_names, num_parents, + id, layout); + if (IS_ERR(clk)) +@@ -265,20 +272,23 @@ of_at91_clk_prog_setup(struct device_nod + } + + +-void __init of_at91rm9200_clk_prog_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_at91rm9200_clk_prog_setup(struct device_node *np) + { +- of_at91_clk_prog_setup(np, pmc, &at91rm9200_programmable_layout); ++ of_at91_clk_prog_setup(np, &at91rm9200_programmable_layout); + } ++CLK_OF_DECLARE(at91rm9200_clk_prog, "atmel,at91rm9200-clk-programmable", ++ of_at91rm9200_clk_prog_setup); + +-void __init of_at91sam9g45_clk_prog_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_at91sam9g45_clk_prog_setup(struct device_node *np) + { +- of_at91_clk_prog_setup(np, pmc, &at91sam9g45_programmable_layout); ++ of_at91_clk_prog_setup(np, &at91sam9g45_programmable_layout); + } ++CLK_OF_DECLARE(at91sam9g45_clk_prog, "atmel,at91sam9g45-clk-programmable", ++ of_at91sam9g45_clk_prog_setup); + +-void __init of_at91sam9x5_clk_prog_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_at91sam9x5_clk_prog_setup(struct device_node *np) + { +- of_at91_clk_prog_setup(np, pmc, &at91sam9x5_programmable_layout); ++ of_at91_clk_prog_setup(np, &at91sam9x5_programmable_layout); + } ++CLK_OF_DECLARE(at91sam9x5_clk_prog, "atmel,at91sam9x5-clk-programmable", ++ of_at91sam9x5_clk_prog_setup); +--- a/drivers/clk/at91/clk-slow.c ++++ b/drivers/clk/at91/clk-slow.c +@@ -22,6 +22,8 @@ + #include <linux/io.h> + #include <linux/interrupt.h> + #include <linux/irq.h> ++#include <linux/mfd/syscon.h> ++#include <linux/regmap.h> + #include <linux/sched.h> + #include <linux/wait.h> + +@@ -59,7 +61,7 @@ struct clk_slow_rc_osc { + + struct clk_sam9260_slow { + struct clk_hw hw; +- struct at91_pmc *pmc; ++ struct regmap *regmap; + }; + + #define to_clk_sam9260_slow(hw) container_of(hw, struct clk_sam9260_slow, hw) +@@ -393,8 +395,11 @@ void __init of_at91sam9x5_clk_slow_setup + static u8 clk_sam9260_slow_get_parent(struct clk_hw *hw) + { + struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(hw); ++ unsigned int status; + +- return !!(pmc_read(slowck->pmc, AT91_PMC_SR) & AT91_PMC_OSCSEL); ++ regmap_read(slowck->regmap, AT91_PMC_SR, &status); ++ ++ return status & AT91_PMC_OSCSEL ? 1 : 0; + } + + static const struct clk_ops sam9260_slow_ops = { +@@ -402,7 +407,7 @@ static const struct clk_ops sam9260_slow + }; + + static struct clk * __init +-at91_clk_register_sam9260_slow(struct at91_pmc *pmc, ++at91_clk_register_sam9260_slow(struct regmap *regmap, + const char *name, + const char **parent_names, + int num_parents) +@@ -411,7 +416,7 @@ at91_clk_register_sam9260_slow(struct at + struct clk *clk = NULL; + struct clk_init_data init; + +- if (!pmc || !name) ++ if (!name) + return ERR_PTR(-EINVAL); + + if (!parent_names || !num_parents) +@@ -428,7 +433,7 @@ at91_clk_register_sam9260_slow(struct at + init.flags = 0; + + slowck->hw.init = &init; +- slowck->pmc = pmc; ++ slowck->regmap = regmap; + + clk = clk_register(NULL, &slowck->hw); + if (IS_ERR(clk)) +@@ -439,29 +444,34 @@ at91_clk_register_sam9260_slow(struct at + return clk; + } + +-void __init of_at91sam9260_clk_slow_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_at91sam9260_clk_slow_setup(struct device_node *np) + { + struct clk *clk; + const char *parent_names[2]; + int num_parents; + const char *name = np->name; ++ struct regmap *regmap; + + num_parents = of_clk_get_parent_count(np); + if (num_parents != 2) + return; + + of_clk_parent_fill(np, parent_names, num_parents); ++ regmap = syscon_node_to_regmap(of_get_parent(np)); ++ if (IS_ERR(regmap)) ++ return; + + of_property_read_string(np, "clock-output-names", &name); + +- clk = at91_clk_register_sam9260_slow(pmc, name, parent_names, ++ clk = at91_clk_register_sam9260_slow(regmap, name, parent_names, + num_parents); + if (IS_ERR(clk)) + return; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); + } ++CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow", ++ of_at91sam9260_clk_slow_setup); + + /* + * FIXME: All slow clk users are not properly claiming it (get + prepare + +--- a/drivers/clk/at91/clk-smd.c ++++ b/drivers/clk/at91/clk-smd.c +@@ -14,6 +14,8 @@ + #include <linux/of.h> + #include <linux/of_address.h> + #include <linux/io.h> ++#include <linux/mfd/syscon.h> ++#include <linux/regmap.h> + + #include "pmc.h" + +@@ -24,7 +26,7 @@ + + struct at91sam9x5_clk_smd { + struct clk_hw hw; +- struct at91_pmc *pmc; ++ struct regmap *regmap; + }; + + #define to_at91sam9x5_clk_smd(hw) \ +@@ -33,13 +35,13 @@ struct at91sam9x5_clk_smd { + static unsigned long at91sam9x5_clk_smd_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) + { +- u32 tmp; +- u8 smddiv; + struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw); +- struct at91_pmc *pmc = smd->pmc; ++ unsigned int smdr; ++ u8 smddiv; ++ ++ regmap_read(smd->regmap, AT91_PMC_SMD, &smdr); ++ smddiv = (smdr & AT91_PMC_SMD_DIV) >> SMD_DIV_SHIFT; + +- tmp = pmc_read(pmc, AT91_PMC_SMD); +- smddiv = (tmp & AT91_PMC_SMD_DIV) >> SMD_DIV_SHIFT; + return parent_rate / (smddiv + 1); + } + +@@ -67,40 +69,38 @@ static long at91sam9x5_clk_smd_round_rat + + static int at91sam9x5_clk_smd_set_parent(struct clk_hw *hw, u8 index) + { +- u32 tmp; + struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw); +- struct at91_pmc *pmc = smd->pmc; + + if (index > 1) + return -EINVAL; +- tmp = pmc_read(pmc, AT91_PMC_SMD) & ~AT91_PMC_SMDS; +- if (index) +- tmp |= AT91_PMC_SMDS; +- pmc_write(pmc, AT91_PMC_SMD, tmp); ++ ++ regmap_update_bits(smd->regmap, AT91_PMC_SMD, AT91_PMC_SMDS, ++ index ? AT91_PMC_SMDS : 0); ++ + return 0; + } + + static u8 at91sam9x5_clk_smd_get_parent(struct clk_hw *hw) + { + struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw); +- struct at91_pmc *pmc = smd->pmc; ++ unsigned int smdr; + +- return pmc_read(pmc, AT91_PMC_SMD) & AT91_PMC_SMDS; ++ regmap_read(smd->regmap, AT91_PMC_SMD, &smdr); ++ ++ return smdr & AT91_PMC_SMDS; + } + + static int at91sam9x5_clk_smd_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) + { +- u32 tmp; + struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw); +- struct at91_pmc *pmc = smd->pmc; + unsigned long div = parent_rate / rate; + + if (parent_rate % rate || div < 1 || div > (SMD_MAX_DIV + 1)) + return -EINVAL; +- tmp = pmc_read(pmc, AT91_PMC_SMD) & ~AT91_PMC_SMD_DIV; +- tmp |= (div - 1) << SMD_DIV_SHIFT; +- pmc_write(pmc, AT91_PMC_SMD, tmp); ++ ++ regmap_update_bits(smd->regmap, AT91_PMC_SMD, AT91_PMC_SMD_DIV, ++ (div - 1) << SMD_DIV_SHIFT); + + return 0; + } +@@ -114,7 +114,7 @@ static const struct clk_ops at91sam9x5_s + }; + + static struct clk * __init +-at91sam9x5_clk_register_smd(struct at91_pmc *pmc, const char *name, ++at91sam9x5_clk_register_smd(struct regmap *regmap, const char *name, + const char **parent_names, u8 num_parents) + { + struct at91sam9x5_clk_smd *smd; +@@ -132,7 +132,7 @@ at91sam9x5_clk_register_smd(struct at91_ + init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; + + smd->hw.init = &init; +- smd->pmc = pmc; ++ smd->regmap = regmap; + + clk = clk_register(NULL, &smd->hw); + if (IS_ERR(clk)) +@@ -141,13 +141,13 @@ at91sam9x5_clk_register_smd(struct at91_ + return clk; + } + +-void __init of_at91sam9x5_clk_smd_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_at91sam9x5_clk_smd_setup(struct device_node *np) + { + struct clk *clk; + int num_parents; + const char *parent_names[SMD_SOURCE_MAX]; + const char *name = np->name; ++ struct regmap *regmap; + + num_parents = of_clk_get_parent_count(np); + if (num_parents <= 0 || num_parents > SMD_SOURCE_MAX) +@@ -157,10 +157,16 @@ void __init of_at91sam9x5_clk_smd_setup( + + of_property_read_string(np, "clock-output-names", &name); + +- clk = at91sam9x5_clk_register_smd(pmc, name, parent_names, ++ regmap = syscon_node_to_regmap(of_get_parent(np)); ++ if (IS_ERR(regmap)) ++ return; ++ ++ clk = at91sam9x5_clk_register_smd(regmap, name, parent_names, + num_parents); + if (IS_ERR(clk)) + return; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); + } ++CLK_OF_DECLARE(at91sam9x5_clk_smd, "atmel,at91sam9x5-clk-smd", ++ of_at91sam9x5_clk_smd_setup); +--- a/drivers/clk/at91/clk-system.c ++++ b/drivers/clk/at91/clk-system.c +@@ -19,6 +19,8 @@ + #include <linux/interrupt.h> + #include <linux/wait.h> + #include <linux/sched.h> ++#include <linux/mfd/syscon.h> ++#include <linux/regmap.h> + + #include "pmc.h" + +@@ -29,7 +31,7 @@ + #define to_clk_system(hw) container_of(hw, struct clk_system, hw) + struct clk_system { + struct clk_hw hw; +- struct at91_pmc *pmc; ++ struct regmap *regmap; + unsigned int irq; + wait_queue_head_t wait; + u8 id; +@@ -49,24 +51,32 @@ static irqreturn_t clk_system_irq_handle + return IRQ_HANDLED; + } + ++static inline bool clk_system_ready(struct regmap *regmap, int id) ++{ ++ unsigned int status; ++ ++ regmap_read(regmap, AT91_PMC_SR, &status); ++ ++ return status & (1 << id) ? 1 : 0; ++} ++ + static int clk_system_prepare(struct clk_hw *hw) + { + struct clk_system *sys = to_clk_system(hw); +- struct at91_pmc *pmc = sys->pmc; +- u32 mask = 1 << sys->id; + +- pmc_write(pmc, AT91_PMC_SCER, mask); ++ regmap_write(sys->regmap, AT91_PMC_SCER, 1 << sys->id); + + if (!is_pck(sys->id)) + return 0; + +- while (!(pmc_read(pmc, AT91_PMC_SR) & mask)) { ++ while (!clk_system_ready(sys->regmap, sys->id)) { + if (sys->irq) { + enable_irq(sys->irq); + wait_event(sys->wait, +- pmc_read(pmc, AT91_PMC_SR) & mask); +- } else ++ clk_system_ready(sys->regmap, sys->id)); ++ } else { + cpu_relax(); ++ } + } + return 0; + } +@@ -74,23 +84,26 @@ static int clk_system_prepare(struct clk + static void clk_system_unprepare(struct clk_hw *hw) + { + struct clk_system *sys = to_clk_system(hw); +- struct at91_pmc *pmc = sys->pmc; + +- pmc_write(pmc, AT91_PMC_SCDR, 1 << sys->id); ++ regmap_write(sys->regmap, AT91_PMC_SCDR, 1 << sys->id); + } + + static int clk_system_is_prepared(struct clk_hw *hw) + { + struct clk_system *sys = to_clk_system(hw); +- struct at91_pmc *pmc = sys->pmc; ++ unsigned int status; ++ ++ regmap_read(sys->regmap, AT91_PMC_SCSR, &status); + +- if (!(pmc_read(pmc, AT91_PMC_SCSR) & (1 << sys->id))) ++ if (!(status & (1 << sys->id))) + return 0; + + if (!is_pck(sys->id)) + return 1; + +- return !!(pmc_read(pmc, AT91_PMC_SR) & (1 << sys->id)); ++ regmap_read(sys->regmap, AT91_PMC_SR, &status); ++ ++ return status & (1 << sys->id) ? 1 : 0; + } + + static const struct clk_ops system_ops = { +@@ -100,7 +113,7 @@ static const struct clk_ops system_ops = + }; + + static struct clk * __init +-at91_clk_register_system(struct at91_pmc *pmc, const char *name, ++at91_clk_register_system(struct regmap *regmap, const char *name, + const char *parent_name, u8 id, int irq) + { + struct clk_system *sys; +@@ -123,7 +136,7 @@ at91_clk_register_system(struct at91_pmc + + sys->id = id; + sys->hw.init = &init; +- sys->pmc = pmc; ++ sys->regmap = regmap; + sys->irq = irq; + if (irq) { + init_waitqueue_head(&sys->wait); +@@ -146,8 +159,7 @@ at91_clk_register_system(struct at91_pmc + return clk; + } + +-static void __init +-of_at91_clk_sys_setup(struct device_node *np, struct at91_pmc *pmc) ++static void __init of_at91rm9200_clk_sys_setup(struct device_node *np) + { + int num; + int irq = 0; +@@ -156,11 +168,16 @@ of_at91_clk_sys_setup(struct device_node + const char *name; + struct device_node *sysclknp; + const char *parent_name; ++ struct regmap *regmap; + + num = of_get_child_count(np); + if (num > (SYSTEM_MAX_ID + 1)) + return; + ++ regmap = syscon_node_to_regmap(of_get_parent(np)); ++ if (IS_ERR(regmap)) ++ return; ++ + for_each_child_of_node(np, sysclknp) { + if (of_property_read_u32(sysclknp, "reg", &id)) + continue; +@@ -173,16 +190,13 @@ of_at91_clk_sys_setup(struct device_node + + parent_name = of_clk_get_parent_name(sysclknp, 0); + +- clk = at91_clk_register_system(pmc, name, parent_name, id, irq); ++ clk = at91_clk_register_system(regmap, name, parent_name, id, ++ irq); + if (IS_ERR(clk)) + continue; + + of_clk_add_provider(sysclknp, of_clk_src_simple_get, clk); + } + } +- +-void __init of_at91rm9200_clk_sys_setup(struct device_node *np, +- struct at91_pmc *pmc) +-{ +- of_at91_clk_sys_setup(np, pmc); +-} ++CLK_OF_DECLARE(at91rm9200_clk_sys, "atmel,at91rm9200-clk-system", ++ of_at91rm9200_clk_sys_setup); +--- a/drivers/clk/at91/clk-usb.c ++++ b/drivers/clk/at91/clk-usb.c +@@ -14,6 +14,8 @@ + #include <linux/of.h> + #include <linux/of_address.h> + #include <linux/io.h> ++#include <linux/mfd/syscon.h> ++#include <linux/regmap.h> + + #include "pmc.h" + +@@ -27,7 +29,7 @@ + + struct at91sam9x5_clk_usb { + struct clk_hw hw; +- struct at91_pmc *pmc; ++ struct regmap *regmap; + }; + + #define to_at91sam9x5_clk_usb(hw) \ +@@ -35,7 +37,7 @@ struct at91sam9x5_clk_usb { + + struct at91rm9200_clk_usb { + struct clk_hw hw; +- struct at91_pmc *pmc; ++ struct regmap *regmap; + u32 divisors[4]; + }; + +@@ -45,13 +47,12 @@ struct at91rm9200_clk_usb { + static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) + { +- u32 tmp; +- u8 usbdiv; + struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); +- struct at91_pmc *pmc = usb->pmc; ++ unsigned int usbr; ++ u8 usbdiv; + +- tmp = pmc_read(pmc, AT91_PMC_USB); +- usbdiv = (tmp & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT; ++ regmap_read(usb->regmap, AT91_PMC_USB, &usbr); ++ usbdiv = (usbr & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT; + + return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1)); + } +@@ -109,33 +110,31 @@ static int at91sam9x5_clk_usb_determine_ + + static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index) + { +- u32 tmp; + struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); +- struct at91_pmc *pmc = usb->pmc; + + if (index > 1) + return -EINVAL; +- tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_USBS; +- if (index) +- tmp |= AT91_PMC_USBS; +- pmc_write(pmc, AT91_PMC_USB, tmp); ++ ++ regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS, ++ index ? AT91_PMC_USBS : 0); ++ + return 0; + } + + static u8 at91sam9x5_clk_usb_get_parent(struct clk_hw *hw) + { + struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); +- struct at91_pmc *pmc = usb->pmc; ++ unsigned int usbr; + +- return pmc_read(pmc, AT91_PMC_USB) & AT91_PMC_USBS; ++ regmap_read(usb->regmap, AT91_PMC_USB, &usbr); ++ ++ return usbr & AT91_PMC_USBS; + } + + static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) + { +- u32 tmp; + struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); +- struct at91_pmc *pmc = usb->pmc; + unsigned long div; + + if (!rate) +@@ -145,9 +144,8 @@ static int at91sam9x5_clk_usb_set_rate(s + if (div > SAM9X5_USB_MAX_DIV + 1 || !div) + return -EINVAL; + +- tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_OHCIUSBDIV; +- tmp |= (div - 1) << SAM9X5_USB_DIV_SHIFT; +- pmc_write(pmc, AT91_PMC_USB, tmp); ++ regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_OHCIUSBDIV, ++ (div - 1) << SAM9X5_USB_DIV_SHIFT); + + return 0; + } +@@ -163,28 +161,28 @@ static const struct clk_ops at91sam9x5_u + static int at91sam9n12_clk_usb_enable(struct clk_hw *hw) + { + struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); +- struct at91_pmc *pmc = usb->pmc; + +- pmc_write(pmc, AT91_PMC_USB, +- pmc_read(pmc, AT91_PMC_USB) | AT91_PMC_USBS); ++ regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS, ++ AT91_PMC_USBS); ++ + return 0; + } + + static void at91sam9n12_clk_usb_disable(struct clk_hw *hw) + { + struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); +- struct at91_pmc *pmc = usb->pmc; + +- pmc_write(pmc, AT91_PMC_USB, +- pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_USBS); ++ regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS, 0); + } + + static int at91sam9n12_clk_usb_is_enabled(struct clk_hw *hw) + { + struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); +- struct at91_pmc *pmc = usb->pmc; ++ unsigned int usbr; + +- return !!(pmc_read(pmc, AT91_PMC_USB) & AT91_PMC_USBS); ++ regmap_read(usb->regmap, AT91_PMC_USB, &usbr); ++ ++ return usbr & AT91_PMC_USBS; + } + + static const struct clk_ops at91sam9n12_usb_ops = { +@@ -197,7 +195,7 @@ static const struct clk_ops at91sam9n12_ + }; + + static struct clk * __init +-at91sam9x5_clk_register_usb(struct at91_pmc *pmc, const char *name, ++at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, + const char **parent_names, u8 num_parents) + { + struct at91sam9x5_clk_usb *usb; +@@ -216,7 +214,7 @@ at91sam9x5_clk_register_usb(struct at91_ + CLK_SET_RATE_PARENT; + + usb->hw.init = &init; +- usb->pmc = pmc; ++ usb->regmap = regmap; + + clk = clk_register(NULL, &usb->hw); + if (IS_ERR(clk)) +@@ -226,7 +224,7 @@ at91sam9x5_clk_register_usb(struct at91_ + } + + static struct clk * __init +-at91sam9n12_clk_register_usb(struct at91_pmc *pmc, const char *name, ++at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name, + const char *parent_name) + { + struct at91sam9x5_clk_usb *usb; +@@ -244,7 +242,7 @@ at91sam9n12_clk_register_usb(struct at91 + init.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT; + + usb->hw.init = &init; +- usb->pmc = pmc; ++ usb->regmap = regmap; + + clk = clk_register(NULL, &usb->hw); + if (IS_ERR(clk)) +@@ -257,12 +255,12 @@ static unsigned long at91rm9200_clk_usb_ + unsigned long parent_rate) + { + struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); +- struct at91_pmc *pmc = usb->pmc; +- u32 tmp; ++ unsigned int pllbr; + u8 usbdiv; + +- tmp = pmc_read(pmc, AT91_CKGR_PLLBR); +- usbdiv = (tmp & AT91_PMC_USBDIV) >> RM9200_USB_DIV_SHIFT; ++ regmap_read(usb->regmap, AT91_CKGR_PLLBR, &pllbr); ++ ++ usbdiv = (pllbr & AT91_PMC_USBDIV) >> RM9200_USB_DIV_SHIFT; + if (usb->divisors[usbdiv]) + return parent_rate / usb->divisors[usbdiv]; + +@@ -310,10 +308,8 @@ static long at91rm9200_clk_usb_round_rat + static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) + { +- u32 tmp; + int i; + struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); +- struct at91_pmc *pmc = usb->pmc; + unsigned long div; + + if (!rate) +@@ -323,10 +319,10 @@ static int at91rm9200_clk_usb_set_rate(s + + for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) { + if (usb->divisors[i] == div) { +- tmp = pmc_read(pmc, AT91_CKGR_PLLBR) & +- ~AT91_PMC_USBDIV; +- tmp |= i << RM9200_USB_DIV_SHIFT; +- pmc_write(pmc, AT91_CKGR_PLLBR, tmp); ++ regmap_update_bits(usb->regmap, AT91_CKGR_PLLBR, ++ AT91_PMC_USBDIV, ++ i << RM9200_USB_DIV_SHIFT); ++ + return 0; + } + } +@@ -341,7 +337,7 @@ static const struct clk_ops at91rm9200_u + }; + + static struct clk * __init +-at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name, ++at91rm9200_clk_register_usb(struct regmap *regmap, const char *name, + const char *parent_name, const u32 *divisors) + { + struct at91rm9200_clk_usb *usb; +@@ -359,7 +355,7 @@ at91rm9200_clk_register_usb(struct at91_ + init.flags = CLK_SET_RATE_PARENT; + + usb->hw.init = &init; +- usb->pmc = pmc; ++ usb->regmap = regmap; + memcpy(usb->divisors, divisors, sizeof(usb->divisors)); + + clk = clk_register(NULL, &usb->hw); +@@ -369,13 +365,13 @@ at91rm9200_clk_register_usb(struct at91_ + return clk; + } + +-void __init of_at91sam9x5_clk_usb_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_at91sam9x5_clk_usb_setup(struct device_node *np) + { + struct clk *clk; + int num_parents; + const char *parent_names[USB_SOURCE_MAX]; + const char *name = np->name; ++ struct regmap *regmap; + + num_parents = of_clk_get_parent_count(np); + if (num_parents <= 0 || num_parents > USB_SOURCE_MAX) +@@ -385,19 +381,26 @@ void __init of_at91sam9x5_clk_usb_setup( + + of_property_read_string(np, "clock-output-names", &name); + +- clk = at91sam9x5_clk_register_usb(pmc, name, parent_names, num_parents); ++ regmap = syscon_node_to_regmap(of_get_parent(np)); ++ if (IS_ERR(regmap)) ++ return; ++ ++ clk = at91sam9x5_clk_register_usb(regmap, name, parent_names, ++ num_parents); + if (IS_ERR(clk)) + return; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); + } ++CLK_OF_DECLARE(at91sam9x5_clk_usb, "atmel,at91sam9x5-clk-usb", ++ of_at91sam9x5_clk_usb_setup); + +-void __init of_at91sam9n12_clk_usb_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_at91sam9n12_clk_usb_setup(struct device_node *np) + { + struct clk *clk; + const char *parent_name; + const char *name = np->name; ++ struct regmap *regmap; + + parent_name = of_clk_get_parent_name(np, 0); + if (!parent_name) +@@ -405,20 +408,26 @@ void __init of_at91sam9n12_clk_usb_setup + + of_property_read_string(np, "clock-output-names", &name); + +- clk = at91sam9n12_clk_register_usb(pmc, name, parent_name); ++ regmap = syscon_node_to_regmap(of_get_parent(np)); ++ if (IS_ERR(regmap)) ++ return; ++ ++ clk = at91sam9n12_clk_register_usb(regmap, name, parent_name); + if (IS_ERR(clk)) + return; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); + } ++CLK_OF_DECLARE(at91sam9n12_clk_usb, "atmel,at91sam9n12-clk-usb", ++ of_at91sam9n12_clk_usb_setup); + +-void __init of_at91rm9200_clk_usb_setup(struct device_node *np, +- struct at91_pmc *pmc) ++static void __init of_at91rm9200_clk_usb_setup(struct device_node *np) + { + struct clk *clk; + const char *parent_name; + const char *name = np->name; + u32 divisors[4] = {0, 0, 0, 0}; ++ struct regmap *regmap; + + parent_name = of_clk_get_parent_name(np, 0); + if (!parent_name) +@@ -430,9 +439,15 @@ void __init of_at91rm9200_clk_usb_setup( + + of_property_read_string(np, "clock-output-names", &name); + +- clk = at91rm9200_clk_register_usb(pmc, name, parent_name, divisors); ++ regmap = syscon_node_to_regmap(of_get_parent(np)); ++ if (IS_ERR(regmap)) ++ return; ++ ++ clk = at91rm9200_clk_register_usb(regmap, name, parent_name, divisors); + if (IS_ERR(clk)) + return; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); + } ++CLK_OF_DECLARE(at91rm9200_clk_usb, "atmel,at91rm9200-clk-usb", ++ of_at91rm9200_clk_usb_setup); +--- a/drivers/clk/at91/clk-utmi.c ++++ b/drivers/clk/at91/clk-utmi.c +@@ -19,6 +19,8 @@ + #include <linux/io.h> + #include <linux/sched.h> + #include <linux/wait.h> ++#include <linux/mfd/syscon.h> ++#include <linux/regmap.h> + + #include "pmc.h" + +@@ -26,7 +28,7 @@ + + struct clk_utmi { + struct clk_hw hw; +- struct at91_pmc *pmc; ++ struct regmap *regmap; + unsigned int irq; + wait_queue_head_t wait; + }; +@@ -43,19 +45,27 @@ static irqreturn_t clk_utmi_irq_handler( + return IRQ_HANDLED; + } + ++static inline bool clk_utmi_ready(struct regmap *regmap) ++{ ++ unsigned int status; ++ ++ regmap_read(regmap, AT91_PMC_SR, &status); ++ ++ return status & AT91_PMC_LOCKU; ++} ++ + static int clk_utmi_prepare(struct clk_hw *hw) + { + struct clk_utmi *utmi = to_clk_utmi(hw); +- struct at91_pmc *pmc = utmi->pmc; +- u32 tmp = pmc_read(pmc, AT91_CKGR_UCKR) | AT91_PMC_UPLLEN | +- AT91_PMC_UPLLCOUNT | AT91_PMC_BIASEN; ++ unsigned int uckr = AT91_PMC_UPLLEN | AT91_PMC_UPLLCOUNT | ++ AT91_PMC_BIASEN; + +- pmc_write(pmc, AT91_CKGR_UCKR, tmp); ++ regmap_update_bits(utmi->regmap, AT91_CKGR_UCKR, uckr, uckr); + +- while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU)) { ++ while (!clk_utmi_ready(utmi->regmap)) { + enable_irq(utmi->irq); + wait_event(utmi->wait, +- pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU); ++ clk_utmi_ready(utmi->regmap)); + } + + return 0; +@@ -64,18 +74,15 @@ static int clk_utmi_prepare(struct clk_h + static int clk_utmi_is_prepared(struct clk_hw *hw) + { + struct clk_utmi *utmi = to_clk_utmi(hw); +- struct at91_pmc *pmc = utmi->pmc; + +- return !!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU); ++ return clk_utmi_ready(utmi->regmap); + } + + static void clk_utmi_unprepare(struct clk_hw *hw) + { + struct clk_utmi *utmi = to_clk_utmi(hw); +- struct at91_pmc *pmc = utmi->pmc; +- u32 tmp = pmc_read(pmc, AT91_CKGR_UCKR) & ~AT91_PMC_UPLLEN; + +- pmc_write(pmc, AT91_CKGR_UCKR, tmp); ++ regmap_update_bits(utmi->regmap, AT91_CKGR_UCKR, AT91_PMC_UPLLEN, 0); + } + + static unsigned long clk_utmi_recalc_rate(struct clk_hw *hw, +@@ -93,7 +100,7 @@ static const struct clk_ops utmi_ops = { + }; + + static struct clk * __init +-at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int irq, ++at91_clk_register_utmi(struct regmap *regmap, unsigned int irq, + const char *name, const char *parent_name) + { + int ret; +@@ -112,7 +119,7 @@ at91_clk_register_utmi(struct at91_pmc * + init.flags = CLK_SET_RATE_GATE; + + utmi->hw.init = &init; +- utmi->pmc = pmc; ++ utmi->regmap = regmap; + utmi->irq = irq; + init_waitqueue_head(&utmi->wait); + irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN); +@@ -132,13 +139,13 @@ at91_clk_register_utmi(struct at91_pmc * + return clk; + } + +-static void __init +-of_at91_clk_utmi_setup(struct device_node *np, struct at91_pmc *pmc) ++static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np) + { + unsigned int irq; + struct clk *clk; + const char *parent_name; + const char *name = np->name; ++ struct regmap *regmap; + + parent_name = of_clk_get_parent_name(np, 0); + +@@ -148,16 +155,16 @@ of_at91_clk_utmi_setup(struct device_nod + if (!irq) + return; + +- clk = at91_clk_register_utmi(pmc, irq, name, parent_name); ++ regmap = syscon_node_to_regmap(of_get_parent(np)); ++ if (IS_ERR(regmap)) ++ return; ++ ++ clk = at91_clk_register_utmi(regmap, irq, name, parent_name); + if (IS_ERR(clk)) + return; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); + return; + } +- +-void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np, +- struct at91_pmc *pmc) +-{ +- of_at91_clk_utmi_setup(np, pmc); +-} ++CLK_OF_DECLARE(at91sam9x5_clk_utmi, "atmel,at91sam9x5-clk-utmi", ++ of_at91sam9x5_clk_utmi_setup); +--- a/drivers/clk/at91/pmc.c ++++ b/drivers/clk/at91/pmc.c +@@ -20,6 +20,7 @@ + #include <linux/irqdomain.h> + #include <linux/of_irq.h> + #include <linux/mfd/syscon.h> ++#include <linux/regmap.h> + + #include <asm/proc-fns.h> + +@@ -70,14 +71,14 @@ static void pmc_irq_mask(struct irq_data + { + struct at91_pmc *pmc = irq_data_get_irq_chip_data(d); + +- pmc_write(pmc, AT91_PMC_IDR, 1 << d->hwirq); ++ regmap_write(pmc->regmap, AT91_PMC_IDR, 1 << d->hwirq); + } + + static void pmc_irq_unmask(struct irq_data *d) + { + struct at91_pmc *pmc = irq_data_get_irq_chip_data(d); + +- pmc_write(pmc, AT91_PMC_IER, 1 << d->hwirq); ++ regmap_write(pmc->regmap, AT91_PMC_IER, 1 << d->hwirq); + } + + static int pmc_irq_set_type(struct irq_data *d, unsigned type) +@@ -94,15 +95,15 @@ static void pmc_irq_suspend(struct irq_d + { + struct at91_pmc *pmc = irq_data_get_irq_chip_data(d); + +- pmc->imr = pmc_read(pmc, AT91_PMC_IMR); +- pmc_write(pmc, AT91_PMC_IDR, pmc->imr); ++ regmap_read(pmc->regmap, AT91_PMC_IMR, &pmc->imr); ++ regmap_write(pmc->regmap, AT91_PMC_IDR, pmc->imr); + } + + static void pmc_irq_resume(struct irq_data *d) + { + struct at91_pmc *pmc = irq_data_get_irq_chip_data(d); + +- pmc_write(pmc, AT91_PMC_IER, pmc->imr); ++ regmap_write(pmc->regmap, AT91_PMC_IER, pmc->imr); + } + + static struct irq_chip pmc_irq = { +@@ -161,10 +162,14 @@ static const struct irq_domain_ops pmc_i + static irqreturn_t pmc_irq_handler(int irq, void *data) + { + struct at91_pmc *pmc = (struct at91_pmc *)data; ++ unsigned int tmpsr, imr; + unsigned long sr; + int n; + +- sr = pmc_read(pmc, AT91_PMC_SR) & pmc_read(pmc, AT91_PMC_IMR); ++ regmap_read(pmc->regmap, AT91_PMC_SR, &tmpsr); ++ regmap_read(pmc->regmap, AT91_PMC_IMR, &imr); ++ ++ sr = tmpsr & imr; + if (!sr) + return IRQ_NONE; + +@@ -239,17 +244,15 @@ static struct at91_pmc *__init at91_pmc_ + if (!pmc) + return NULL; + +- spin_lock_init(&pmc->lock); + pmc->regmap = regmap; + pmc->virq = virq; + pmc->caps = caps; + + pmc->irqdomain = irq_domain_add_linear(np, 32, &pmc_irq_ops, pmc); +- + if (!pmc->irqdomain) + goto out_free_pmc; + +- pmc_write(pmc, AT91_PMC_IDR, 0xffffffff); ++ regmap_write(pmc->regmap, AT91_PMC_IDR, 0xffffffff); + if (request_irq(pmc->virq, pmc_irq_handler, + IRQF_SHARED | IRQF_COND_SUSPEND, "pmc", pmc)) + goto out_remove_irqdomain; +@@ -264,137 +267,10 @@ static struct at91_pmc *__init at91_pmc_ + return NULL; + } + +-static const struct of_device_id pmc_clk_ids[] __initconst = { +- /* Slow oscillator */ +- { +- .compatible = "atmel,at91sam9260-clk-slow", +- .data = of_at91sam9260_clk_slow_setup, +- }, +- /* Main clock */ +- { +- .compatible = "atmel,at91rm9200-clk-main-osc", +- .data = of_at91rm9200_clk_main_osc_setup, +- }, +- { +- .compatible = "atmel,at91sam9x5-clk-main-rc-osc", +- .data = of_at91sam9x5_clk_main_rc_osc_setup, +- }, +- { +- .compatible = "atmel,at91rm9200-clk-main", +- .data = of_at91rm9200_clk_main_setup, +- }, +- { +- .compatible = "atmel,at91sam9x5-clk-main", +- .data = of_at91sam9x5_clk_main_setup, +- }, +- /* PLL clocks */ +- { +- .compatible = "atmel,at91rm9200-clk-pll", +- .data = of_at91rm9200_clk_pll_setup, +- }, +- { +- .compatible = "atmel,at91sam9g45-clk-pll", +- .data = of_at91sam9g45_clk_pll_setup, +- }, +- { +- .compatible = "atmel,at91sam9g20-clk-pllb", +- .data = of_at91sam9g20_clk_pllb_setup, +- }, +- { +- .compatible = "atmel,sama5d3-clk-pll", +- .data = of_sama5d3_clk_pll_setup, +- }, +- { +- .compatible = "atmel,at91sam9x5-clk-plldiv", +- .data = of_at91sam9x5_clk_plldiv_setup, +- }, +- /* Master clock */ +- { +- .compatible = "atmel,at91rm9200-clk-master", +- .data = of_at91rm9200_clk_master_setup, +- }, +- { +- .compatible = "atmel,at91sam9x5-clk-master", +- .data = of_at91sam9x5_clk_master_setup, +- }, +- /* System clocks */ +- { +- .compatible = "atmel,at91rm9200-clk-system", +- .data = of_at91rm9200_clk_sys_setup, +- }, +- /* Peripheral clocks */ +- { +- .compatible = "atmel,at91rm9200-clk-peripheral", +- .data = of_at91rm9200_clk_periph_setup, +- }, +- { +- .compatible = "atmel,at91sam9x5-clk-peripheral", +- .data = of_at91sam9x5_clk_periph_setup, +- }, +- /* Programmable clocks */ +- { +- .compatible = "atmel,at91rm9200-clk-programmable", +- .data = of_at91rm9200_clk_prog_setup, +- }, +- { +- .compatible = "atmel,at91sam9g45-clk-programmable", +- .data = of_at91sam9g45_clk_prog_setup, +- }, +- { +- .compatible = "atmel,at91sam9x5-clk-programmable", +- .data = of_at91sam9x5_clk_prog_setup, +- }, +- /* UTMI clock */ +-#if defined(CONFIG_HAVE_AT91_UTMI) +- { +- .compatible = "atmel,at91sam9x5-clk-utmi", +- .data = of_at91sam9x5_clk_utmi_setup, +- }, +-#endif +- /* USB clock */ +-#if defined(CONFIG_HAVE_AT91_USB_CLK) +- { +- .compatible = "atmel,at91rm9200-clk-usb", +- .data = of_at91rm9200_clk_usb_setup, +- }, +- { +- .compatible = "atmel,at91sam9x5-clk-usb", +- .data = of_at91sam9x5_clk_usb_setup, +- }, +- { +- .compatible = "atmel,at91sam9n12-clk-usb", +- .data = of_at91sam9n12_clk_usb_setup, +- }, +-#endif +- /* SMD clock */ +-#if defined(CONFIG_HAVE_AT91_SMD) +- { +- .compatible = "atmel,at91sam9x5-clk-smd", +- .data = of_at91sam9x5_clk_smd_setup, +- }, +-#endif +-#if defined(CONFIG_HAVE_AT91_H32MX) +- { +- .compatible = "atmel,sama5d4-clk-h32mx", +- .data = of_sama5d4_clk_h32mx_setup, +- }, +-#endif +-#if defined(CONFIG_HAVE_AT91_GENERATED_CLK) +- { +- .compatible = "atmel,sama5d2-clk-generated", +- .data = of_sama5d2_clk_generated_setup, +- }, +-#endif +- { /*sentinel*/ } +-}; +- + static void __init of_at91_pmc_setup(struct device_node *np, + const struct at91_pmc_caps *caps) + { + struct at91_pmc *pmc; +- struct device_node *childnp; +- void (*clk_setup)(struct device_node *, struct at91_pmc *); +- const struct of_device_id *clk_id; + void __iomem *regbase = of_iomap(np, 0); + struct regmap *regmap; + int virq; +@@ -410,13 +286,6 @@ static void __init of_at91_pmc_setup(str + pmc = at91_pmc_init(np, regmap, regbase, virq, caps); + if (!pmc) + return; +- for_each_child_of_node(np, childnp) { +- clk_id = of_match_node(pmc_clk_ids, childnp); +- if (!clk_id) +- continue; +- clk_setup = clk_id->data; +- clk_setup(childnp, pmc); +- } + } + + static void __init of_at91rm9200_pmc_setup(struct device_node *np) +--- a/drivers/clk/at91/pmc.h ++++ b/drivers/clk/at91/pmc.h +@@ -17,6 +17,8 @@ + #include <linux/regmap.h> + #include <linux/spinlock.h> + ++extern spinlock_t pmc_pcr_lock; ++ + struct clk_range { + unsigned long min; + unsigned long max; +@@ -31,99 +33,12 @@ struct at91_pmc_caps { + struct at91_pmc { + struct regmap *regmap; + int virq; +- spinlock_t lock; + const struct at91_pmc_caps *caps; + struct irq_domain *irqdomain; + u32 imr; + }; + +-static inline void pmc_lock(struct at91_pmc *pmc) +-{ +- spin_lock(&pmc->lock); +-} +- +-static inline void pmc_unlock(struct at91_pmc *pmc) +-{ +- spin_unlock(&pmc->lock); +-} +- +-static inline u32 pmc_read(struct at91_pmc *pmc, int offset) +-{ +- unsigned int ret = 0; +- +- regmap_read(pmc->regmap, offset, &ret); +- +- return ret; +-} +- +-static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 value) +-{ +- regmap_write(pmc->regmap, offset, value); +-} +- + int of_at91_get_clk_range(struct device_node *np, const char *propname, + struct clk_range *range); + +-void of_at91sam9260_clk_slow_setup(struct device_node *np, +- struct at91_pmc *pmc); +- +-void of_at91rm9200_clk_main_osc_setup(struct device_node *np, +- struct at91_pmc *pmc); +-void of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np, +- struct at91_pmc *pmc); +-void of_at91rm9200_clk_main_setup(struct device_node *np, +- struct at91_pmc *pmc); +-void of_at91sam9x5_clk_main_setup(struct device_node *np, +- struct at91_pmc *pmc); +- +-void of_at91rm9200_clk_pll_setup(struct device_node *np, +- struct at91_pmc *pmc); +-void of_at91sam9g45_clk_pll_setup(struct device_node *np, +- struct at91_pmc *pmc); +-void of_at91sam9g20_clk_pllb_setup(struct device_node *np, +- struct at91_pmc *pmc); +-void of_sama5d3_clk_pll_setup(struct device_node *np, +- struct at91_pmc *pmc); +-void of_at91sam9x5_clk_plldiv_setup(struct device_node *np, +- struct at91_pmc *pmc); +- +-void of_at91rm9200_clk_master_setup(struct device_node *np, +- struct at91_pmc *pmc); +-void of_at91sam9x5_clk_master_setup(struct device_node *np, +- struct at91_pmc *pmc); +- +-void of_at91rm9200_clk_sys_setup(struct device_node *np, +- struct at91_pmc *pmc); +- +-void of_at91rm9200_clk_periph_setup(struct device_node *np, +- struct at91_pmc *pmc); +-void of_at91sam9x5_clk_periph_setup(struct device_node *np, +- struct at91_pmc *pmc); +- +-void of_at91rm9200_clk_prog_setup(struct device_node *np, +- struct at91_pmc *pmc); +-void of_at91sam9g45_clk_prog_setup(struct device_node *np, +- struct at91_pmc *pmc); +-void of_at91sam9x5_clk_prog_setup(struct device_node *np, +- struct at91_pmc *pmc); +- +-void of_at91sam9x5_clk_utmi_setup(struct device_node *np, +- struct at91_pmc *pmc); +- +-void of_at91rm9200_clk_usb_setup(struct device_node *np, +- struct at91_pmc *pmc); +-void of_at91sam9x5_clk_usb_setup(struct device_node *np, +- struct at91_pmc *pmc); +-void of_at91sam9n12_clk_usb_setup(struct device_node *np, +- struct at91_pmc *pmc); +- +-void of_at91sam9x5_clk_smd_setup(struct device_node *np, +- struct at91_pmc *pmc); +- +-void of_sama5d4_clk_h32mx_setup(struct device_node *np, +- struct at91_pmc *pmc); +- +-void of_sama5d2_clk_generated_setup(struct device_node *np, +- struct at91_pmc *pmc); +- + #endif /* __PMC_H_ */ diff --git a/patches/0002-kbuild-Add-option-to-turn-incompatible-pointer-check.patch b/patches/0002-kbuild-Add-option-to-turn-incompatible-pointer-check.patch new file mode 100644 index 00000000000000..e77f4c506af276 --- /dev/null +++ b/patches/0002-kbuild-Add-option-to-turn-incompatible-pointer-check.patch @@ -0,0 +1,52 @@ +From: Daniel Wagner <daniel.wagner@bmw-carit.de> +Date: Fri, 19 Feb 2016 09:46:38 +0100 +Subject: [PATCH 2/5] kbuild: Add option to turn incompatible pointer check + into error + +With the introduction of the simple wait API we have two very +similar APIs in the kernel. For example wake_up() and swake_up() +is only one character away. Although the compiler will warn +happily the wrong usage it keeps on going an even links the kernel. +Thomas and Peter would rather like to see early missuses reported +as error early on. + +In a first attempt we tried to wrap all swait and wait calls +into a macro which has an compile time type assertion. The result +was pretty ugly and wasn't able to catch all wrong usages. +woken_wake_function(), autoremove_wake_function() and wake_bit_function() +are assigned as function pointers. Wrapping them with a macro around is +not possible. Prefixing them with '_' was also not a real option +because there some users in the kernel which do use them as well. +All in all this attempt looked to intrusive and too ugly. + +An alternative is to turn the pointer type check into an error which +catches wrong type uses. Obviously not only the swait/wait ones. That +isn't a bad thing either. + +Signed-off-by: Daniel Wagner <daniel.wagner@bmw-carit.de> +Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> +Cc: linux-rt-users@vger.kernel.org +Cc: Boqun Feng <boqun.feng@gmail.com> +Cc: Marcelo Tosatti <mtosatti@redhat.com> +Cc: Steven Rostedt <rostedt@goodmis.org> +Cc: Paul Gortmaker <paul.gortmaker@windriver.com> +Cc: Paolo Bonzini <pbonzini@redhat.com> +Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> +Link: http://lkml.kernel.org/r/1455871601-27484-3-git-send-email-wagi@monom.org +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +--- + Makefile | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/Makefile ++++ b/Makefile +@@ -767,6 +767,9 @@ KBUILD_CFLAGS += $(call cc-option,-Wer + # Prohibit date/time macros, which would make the build non-deterministic + KBUILD_CFLAGS += $(call cc-option,-Werror=date-time) + ++# enforce correct pointer usage ++KBUILD_CFLAGS += $(call cc-option,-Werror=incompatible-pointer-types) ++ + # use the deterministic mode of AR if available + KBUILD_ARFLAGS := $(call ar-option,D) + diff --git a/patches/KVM-use-simple-waitqueue-for-vcpu-wq.patch b/patches/0003-KVM-Use-simple-waitqueue-for-vcpu-wq.patch index b461f6f3bb9e23..09a82350cab45c 100644 --- a/patches/KVM-use-simple-waitqueue-for-vcpu-wq.patch +++ b/patches/0003-KVM-Use-simple-waitqueue-for-vcpu-wq.patch @@ -1,10 +1,10 @@ From: Marcelo Tosatti <mtosatti@redhat.com> -Date: Wed, 8 Apr 2015 20:33:24 -0300 -Subject: KVM: use simple waitqueue for vcpu->wq +Date: Fri, 19 Feb 2016 09:46:39 +0100 +Subject: [PATCH 3/5] KVM: Use simple waitqueue for vcpu->wq The problem: -On -RT, an emulated LAPIC timer instances has the following path: +On -rt, an emulated LAPIC timer instances has the following path: 1) hard interrupt 2) ksoftirqd is scheduled @@ -25,24 +25,77 @@ waiter involves locking a sleeping lock, which is not allowed from hard interrupt context. cyclictest command line: -# cyclictest -m -n -q -p99 -l 1000000 -h60 -D 1m This patch reduces the average latency in my tests from 14us to 11us. -Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> -Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Daniel writes: +Paolo asked for numbers from kvm-unit-tests/tscdeadline_latency +benchmark on mainline. The test was run 1000 times on +tip/sched/core 4.4.0-rc8-01134-g0905f04: + + ./x86-run x86/tscdeadline_latency.flat -cpu host + +with idle=poll. + +The test seems not to deliver really stable numbers though most of +them are smaller. Paolo write: + +"Anything above ~10000 cycles means that the host went to C1 or +lower---the number means more or less nothing in that case. + +The mean shows an improvement indeed." + +Before: + + min max mean std +count 1000.000000 1000.000000 1000.000000 1000.000000 +mean 5162.596000 2019270.084000 5824.491541 20681.645558 +std 75.431231 622607.723969 89.575700 6492.272062 +min 4466.000000 23928.000000 5537.926500 585.864966 +25% 5163.000000 1613252.750000 5790.132275 16683.745433 +50% 5175.000000 2281919.000000 5834.654000 23151.990026 +75% 5190.000000 2382865.750000 5861.412950 24148.206168 +max 5228.000000 4175158.000000 6254.827300 46481.048691 + +After + min max mean std +count 1000.000000 1000.00000 1000.000000 1000.000000 +mean 5143.511000 2076886.10300 5813.312474 21207.357565 +std 77.668322 610413.09583 86.541500 6331.915127 +min 4427.000000 25103.00000 5529.756600 559.187707 +25% 5148.000000 1691272.75000 5784.889825 17473.518244 +50% 5160.000000 2308328.50000 5832.025000 23464.837068 +75% 5172.000000 2393037.75000 5853.177675 24223.969976 +max 5222.000000 3922458.00000 6186.720500 42520.379830 + +[Patch was originaly based on the swait implementation found in the -rt + tree. Daniel ported it to mainline's version and gathered the + benchmark numbers for tscdeadline_latency test.] + +Signed-off-by: Daniel Wagner <daniel.wagner@bmw-carit.de> +Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> +Cc: linux-rt-users@vger.kernel.org +Cc: Boqun Feng <boqun.feng@gmail.com> +Cc: Marcelo Tosatti <mtosatti@redhat.com> +Cc: Steven Rostedt <rostedt@goodmis.org> +Cc: Paul Gortmaker <paul.gortmaker@windriver.com> +Cc: Paolo Bonzini <pbonzini@redhat.com> +Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> +Link: http://lkml.kernel.org/r/1455871601-27484-4-git-send-email-wagi@monom.org +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- arch/arm/kvm/arm.c | 8 ++++---- arch/arm/kvm/psci.c | 4 ++-- + arch/mips/kvm/mips.c | 8 ++++---- arch/powerpc/include/asm/kvm_host.h | 4 ++-- arch/powerpc/kvm/book3s_hv.c | 23 +++++++++++------------ arch/s390/include/asm/kvm_host.h | 2 +- arch/s390/kvm/interrupt.c | 4 ++-- arch/x86/kvm/lapic.c | 6 +++--- - include/linux/kvm_host.h | 4 ++-- + include/linux/kvm_host.h | 5 +++-- virt/kvm/async_pf.c | 4 ++-- - virt/kvm/kvm_main.c | 16 ++++++++-------- - 10 files changed, 37 insertions(+), 38 deletions(-) + virt/kvm/kvm_main.c | 17 ++++++++--------- + 11 files changed, 42 insertions(+), 43 deletions(-) --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -51,18 +104,18 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> kvm_for_each_vcpu(i, vcpu, kvm) { - wait_queue_head_t *wq = kvm_arch_vcpu_wq(vcpu); -+ struct swait_head *wq = kvm_arch_vcpu_wq(vcpu); ++ struct swait_queue_head *wq = kvm_arch_vcpu_wq(vcpu); vcpu->arch.pause = false; - wake_up_interruptible(wq); -+ swait_wake_interruptible(wq); ++ swake_up(wq); } } static void vcpu_sleep(struct kvm_vcpu *vcpu) { - wait_queue_head_t *wq = kvm_arch_vcpu_wq(vcpu); -+ struct swait_head *wq = kvm_arch_vcpu_wq(vcpu); ++ struct swait_queue_head *wq = kvm_arch_vcpu_wq(vcpu); - wait_event_interruptible(*wq, ((!vcpu->arch.power_off) && + swait_event_interruptible(*wq, ((!vcpu->arch.power_off) && @@ -76,7 +129,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> struct kvm *kvm = source_vcpu->kvm; struct kvm_vcpu *vcpu = NULL; - wait_queue_head_t *wq; -+ struct swait_head *wq; ++ struct swait_queue_head *wq; unsigned long cpu_id; unsigned long context_id; phys_addr_t target_pc; @@ -85,10 +138,34 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> wq = kvm_arch_vcpu_wq(vcpu); - wake_up_interruptible(wq); -+ swait_wake_interruptible(wq); ++ swake_up(wq); return PSCI_RET_SUCCESS; } +--- a/arch/mips/kvm/mips.c ++++ b/arch/mips/kvm/mips.c +@@ -445,8 +445,8 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_ + + dvcpu->arch.wait = 0; + +- if (waitqueue_active(&dvcpu->wq)) +- wake_up_interruptible(&dvcpu->wq); ++ if (swait_active(&dvcpu->wq)) ++ swake_up(&dvcpu->wq); + + return 0; + } +@@ -1174,8 +1174,8 @@ static void kvm_mips_comparecount_func(u + kvm_mips_callbacks->queue_timer_int(vcpu); + + vcpu->arch.wait = 0; +- if (waitqueue_active(&vcpu->wq)) +- wake_up_interruptible(&vcpu->wq); ++ if (swait_active(&vcpu->wq)) ++ swake_up(&vcpu->wq); + } + + /* low level hrtimer wake routine */ --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -286,7 +286,7 @@ struct kvmppc_vcore { @@ -96,7 +173,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> struct list_head preempt_list; spinlock_t lock; - wait_queue_head_t wq; -+ struct swait_head wq; ++ struct swait_queue_head wq; spinlock_t stoltb_lock; /* protects stolen_tb and preempt_tb */ u64 stolen_tb; u64 preempt_tb; @@ -105,7 +182,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> u32 last_inst; - wait_queue_head_t *wqp; -+ struct swait_head *wqp; ++ struct swait_queue_head *wqp; struct kvmppc_vcore *vcore; int ret; int trap; @@ -116,13 +193,13 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> { int cpu; - wait_queue_head_t *wqp; -+ struct swait_head *wqp; ++ struct swait_queue_head *wqp; wqp = kvm_arch_vcpu_wq(vcpu); - if (waitqueue_active(wqp)) { - wake_up_interruptible(wqp); -+ if (swaitqueue_active(wqp)) { -+ swait_wake_interruptible(wqp); ++ if (swait_active(wqp)) { ++ swake_up(wqp); ++vcpu->stat.halt_wakeup; } @@ -132,8 +209,8 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> if (vcpu->arch.ceded) { - if (waitqueue_active(&vcpu->wq)) { - wake_up_interruptible(&vcpu->wq); -+ if (swaitqueue_active(&vcpu->wq)) { -+ swait_wake_interruptible(&vcpu->wq); ++ if (swait_active(&vcpu->wq)) { ++ swake_up(&vcpu->wq); vcpu->stat.halt_wakeup++; } } @@ -142,7 +219,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> spin_lock_init(&vcore->lock); spin_lock_init(&vcore->stoltb_lock); - init_waitqueue_head(&vcore->wq); -+ init_swait_head(&vcore->wq); ++ init_swait_queue_head(&vcore->wq); vcore->preempt_tb = TB_NIL; vcore->lpcr = kvm->arch.lpcr; vcore->first_vcpuid = core * threads_per_subcore; @@ -150,12 +227,12 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> { struct kvm_vcpu *vcpu; int do_sleep = 1; -+ DEFINE_SWAITER(wait); ++ DECLARE_SWAITQUEUE(wait); - DEFINE_WAIT(wait); - - prepare_to_wait(&vc->wq, &wait, TASK_INTERRUPTIBLE); -+ swait_prepare(&vc->wq, &wait, TASK_INTERRUPTIBLE); ++ prepare_to_swait(&vc->wq, &wait, TASK_INTERRUPTIBLE); /* * Check one last time for pending exceptions and ceded state after @@ -164,7 +241,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> if (!do_sleep) { - finish_wait(&vc->wq, &wait); -+ swait_finish(&vc->wq, &wait); ++ finish_swait(&vc->wq, &wait); return; } @@ -173,7 +250,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> spin_unlock(&vc->lock); schedule(); - finish_wait(&vc->wq, &wait); -+ swait_finish(&vc->wq, &wait); ++ finish_swait(&vc->wq, &wait); spin_lock(&vc->lock); vc->vcore_state = VCORE_INACTIVE; trace_kvmppc_vcore_blocked(vc, 1); @@ -182,7 +259,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> trace_kvm_guest_enter(vcpu); } else if (vc->vcore_state == VCORE_SLEEPING) { - wake_up(&vc->wq); -+ swait_wake(&vc->wq); ++ swake_up(&vc->wq); } } @@ -193,7 +270,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> spinlock_t lock; struct kvm_s390_float_interrupt *float_int; - wait_queue_head_t *wq; -+ struct swait_head *wq; ++ struct swait_queue_head *wq; atomic_t *cpuflags; DECLARE_BITMAP(sigp_emerg_pending, KVM_MAX_VCPUS); struct kvm_s390_irq_payload irq; @@ -204,14 +281,14 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> void kvm_s390_vcpu_wakeup(struct kvm_vcpu *vcpu) { - if (waitqueue_active(&vcpu->wq)) { -+ if (swaitqueue_active(&vcpu->wq)) { ++ if (swait_active(&vcpu->wq)) { /* * The vcpu gave up the cpu voluntarily, mark it as a good * yield-candidate. */ vcpu->preempted = true; - wake_up_interruptible(&vcpu->wq); -+ swait_wake_interruptible(&vcpu->wq); ++ swake_up(&vcpu->wq); vcpu->stat.halt_wakeup++; } } @@ -222,7 +299,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> { struct kvm_vcpu *vcpu = apic->vcpu; - wait_queue_head_t *q = &vcpu->wq; -+ struct swait_head *q = &vcpu->wq; ++ struct swait_queue_head *q = &vcpu->wq; struct kvm_timer *ktimer = &apic->lapic_timer; if (atomic_read(&apic->lapic_timer.pending)) @@ -232,28 +309,36 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> - if (waitqueue_active(q)) - wake_up_interruptible(q); -+ if (swaitqueue_active(q)) -+ swait_wake_interruptible(q); ++ if (swait_active(q)) ++ swake_up(q); if (apic_lvtt_tscdeadline(apic)) ktimer->expired_tscdeadline = ktimer->tscdeadline; --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h -@@ -243,7 +243,7 @@ struct kvm_vcpu { +@@ -25,6 +25,7 @@ + #include <linux/irqflags.h> + #include <linux/context_tracking.h> + #include <linux/irqbypass.h> ++#include <linux/swait.h> + #include <asm/signal.h> + + #include <linux/kvm.h> +@@ -243,7 +244,7 @@ struct kvm_vcpu { int fpu_active; int guest_fpu_loaded, guest_xcr0_loaded; unsigned char fpu_counter; - wait_queue_head_t wq; -+ struct swait_head wq; ++ struct swait_queue_head wq; struct pid *pid; int sigset_active; sigset_t sigset; -@@ -794,7 +794,7 @@ static inline bool kvm_arch_has_assigned +@@ -794,7 +795,7 @@ static inline bool kvm_arch_has_assigned } #endif -static inline wait_queue_head_t *kvm_arch_vcpu_wq(struct kvm_vcpu *vcpu) -+static inline struct swait_head *kvm_arch_vcpu_wq(struct kvm_vcpu *vcpu) ++static inline struct swait_queue_head *kvm_arch_vcpu_wq(struct kvm_vcpu *vcpu) { #ifdef __KVM_HAVE_ARCH_WQP return vcpu->arch.wqp; @@ -265,70 +350,71 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> smp_mb(); - if (waitqueue_active(&vcpu->wq)) - wake_up_interruptible(&vcpu->wq); -+ if (swaitqueue_active(&vcpu->wq)) -+ swait_wake_interruptible(&vcpu->wq); ++ if (swait_active(&vcpu->wq)) ++ swake_up(&vcpu->wq); mmput(mm); kvm_put_kvm(vcpu->kvm); --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c -@@ -227,7 +227,7 @@ int kvm_vcpu_init(struct kvm_vcpu *vcpu, +@@ -226,8 +226,7 @@ int kvm_vcpu_init(struct kvm_vcpu *vcpu, + vcpu->kvm = kvm; vcpu->vcpu_id = id; vcpu->pid = NULL; - vcpu->halt_poll_ns = 0; +- vcpu->halt_poll_ns = 0; - init_waitqueue_head(&vcpu->wq); -+ init_swait_head(&vcpu->wq); ++ init_swait_queue_head(&vcpu->wq); kvm_async_pf_vcpu_init(vcpu); vcpu->pre_pcpu = -1; -@@ -1999,7 +1999,7 @@ static int kvm_vcpu_check_block(struct k +@@ -1999,7 +1998,7 @@ static int kvm_vcpu_check_block(struct k void kvm_vcpu_block(struct kvm_vcpu *vcpu) { ktime_t start, cur; - DEFINE_WAIT(wait); -+ DEFINE_SWAITER(wait); ++ DECLARE_SWAITQUEUE(wait); bool waited = false; u64 block_ns; -@@ -2024,7 +2024,7 @@ void kvm_vcpu_block(struct kvm_vcpu *vcp +@@ -2024,7 +2023,7 @@ void kvm_vcpu_block(struct kvm_vcpu *vcp kvm_arch_vcpu_blocking(vcpu); for (;;) { - prepare_to_wait(&vcpu->wq, &wait, TASK_INTERRUPTIBLE); -+ swait_prepare(&vcpu->wq, &wait, TASK_INTERRUPTIBLE); ++ prepare_to_swait(&vcpu->wq, &wait, TASK_INTERRUPTIBLE); if (kvm_vcpu_check_block(vcpu) < 0) break; -@@ -2033,7 +2033,7 @@ void kvm_vcpu_block(struct kvm_vcpu *vcp +@@ -2033,7 +2032,7 @@ void kvm_vcpu_block(struct kvm_vcpu *vcp schedule(); } - finish_wait(&vcpu->wq, &wait); -+ swait_finish(&vcpu->wq, &wait); ++ finish_swait(&vcpu->wq, &wait); cur = ktime_get(); kvm_arch_vcpu_unblocking(vcpu); -@@ -2065,11 +2065,11 @@ void kvm_vcpu_kick(struct kvm_vcpu *vcpu +@@ -2065,11 +2064,11 @@ void kvm_vcpu_kick(struct kvm_vcpu *vcpu { int me; int cpu = vcpu->cpu; - wait_queue_head_t *wqp; -+ struct swait_head *wqp; ++ struct swait_queue_head *wqp; wqp = kvm_arch_vcpu_wq(vcpu); - if (waitqueue_active(wqp)) { - wake_up_interruptible(wqp); -+ if (swaitqueue_active(wqp)) { -+ swait_wake_interruptible(wqp); ++ if (swait_active(wqp)) { ++ swake_up(wqp); ++vcpu->stat.halt_wakeup; } -@@ -2170,7 +2170,7 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *m +@@ -2170,7 +2169,7 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *m continue; if (vcpu == me) continue; - if (waitqueue_active(&vcpu->wq) && !kvm_arch_vcpu_runnable(vcpu)) -+ if (swaitqueue_active(&vcpu->wq) && !kvm_arch_vcpu_runnable(vcpu)) ++ if (swait_active(&vcpu->wq) && !kvm_arch_vcpu_runnable(vcpu)) continue; if (!kvm_vcpu_eligible_for_directed_yield(vcpu)) continue; diff --git a/patches/0003-clk-at91-remove-IRQ-handling-and-use-polling.patch b/patches/0003-clk-at91-remove-IRQ-handling-and-use-polling.patch new file mode 100644 index 00000000000000..b64bd5cb07ba9e --- /dev/null +++ b/patches/0003-clk-at91-remove-IRQ-handling-and-use-polling.patch @@ -0,0 +1,1033 @@ +From: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Date: Wed, 16 Sep 2015 23:47:39 +0200 +Subject: [PATCH 03/13] clk: at91: remove IRQ handling and use polling + +The AT91 clock drivers make use of IRQs to avoid polling when waiting for +some clocks to be enabled. Unfortunately, this leads to a crash when those +IRQs are threaded (which happens when using preempt-rt) because they are +registered before thread creation is possible. + +Use polling on those clocks instead to avoid the problem. + +Acked-by: Stephen Boyd <sboyd@codeaurora.org> +Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + drivers/clk/at91/clk-main.c | 138 ++++------------------------------------ + drivers/clk/at91/clk-master.c | 46 +------------ + drivers/clk/at91/clk-pll.c | 47 +------------ + drivers/clk/at91/clk-system.c | 56 +--------------- + drivers/clk/at91/clk-utmi.c | 49 +------------- + drivers/clk/at91/pmc.c | 144 ------------------------------------------ + drivers/clk/at91/pmc.h | 3 + 7 files changed, 37 insertions(+), 446 deletions(-) + +--- a/drivers/clk/at91/clk-main.c ++++ b/drivers/clk/at91/clk-main.c +@@ -13,15 +13,8 @@ + #include <linux/clk/at91_pmc.h> + #include <linux/delay.h> + #include <linux/of.h> +-#include <linux/of_address.h> +-#include <linux/of_irq.h> +-#include <linux/io.h> +-#include <linux/interrupt.h> +-#include <linux/irq.h> + #include <linux/mfd/syscon.h> + #include <linux/regmap.h> +-#include <linux/sched.h> +-#include <linux/wait.h> + + #include "pmc.h" + +@@ -37,8 +30,6 @@ + struct clk_main_osc { + struct clk_hw hw; + struct regmap *regmap; +- unsigned int irq; +- wait_queue_head_t wait; + }; + + #define to_clk_main_osc(hw) container_of(hw, struct clk_main_osc, hw) +@@ -46,8 +37,6 @@ struct clk_main_osc { + struct clk_main_rc_osc { + struct clk_hw hw; + struct regmap *regmap; +- unsigned int irq; +- wait_queue_head_t wait; + unsigned long frequency; + unsigned long accuracy; + }; +@@ -64,23 +53,11 @@ struct clk_rm9200_main { + struct clk_sam9x5_main { + struct clk_hw hw; + struct regmap *regmap; +- unsigned int irq; +- wait_queue_head_t wait; + u8 parent; + }; + + #define to_clk_sam9x5_main(hw) container_of(hw, struct clk_sam9x5_main, hw) + +-static irqreturn_t clk_main_osc_irq_handler(int irq, void *dev_id) +-{ +- struct clk_main_osc *osc = dev_id; +- +- wake_up(&osc->wait); +- disable_irq_nosync(osc->irq); +- +- return IRQ_HANDLED; +-} +- + static inline bool clk_main_osc_ready(struct regmap *regmap) + { + unsigned int status; +@@ -107,11 +84,8 @@ static int clk_main_osc_prepare(struct c + regmap_write(regmap, AT91_CKGR_MOR, tmp); + } + +- while (!clk_main_osc_ready(regmap)) { +- enable_irq(osc->irq); +- wait_event(osc->wait, +- clk_main_osc_ready(regmap)); +- } ++ while (!clk_main_osc_ready(regmap)) ++ cpu_relax(); + + return 0; + } +@@ -156,17 +130,15 @@ static const struct clk_ops main_osc_ops + + static struct clk * __init + at91_clk_register_main_osc(struct regmap *regmap, +- unsigned int irq, + const char *name, + const char *parent_name, + bool bypass) + { +- int ret; + struct clk_main_osc *osc; + struct clk *clk = NULL; + struct clk_init_data init; + +- if (!irq || !name || !parent_name) ++ if (!name || !parent_name) + return ERR_PTR(-EINVAL); + + osc = kzalloc(sizeof(*osc), GFP_KERNEL); +@@ -181,16 +153,6 @@ at91_clk_register_main_osc(struct regmap + + osc->hw.init = &init; + osc->regmap = regmap; +- osc->irq = irq; +- +- init_waitqueue_head(&osc->wait); +- irq_set_status_flags(osc->irq, IRQ_NOAUTOEN); +- ret = request_irq(osc->irq, clk_main_osc_irq_handler, +- IRQF_TRIGGER_HIGH, name, osc); +- if (ret) { +- kfree(osc); +- return ERR_PTR(ret); +- } + + if (bypass) + regmap_update_bits(regmap, +@@ -199,10 +161,8 @@ at91_clk_register_main_osc(struct regmap + AT91_PMC_OSCBYPASS | AT91_PMC_KEY); + + clk = clk_register(NULL, &osc->hw); +- if (IS_ERR(clk)) { +- free_irq(irq, osc); ++ if (IS_ERR(clk)) + kfree(osc); +- } + + return clk; + } +@@ -210,7 +170,6 @@ at91_clk_register_main_osc(struct regmap + static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np) + { + struct clk *clk; +- unsigned int irq; + const char *name = np->name; + const char *parent_name; + struct regmap *regmap; +@@ -224,11 +183,7 @@ static void __init of_at91rm9200_clk_mai + if (IS_ERR(regmap)) + return; + +- irq = irq_of_parse_and_map(np, 0); +- if (!irq) +- return; +- +- clk = at91_clk_register_main_osc(regmap, irq, name, parent_name, bypass); ++ clk = at91_clk_register_main_osc(regmap, name, parent_name, bypass); + if (IS_ERR(clk)) + return; + +@@ -237,16 +192,6 @@ static void __init of_at91rm9200_clk_mai + CLK_OF_DECLARE(at91rm9200_clk_main_osc, "atmel,at91rm9200-clk-main-osc", + of_at91rm9200_clk_main_osc_setup); + +-static irqreturn_t clk_main_rc_osc_irq_handler(int irq, void *dev_id) +-{ +- struct clk_main_rc_osc *osc = dev_id; +- +- wake_up(&osc->wait); +- disable_irq_nosync(osc->irq); +- +- return IRQ_HANDLED; +-} +- + static bool clk_main_rc_osc_ready(struct regmap *regmap) + { + unsigned int status; +@@ -269,11 +214,8 @@ static int clk_main_rc_osc_prepare(struc + MOR_KEY_MASK | AT91_PMC_MOSCRCEN, + AT91_PMC_MOSCRCEN | AT91_PMC_KEY); + +- while (!clk_main_rc_osc_ready(regmap)) { +- enable_irq(osc->irq); +- wait_event(osc->wait, +- clk_main_rc_osc_ready(regmap)); +- } ++ while (!clk_main_rc_osc_ready(regmap)) ++ cpu_relax(); + + return 0; + } +@@ -331,11 +273,9 @@ static const struct clk_ops main_rc_osc_ + + static struct clk * __init + at91_clk_register_main_rc_osc(struct regmap *regmap, +- unsigned int irq, + const char *name, + u32 frequency, u32 accuracy) + { +- int ret; + struct clk_main_rc_osc *osc; + struct clk *clk = NULL; + struct clk_init_data init; +@@ -355,22 +295,12 @@ at91_clk_register_main_rc_osc(struct reg + + osc->hw.init = &init; + osc->regmap = regmap; +- osc->irq = irq; + osc->frequency = frequency; + osc->accuracy = accuracy; + +- init_waitqueue_head(&osc->wait); +- irq_set_status_flags(osc->irq, IRQ_NOAUTOEN); +- ret = request_irq(osc->irq, clk_main_rc_osc_irq_handler, +- IRQF_TRIGGER_HIGH, name, osc); +- if (ret) +- return ERR_PTR(ret); +- + clk = clk_register(NULL, &osc->hw); +- if (IS_ERR(clk)) { +- free_irq(irq, osc); ++ if (IS_ERR(clk)) + kfree(osc); +- } + + return clk; + } +@@ -378,7 +308,6 @@ at91_clk_register_main_rc_osc(struct reg + static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np) + { + struct clk *clk; +- unsigned int irq; + u32 frequency = 0; + u32 accuracy = 0; + const char *name = np->name; +@@ -388,16 +317,11 @@ static void __init of_at91sam9x5_clk_mai + of_property_read_u32(np, "clock-frequency", &frequency); + of_property_read_u32(np, "clock-accuracy", &accuracy); + +- irq = irq_of_parse_and_map(np, 0); +- if (!irq) +- return; +- + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + +- clk = at91_clk_register_main_rc_osc(regmap, irq, name, frequency, +- accuracy); ++ clk = at91_clk_register_main_rc_osc(regmap, name, frequency, accuracy); + if (IS_ERR(clk)) + return; + +@@ -529,16 +453,6 @@ static void __init of_at91rm9200_clk_mai + CLK_OF_DECLARE(at91rm9200_clk_main, "atmel,at91rm9200-clk-main", + of_at91rm9200_clk_main_setup); + +-static irqreturn_t clk_sam9x5_main_irq_handler(int irq, void *dev_id) +-{ +- struct clk_sam9x5_main *clkmain = dev_id; +- +- wake_up(&clkmain->wait); +- disable_irq_nosync(clkmain->irq); +- +- return IRQ_HANDLED; +-} +- + static inline bool clk_sam9x5_main_ready(struct regmap *regmap) + { + unsigned int status; +@@ -553,11 +467,8 @@ static int clk_sam9x5_main_prepare(struc + struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw); + struct regmap *regmap = clkmain->regmap; + +- while (!clk_sam9x5_main_ready(regmap)) { +- enable_irq(clkmain->irq); +- wait_event(clkmain->wait, +- clk_sam9x5_main_ready(regmap)); +- } ++ while (!clk_sam9x5_main_ready(regmap)) ++ cpu_relax(); + + return clk_main_probe_frequency(regmap); + } +@@ -594,11 +505,8 @@ static int clk_sam9x5_main_set_parent(st + else if (!index && (tmp & AT91_PMC_MOSCSEL)) + regmap_write(regmap, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL); + +- while (!clk_sam9x5_main_ready(regmap)) { +- enable_irq(clkmain->irq); +- wait_event(clkmain->wait, +- clk_sam9x5_main_ready(regmap)); +- } ++ while (!clk_sam9x5_main_ready(regmap)) ++ cpu_relax(); + + return 0; + } +@@ -623,12 +531,10 @@ static const struct clk_ops sam9x5_main_ + + static struct clk * __init + at91_clk_register_sam9x5_main(struct regmap *regmap, +- unsigned int irq, + const char *name, + const char **parent_names, + int num_parents) + { +- int ret; + struct clk_sam9x5_main *clkmain; + struct clk *clk = NULL; + struct clk_init_data init; +@@ -652,21 +558,12 @@ at91_clk_register_sam9x5_main(struct reg + + clkmain->hw.init = &init; + clkmain->regmap = regmap; +- clkmain->irq = irq; + regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status); + clkmain->parent = status & AT91_PMC_MOSCEN ? 1 : 0; +- init_waitqueue_head(&clkmain->wait); +- irq_set_status_flags(clkmain->irq, IRQ_NOAUTOEN); +- ret = request_irq(clkmain->irq, clk_sam9x5_main_irq_handler, +- IRQF_TRIGGER_HIGH, name, clkmain); +- if (ret) +- return ERR_PTR(ret); + + clk = clk_register(NULL, &clkmain->hw); +- if (IS_ERR(clk)) { +- free_irq(clkmain->irq, clkmain); ++ if (IS_ERR(clk)) + kfree(clkmain); +- } + + return clk; + } +@@ -676,7 +573,6 @@ static void __init of_at91sam9x5_clk_mai + struct clk *clk; + const char *parent_names[2]; + int num_parents; +- unsigned int irq; + const char *name = np->name; + struct regmap *regmap; + +@@ -691,11 +587,7 @@ static void __init of_at91sam9x5_clk_mai + + of_property_read_string(np, "clock-output-names", &name); + +- irq = irq_of_parse_and_map(np, 0); +- if (!irq) +- return; +- +- clk = at91_clk_register_sam9x5_main(regmap, irq, name, parent_names, ++ clk = at91_clk_register_sam9x5_main(regmap, name, parent_names, + num_parents); + if (IS_ERR(clk)) + return; +--- a/drivers/clk/at91/clk-master.c ++++ b/drivers/clk/at91/clk-master.c +@@ -12,13 +12,6 @@ + #include <linux/clkdev.h> + #include <linux/clk/at91_pmc.h> + #include <linux/of.h> +-#include <linux/of_address.h> +-#include <linux/of_irq.h> +-#include <linux/io.h> +-#include <linux/wait.h> +-#include <linux/sched.h> +-#include <linux/interrupt.h> +-#include <linux/irq.h> + #include <linux/mfd/syscon.h> + #include <linux/regmap.h> + +@@ -47,22 +40,10 @@ struct clk_master_layout { + struct clk_master { + struct clk_hw hw; + struct regmap *regmap; +- unsigned int irq; +- wait_queue_head_t wait; + const struct clk_master_layout *layout; + const struct clk_master_characteristics *characteristics; + }; + +-static irqreturn_t clk_master_irq_handler(int irq, void *dev_id) +-{ +- struct clk_master *master = (struct clk_master *)dev_id; +- +- wake_up(&master->wait); +- disable_irq_nosync(master->irq); +- +- return IRQ_HANDLED; +-} +- + static inline bool clk_master_ready(struct regmap *regmap) + { + unsigned int status; +@@ -76,11 +57,8 @@ static int clk_master_prepare(struct clk + { + struct clk_master *master = to_clk_master(hw); + +- while (!clk_master_ready(master->regmap)) { +- enable_irq(master->irq); +- wait_event(master->wait, +- clk_master_ready(master->regmap)); +- } ++ while (!clk_master_ready(master->regmap)) ++ cpu_relax(); + + return 0; + } +@@ -143,13 +121,12 @@ static const struct clk_ops master_ops = + }; + + static struct clk * __init +-at91_clk_register_master(struct regmap *regmap, unsigned int irq, ++at91_clk_register_master(struct regmap *regmap, + const char *name, int num_parents, + const char **parent_names, + const struct clk_master_layout *layout, + const struct clk_master_characteristics *characteristics) + { +- int ret; + struct clk_master *master; + struct clk *clk = NULL; + struct clk_init_data init; +@@ -171,19 +148,9 @@ at91_clk_register_master(struct regmap * + master->layout = layout; + master->characteristics = characteristics; + master->regmap = regmap; +- master->irq = irq; +- init_waitqueue_head(&master->wait); +- irq_set_status_flags(master->irq, IRQ_NOAUTOEN); +- ret = request_irq(master->irq, clk_master_irq_handler, +- IRQF_TRIGGER_HIGH, "clk-master", master); +- if (ret) { +- kfree(master); +- return ERR_PTR(ret); +- } + + clk = clk_register(NULL, &master->hw); + if (IS_ERR(clk)) { +- free_irq(master->irq, master); + kfree(master); + } + +@@ -233,7 +200,6 @@ of_at91_clk_master_setup(struct device_n + { + struct clk *clk; + int num_parents; +- unsigned int irq; + const char *parent_names[MASTER_SOURCE_MAX]; + const char *name = np->name; + struct clk_master_characteristics *characteristics; +@@ -255,11 +221,7 @@ of_at91_clk_master_setup(struct device_n + if (IS_ERR(regmap)) + return; + +- irq = irq_of_parse_and_map(np, 0); +- if (!irq) +- goto out_free_characteristics; +- +- clk = at91_clk_register_master(regmap, irq, name, num_parents, ++ clk = at91_clk_register_master(regmap, name, num_parents, + parent_names, layout, + characteristics); + if (IS_ERR(clk)) +--- a/drivers/clk/at91/clk-pll.c ++++ b/drivers/clk/at91/clk-pll.c +@@ -12,14 +12,6 @@ + #include <linux/clkdev.h> + #include <linux/clk/at91_pmc.h> + #include <linux/of.h> +-#include <linux/of_address.h> +-#include <linux/of_irq.h> +-#include <linux/io.h> +-#include <linux/kernel.h> +-#include <linux/wait.h> +-#include <linux/sched.h> +-#include <linux/interrupt.h> +-#include <linux/irq.h> + #include <linux/mfd/syscon.h> + #include <linux/regmap.h> + +@@ -61,8 +53,6 @@ struct clk_pll_layout { + struct clk_pll { + struct clk_hw hw; + struct regmap *regmap; +- unsigned int irq; +- wait_queue_head_t wait; + u8 id; + u8 div; + u8 range; +@@ -71,16 +61,6 @@ struct clk_pll { + const struct clk_pll_characteristics *characteristics; + }; + +-static irqreturn_t clk_pll_irq_handler(int irq, void *dev_id) +-{ +- struct clk_pll *pll = (struct clk_pll *)dev_id; +- +- wake_up(&pll->wait); +- disable_irq_nosync(pll->irq); +- +- return IRQ_HANDLED; +-} +- + static inline bool clk_pll_ready(struct regmap *regmap, int id) + { + unsigned int status; +@@ -127,11 +107,8 @@ static int clk_pll_prepare(struct clk_hw + (out << PLL_OUT_SHIFT) | + ((pll->mul & layout->mul_mask) << layout->mul_shift)); + +- while (!clk_pll_ready(regmap, pll->id)) { +- enable_irq(pll->irq); +- wait_event(pll->wait, +- clk_pll_ready(regmap, pll->id)); +- } ++ while (!clk_pll_ready(regmap, pll->id)) ++ cpu_relax(); + + return 0; + } +@@ -320,7 +297,7 @@ static const struct clk_ops pll_ops = { + }; + + static struct clk * __init +-at91_clk_register_pll(struct regmap *regmap, unsigned int irq, const char *name, ++at91_clk_register_pll(struct regmap *regmap, const char *name, + const char *parent_name, u8 id, + const struct clk_pll_layout *layout, + const struct clk_pll_characteristics *characteristics) +@@ -328,7 +305,6 @@ at91_clk_register_pll(struct regmap *reg + struct clk_pll *pll; + struct clk *clk = NULL; + struct clk_init_data init; +- int ret; + int offset = PLL_REG(id); + unsigned int pllr; + +@@ -350,22 +326,12 @@ at91_clk_register_pll(struct regmap *reg + pll->layout = layout; + pll->characteristics = characteristics; + pll->regmap = regmap; +- pll->irq = irq; + regmap_read(regmap, offset, &pllr); + pll->div = PLL_DIV(pllr); + pll->mul = PLL_MUL(pllr, layout); +- init_waitqueue_head(&pll->wait); +- irq_set_status_flags(pll->irq, IRQ_NOAUTOEN); +- ret = request_irq(pll->irq, clk_pll_irq_handler, IRQF_TRIGGER_HIGH, +- id ? "clk-pllb" : "clk-plla", pll); +- if (ret) { +- kfree(pll); +- return ERR_PTR(ret); +- } + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) { +- free_irq(pll->irq, pll); + kfree(pll); + } + +@@ -499,7 +465,6 @@ of_at91_clk_pll_setup(struct device_node + const struct clk_pll_layout *layout) + { + u32 id; +- unsigned int irq; + struct clk *clk; + struct regmap *regmap; + const char *parent_name; +@@ -521,11 +486,7 @@ of_at91_clk_pll_setup(struct device_node + if (!characteristics) + return; + +- irq = irq_of_parse_and_map(np, 0); +- if (!irq) +- return; +- +- clk = at91_clk_register_pll(regmap, irq, name, parent_name, id, layout, ++ clk = at91_clk_register_pll(regmap, name, parent_name, id, layout, + characteristics); + if (IS_ERR(clk)) + goto out_free_characteristics; +--- a/drivers/clk/at91/clk-system.c ++++ b/drivers/clk/at91/clk-system.c +@@ -12,13 +12,6 @@ + #include <linux/clkdev.h> + #include <linux/clk/at91_pmc.h> + #include <linux/of.h> +-#include <linux/of_address.h> +-#include <linux/io.h> +-#include <linux/irq.h> +-#include <linux/of_irq.h> +-#include <linux/interrupt.h> +-#include <linux/wait.h> +-#include <linux/sched.h> + #include <linux/mfd/syscon.h> + #include <linux/regmap.h> + +@@ -32,8 +25,6 @@ + struct clk_system { + struct clk_hw hw; + struct regmap *regmap; +- unsigned int irq; +- wait_queue_head_t wait; + u8 id; + }; + +@@ -41,15 +32,6 @@ static inline int is_pck(int id) + { + return (id >= 8) && (id <= 15); + } +-static irqreturn_t clk_system_irq_handler(int irq, void *dev_id) +-{ +- struct clk_system *sys = (struct clk_system *)dev_id; +- +- wake_up(&sys->wait); +- disable_irq_nosync(sys->irq); +- +- return IRQ_HANDLED; +-} + + static inline bool clk_system_ready(struct regmap *regmap, int id) + { +@@ -69,15 +51,9 @@ static int clk_system_prepare(struct clk + if (!is_pck(sys->id)) + return 0; + +- while (!clk_system_ready(sys->regmap, sys->id)) { +- if (sys->irq) { +- enable_irq(sys->irq); +- wait_event(sys->wait, +- clk_system_ready(sys->regmap, sys->id)); +- } else { +- cpu_relax(); +- } +- } ++ while (!clk_system_ready(sys->regmap, sys->id)) ++ cpu_relax(); ++ + return 0; + } + +@@ -114,12 +90,11 @@ static const struct clk_ops system_ops = + + static struct clk * __init + at91_clk_register_system(struct regmap *regmap, const char *name, +- const char *parent_name, u8 id, int irq) ++ const char *parent_name, u8 id) + { + struct clk_system *sys; + struct clk *clk = NULL; + struct clk_init_data init; +- int ret; + + if (!parent_name || id > SYSTEM_MAX_ID) + return ERR_PTR(-EINVAL); +@@ -137,24 +112,10 @@ at91_clk_register_system(struct regmap * + sys->id = id; + sys->hw.init = &init; + sys->regmap = regmap; +- sys->irq = irq; +- if (irq) { +- init_waitqueue_head(&sys->wait); +- irq_set_status_flags(sys->irq, IRQ_NOAUTOEN); +- ret = request_irq(sys->irq, clk_system_irq_handler, +- IRQF_TRIGGER_HIGH, name, sys); +- if (ret) { +- kfree(sys); +- return ERR_PTR(ret); +- } +- } + + clk = clk_register(NULL, &sys->hw); +- if (IS_ERR(clk)) { +- if (irq) +- free_irq(sys->irq, sys); ++ if (IS_ERR(clk)) + kfree(sys); +- } + + return clk; + } +@@ -162,7 +123,6 @@ at91_clk_register_system(struct regmap * + static void __init of_at91rm9200_clk_sys_setup(struct device_node *np) + { + int num; +- int irq = 0; + u32 id; + struct clk *clk; + const char *name; +@@ -185,13 +145,9 @@ static void __init of_at91rm9200_clk_sys + if (of_property_read_string(np, "clock-output-names", &name)) + name = sysclknp->name; + +- if (is_pck(id)) +- irq = irq_of_parse_and_map(sysclknp, 0); +- + parent_name = of_clk_get_parent_name(sysclknp, 0); + +- clk = at91_clk_register_system(regmap, name, parent_name, id, +- irq); ++ clk = at91_clk_register_system(regmap, name, parent_name, id); + if (IS_ERR(clk)) + continue; + +--- a/drivers/clk/at91/clk-utmi.c ++++ b/drivers/clk/at91/clk-utmi.c +@@ -11,14 +11,7 @@ + #include <linux/clk-provider.h> + #include <linux/clkdev.h> + #include <linux/clk/at91_pmc.h> +-#include <linux/interrupt.h> +-#include <linux/irq.h> + #include <linux/of.h> +-#include <linux/of_address.h> +-#include <linux/of_irq.h> +-#include <linux/io.h> +-#include <linux/sched.h> +-#include <linux/wait.h> + #include <linux/mfd/syscon.h> + #include <linux/regmap.h> + +@@ -29,22 +22,10 @@ + struct clk_utmi { + struct clk_hw hw; + struct regmap *regmap; +- unsigned int irq; +- wait_queue_head_t wait; + }; + + #define to_clk_utmi(hw) container_of(hw, struct clk_utmi, hw) + +-static irqreturn_t clk_utmi_irq_handler(int irq, void *dev_id) +-{ +- struct clk_utmi *utmi = (struct clk_utmi *)dev_id; +- +- wake_up(&utmi->wait); +- disable_irq_nosync(utmi->irq); +- +- return IRQ_HANDLED; +-} +- + static inline bool clk_utmi_ready(struct regmap *regmap) + { + unsigned int status; +@@ -62,11 +43,8 @@ static int clk_utmi_prepare(struct clk_h + + regmap_update_bits(utmi->regmap, AT91_CKGR_UCKR, uckr, uckr); + +- while (!clk_utmi_ready(utmi->regmap)) { +- enable_irq(utmi->irq); +- wait_event(utmi->wait, +- clk_utmi_ready(utmi->regmap)); +- } ++ while (!clk_utmi_ready(utmi->regmap)) ++ cpu_relax(); + + return 0; + } +@@ -100,10 +78,9 @@ static const struct clk_ops utmi_ops = { + }; + + static struct clk * __init +-at91_clk_register_utmi(struct regmap *regmap, unsigned int irq, ++at91_clk_register_utmi(struct regmap *regmap, + const char *name, const char *parent_name) + { +- int ret; + struct clk_utmi *utmi; + struct clk *clk = NULL; + struct clk_init_data init; +@@ -120,28 +97,16 @@ at91_clk_register_utmi(struct regmap *re + + utmi->hw.init = &init; + utmi->regmap = regmap; +- utmi->irq = irq; +- init_waitqueue_head(&utmi->wait); +- irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN); +- ret = request_irq(utmi->irq, clk_utmi_irq_handler, +- IRQF_TRIGGER_HIGH, "clk-utmi", utmi); +- if (ret) { +- kfree(utmi); +- return ERR_PTR(ret); +- } + + clk = clk_register(NULL, &utmi->hw); +- if (IS_ERR(clk)) { +- free_irq(utmi->irq, utmi); ++ if (IS_ERR(clk)) + kfree(utmi); +- } + + return clk; + } + + static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np) + { +- unsigned int irq; + struct clk *clk; + const char *parent_name; + const char *name = np->name; +@@ -151,15 +116,11 @@ static void __init of_at91sam9x5_clk_utm + + of_property_read_string(np, "clock-output-names", &name); + +- irq = irq_of_parse_and_map(np, 0); +- if (!irq) +- return; +- + regmap = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap)) + return; + +- clk = at91_clk_register_utmi(regmap, irq, name, parent_name); ++ clk = at91_clk_register_utmi(regmap, name, parent_name); + if (IS_ERR(clk)) + return; + +--- a/drivers/clk/at91/pmc.c ++++ b/drivers/clk/at91/pmc.c +@@ -13,12 +13,6 @@ + #include <linux/clk/at91_pmc.h> + #include <linux/of.h> + #include <linux/of_address.h> +-#include <linux/io.h> +-#include <linux/interrupt.h> +-#include <linux/irq.h> +-#include <linux/irqchip/chained_irq.h> +-#include <linux/irqdomain.h> +-#include <linux/of_irq.h> + #include <linux/mfd/syscon.h> + #include <linux/regmap.h> + +@@ -67,118 +61,6 @@ int of_at91_get_clk_range(struct device_ + } + EXPORT_SYMBOL_GPL(of_at91_get_clk_range); + +-static void pmc_irq_mask(struct irq_data *d) +-{ +- struct at91_pmc *pmc = irq_data_get_irq_chip_data(d); +- +- regmap_write(pmc->regmap, AT91_PMC_IDR, 1 << d->hwirq); +-} +- +-static void pmc_irq_unmask(struct irq_data *d) +-{ +- struct at91_pmc *pmc = irq_data_get_irq_chip_data(d); +- +- regmap_write(pmc->regmap, AT91_PMC_IER, 1 << d->hwirq); +-} +- +-static int pmc_irq_set_type(struct irq_data *d, unsigned type) +-{ +- if (type != IRQ_TYPE_LEVEL_HIGH) { +- pr_warn("PMC: type not supported (support only IRQ_TYPE_LEVEL_HIGH type)\n"); +- return -EINVAL; +- } +- +- return 0; +-} +- +-static void pmc_irq_suspend(struct irq_data *d) +-{ +- struct at91_pmc *pmc = irq_data_get_irq_chip_data(d); +- +- regmap_read(pmc->regmap, AT91_PMC_IMR, &pmc->imr); +- regmap_write(pmc->regmap, AT91_PMC_IDR, pmc->imr); +-} +- +-static void pmc_irq_resume(struct irq_data *d) +-{ +- struct at91_pmc *pmc = irq_data_get_irq_chip_data(d); +- +- regmap_write(pmc->regmap, AT91_PMC_IER, pmc->imr); +-} +- +-static struct irq_chip pmc_irq = { +- .name = "PMC", +- .irq_disable = pmc_irq_mask, +- .irq_mask = pmc_irq_mask, +- .irq_unmask = pmc_irq_unmask, +- .irq_set_type = pmc_irq_set_type, +- .irq_suspend = pmc_irq_suspend, +- .irq_resume = pmc_irq_resume, +-}; +- +-static struct lock_class_key pmc_lock_class; +- +-static int pmc_irq_map(struct irq_domain *h, unsigned int virq, +- irq_hw_number_t hw) +-{ +- struct at91_pmc *pmc = h->host_data; +- +- irq_set_lockdep_class(virq, &pmc_lock_class); +- +- irq_set_chip_and_handler(virq, &pmc_irq, +- handle_level_irq); +- irq_set_chip_data(virq, pmc); +- +- return 0; +-} +- +-static int pmc_irq_domain_xlate(struct irq_domain *d, +- struct device_node *ctrlr, +- const u32 *intspec, unsigned int intsize, +- irq_hw_number_t *out_hwirq, +- unsigned int *out_type) +-{ +- struct at91_pmc *pmc = d->host_data; +- const struct at91_pmc_caps *caps = pmc->caps; +- +- if (WARN_ON(intsize < 1)) +- return -EINVAL; +- +- *out_hwirq = intspec[0]; +- +- if (!(caps->available_irqs & (1 << *out_hwirq))) +- return -EINVAL; +- +- *out_type = IRQ_TYPE_LEVEL_HIGH; +- +- return 0; +-} +- +-static const struct irq_domain_ops pmc_irq_ops = { +- .map = pmc_irq_map, +- .xlate = pmc_irq_domain_xlate, +-}; +- +-static irqreturn_t pmc_irq_handler(int irq, void *data) +-{ +- struct at91_pmc *pmc = (struct at91_pmc *)data; +- unsigned int tmpsr, imr; +- unsigned long sr; +- int n; +- +- regmap_read(pmc->regmap, AT91_PMC_SR, &tmpsr); +- regmap_read(pmc->regmap, AT91_PMC_IMR, &imr); +- +- sr = tmpsr & imr; +- if (!sr) +- return IRQ_NONE; +- +- for_each_set_bit(n, &sr, BITS_PER_LONG) +- generic_handle_irq(irq_find_mapping(pmc->irqdomain, n)); +- +- return IRQ_HANDLED; +-} +- + static const struct at91_pmc_caps at91rm9200_caps = { + .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB | + AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY | +@@ -230,12 +112,12 @@ static const struct at91_pmc_caps sama5d + + static struct at91_pmc *__init at91_pmc_init(struct device_node *np, + struct regmap *regmap, +- void __iomem *regbase, int virq, ++ void __iomem *regbase, + const struct at91_pmc_caps *caps) + { + struct at91_pmc *pmc; + +- if (!regbase || !virq || !caps) ++ if (!regbase || !caps) + return NULL; + + at91_pmc_base = regbase; +@@ -245,26 +127,11 @@ static struct at91_pmc *__init at91_pmc_ + return NULL; + + pmc->regmap = regmap; +- pmc->virq = virq; + pmc->caps = caps; + +- pmc->irqdomain = irq_domain_add_linear(np, 32, &pmc_irq_ops, pmc); +- if (!pmc->irqdomain) +- goto out_free_pmc; +- + regmap_write(pmc->regmap, AT91_PMC_IDR, 0xffffffff); +- if (request_irq(pmc->virq, pmc_irq_handler, +- IRQF_SHARED | IRQF_COND_SUSPEND, "pmc", pmc)) +- goto out_remove_irqdomain; + + return pmc; +- +-out_remove_irqdomain: +- irq_domain_remove(pmc->irqdomain); +-out_free_pmc: +- kfree(pmc); +- +- return NULL; + } + + static void __init of_at91_pmc_setup(struct device_node *np, +@@ -273,17 +140,12 @@ static void __init of_at91_pmc_setup(str + struct at91_pmc *pmc; + void __iomem *regbase = of_iomap(np, 0); + struct regmap *regmap; +- int virq; + + regmap = syscon_node_to_regmap(np); + if (IS_ERR(regmap)) + panic("Could not retrieve syscon regmap"); + +- virq = irq_of_parse_and_map(np, 0); +- if (!virq) +- return; +- +- pmc = at91_pmc_init(np, regmap, regbase, virq, caps); ++ pmc = at91_pmc_init(np, regmap, regbase, caps); + if (!pmc) + return; + } +--- a/drivers/clk/at91/pmc.h ++++ b/drivers/clk/at91/pmc.h +@@ -32,10 +32,7 @@ struct at91_pmc_caps { + + struct at91_pmc { + struct regmap *regmap; +- int virq; + const struct at91_pmc_caps *caps; +- struct irq_domain *irqdomain; +- u32 imr; + }; + + int of_at91_get_clk_range(struct device_node *np, const char *propname, diff --git a/patches/0004-clk-at91-pmc-merge-at91_pmc_init-in-atmel_pmc_probe.patch b/patches/0004-clk-at91-pmc-merge-at91_pmc_init-in-atmel_pmc_probe.patch new file mode 100644 index 00000000000000..24f18b5e5d3cc2 --- /dev/null +++ b/patches/0004-clk-at91-pmc-merge-at91_pmc_init-in-atmel_pmc_probe.patch @@ -0,0 +1,70 @@ +From: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Date: Wed, 27 Jan 2016 14:59:47 +0100 +Subject: [PATCH 04/13] clk: at91: pmc: merge at91_pmc_init in atmel_pmc_probe + +at91_pmc_init() doesn't do much anymore, merge it in atmel_pmc_probe(). + +Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com> +Acked-by: Stephen Boyd <sboyd@codeaurora.org> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + drivers/clk/at91/pmc.c | 34 +++++++++------------------------- + 1 file changed, 9 insertions(+), 25 deletions(-) + +--- a/drivers/clk/at91/pmc.c ++++ b/drivers/clk/at91/pmc.c +@@ -110,30 +110,6 @@ static const struct at91_pmc_caps sama5d + AT91_PMC_CFDEV, + }; + +-static struct at91_pmc *__init at91_pmc_init(struct device_node *np, +- struct regmap *regmap, +- void __iomem *regbase, +- const struct at91_pmc_caps *caps) +-{ +- struct at91_pmc *pmc; +- +- if (!regbase || !caps) +- return NULL; +- +- at91_pmc_base = regbase; +- +- pmc = kzalloc(sizeof(*pmc), GFP_KERNEL); +- if (!pmc) +- return NULL; +- +- pmc->regmap = regmap; +- pmc->caps = caps; +- +- regmap_write(pmc->regmap, AT91_PMC_IDR, 0xffffffff); +- +- return pmc; +-} +- + static void __init of_at91_pmc_setup(struct device_node *np, + const struct at91_pmc_caps *caps) + { +@@ -141,13 +117,21 @@ static void __init of_at91_pmc_setup(str + void __iomem *regbase = of_iomap(np, 0); + struct regmap *regmap; + ++ at91_pmc_base = regbase; ++ + regmap = syscon_node_to_regmap(np); + if (IS_ERR(regmap)) + panic("Could not retrieve syscon regmap"); + +- pmc = at91_pmc_init(np, regmap, regbase, caps); ++ pmc = kzalloc(sizeof(*pmc), GFP_KERNEL); + if (!pmc) + return; ++ ++ pmc->regmap = regmap; ++ pmc->caps = caps; ++ ++ regmap_write(pmc->regmap, AT91_PMC_IDR, 0xffffffff); ++ + } + + static void __init of_at91rm9200_pmc_setup(struct device_node *np) diff --git a/patches/0004-rcu-Do-not-call-rcu_nocb_gp_cleanup-while-holding-rn.patch b/patches/0004-rcu-Do-not-call-rcu_nocb_gp_cleanup-while-holding-rn.patch new file mode 100644 index 00000000000000..67e5440001be66 --- /dev/null +++ b/patches/0004-rcu-Do-not-call-rcu_nocb_gp_cleanup-while-holding-rn.patch @@ -0,0 +1,190 @@ +From: Daniel Wagner <daniel.wagner@bmw-carit.de> +Date: Fri, 19 Feb 2016 09:46:40 +0100 +Subject: [PATCH 4/5] rcu: Do not call rcu_nocb_gp_cleanup() while holding + rnp->lock + +rcu_nocb_gp_cleanup() is called while holding rnp->lock. Currently, +this is okay because the wake_up_all() in rcu_nocb_gp_cleanup() will +not enable the IRQs. lockdep is happy. + +By switching over using swait this is not true anymore. swake_up_all() +enables the IRQs while processing the waiters. __do_softirq() can now +run and will eventually call rcu_process_callbacks() which wants to +grap nrp->lock. + +Let's move the rcu_nocb_gp_cleanup() call outside the lock before we +switch over to swait. + +If we would hold the rnp->lock and use swait, lockdep reports +following: + + ================================= + [ INFO: inconsistent lock state ] + 4.2.0-rc5-00025-g9a73ba0 #136 Not tainted + --------------------------------- + inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage. + rcu_preempt/8 [HC0[0]:SC0[0]:HE1:SE1] takes: + (rcu_node_1){+.?...}, at: [<ffffffff811387c7>] rcu_gp_kthread+0xb97/0xeb0 + {IN-SOFTIRQ-W} state was registered at: + [<ffffffff81109b9f>] __lock_acquire+0xd5f/0x21e0 + [<ffffffff8110be0f>] lock_acquire+0xdf/0x2b0 + [<ffffffff81841cc9>] _raw_spin_lock_irqsave+0x59/0xa0 + [<ffffffff81136991>] rcu_process_callbacks+0x141/0x3c0 + [<ffffffff810b1a9d>] __do_softirq+0x14d/0x670 + [<ffffffff810b2214>] irq_exit+0x104/0x110 + [<ffffffff81844e96>] smp_apic_timer_interrupt+0x46/0x60 + [<ffffffff81842e70>] apic_timer_interrupt+0x70/0x80 + [<ffffffff810dba66>] rq_attach_root+0xa6/0x100 + [<ffffffff810dbc2d>] cpu_attach_domain+0x16d/0x650 + [<ffffffff810e4b42>] build_sched_domains+0x942/0xb00 + [<ffffffff821777c2>] sched_init_smp+0x509/0x5c1 + [<ffffffff821551e3>] kernel_init_freeable+0x172/0x28f + [<ffffffff8182cdce>] kernel_init+0xe/0xe0 + [<ffffffff8184231f>] ret_from_fork+0x3f/0x70 + irq event stamp: 76 + hardirqs last enabled at (75): [<ffffffff81841330>] _raw_spin_unlock_irq+0x30/0x60 + hardirqs last disabled at (76): [<ffffffff8184116f>] _raw_spin_lock_irq+0x1f/0x90 + softirqs last enabled at (0): [<ffffffff810a8df2>] copy_process.part.26+0x602/0x1cf0 + softirqs last disabled at (0): [< (null)>] (null) + other info that might help us debug this: + Possible unsafe locking scenario: + CPU0 + ---- + lock(rcu_node_1); + <Interrupt> + lock(rcu_node_1); + *** DEADLOCK *** + 1 lock held by rcu_preempt/8: + #0: (rcu_node_1){+.?...}, at: [<ffffffff811387c7>] rcu_gp_kthread+0xb97/0xeb0 + stack backtrace: + CPU: 0 PID: 8 Comm: rcu_preempt Not tainted 4.2.0-rc5-00025-g9a73ba0 #136 + Hardware name: Dell Inc. PowerEdge R820/066N7P, BIOS 2.0.20 01/16/2014 + 0000000000000000 000000006d7e67d8 ffff881fb081fbd8 ffffffff818379e0 + 0000000000000000 ffff881fb0812a00 ffff881fb081fc38 ffffffff8110813b + 0000000000000000 0000000000000001 ffff881f00000001 ffffffff8102fa4f + Call Trace: + [<ffffffff818379e0>] dump_stack+0x4f/0x7b + [<ffffffff8110813b>] print_usage_bug+0x1db/0x1e0 + [<ffffffff8102fa4f>] ? save_stack_trace+0x2f/0x50 + [<ffffffff811087ad>] mark_lock+0x66d/0x6e0 + [<ffffffff81107790>] ? check_usage_forwards+0x150/0x150 + [<ffffffff81108898>] mark_held_locks+0x78/0xa0 + [<ffffffff81841330>] ? _raw_spin_unlock_irq+0x30/0x60 + [<ffffffff81108a28>] trace_hardirqs_on_caller+0x168/0x220 + [<ffffffff81108aed>] trace_hardirqs_on+0xd/0x10 + [<ffffffff81841330>] _raw_spin_unlock_irq+0x30/0x60 + [<ffffffff810fd1c7>] swake_up_all+0xb7/0xe0 + [<ffffffff811386e1>] rcu_gp_kthread+0xab1/0xeb0 + [<ffffffff811089bf>] ? trace_hardirqs_on_caller+0xff/0x220 + [<ffffffff81841341>] ? _raw_spin_unlock_irq+0x41/0x60 + [<ffffffff81137c30>] ? rcu_barrier+0x20/0x20 + [<ffffffff810d2014>] kthread+0x104/0x120 + [<ffffffff81841330>] ? _raw_spin_unlock_irq+0x30/0x60 + [<ffffffff810d1f10>] ? kthread_create_on_node+0x260/0x260 + [<ffffffff8184231f>] ret_from_fork+0x3f/0x70 + [<ffffffff810d1f10>] ? kthread_create_on_node+0x260/0x260 + +Signed-off-by: Daniel Wagner <daniel.wagner@bmw-carit.de> +Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> +Cc: linux-rt-users@vger.kernel.org +Cc: Boqun Feng <boqun.feng@gmail.com> +Cc: Marcelo Tosatti <mtosatti@redhat.com> +Cc: Steven Rostedt <rostedt@goodmis.org> +Cc: Paul Gortmaker <paul.gortmaker@windriver.com> +Cc: Paolo Bonzini <pbonzini@redhat.com> +Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> +Link: http://lkml.kernel.org/r/1455871601-27484-5-git-send-email-wagi@monom.org +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +--- + kernel/rcu/tree.c | 4 +++- + kernel/rcu/tree.h | 3 ++- + kernel/rcu/tree_plugin.h | 16 +++++++++++++--- + 3 files changed, 18 insertions(+), 5 deletions(-) + +--- a/kernel/rcu/tree.c ++++ b/kernel/rcu/tree.c +@@ -1590,7 +1590,6 @@ static int rcu_future_gp_cleanup(struct + int needmore; + struct rcu_data *rdp = this_cpu_ptr(rsp->rda); + +- rcu_nocb_gp_cleanup(rsp, rnp); + rnp->need_future_gp[c & 0x1] = 0; + needmore = rnp->need_future_gp[(c + 1) & 0x1]; + trace_rcu_future_gp(rnp, rdp, c, +@@ -1991,6 +1990,7 @@ static void rcu_gp_cleanup(struct rcu_st + int nocb = 0; + struct rcu_data *rdp; + struct rcu_node *rnp = rcu_get_root(rsp); ++ wait_queue_head_t *sq; + + WRITE_ONCE(rsp->gp_activity, jiffies); + raw_spin_lock_irq(&rnp->lock); +@@ -2029,7 +2029,9 @@ static void rcu_gp_cleanup(struct rcu_st + needgp = __note_gp_changes(rsp, rnp, rdp) || needgp; + /* smp_mb() provided by prior unlock-lock pair. */ + nocb += rcu_future_gp_cleanup(rsp, rnp); ++ sq = rcu_nocb_gp_get(rnp); + raw_spin_unlock_irq(&rnp->lock); ++ rcu_nocb_gp_cleanup(sq); + cond_resched_rcu_qs(); + WRITE_ONCE(rsp->gp_activity, jiffies); + rcu_gp_slow(rsp, gp_cleanup_delay); +--- a/kernel/rcu/tree.h ++++ b/kernel/rcu/tree.h +@@ -607,7 +607,8 @@ static void zero_cpu_stall_ticks(struct + static void increment_cpu_stall_ticks(void); + static bool rcu_nocb_cpu_needs_barrier(struct rcu_state *rsp, int cpu); + static void rcu_nocb_gp_set(struct rcu_node *rnp, int nrq); +-static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp); ++static wait_queue_head_t *rcu_nocb_gp_get(struct rcu_node *rnp); ++static void rcu_nocb_gp_cleanup(wait_queue_head_t *sq); + static void rcu_init_one_nocb(struct rcu_node *rnp); + static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp, + bool lazy, unsigned long flags); +--- a/kernel/rcu/tree_plugin.h ++++ b/kernel/rcu/tree_plugin.h +@@ -1822,9 +1822,9 @@ early_param("rcu_nocb_poll", parse_rcu_n + * Wake up any no-CBs CPUs' kthreads that were waiting on the just-ended + * grace period. + */ +-static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp) ++static void rcu_nocb_gp_cleanup(wait_queue_head_t *sq) + { +- wake_up_all(&rnp->nocb_gp_wq[rnp->completed & 0x1]); ++ wake_up_all(sq); + } + + /* +@@ -1840,6 +1840,11 @@ static void rcu_nocb_gp_set(struct rcu_n + rnp->need_future_gp[(rnp->completed + 1) & 0x1] += nrq; + } + ++static wait_queue_head_t *rcu_nocb_gp_get(struct rcu_node *rnp) ++{ ++ return &rnp->nocb_gp_wq[rnp->completed & 0x1]; ++} ++ + static void rcu_init_one_nocb(struct rcu_node *rnp) + { + init_waitqueue_head(&rnp->nocb_gp_wq[0]); +@@ -2514,7 +2519,7 @@ static bool rcu_nocb_cpu_needs_barrier(s + return false; + } + +-static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp) ++static void rcu_nocb_gp_cleanup(wait_queue_head_t *sq) + { + } + +@@ -2522,6 +2527,11 @@ static void rcu_nocb_gp_set(struct rcu_n + { + } + ++static wait_queue_head_t *rcu_nocb_gp_get(struct rcu_node *rnp) ++{ ++ return NULL; ++} ++ + static void rcu_init_one_nocb(struct rcu_node *rnp) + { + } diff --git a/patches/0005-clk-at91-pmc-move-pmc-structures-to-C-file.patch b/patches/0005-clk-at91-pmc-move-pmc-structures-to-C-file.patch new file mode 100644 index 00000000000000..294e4cdd676457 --- /dev/null +++ b/patches/0005-clk-at91-pmc-move-pmc-structures-to-C-file.patch @@ -0,0 +1,52 @@ +From: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Date: Thu, 17 Sep 2015 15:26:46 +0200 +Subject: [PATCH 05/13] clk: at91: pmc: move pmc structures to C file + +pmc.c is now the only user of struct at91_pmc*, move their definition in +the C file. + +Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com> +Acked-by: Stephen Boyd <sboyd@codeaurora.org> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + drivers/clk/at91/pmc.c | 9 +++++++++ + drivers/clk/at91/pmc.h | 9 --------- + 2 files changed, 9 insertions(+), 9 deletions(-) + +--- a/drivers/clk/at91/pmc.c ++++ b/drivers/clk/at91/pmc.c +@@ -20,6 +20,15 @@ + + #include "pmc.h" + ++struct at91_pmc_caps { ++ u32 available_irqs; ++}; ++ ++struct at91_pmc { ++ struct regmap *regmap; ++ const struct at91_pmc_caps *caps; ++}; ++ + void __iomem *at91_pmc_base; + EXPORT_SYMBOL_GPL(at91_pmc_base); + +--- a/drivers/clk/at91/pmc.h ++++ b/drivers/clk/at91/pmc.h +@@ -26,15 +26,6 @@ struct clk_range { + + #define CLK_RANGE(MIN, MAX) {.min = MIN, .max = MAX,} + +-struct at91_pmc_caps { +- u32 available_irqs; +-}; +- +-struct at91_pmc { +- struct regmap *regmap; +- const struct at91_pmc_caps *caps; +-}; +- + int of_at91_get_clk_range(struct device_node *np, const char *propname, + struct clk_range *range); + diff --git a/patches/0005-rcu-Use-simple-wait-queues-where-possible-in-rcutree.patch b/patches/0005-rcu-Use-simple-wait-queues-where-possible-in-rcutree.patch new file mode 100644 index 00000000000000..cb37231ba67eb9 --- /dev/null +++ b/patches/0005-rcu-Use-simple-wait-queues-where-possible-in-rcutree.patch @@ -0,0 +1,310 @@ +From: Paul Gortmaker <paul.gortmaker@windriver.com> +Date: Fri, 19 Feb 2016 09:46:41 +0100 +Subject: [PATCH 5/5] rcu: Use simple wait queues where possible in rcutree + +As of commit dae6e64d2bcfd ("rcu: Introduce proper blocking to no-CBs kthreads +GP waits") the RCU subsystem started making use of wait queues. + +Here we convert all additions of RCU wait queues to use simple wait queues, +since they don't need the extra overhead of the full wait queue features. + +Originally this was done for RT kernels[1], since we would get things like... + + BUG: sleeping function called from invalid context at kernel/rtmutex.c:659 + in_atomic(): 1, irqs_disabled(): 1, pid: 8, name: rcu_preempt + Pid: 8, comm: rcu_preempt Not tainted + Call Trace: + [<ffffffff8106c8d0>] __might_sleep+0xd0/0xf0 + [<ffffffff817d77b4>] rt_spin_lock+0x24/0x50 + [<ffffffff8106fcf6>] __wake_up+0x36/0x70 + [<ffffffff810c4542>] rcu_gp_kthread+0x4d2/0x680 + [<ffffffff8105f910>] ? __init_waitqueue_head+0x50/0x50 + [<ffffffff810c4070>] ? rcu_gp_fqs+0x80/0x80 + [<ffffffff8105eabb>] kthread+0xdb/0xe0 + [<ffffffff8106b912>] ? finish_task_switch+0x52/0x100 + [<ffffffff817e0754>] kernel_thread_helper+0x4/0x10 + [<ffffffff8105e9e0>] ? __init_kthread_worker+0x60/0x60 + [<ffffffff817e0750>] ? gs_change+0xb/0xb + +...and hence simple wait queues were deployed on RT out of necessity +(as simple wait uses a raw lock), but mainline might as well take +advantage of the more streamline support as well. + +[1] This is a carry forward of work from v3.10-rt; the original conversion +was by Thomas on an earlier -rt version, and Sebastian extended it to +additional post-3.10 added RCU waiters; here I've added a commit log and +unified the RCU changes into one, and uprev'd it to match mainline RCU. + +Signed-off-by: Daniel Wagner <daniel.wagner@bmw-carit.de> +Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> +Cc: linux-rt-users@vger.kernel.org +Cc: Boqun Feng <boqun.feng@gmail.com> +Cc: Marcelo Tosatti <mtosatti@redhat.com> +Cc: Steven Rostedt <rostedt@goodmis.org> +Cc: Paul Gortmaker <paul.gortmaker@windriver.com> +Cc: Paolo Bonzini <pbonzini@redhat.com> +Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> +Link: http://lkml.kernel.org/r/1455871601-27484-6-git-send-email-wagi@monom.org +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +--- + kernel/rcu/tree.c | 22 +++++++++++----------- + kernel/rcu/tree.h | 13 +++++++------ + kernel/rcu/tree_plugin.h | 26 +++++++++++++------------- + 3 files changed, 31 insertions(+), 30 deletions(-) + +--- a/kernel/rcu/tree.c ++++ b/kernel/rcu/tree.c +@@ -1610,7 +1610,7 @@ static void rcu_gp_kthread_wake(struct r + !READ_ONCE(rsp->gp_flags) || + !rsp->gp_kthread) + return; +- wake_up(&rsp->gp_wq); ++ swake_up(&rsp->gp_wq); + } + + /* +@@ -1990,7 +1990,7 @@ static void rcu_gp_cleanup(struct rcu_st + int nocb = 0; + struct rcu_data *rdp; + struct rcu_node *rnp = rcu_get_root(rsp); +- wait_queue_head_t *sq; ++ struct swait_queue_head *sq; + + WRITE_ONCE(rsp->gp_activity, jiffies); + raw_spin_lock_irq(&rnp->lock); +@@ -2078,7 +2078,7 @@ static int __noreturn rcu_gp_kthread(voi + READ_ONCE(rsp->gpnum), + TPS("reqwait")); + rsp->gp_state = RCU_GP_WAIT_GPS; +- wait_event_interruptible(rsp->gp_wq, ++ swait_event_interruptible(rsp->gp_wq, + READ_ONCE(rsp->gp_flags) & + RCU_GP_FLAG_INIT); + rsp->gp_state = RCU_GP_DONE_GPS; +@@ -2108,7 +2108,7 @@ static int __noreturn rcu_gp_kthread(voi + READ_ONCE(rsp->gpnum), + TPS("fqswait")); + rsp->gp_state = RCU_GP_WAIT_FQS; +- ret = wait_event_interruptible_timeout(rsp->gp_wq, ++ ret = swait_event_interruptible_timeout(rsp->gp_wq, + rcu_gp_fqs_check_wake(rsp, &gf), j); + rsp->gp_state = RCU_GP_DOING_FQS; + /* Locking provides needed memory barriers. */ +@@ -2232,7 +2232,7 @@ static void rcu_report_qs_rsp(struct rcu + WARN_ON_ONCE(!rcu_gp_in_progress(rsp)); + WRITE_ONCE(rsp->gp_flags, READ_ONCE(rsp->gp_flags) | RCU_GP_FLAG_FQS); + raw_spin_unlock_irqrestore(&rcu_get_root(rsp)->lock, flags); +- rcu_gp_kthread_wake(rsp); ++ swake_up(&rsp->gp_wq); /* Memory barrier implied by swake_up() path. */ + } + + /* +@@ -2893,7 +2893,7 @@ static void force_quiescent_state(struct + } + WRITE_ONCE(rsp->gp_flags, READ_ONCE(rsp->gp_flags) | RCU_GP_FLAG_FQS); + raw_spin_unlock_irqrestore(&rnp_old->lock, flags); +- rcu_gp_kthread_wake(rsp); ++ swake_up(&rsp->gp_wq); /* Memory barrier implied by swake_up() path. */ + } + + /* +@@ -3526,7 +3526,7 @@ static void __rcu_report_exp_rnp(struct + raw_spin_unlock_irqrestore(&rnp->lock, flags); + if (wake) { + smp_mb(); /* EGP done before wake_up(). */ +- wake_up(&rsp->expedited_wq); ++ swake_up(&rsp->expedited_wq); + } + break; + } +@@ -3783,7 +3783,7 @@ static void synchronize_sched_expedited_ + jiffies_start = jiffies; + + for (;;) { +- ret = wait_event_interruptible_timeout( ++ ret = swait_event_timeout( + rsp->expedited_wq, + sync_rcu_preempt_exp_done(rnp_root), + jiffies_stall); +@@ -3791,7 +3791,7 @@ static void synchronize_sched_expedited_ + return; + if (ret < 0) { + /* Hit a signal, disable CPU stall warnings. */ +- wait_event(rsp->expedited_wq, ++ swait_event(rsp->expedited_wq, + sync_rcu_preempt_exp_done(rnp_root)); + return; + } +@@ -4457,8 +4457,8 @@ static void __init rcu_init_one(struct r + } + } + +- init_waitqueue_head(&rsp->gp_wq); +- init_waitqueue_head(&rsp->expedited_wq); ++ init_swait_queue_head(&rsp->gp_wq); ++ init_swait_queue_head(&rsp->expedited_wq); + rnp = rsp->level[rcu_num_lvls - 1]; + for_each_possible_cpu(i) { + while (i > rnp->grphi) +--- a/kernel/rcu/tree.h ++++ b/kernel/rcu/tree.h +@@ -27,6 +27,7 @@ + #include <linux/threads.h> + #include <linux/cpumask.h> + #include <linux/seqlock.h> ++#include <linux/swait.h> + #include <linux/stop_machine.h> + + /* +@@ -241,7 +242,7 @@ struct rcu_node { + /* Refused to boost: not sure why, though. */ + /* This can happen due to race conditions. */ + #ifdef CONFIG_RCU_NOCB_CPU +- wait_queue_head_t nocb_gp_wq[2]; ++ struct swait_queue_head nocb_gp_wq[2]; + /* Place for rcu_nocb_kthread() to wait GP. */ + #endif /* #ifdef CONFIG_RCU_NOCB_CPU */ + int need_future_gp[2]; +@@ -393,7 +394,7 @@ struct rcu_data { + atomic_long_t nocb_q_count_lazy; /* invocation (all stages). */ + struct rcu_head *nocb_follower_head; /* CBs ready to invoke. */ + struct rcu_head **nocb_follower_tail; +- wait_queue_head_t nocb_wq; /* For nocb kthreads to sleep on. */ ++ struct swait_queue_head nocb_wq; /* For nocb kthreads to sleep on. */ + struct task_struct *nocb_kthread; + int nocb_defer_wakeup; /* Defer wakeup of nocb_kthread. */ + +@@ -472,7 +473,7 @@ struct rcu_state { + unsigned long gpnum; /* Current gp number. */ + unsigned long completed; /* # of last completed gp. */ + struct task_struct *gp_kthread; /* Task for grace periods. */ +- wait_queue_head_t gp_wq; /* Where GP task waits. */ ++ struct swait_queue_head gp_wq; /* Where GP task waits. */ + short gp_flags; /* Commands for GP task. */ + short gp_state; /* GP kthread sleep state. */ + +@@ -504,7 +505,7 @@ struct rcu_state { + atomic_long_t expedited_workdone3; /* # done by others #3. */ + atomic_long_t expedited_normal; /* # fallbacks to normal. */ + atomic_t expedited_need_qs; /* # CPUs left to check in. */ +- wait_queue_head_t expedited_wq; /* Wait for check-ins. */ ++ struct swait_queue_head expedited_wq; /* Wait for check-ins. */ + int ncpus_snap; /* # CPUs seen last time. */ + + unsigned long jiffies_force_qs; /* Time at which to invoke */ +@@ -607,8 +608,8 @@ static void zero_cpu_stall_ticks(struct + static void increment_cpu_stall_ticks(void); + static bool rcu_nocb_cpu_needs_barrier(struct rcu_state *rsp, int cpu); + static void rcu_nocb_gp_set(struct rcu_node *rnp, int nrq); +-static wait_queue_head_t *rcu_nocb_gp_get(struct rcu_node *rnp); +-static void rcu_nocb_gp_cleanup(wait_queue_head_t *sq); ++static struct swait_queue_head *rcu_nocb_gp_get(struct rcu_node *rnp); ++static void rcu_nocb_gp_cleanup(struct swait_queue_head *sq); + static void rcu_init_one_nocb(struct rcu_node *rnp); + static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp, + bool lazy, unsigned long flags); +--- a/kernel/rcu/tree_plugin.h ++++ b/kernel/rcu/tree_plugin.h +@@ -1822,9 +1822,9 @@ early_param("rcu_nocb_poll", parse_rcu_n + * Wake up any no-CBs CPUs' kthreads that were waiting on the just-ended + * grace period. + */ +-static void rcu_nocb_gp_cleanup(wait_queue_head_t *sq) ++static void rcu_nocb_gp_cleanup(struct swait_queue_head *sq) + { +- wake_up_all(sq); ++ swake_up_all(sq); + } + + /* +@@ -1840,15 +1840,15 @@ static void rcu_nocb_gp_set(struct rcu_n + rnp->need_future_gp[(rnp->completed + 1) & 0x1] += nrq; + } + +-static wait_queue_head_t *rcu_nocb_gp_get(struct rcu_node *rnp) ++static struct swait_queue_head *rcu_nocb_gp_get(struct rcu_node *rnp) + { + return &rnp->nocb_gp_wq[rnp->completed & 0x1]; + } + + static void rcu_init_one_nocb(struct rcu_node *rnp) + { +- init_waitqueue_head(&rnp->nocb_gp_wq[0]); +- init_waitqueue_head(&rnp->nocb_gp_wq[1]); ++ init_swait_queue_head(&rnp->nocb_gp_wq[0]); ++ init_swait_queue_head(&rnp->nocb_gp_wq[1]); + } + + #ifndef CONFIG_RCU_NOCB_CPU_ALL +@@ -1873,7 +1873,7 @@ static void wake_nocb_leader(struct rcu_ + if (READ_ONCE(rdp_leader->nocb_leader_sleep) || force) { + /* Prior smp_mb__after_atomic() orders against prior enqueue. */ + WRITE_ONCE(rdp_leader->nocb_leader_sleep, false); +- wake_up(&rdp_leader->nocb_wq); ++ swake_up(&rdp_leader->nocb_wq); + } + } + +@@ -2086,7 +2086,7 @@ static void rcu_nocb_wait_gp(struct rcu_ + */ + trace_rcu_future_gp(rnp, rdp, c, TPS("StartWait")); + for (;;) { +- wait_event_interruptible( ++ swait_event_interruptible( + rnp->nocb_gp_wq[c & 0x1], + (d = ULONG_CMP_GE(READ_ONCE(rnp->completed), c))); + if (likely(d)) +@@ -2114,7 +2114,7 @@ static void nocb_leader_wait(struct rcu_ + /* Wait for callbacks to appear. */ + if (!rcu_nocb_poll) { + trace_rcu_nocb_wake(my_rdp->rsp->name, my_rdp->cpu, "Sleep"); +- wait_event_interruptible(my_rdp->nocb_wq, ++ swait_event_interruptible(my_rdp->nocb_wq, + !READ_ONCE(my_rdp->nocb_leader_sleep)); + /* Memory barrier handled by smp_mb() calls below and repoll. */ + } else if (firsttime) { +@@ -2189,7 +2189,7 @@ static void nocb_leader_wait(struct rcu_ + * List was empty, wake up the follower. + * Memory barriers supplied by atomic_long_add(). + */ +- wake_up(&rdp->nocb_wq); ++ swake_up(&rdp->nocb_wq); + } + } + +@@ -2210,7 +2210,7 @@ static void nocb_follower_wait(struct rc + if (!rcu_nocb_poll) { + trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, + "FollowerSleep"); +- wait_event_interruptible(rdp->nocb_wq, ++ swait_event_interruptible(rdp->nocb_wq, + READ_ONCE(rdp->nocb_follower_head)); + } else if (firsttime) { + /* Don't drown trace log with "Poll"! */ +@@ -2369,7 +2369,7 @@ void __init rcu_init_nohz(void) + static void __init rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp) + { + rdp->nocb_tail = &rdp->nocb_head; +- init_waitqueue_head(&rdp->nocb_wq); ++ init_swait_queue_head(&rdp->nocb_wq); + rdp->nocb_follower_tail = &rdp->nocb_follower_head; + } + +@@ -2519,7 +2519,7 @@ static bool rcu_nocb_cpu_needs_barrier(s + return false; + } + +-static void rcu_nocb_gp_cleanup(wait_queue_head_t *sq) ++static void rcu_nocb_gp_cleanup(struct swait_queue_head *sq) + { + } + +@@ -2527,7 +2527,7 @@ static void rcu_nocb_gp_set(struct rcu_n + { + } + +-static wait_queue_head_t *rcu_nocb_gp_get(struct rcu_node *rnp) ++static struct swait_queue_head *rcu_nocb_gp_get(struct rcu_node *rnp) + { + return NULL; + } diff --git a/patches/0006-ARM-at91-pm-simply-call-at91_pm_init.patch b/patches/0006-ARM-at91-pm-simply-call-at91_pm_init.patch new file mode 100644 index 00000000000000..cb5d3f2ae01539 --- /dev/null +++ b/patches/0006-ARM-at91-pm-simply-call-at91_pm_init.patch @@ -0,0 +1,41 @@ +From: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Date: Wed, 30 Sep 2015 01:08:33 +0200 +Subject: [PATCH 06/13] ARM: at91: pm: simply call at91_pm_init + +at91_pm_init() doesn't return a value, as is the case for its callers, +simply call it instead of returning its non-existent return value. + +Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + arch/arm/mach-at91/pm.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/arch/arm/mach-at91/pm.c ++++ b/arch/arm/mach-at91/pm.c +@@ -432,7 +432,7 @@ void __init at91sam9260_pm_init(void) + at91_dt_ramc(); + at91_pm_data.memctrl = AT91_MEMCTRL_SDRAMC; + at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP; +- return at91_pm_init(); ++ at91_pm_init(); + } + + void __init at91sam9g45_pm_init(void) +@@ -440,7 +440,7 @@ void __init at91sam9g45_pm_init(void) + at91_dt_ramc(); + at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP; + at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR; +- return at91_pm_init(); ++ at91_pm_init(); + } + + void __init at91sam9x5_pm_init(void) +@@ -448,5 +448,5 @@ void __init at91sam9x5_pm_init(void) + at91_dt_ramc(); + at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP; + at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR; +- return at91_pm_init(); ++ at91_pm_init(); + } diff --git a/patches/0007-ARM-at91-pm-find-and-remap-the-pmc.patch b/patches/0007-ARM-at91-pm-find-and-remap-the-pmc.patch new file mode 100644 index 00000000000000..5564ca952fb2f9 --- /dev/null +++ b/patches/0007-ARM-at91-pm-find-and-remap-the-pmc.patch @@ -0,0 +1,90 @@ +From: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Date: Wed, 30 Sep 2015 01:31:34 +0200 +Subject: [PATCH 07/13] ARM: at91: pm: find and remap the pmc + +To avoid relying on at91_pmc_read(), find the pmc node and remap it +locally. + +Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + arch/arm/mach-at91/pm.c | 33 +++++++++++++++++++++++++++------ + 1 file changed, 27 insertions(+), 6 deletions(-) + +--- a/arch/arm/mach-at91/pm.c ++++ b/arch/arm/mach-at91/pm.c +@@ -35,6 +35,8 @@ + #include "generic.h" + #include "pm.h" + ++static void __iomem *pmc; ++ + /* + * FIXME: this is needed to communicate between the pinctrl driver and + * the PM implementation in the machine. Possibly part of the PM +@@ -87,7 +89,7 @@ static int at91_pm_verify_clocks(void) + unsigned long scsr; + int i; + +- scsr = at91_pmc_read(AT91_PMC_SCSR); ++ scsr = readl(pmc + AT91_PMC_SCSR); + + /* USB must not be using PLLB */ + if ((scsr & at91_pm_data.uhp_udp_mask) != 0) { +@@ -101,8 +103,7 @@ static int at91_pm_verify_clocks(void) + + if ((scsr & (AT91_PMC_PCK0 << i)) == 0) + continue; +- +- css = at91_pmc_read(AT91_PMC_PCKR(i)) & AT91_PMC_CSS; ++ css = readl(pmc + AT91_PMC_PCKR(i)) & AT91_PMC_CSS; + if (css != AT91_PMC_CSS_SLOW) { + pr_err("AT91: PM - Suspend-to-RAM with PCK%d src %d\n", i, css); + return 0; +@@ -145,8 +146,8 @@ static void at91_pm_suspend(suspend_stat + flush_cache_all(); + outer_disable(); + +- at91_suspend_sram_fn(at91_pmc_base, at91_ramc_base[0], +- at91_ramc_base[1], pm_data); ++ at91_suspend_sram_fn(pmc, at91_ramc_base[0], ++ at91_ramc_base[1], pm_data); + + outer_resume(); + } +@@ -399,13 +400,33 @@ static void __init at91_pm_sram_init(voi + &at91_pm_suspend_in_sram, at91_pm_suspend_in_sram_sz); + } + ++static const struct of_device_id atmel_pmc_ids[] __initconst = { ++ { .compatible = "atmel,at91rm9200-pmc" }, ++ { .compatible = "atmel,at91sam9260-pmc" }, ++ { .compatible = "atmel,at91sam9g45-pmc" }, ++ { .compatible = "atmel,at91sam9n12-pmc" }, ++ { .compatible = "atmel,at91sam9x5-pmc" }, ++ { .compatible = "atmel,sama5d3-pmc" }, ++ { .compatible = "atmel,sama5d2-pmc" }, ++ { /* sentinel */ }, ++}; ++ + static void __init at91_pm_init(void) + { +- at91_pm_sram_init(); ++ struct device_node *pmc_np; + + if (at91_cpuidle_device.dev.platform_data) + platform_device_register(&at91_cpuidle_device); + ++ pmc_np = of_find_matching_node(NULL, atmel_pmc_ids); ++ pmc = of_iomap(pmc_np, 0); ++ if (!pmc) { ++ pr_err("AT91: PM not supported, PMC not found\n"); ++ return; ++ } ++ ++ at91_pm_sram_init(); ++ + if (at91_suspend_sram_fn) + suspend_set_ops(&at91_pm_ops); + else diff --git a/patches/0008-ARM-at91-pm-move-idle-functions-to-pm.c.patch b/patches/0008-ARM-at91-pm-move-idle-functions-to-pm.c.patch new file mode 100644 index 00000000000000..1d016641f0d6d7 --- /dev/null +++ b/patches/0008-ARM-at91-pm-move-idle-functions-to-pm.c.patch @@ -0,0 +1,201 @@ +From: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Date: Wed, 30 Sep 2015 01:58:40 +0200 +Subject: [PATCH 08/13] ARM: at91: pm: move idle functions to pm.c + +Avoid using code from clk/at91 for PM. +This also has the bonus effect of setting arm_pm_idle for sama5 platforms. + +Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + arch/arm/mach-at91/at91rm9200.c | 2 -- + arch/arm/mach-at91/at91sam9.c | 2 -- + arch/arm/mach-at91/generic.h | 6 ++---- + arch/arm/mach-at91/pm.c | 37 ++++++++++++++++++++++++++++++++----- + arch/arm/mach-at91/sama5.c | 2 +- + drivers/clk/at91/pmc.c | 15 --------------- + 6 files changed, 35 insertions(+), 29 deletions(-) + +--- a/arch/arm/mach-at91/at91rm9200.c ++++ b/arch/arm/mach-at91/at91rm9200.c +@@ -12,7 +12,6 @@ + #include <linux/of_platform.h> + + #include <asm/mach/arch.h> +-#include <asm/system_misc.h> + + #include "generic.h" + #include "soc.h" +@@ -33,7 +32,6 @@ static void __init at91rm9200_dt_device_ + + of_platform_populate(NULL, of_default_bus_match_table, NULL, soc_dev); + +- arm_pm_idle = at91rm9200_idle; + at91rm9200_pm_init(); + } + +--- a/arch/arm/mach-at91/at91sam9.c ++++ b/arch/arm/mach-at91/at91sam9.c +@@ -62,8 +62,6 @@ static void __init at91sam9_common_init( + soc_dev = soc_device_to_device(soc); + + of_platform_populate(NULL, of_default_bus_match_table, NULL, soc_dev); +- +- arm_pm_idle = at91sam9_idle; + } + + static void __init at91sam9_dt_device_init(void) +--- a/arch/arm/mach-at91/generic.h ++++ b/arch/arm/mach-at91/generic.h +@@ -18,20 +18,18 @@ + extern void __init at91_map_io(void); + extern void __init at91_alt_map_io(void); + +-/* idle */ +-extern void at91rm9200_idle(void); +-extern void at91sam9_idle(void); +- + #ifdef CONFIG_PM + extern void __init at91rm9200_pm_init(void); + extern void __init at91sam9260_pm_init(void); + extern void __init at91sam9g45_pm_init(void); + extern void __init at91sam9x5_pm_init(void); ++extern void __init sama5_pm_init(void); + #else + static inline void __init at91rm9200_pm_init(void) { } + static inline void __init at91sam9260_pm_init(void) { } + static inline void __init at91sam9g45_pm_init(void) { } + static inline void __init at91sam9x5_pm_init(void) { } ++static inline void __init sama5_pm_init(void) { } + #endif + + #endif /* _AT91_GENERIC_H */ +--- a/arch/arm/mach-at91/pm.c ++++ b/arch/arm/mach-at91/pm.c +@@ -31,6 +31,7 @@ + #include <asm/mach/irq.h> + #include <asm/fncpy.h> + #include <asm/cacheflush.h> ++#include <asm/system_misc.h> + + #include "generic.h" + #include "pm.h" +@@ -354,6 +355,21 @@ static __init void at91_dt_ramc(void) + at91_pm_set_standby(standby); + } + ++void at91rm9200_idle(void) ++{ ++ /* ++ * Disable the processor clock. The processor will be automatically ++ * re-enabled by an interrupt or by a reset. ++ */ ++ writel(AT91_PMC_PCK, pmc + AT91_PMC_SCDR); ++} ++ ++void at91sam9_idle(void) ++{ ++ writel(AT91_PMC_PCK, pmc + AT91_PMC_SCDR); ++ cpu_do_idle(); ++} ++ + static void __init at91_pm_sram_init(void) + { + struct gen_pool *sram_pool; +@@ -411,7 +427,7 @@ static const struct of_device_id atmel_p + { /* sentinel */ }, + }; + +-static void __init at91_pm_init(void) ++static void __init at91_pm_init(void (*pm_idle)(void)) + { + struct device_node *pmc_np; + +@@ -425,6 +441,9 @@ static void __init at91_pm_init(void) + return; + } + ++ if (pm_idle) ++ arm_pm_idle = pm_idle; ++ + at91_pm_sram_init(); + + if (at91_suspend_sram_fn) +@@ -445,7 +464,7 @@ void __init at91rm9200_pm_init(void) + at91_pm_data.uhp_udp_mask = AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP; + at91_pm_data.memctrl = AT91_MEMCTRL_MC; + +- at91_pm_init(); ++ at91_pm_init(at91rm9200_idle); + } + + void __init at91sam9260_pm_init(void) +@@ -453,7 +472,7 @@ void __init at91sam9260_pm_init(void) + at91_dt_ramc(); + at91_pm_data.memctrl = AT91_MEMCTRL_SDRAMC; + at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP; +- at91_pm_init(); ++ at91_pm_init(at91sam9_idle); + } + + void __init at91sam9g45_pm_init(void) +@@ -461,7 +480,7 @@ void __init at91sam9g45_pm_init(void) + at91_dt_ramc(); + at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP; + at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR; +- at91_pm_init(); ++ at91_pm_init(at91sam9_idle); + } + + void __init at91sam9x5_pm_init(void) +@@ -469,5 +488,13 @@ void __init at91sam9x5_pm_init(void) + at91_dt_ramc(); + at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP; + at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR; +- at91_pm_init(); ++ at91_pm_init(at91sam9_idle); ++} ++ ++void __init sama5_pm_init(void) ++{ ++ at91_dt_ramc(); ++ at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP; ++ at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR; ++ at91_pm_init(NULL); + } +--- a/arch/arm/mach-at91/sama5.c ++++ b/arch/arm/mach-at91/sama5.c +@@ -51,7 +51,7 @@ static void __init sama5_dt_device_init( + soc_dev = soc_device_to_device(soc); + + of_platform_populate(NULL, of_default_bus_match_table, NULL, soc_dev); +- at91sam9x5_pm_init(); ++ sama5_pm_init(); + } + + static const char *const sama5_dt_board_compat[] __initconst = { +--- a/drivers/clk/at91/pmc.c ++++ b/drivers/clk/at91/pmc.c +@@ -32,21 +32,6 @@ struct at91_pmc { + void __iomem *at91_pmc_base; + EXPORT_SYMBOL_GPL(at91_pmc_base); + +-void at91rm9200_idle(void) +-{ +- /* +- * Disable the processor clock. The processor will be automatically +- * re-enabled by an interrupt or by a reset. +- */ +- at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK); +-} +- +-void at91sam9_idle(void) +-{ +- at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK); +- cpu_do_idle(); +-} +- + int of_at91_get_clk_range(struct device_node *np, const char *propname, + struct clk_range *range) + { diff --git a/patches/0009-ARM-at91-remove-useless-includes-and-function-protot.patch b/patches/0009-ARM-at91-remove-useless-includes-and-function-protot.patch new file mode 100644 index 00000000000000..4fac07bd3bfc5c --- /dev/null +++ b/patches/0009-ARM-at91-remove-useless-includes-and-function-protot.patch @@ -0,0 +1,30 @@ +From: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Date: Wed, 30 Sep 2015 02:01:20 +0200 +Subject: [PATCH 09/13] ARM: at91: remove useless includes and function + prototypes + +Remove leftover from the previous cleanup + +Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + arch/arm/mach-at91/generic.h | 7 ------- + 1 file changed, 7 deletions(-) + +--- a/arch/arm/mach-at91/generic.h ++++ b/arch/arm/mach-at91/generic.h +@@ -11,13 +11,6 @@ + #ifndef _AT91_GENERIC_H + #define _AT91_GENERIC_H + +-#include <linux/of.h> +-#include <linux/reboot.h> +- +- /* Map io */ +-extern void __init at91_map_io(void); +-extern void __init at91_alt_map_io(void); +- + #ifdef CONFIG_PM + extern void __init at91rm9200_pm_init(void); + extern void __init at91sam9260_pm_init(void); diff --git a/patches/0010-usb-gadget-atmel-access-the-PMC-using-regmap.patch b/patches/0010-usb-gadget-atmel-access-the-PMC-using-regmap.patch new file mode 100644 index 00000000000000..379a98ba87f968 --- /dev/null +++ b/patches/0010-usb-gadget-atmel-access-the-PMC-using-regmap.patch @@ -0,0 +1,75 @@ +From: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Date: Wed, 30 Sep 2015 12:57:10 +0200 +Subject: [PATCH 10/13] usb: gadget: atmel: access the PMC using regmap + +Use regmap to access the PMC to avoid using at91_pmc_read and +at91_pmc_write. + +Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com> +Acked-by: Felipe Balbi <balbi@ti.com> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + drivers/usb/gadget/udc/atmel_usba_udc.c | 20 ++++++++++---------- + drivers/usb/gadget/udc/atmel_usba_udc.h | 2 ++ + 2 files changed, 12 insertions(+), 10 deletions(-) + +--- a/drivers/usb/gadget/udc/atmel_usba_udc.c ++++ b/drivers/usb/gadget/udc/atmel_usba_udc.c +@@ -17,7 +17,9 @@ + #include <linux/device.h> + #include <linux/dma-mapping.h> + #include <linux/list.h> ++#include <linux/mfd/syscon.h> + #include <linux/platform_device.h> ++#include <linux/regmap.h> + #include <linux/usb/ch9.h> + #include <linux/usb/gadget.h> + #include <linux/usb/atmel_usba_udc.h> +@@ -1888,20 +1890,15 @@ static int atmel_usba_stop(struct usb_ga + #ifdef CONFIG_OF + static void at91sam9rl_toggle_bias(struct usba_udc *udc, int is_on) + { +- unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR); +- +- if (is_on) +- at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN); +- else +- at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN)); ++ regmap_update_bits(udc->pmc, AT91_CKGR_UCKR, AT91_PMC_BIASEN, ++ is_on ? AT91_PMC_BIASEN : 0); + } + + static void at91sam9g45_pulse_bias(struct usba_udc *udc) + { +- unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR); +- +- at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN)); +- at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN); ++ regmap_update_bits(udc->pmc, AT91_CKGR_UCKR, AT91_PMC_BIASEN, 0); ++ regmap_update_bits(udc->pmc, AT91_CKGR_UCKR, AT91_PMC_BIASEN, ++ AT91_PMC_BIASEN); + } + + static const struct usba_udc_errata at91sam9rl_errata = { +@@ -1938,6 +1935,9 @@ static struct usba_ep * atmel_udc_of_ini + return ERR_PTR(-EINVAL); + + udc->errata = match->data; ++ udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9g45-pmc"); ++ if (udc->errata && IS_ERR(udc->pmc)) ++ return ERR_CAST(udc->pmc); + + udc->num_ep = 0; + +--- a/drivers/usb/gadget/udc/atmel_usba_udc.h ++++ b/drivers/usb/gadget/udc/atmel_usba_udc.h +@@ -354,6 +354,8 @@ struct usba_udc { + struct dentry *debugfs_root; + struct dentry *debugfs_regs; + #endif ++ ++ struct regmap *pmc; + }; + + static inline struct usba_ep *to_usba_ep(struct usb_ep *ep) diff --git a/patches/0011-clk-at91-pmc-drop-at91_pmc_base.patch b/patches/0011-clk-at91-pmc-drop-at91_pmc_base.patch new file mode 100644 index 00000000000000..39addf9379a132 --- /dev/null +++ b/patches/0011-clk-at91-pmc-drop-at91_pmc_base.patch @@ -0,0 +1,69 @@ +From: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Date: Wed, 30 Sep 2015 13:02:01 +0200 +Subject: [PATCH 11/13] clk: at91: pmc: drop at91_pmc_base + +at91_pmc_base is not used anymore, remove it along with at91_pmc_read and +at91_pmc_write. + +Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com> +Acked-by: Stephen Boyd <sboyd@codeaurora.org> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + drivers/clk/at91/pmc.c | 7 ------- + include/linux/clk/at91_pmc.h | 12 ------------ + 2 files changed, 19 deletions(-) + +--- a/drivers/clk/at91/pmc.c ++++ b/drivers/clk/at91/pmc.c +@@ -12,7 +12,6 @@ + #include <linux/clkdev.h> + #include <linux/clk/at91_pmc.h> + #include <linux/of.h> +-#include <linux/of_address.h> + #include <linux/mfd/syscon.h> + #include <linux/regmap.h> + +@@ -29,9 +28,6 @@ struct at91_pmc { + const struct at91_pmc_caps *caps; + }; + +-void __iomem *at91_pmc_base; +-EXPORT_SYMBOL_GPL(at91_pmc_base); +- + int of_at91_get_clk_range(struct device_node *np, const char *propname, + struct clk_range *range) + { +@@ -108,11 +104,8 @@ static void __init of_at91_pmc_setup(str + const struct at91_pmc_caps *caps) + { + struct at91_pmc *pmc; +- void __iomem *regbase = of_iomap(np, 0); + struct regmap *regmap; + +- at91_pmc_base = regbase; +- + regmap = syscon_node_to_regmap(np); + if (IS_ERR(regmap)) + panic("Could not retrieve syscon regmap"); +--- a/include/linux/clk/at91_pmc.h ++++ b/include/linux/clk/at91_pmc.h +@@ -16,18 +16,6 @@ + #ifndef AT91_PMC_H + #define AT91_PMC_H + +-#ifndef __ASSEMBLY__ +-extern void __iomem *at91_pmc_base; +- +-#define at91_pmc_read(field) \ +- readl_relaxed(at91_pmc_base + field) +- +-#define at91_pmc_write(field, value) \ +- writel_relaxed(value, at91_pmc_base + field) +-#else +-.extern at91_pmc_base +-#endif +- + #define AT91_PMC_SCER 0x00 /* System Clock Enable Register */ + #define AT91_PMC_SCDR 0x04 /* System Clock Disable Register */ + diff --git a/patches/0012-clk-at91-pmc-remove-useless-capacities-handling.patch b/patches/0012-clk-at91-pmc-remove-useless-capacities-handling.patch new file mode 100644 index 00000000000000..b54c5bf6fdb5b7 --- /dev/null +++ b/patches/0012-clk-at91-pmc-remove-useless-capacities-handling.patch @@ -0,0 +1,155 @@ +From: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Date: Wed, 27 Jan 2016 15:05:55 +0100 +Subject: [PATCH 12/13] clk: at91: pmc: remove useless capacities handling + +Capacities only handles interrupts and they are not use anymore. Remove the +whole initialisation. + +Acked-by: Stephen Boyd <sboyd@codeaurora.org> +Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + drivers/clk/at91/pmc.c | 128 ------------------------------------------------- + 1 file changed, 128 deletions(-) + +--- a/drivers/clk/at91/pmc.c ++++ b/drivers/clk/at91/pmc.c +@@ -19,15 +19,6 @@ + + #include "pmc.h" + +-struct at91_pmc_caps { +- u32 available_irqs; +-}; +- +-struct at91_pmc { +- struct regmap *regmap; +- const struct at91_pmc_caps *caps; +-}; +- + int of_at91_get_clk_range(struct device_node *np, const char *propname, + struct clk_range *range) + { +@@ -50,122 +41,3 @@ int of_at91_get_clk_range(struct device_ + return 0; + } + EXPORT_SYMBOL_GPL(of_at91_get_clk_range); +- +-static const struct at91_pmc_caps at91rm9200_caps = { +- .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB | +- AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY | +- AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY | +- AT91_PMC_PCK3RDY, +-}; +- +-static const struct at91_pmc_caps at91sam9260_caps = { +- .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB | +- AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY | +- AT91_PMC_PCK1RDY, +-}; +- +-static const struct at91_pmc_caps at91sam9g45_caps = { +- .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY | +- AT91_PMC_LOCKU | AT91_PMC_PCK0RDY | +- AT91_PMC_PCK1RDY, +-}; +- +-static const struct at91_pmc_caps at91sam9n12_caps = { +- .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB | +- AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY | +- AT91_PMC_PCK1RDY | AT91_PMC_MOSCSELS | +- AT91_PMC_MOSCRCS | AT91_PMC_CFDEV, +-}; +- +-static const struct at91_pmc_caps at91sam9x5_caps = { +- .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY | +- AT91_PMC_LOCKU | AT91_PMC_PCK0RDY | +- AT91_PMC_PCK1RDY | AT91_PMC_MOSCSELS | +- AT91_PMC_MOSCRCS | AT91_PMC_CFDEV, +-}; +- +-static const struct at91_pmc_caps sama5d2_caps = { +- .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY | +- AT91_PMC_LOCKU | AT91_PMC_PCK0RDY | +- AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY | +- AT91_PMC_MOSCSELS | AT91_PMC_MOSCRCS | +- AT91_PMC_CFDEV | AT91_PMC_GCKRDY, +-}; +- +-static const struct at91_pmc_caps sama5d3_caps = { +- .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY | +- AT91_PMC_LOCKU | AT91_PMC_PCK0RDY | +- AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY | +- AT91_PMC_MOSCSELS | AT91_PMC_MOSCRCS | +- AT91_PMC_CFDEV, +-}; +- +-static void __init of_at91_pmc_setup(struct device_node *np, +- const struct at91_pmc_caps *caps) +-{ +- struct at91_pmc *pmc; +- struct regmap *regmap; +- +- regmap = syscon_node_to_regmap(np); +- if (IS_ERR(regmap)) +- panic("Could not retrieve syscon regmap"); +- +- pmc = kzalloc(sizeof(*pmc), GFP_KERNEL); +- if (!pmc) +- return; +- +- pmc->regmap = regmap; +- pmc->caps = caps; +- +- regmap_write(pmc->regmap, AT91_PMC_IDR, 0xffffffff); +- +-} +- +-static void __init of_at91rm9200_pmc_setup(struct device_node *np) +-{ +- of_at91_pmc_setup(np, &at91rm9200_caps); +-} +-CLK_OF_DECLARE(at91rm9200_clk_pmc, "atmel,at91rm9200-pmc", +- of_at91rm9200_pmc_setup); +- +-static void __init of_at91sam9260_pmc_setup(struct device_node *np) +-{ +- of_at91_pmc_setup(np, &at91sam9260_caps); +-} +-CLK_OF_DECLARE(at91sam9260_clk_pmc, "atmel,at91sam9260-pmc", +- of_at91sam9260_pmc_setup); +- +-static void __init of_at91sam9g45_pmc_setup(struct device_node *np) +-{ +- of_at91_pmc_setup(np, &at91sam9g45_caps); +-} +-CLK_OF_DECLARE(at91sam9g45_clk_pmc, "atmel,at91sam9g45-pmc", +- of_at91sam9g45_pmc_setup); +- +-static void __init of_at91sam9n12_pmc_setup(struct device_node *np) +-{ +- of_at91_pmc_setup(np, &at91sam9n12_caps); +-} +-CLK_OF_DECLARE(at91sam9n12_clk_pmc, "atmel,at91sam9n12-pmc", +- of_at91sam9n12_pmc_setup); +- +-static void __init of_at91sam9x5_pmc_setup(struct device_node *np) +-{ +- of_at91_pmc_setup(np, &at91sam9x5_caps); +-} +-CLK_OF_DECLARE(at91sam9x5_clk_pmc, "atmel,at91sam9x5-pmc", +- of_at91sam9x5_pmc_setup); +- +-static void __init of_sama5d2_pmc_setup(struct device_node *np) +-{ +- of_at91_pmc_setup(np, &sama5d2_caps); +-} +-CLK_OF_DECLARE(sama5d2_clk_pmc, "atmel,sama5d2-pmc", +- of_sama5d2_pmc_setup); +- +-static void __init of_sama5d3_pmc_setup(struct device_node *np) +-{ +- of_at91_pmc_setup(np, &sama5d3_caps); +-} +-CLK_OF_DECLARE(sama5d3_clk_pmc, "atmel,sama5d3-pmc", +- of_sama5d3_pmc_setup); diff --git a/patches/0013-clk-at91-remove-useless-includes.patch b/patches/0013-clk-at91-remove-useless-includes.patch new file mode 100644 index 00000000000000..4329c9e237d4a9 --- /dev/null +++ b/patches/0013-clk-at91-remove-useless-includes.patch @@ -0,0 +1,129 @@ +From: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Date: Wed, 27 Jan 2016 15:17:37 +0100 +Subject: [PATCH 13/13] clk: at91: remove useless includes + +Over time, some includes were copy pasted from other clocks drivers but are +not necessary. + +Acked-by: Stephen Boyd <sboyd@codeaurora.org> +Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + drivers/clk/at91/clk-generated.c | 2 -- + drivers/clk/at91/clk-h32mx.c | 8 -------- + drivers/clk/at91/clk-peripheral.c | 2 -- + drivers/clk/at91/clk-plldiv.c | 2 -- + drivers/clk/at91/clk-programmable.c | 4 ---- + drivers/clk/at91/clk-slow.c | 8 -------- + drivers/clk/at91/clk-smd.c | 2 -- + drivers/clk/at91/clk-usb.c | 2 -- + 8 files changed, 30 deletions(-) + +--- a/drivers/clk/at91/clk-generated.c ++++ b/drivers/clk/at91/clk-generated.c +@@ -15,8 +15,6 @@ + #include <linux/clkdev.h> + #include <linux/clk/at91_pmc.h> + #include <linux/of.h> +-#include <linux/of_address.h> +-#include <linux/io.h> + #include <linux/mfd/syscon.h> + #include <linux/regmap.h> + +--- a/drivers/clk/at91/clk-h32mx.c ++++ b/drivers/clk/at91/clk-h32mx.c +@@ -15,15 +15,7 @@ + #include <linux/clk-provider.h> + #include <linux/clkdev.h> + #include <linux/clk/at91_pmc.h> +-#include <linux/delay.h> + #include <linux/of.h> +-#include <linux/of_address.h> +-#include <linux/of_irq.h> +-#include <linux/io.h> +-#include <linux/interrupt.h> +-#include <linux/irq.h> +-#include <linux/sched.h> +-#include <linux/wait.h> + #include <linux/regmap.h> + #include <linux/mfd/syscon.h> + +--- a/drivers/clk/at91/clk-peripheral.c ++++ b/drivers/clk/at91/clk-peripheral.c +@@ -12,8 +12,6 @@ + #include <linux/clkdev.h> + #include <linux/clk/at91_pmc.h> + #include <linux/of.h> +-#include <linux/of_address.h> +-#include <linux/io.h> + #include <linux/mfd/syscon.h> + #include <linux/regmap.h> + +--- a/drivers/clk/at91/clk-plldiv.c ++++ b/drivers/clk/at91/clk-plldiv.c +@@ -12,8 +12,6 @@ + #include <linux/clkdev.h> + #include <linux/clk/at91_pmc.h> + #include <linux/of.h> +-#include <linux/of_address.h> +-#include <linux/io.h> + #include <linux/mfd/syscon.h> + #include <linux/regmap.h> + +--- a/drivers/clk/at91/clk-programmable.c ++++ b/drivers/clk/at91/clk-programmable.c +@@ -12,10 +12,6 @@ + #include <linux/clkdev.h> + #include <linux/clk/at91_pmc.h> + #include <linux/of.h> +-#include <linux/of_address.h> +-#include <linux/io.h> +-#include <linux/wait.h> +-#include <linux/sched.h> + #include <linux/mfd/syscon.h> + #include <linux/regmap.h> + +--- a/drivers/clk/at91/clk-slow.c ++++ b/drivers/clk/at91/clk-slow.c +@@ -13,19 +13,11 @@ + #include <linux/clk.h> + #include <linux/clk-provider.h> + #include <linux/clkdev.h> +-#include <linux/slab.h> + #include <linux/clk/at91_pmc.h> + #include <linux/delay.h> + #include <linux/of.h> +-#include <linux/of_address.h> +-#include <linux/of_irq.h> +-#include <linux/io.h> +-#include <linux/interrupt.h> +-#include <linux/irq.h> + #include <linux/mfd/syscon.h> + #include <linux/regmap.h> +-#include <linux/sched.h> +-#include <linux/wait.h> + + #include "pmc.h" + #include "sckc.h" +--- a/drivers/clk/at91/clk-smd.c ++++ b/drivers/clk/at91/clk-smd.c +@@ -12,8 +12,6 @@ + #include <linux/clkdev.h> + #include <linux/clk/at91_pmc.h> + #include <linux/of.h> +-#include <linux/of_address.h> +-#include <linux/io.h> + #include <linux/mfd/syscon.h> + #include <linux/regmap.h> + +--- a/drivers/clk/at91/clk-usb.c ++++ b/drivers/clk/at91/clk-usb.c +@@ -12,8 +12,6 @@ + #include <linux/clkdev.h> + #include <linux/clk/at91_pmc.h> + #include <linux/of.h> +-#include <linux/of_address.h> +-#include <linux/io.h> + #include <linux/mfd/syscon.h> + #include <linux/regmap.h> + diff --git a/patches/KVM-arm-arm64-downgrade-preempt_disable-d-region-to-.patch b/patches/KVM-arm-arm64-downgrade-preempt_disable-d-region-to-.patch index 0ceb93625b547e..ab153a020324a7 100644 --- a/patches/KVM-arm-arm64-downgrade-preempt_disable-d-region-to-.patch +++ b/patches/KVM-arm-arm64-downgrade-preempt_disable-d-region-to-.patch @@ -1,8 +1,6 @@ -From bdf6fc2d467f0db2122b1010106542dbc7a8398c Mon Sep 17 00:00:00 2001 From: Josh Cartwright <joshc@ni.com> Date: Thu, 11 Feb 2016 11:54:01 -0600 -Subject: [PATCH 2/2] KVM: arm/arm64: downgrade preempt_disable()d region to - migrate_disable() +Subject: KVM: arm/arm64: downgrade preempt_disable()d region to migrate_disable() kvm_arch_vcpu_ioctl_run() disables the use of preemption when updating the vgic and timer states to prevent the calling task from migrating to diff --git a/patches/at91_dont_enable_disable_clock.patch b/patches/at91_dont_enable_disable_clock.patch new file mode 100644 index 00000000000000..c098bbdd782201 --- /dev/null +++ b/patches/at91_dont_enable_disable_clock.patch @@ -0,0 +1,91 @@ +From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Date: Wed, 09 Mar 2016 10:51:06 +0100 +Subject: arm: at91: do not disable/enable clocks in a row + +Currently the driver will disable the clock and enable it one line later +if it is switching from periodic mode into one shot. +This can be avoided and causes a needless warning on -RT. + +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + drivers/clocksource/tcb_clksrc.c | 33 +++++++++++++++++++++++++++++---- + 1 file changed, 29 insertions(+), 4 deletions(-) + +--- a/drivers/clocksource/tcb_clksrc.c ++++ b/drivers/clocksource/tcb_clksrc.c +@@ -74,6 +74,7 @@ static struct clocksource clksrc = { + struct tc_clkevt_device { + struct clock_event_device clkevt; + struct clk *clk; ++ bool clk_enabled; + void __iomem *regs; + }; + +@@ -91,6 +92,24 @@ static struct tc_clkevt_device *to_tc_cl + */ + static u32 timer_clock; + ++static void tc_clk_disable(struct clock_event_device *d) ++{ ++ struct tc_clkevt_device *tcd = to_tc_clkevt(d); ++ ++ clk_disable(tcd->clk); ++ tcd->clk_enabled = false; ++} ++ ++static void tc_clk_enable(struct clock_event_device *d) ++{ ++ struct tc_clkevt_device *tcd = to_tc_clkevt(d); ++ ++ if (tcd->clk_enabled) ++ return; ++ clk_enable(tcd->clk); ++ tcd->clk_enabled = true; ++} ++ + static int tc_shutdown(struct clock_event_device *d) + { + struct tc_clkevt_device *tcd = to_tc_clkevt(d); +@@ -98,8 +117,14 @@ static int tc_shutdown(struct clock_even + + __raw_writel(0xff, regs + ATMEL_TC_REG(2, IDR)); + __raw_writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR)); ++ return 0; ++} ++ ++static int tc_shutdown_clk_off(struct clock_event_device *d) ++{ ++ tc_shutdown(d); + if (!clockevent_state_detached(d)) +- clk_disable(tcd->clk); ++ tc_clk_disable(d); + + return 0; + } +@@ -112,7 +137,7 @@ static int tc_set_oneshot(struct clock_e + if (clockevent_state_oneshot(d) || clockevent_state_periodic(d)) + tc_shutdown(d); + +- clk_enable(tcd->clk); ++ tc_clk_enable(d); + + /* slow clock, count up to RC, then irq and stop */ + __raw_writel(timer_clock | ATMEL_TC_CPCSTOP | ATMEL_TC_WAVE | +@@ -134,7 +159,7 @@ static int tc_set_periodic(struct clock_ + /* By not making the gentime core emulate periodic mode on top + * of oneshot, we get lower overhead and improved accuracy. + */ +- clk_enable(tcd->clk); ++ tc_clk_enable(d); + + /* slow clock, count up to RC, then irq and restart */ + __raw_writel(timer_clock | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO, +@@ -168,7 +193,7 @@ static struct tc_clkevt_device clkevt = + /* Should be lower than at91rm9200's system timer */ + .rating = 125, + .set_next_event = tc_next_event, +- .set_state_shutdown = tc_shutdown, ++ .set_state_shutdown = tc_shutdown_clk_off, + .set_state_periodic = tc_set_periodic, + .set_state_oneshot = tc_set_oneshot, + }, diff --git a/patches/block-blk-mq-use-swait.patch b/patches/block-blk-mq-use-swait.patch index d0c2e94918e603..84da6e0c5adbd9 100644 --- a/patches/block-blk-mq-use-swait.patch +++ b/patches/block-blk-mq-use-swait.patch @@ -59,7 +59,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> container_of(ref, struct request_queue, q_usage_counter); - wake_up_all(&q->mq_freeze_wq); -+ swait_wake_all(&q->mq_freeze_wq); ++ swake_up_all(&q->mq_freeze_wq); } struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) @@ -68,7 +68,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> __set_bit(QUEUE_FLAG_BYPASS, &q->queue_flags); - init_waitqueue_head(&q->mq_freeze_wq); -+ init_swait_head(&q->mq_freeze_wq); ++ init_swait_queue_head(&q->mq_freeze_wq); /* * Init percpu_ref in atomic mode so that it's faster to shutdown. @@ -88,7 +88,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> if (!freeze_depth) { percpu_ref_reinit(&q->q_usage_counter); - wake_up_all(&q->mq_freeze_wq); -+ swait_wake_all(&q->mq_freeze_wq); ++ swake_up_all(&q->mq_freeze_wq); } } EXPORT_SYMBOL_GPL(blk_mq_unfreeze_queue); @@ -97,7 +97,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> * the queue are notified as well. */ - wake_up_all(&q->mq_freeze_wq); -+ swait_wake_all(&q->mq_freeze_wq); ++ swake_up_all(&q->mq_freeze_wq); } bool blk_mq_can_queue(struct blk_mq_hw_ctx *hctx) @@ -108,7 +108,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> #endif struct rcu_head rcu_head; - wait_queue_head_t mq_freeze_wq; -+ struct swait_head mq_freeze_wq; ++ struct swait_queue_head mq_freeze_wq; struct percpu_ref q_usage_counter; struct list_head all_q_node; diff --git a/patches/clocksource-tclib-allow-higher-clockrates.patch b/patches/clocksource-tclib-allow-higher-clockrates.patch index cb833190e016dc..ca4647a942e16c 100644 --- a/patches/clocksource-tclib-allow-higher-clockrates.patch +++ b/patches/clocksource-tclib-allow-higher-clockrates.patch @@ -26,15 +26,15 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> * * A boot clocksource and clockevent source are also currently needed, * unless the relevant platforms (ARM/AT91, AVR32/AT32) are changed so -@@ -74,6 +73,7 @@ static struct clocksource clksrc = { - struct tc_clkevt_device { +@@ -75,6 +74,7 @@ struct tc_clkevt_device { struct clock_event_device clkevt; struct clk *clk; + bool clk_enabled; + u32 freq; void __iomem *regs; }; -@@ -82,13 +82,6 @@ static struct tc_clkevt_device *to_tc_cl +@@ -83,13 +83,6 @@ static struct tc_clkevt_device *to_tc_cl return container_of(clkevt, struct tc_clkevt_device, clkevt); } @@ -47,19 +47,19 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> - */ static u32 timer_clock; - static int tc_shutdown(struct clock_event_device *d) -@@ -114,7 +107,7 @@ static int tc_set_oneshot(struct clock_e + static void tc_clk_disable(struct clock_event_device *d) +@@ -139,7 +132,7 @@ static int tc_set_oneshot(struct clock_e - clk_enable(tcd->clk); + tc_clk_enable(d); - /* slow clock, count up to RC, then irq and stop */ + /* count up to RC, then irq and stop */ __raw_writel(timer_clock | ATMEL_TC_CPCSTOP | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO, regs + ATMEL_TC_REG(2, CMR)); __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER)); -@@ -136,10 +129,10 @@ static int tc_set_periodic(struct clock_ +@@ -161,10 +154,10 @@ static int tc_set_periodic(struct clock_ */ - clk_enable(tcd->clk); + tc_clk_enable(d); - /* slow clock, count up to RC, then irq and restart */ + /* count up to RC, then irq and restart */ @@ -70,7 +70,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> /* Enable clock and interrupts on RC compare */ __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER)); -@@ -166,7 +159,11 @@ static struct tc_clkevt_device clkevt = +@@ -191,7 +184,11 @@ static struct tc_clkevt_device clkevt = .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, /* Should be lower than at91rm9200's system timer */ @@ -80,9 +80,9 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> + .rating = 200, +#endif .set_next_event = tc_next_event, - .set_state_shutdown = tc_shutdown, + .set_state_shutdown = tc_shutdown_clk_off, .set_state_periodic = tc_set_periodic, -@@ -188,8 +185,9 @@ static irqreturn_t ch2_irq(int irq, void +@@ -213,8 +210,9 @@ static irqreturn_t ch2_irq(int irq, void return IRQ_NONE; } @@ -93,7 +93,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> int ret; struct clk *t2_clk = tc->clk[2]; int irq = tc->irq[2]; -@@ -210,7 +208,11 @@ static int __init setup_clkevents(struct +@@ -235,7 +233,11 @@ static int __init setup_clkevents(struct clkevt.regs = tc->regs; clkevt.clk = t2_clk; @@ -106,7 +106,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> clkevt.clkevt.cpumask = cpumask_of(0); -@@ -221,7 +223,7 @@ static int __init setup_clkevents(struct +@@ -246,7 +248,7 @@ static int __init setup_clkevents(struct return ret; } @@ -115,7 +115,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> return ret; } -@@ -358,7 +360,11 @@ static int __init tcb_clksrc_init(void) +@@ -383,7 +385,11 @@ static int __init tcb_clksrc_init(void) goto err_disable_t1; /* channel 2: periodic and oneshot timer support */ diff --git a/patches/completion-use-simple-wait-queues.patch b/patches/completion-use-simple-wait-queues.patch index b67e24d4afd450..4b128206a83e0c 100644 --- a/patches/completion-use-simple-wait-queues.patch +++ b/patches/completion-use-simple-wait-queues.patch @@ -12,10 +12,12 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> drivers/usb/gadget/function/f_fs.c | 2 - drivers/usb/gadget/legacy/inode.c | 4 +-- include/linux/completion.h | 9 +++----- + include/linux/swait.h | 1 include/linux/uprobes.h | 1 kernel/sched/completion.c | 32 ++++++++++++++--------------- kernel/sched/core.c | 10 +++++++-- - 7 files changed, 33 insertions(+), 27 deletions(-) + kernel/sched/swait.c | 17 +++++++++++++++ + 9 files changed, 51 insertions(+), 27 deletions(-) --- a/drivers/net/wireless/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/orinoco/orinoco_usb.c @@ -35,7 +37,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> ffs_data_clear(ffs); BUG_ON(waitqueue_active(&ffs->ev.waitq) || - waitqueue_active(&ffs->ep0req_completion.wait)); -+ swaitqueue_active(&ffs->ep0req_completion.wait)); ++ swait_active(&ffs->ep0req_completion.wait)); kfree(ffs->dev_name); kfree(ffs); } @@ -67,7 +69,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> */ - -#include <linux/wait.h> -+#include <linux/wait-simple.h> ++#include <linux/swait.h> /* * struct completion - structure used to maintain state for a "completion" @@ -76,12 +78,12 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> struct completion { unsigned int done; - wait_queue_head_t wait; -+ struct swait_head wait; ++ struct swait_queue_head wait; }; #define COMPLETION_INITIALIZER(work) \ - { 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait) } -+ { 0, SWAIT_HEAD_INITIALIZER((work).wait) } ++ { 0, __SWAIT_QUEUE_HEAD_INITIALIZER((work).wait) } #define COMPLETION_INITIALIZER_ONSTACK(work) \ ({ init_completion(&work); work; }) @@ -90,10 +92,20 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> { x->done = 0; - init_waitqueue_head(&x->wait); -+ init_swait_head(&x->wait); ++ init_swait_queue_head(&x->wait); } /** +--- a/include/linux/swait.h ++++ b/include/linux/swait.h +@@ -87,6 +87,7 @@ static inline int swait_active(struct sw + extern void swake_up(struct swait_queue_head *q); + extern void swake_up_all(struct swait_queue_head *q); + extern void swake_up_locked(struct swait_queue_head *q); ++extern void swake_up_all_locked(struct swait_queue_head *q); + + extern void __prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait); + extern void prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait, int state); --- a/include/linux/uprobes.h +++ b/include/linux/uprobes.h @@ -27,6 +27,7 @@ @@ -115,7 +127,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> x->done++; - __wake_up_locked(&x->wait, TASK_NORMAL, 1); - spin_unlock_irqrestore(&x->wait.lock, flags); -+ __swait_wake_locked(&x->wait, TASK_NORMAL, 1); ++ swake_up_locked(&x->wait); + raw_spin_unlock_irqrestore(&x->wait.lock, flags); } EXPORT_SYMBOL(complete); @@ -129,7 +141,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> x->done += UINT_MAX/2; - __wake_up_locked(&x->wait, TASK_NORMAL, 0); - spin_unlock_irqrestore(&x->wait.lock, flags); -+ __swait_wake_locked(&x->wait, TASK_NORMAL, 0); ++ swake_up_all_locked(&x->wait); + raw_spin_unlock_irqrestore(&x->wait.lock, flags); } EXPORT_SYMBOL(complete_all); @@ -139,10 +151,10 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> { if (!x->done) { - DECLARE_WAITQUEUE(wait, current); -+ DEFINE_SWAITER(wait); ++ DECLARE_SWAITQUEUE(wait); - __add_wait_queue_tail_exclusive(&x->wait, &wait); -+ swait_prepare_locked(&x->wait, &wait); ++ __prepare_to_swait(&x->wait, &wait); do { if (signal_pending_state(state, current)) { timeout = -ERESTARTSYS; @@ -156,7 +168,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> + raw_spin_lock_irq(&x->wait.lock); } while (!x->done && timeout); - __remove_wait_queue(&x->wait, &wait); -+ swait_finish_locked(&x->wait, &wait); ++ __finish_swait(&x->wait, &wait); if (!x->done) return timeout; } @@ -222,3 +234,29 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> #endif WARN_ON_ONCE(p->migrate_disable <= 0); +--- a/kernel/sched/swait.c ++++ b/kernel/sched/swait.c +@@ -29,6 +29,23 @@ void swake_up_locked(struct swait_queue_ + } + EXPORT_SYMBOL(swake_up_locked); + ++void swake_up_all_locked(struct swait_queue_head *q) ++{ ++ struct swait_queue *curr; ++ int wakes = 0; ++ ++ while (!list_empty(&q->task_list)) { ++ ++ curr = list_first_entry(&q->task_list, typeof(*curr), ++ task_list); ++ wake_up_process(curr->task); ++ list_del_init(&curr->task_list); ++ wakes++; ++ } ++ WARN_ON(wakes > 2); ++} ++EXPORT_SYMBOL(swake_up_all_locked); ++ + void swake_up(struct swait_queue_head *q) + { + unsigned long flags; diff --git a/patches/genirq-update-irq_set_irqchip_state-documentation.patch b/patches/genirq-update-irq_set_irqchip_state-documentation.patch index 6b40fdd0041323..2e4440a13fe1d2 100644 --- a/patches/genirq-update-irq_set_irqchip_state-documentation.patch +++ b/patches/genirq-update-irq_set_irqchip_state-documentation.patch @@ -1,7 +1,6 @@ -From 85b7f1606fb707c9da7984e052e47cfa12e85e67 Mon Sep 17 00:00:00 2001 From: Josh Cartwright <joshc@ni.com> Date: Thu, 11 Feb 2016 11:54:00 -0600 -Subject: [PATCH 1/2] genirq: update irq_set_irqchip_state documentation +Subject: genirq: update irq_set_irqchip_state documentation On -rt kernels, the use of migrate_disable()/migrate_enable() is sufficient to guarantee a task isn't moved to another CPU. Update the diff --git a/patches/latency-hist.patch b/patches/latency-hist.patch index 6d7948a7c4719e..411216eb3c00b3 100644 --- a/patches/latency-hist.patch +++ b/patches/latency-hist.patch @@ -16,14 +16,14 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Documentation/trace/histograms.txt | 186 +++++ include/linux/hrtimer.h | 4 include/linux/sched.h | 6 - include/trace/events/hist.h | 72 ++ + include/trace/events/hist.h | 73 ++ include/trace/events/latency_hist.h | 29 kernel/time/hrtimer.c | 21 kernel/trace/Kconfig | 104 +++ kernel/trace/Makefile | 4 kernel/trace/latency_hist.c | 1178 ++++++++++++++++++++++++++++++++++++ kernel/trace/trace_irqsoff.c | 11 - 10 files changed, 1615 insertions(+) + 10 files changed, 1616 insertions(+) --- /dev/null +++ b/Documentation/trace/histograms.txt @@ -251,7 +251,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> struct mem_cgroup *memcg_in_oom; --- /dev/null +++ b/include/trace/events/hist.h -@@ -0,0 +1,72 @@ +@@ -0,0 +1,73 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hist + @@ -263,6 +263,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> + +#if !defined(CONFIG_PREEMPT_OFF_HIST) && !defined(CONFIG_INTERRUPT_OFF_HIST) +#define trace_preemptirqsoff_hist(a, b) ++#define trace_preemptirqsoff_hist_rcuidle(a, b) +#else +TRACE_EVENT(preemptirqsoff_hist, + diff --git a/patches/localversion.patch b/patches/localversion.patch index 0484a008be4628..487209c1e1991f 100644 --- a/patches/localversion.patch +++ b/patches/localversion.patch @@ -1,4 +1,4 @@ -Subject: v4.4.4-rt10 +Subject: v4.4.4-rt11 From: Thomas Gleixner <tglx@linutronix.de> Date: Fri, 08 Jul 2011 20:25:16 +0200 @@ -10,4 +10,4 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- /dev/null +++ b/localversion-rt @@ -0,0 +1 @@ -+-rt10 ++-rt11 diff --git a/patches/mm--rt--Fix-generic-kmap_atomic-for-RT b/patches/mm--rt--Fix-generic-kmap_atomic-for-RT.patch index 6814afe977c97b..6814afe977c97b 100644 --- a/patches/mm--rt--Fix-generic-kmap_atomic-for-RT +++ b/patches/mm--rt--Fix-generic-kmap_atomic-for-RT.patch diff --git a/patches/net__Make_synchronize-rcu_expedited_conditional-on-non-rt b/patches/net__Make_synchronize-rcu_expedited_conditional-on-non-rt.patch index d454b642c4ba33..d454b642c4ba33 100644 --- a/patches/net__Make_synchronize-rcu_expedited_conditional-on-non-rt +++ b/patches/net__Make_synchronize-rcu_expedited_conditional-on-non-rt.patch diff --git a/patches/rcu-Eliminate-softirq-processing-from-rcutree.patch b/patches/rcu-Eliminate-softirq-processing-from-rcutree.patch index 73cf44e168185f..eca80c4e010b26 100644 --- a/patches/rcu-Eliminate-softirq-processing-from-rcutree.patch +++ b/patches/rcu-Eliminate-softirq-processing-from-rcutree.patch @@ -35,7 +35,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> #include "tree.h" #include "rcu.h" -@@ -2960,18 +2965,17 @@ static void +@@ -2962,18 +2967,17 @@ static void /* * Do RCU core processing for the current CPU. */ @@ -56,7 +56,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> /* * Schedule RCU callback invocation. If the specified type of RCU * does not support RCU priority boosting, just do a direct call, -@@ -2983,18 +2987,105 @@ static void invoke_rcu_callbacks(struct +@@ -2985,18 +2989,105 @@ static void invoke_rcu_callbacks(struct { if (unlikely(!READ_ONCE(rcu_scheduler_fully_active))) return; @@ -168,7 +168,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> /* * Handle any core-RCU processing required by a call_rcu() invocation. -@@ -4615,7 +4706,6 @@ void __init rcu_init(void) +@@ -4617,7 +4708,6 @@ void __init rcu_init(void) if (dump_tree) rcu_dump_rcu_node_tree(&rcu_sched_state); __rcu_init_preempt(); diff --git a/patches/rcu-disable-more-spots-of-rcu_bh.patch b/patches/rcu-disable-more-spots-of-rcu_bh.patch index 3697ffc546f5f7..e6ea86c222f154 100644 --- a/patches/rcu-disable-more-spots-of-rcu_bh.patch +++ b/patches/rcu-disable-more-spots-of-rcu_bh.patch @@ -39,7 +39,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> case RCU_SCHED_FLAVOR: rsp = &rcu_sched_state; break; -@@ -4604,7 +4608,9 @@ void __init rcu_init(void) +@@ -4606,7 +4610,9 @@ void __init rcu_init(void) rcu_bootup_announce(); rcu_init_geometry(); @@ -51,7 +51,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> rcu_dump_rcu_node_tree(&rcu_sched_state); --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h -@@ -556,7 +556,9 @@ extern struct list_head rcu_struct_flavo +@@ -557,7 +557,9 @@ extern struct list_head rcu_struct_flavo */ extern struct rcu_state rcu_sched_state; diff --git a/patches/rcu-merge-rcu-bh-into-rcu-preempt-for-rt.patch b/patches/rcu-merge-rcu-bh-into-rcu-preempt-for-rt.patch index 68b0992c89f1a8..d398665373b1f1 100644 --- a/patches/rcu-merge-rcu-bh-into-rcu-preempt-for-rt.patch +++ b/patches/rcu-merge-rcu-bh-into-rcu-preempt-for-rt.patch @@ -201,7 +201,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> /* * Force a quiescent state for RCU-sched. */ -@@ -3114,6 +3124,7 @@ void call_rcu_sched(struct rcu_head *hea +@@ -3116,6 +3126,7 @@ void call_rcu_sched(struct rcu_head *hea } EXPORT_SYMBOL_GPL(call_rcu_sched); @@ -209,7 +209,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> /* * Queue an RCU callback for invocation after a quicker grace period. */ -@@ -3122,6 +3133,7 @@ void call_rcu_bh(struct rcu_head *head, +@@ -3124,6 +3135,7 @@ void call_rcu_bh(struct rcu_head *head, __call_rcu(head, func, &rcu_bh_state, -1, 0); } EXPORT_SYMBOL_GPL(call_rcu_bh); @@ -217,7 +217,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> /* * Queue an RCU callback for lazy invocation after a grace period. -@@ -3213,6 +3225,7 @@ void synchronize_sched(void) +@@ -3215,6 +3227,7 @@ void synchronize_sched(void) } EXPORT_SYMBOL_GPL(synchronize_sched); @@ -225,7 +225,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> /** * synchronize_rcu_bh - wait until an rcu_bh grace period has elapsed. * -@@ -3239,6 +3252,7 @@ void synchronize_rcu_bh(void) +@@ -3241,6 +3254,7 @@ void synchronize_rcu_bh(void) wait_rcu_gp(call_rcu_bh); } EXPORT_SYMBOL_GPL(synchronize_rcu_bh); @@ -233,7 +233,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> /** * get_state_synchronize_rcu - Snapshot current RCU state -@@ -4101,6 +4115,7 @@ static void _rcu_barrier(struct rcu_stat +@@ -4103,6 +4117,7 @@ static void _rcu_barrier(struct rcu_stat mutex_unlock(&rsp->barrier_mutex); } @@ -241,7 +241,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> /** * rcu_barrier_bh - Wait until all in-flight call_rcu_bh() callbacks complete. */ -@@ -4109,6 +4124,7 @@ void rcu_barrier_bh(void) +@@ -4111,6 +4126,7 @@ void rcu_barrier_bh(void) _rcu_barrier(&rcu_bh_state); } EXPORT_SYMBOL_GPL(rcu_barrier_bh); diff --git a/patches/rcu-more-swait-conversions.patch b/patches/rcu-more-swait-conversions.patch deleted file mode 100644 index 779a02922c54f9..00000000000000 --- a/patches/rcu-more-swait-conversions.patch +++ /dev/null @@ -1,212 +0,0 @@ -From: Thomas Gleixner <tglx@linutronix.de> -Date: Wed, 31 Jul 2013 19:00:35 +0200 -Subject: rcu: use simple waitqueues - -Convert RCU's wait-queues into simple waitqueues. - -Signed-off-by: Thomas Gleixner <tglx@linutronix.de> - -Merged Steven's - - static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp) { -- swait_wake(&rnp->nocb_gp_wq[rnp->completed & 0x1]); -+ wake_up_all(&rnp->nocb_gp_wq[rnp->completed & 0x1]); - } - -Signed-off-by: Steven Rostedt <rostedt@goodmis.org> -Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> ---- - kernel/rcu/tree.c | 16 ++++++++-------- - kernel/rcu/tree.h | 9 +++++---- - kernel/rcu/tree_plugin.h | 18 +++++++++--------- - 3 files changed, 22 insertions(+), 21 deletions(-) - ---- a/kernel/rcu/tree.c -+++ b/kernel/rcu/tree.c -@@ -1637,7 +1637,7 @@ static void rcu_gp_kthread_wake(struct r - !READ_ONCE(rsp->gp_flags) || - !rsp->gp_kthread) - return; -- wake_up(&rsp->gp_wq); -+ swait_wake(&rsp->gp_wq); - } - - /* -@@ -2102,7 +2102,7 @@ static int __noreturn rcu_gp_kthread(voi - READ_ONCE(rsp->gpnum), - TPS("reqwait")); - rsp->gp_state = RCU_GP_WAIT_GPS; -- wait_event_interruptible(rsp->gp_wq, -+ swait_event_interruptible(rsp->gp_wq, - READ_ONCE(rsp->gp_flags) & - RCU_GP_FLAG_INIT); - rsp->gp_state = RCU_GP_DONE_GPS; -@@ -2132,7 +2132,7 @@ static int __noreturn rcu_gp_kthread(voi - READ_ONCE(rsp->gpnum), - TPS("fqswait")); - rsp->gp_state = RCU_GP_WAIT_FQS; -- ret = wait_event_interruptible_timeout(rsp->gp_wq, -+ ret = swait_event_interruptible_timeout(rsp->gp_wq, - rcu_gp_fqs_check_wake(rsp, &gf), j); - rsp->gp_state = RCU_GP_DOING_FQS; - /* Locking provides needed memory barriers. */ -@@ -3554,7 +3554,7 @@ static void __rcu_report_exp_rnp(struct - raw_spin_unlock_irqrestore(&rnp->lock, flags); - if (wake) { - smp_mb(); /* EGP done before wake_up(). */ -- wake_up(&rsp->expedited_wq); -+ swait_wake(&rsp->expedited_wq); - } - break; - } -@@ -3811,7 +3811,7 @@ static void synchronize_sched_expedited_ - jiffies_start = jiffies; - - for (;;) { -- ret = wait_event_interruptible_timeout( -+ ret = swait_event_interruptible_timeout( - rsp->expedited_wq, - sync_rcu_preempt_exp_done(rnp_root), - jiffies_stall); -@@ -3819,7 +3819,7 @@ static void synchronize_sched_expedited_ - return; - if (ret < 0) { - /* Hit a signal, disable CPU stall warnings. */ -- wait_event(rsp->expedited_wq, -+ swait_event(rsp->expedited_wq, - sync_rcu_preempt_exp_done(rnp_root)); - return; - } -@@ -4487,8 +4487,8 @@ static void __init rcu_init_one(struct r - } - } - -- init_waitqueue_head(&rsp->gp_wq); -- init_waitqueue_head(&rsp->expedited_wq); -+ init_swait_head(&rsp->gp_wq); -+ init_swait_head(&rsp->expedited_wq); - rnp = rsp->level[rcu_num_lvls - 1]; - for_each_possible_cpu(i) { - while (i > rnp->grphi) ---- a/kernel/rcu/tree.h -+++ b/kernel/rcu/tree.h -@@ -28,6 +28,7 @@ - #include <linux/cpumask.h> - #include <linux/seqlock.h> - #include <linux/stop_machine.h> -+#include <linux/wait-simple.h> - - /* - * Define shape of hierarchy based on NR_CPUS, CONFIG_RCU_FANOUT, and -@@ -241,7 +242,7 @@ struct rcu_node { - /* Refused to boost: not sure why, though. */ - /* This can happen due to race conditions. */ - #ifdef CONFIG_RCU_NOCB_CPU -- wait_queue_head_t nocb_gp_wq[2]; -+ struct swait_head nocb_gp_wq[2]; - /* Place for rcu_nocb_kthread() to wait GP. */ - #endif /* #ifdef CONFIG_RCU_NOCB_CPU */ - int need_future_gp[2]; -@@ -393,7 +394,7 @@ struct rcu_data { - atomic_long_t nocb_q_count_lazy; /* invocation (all stages). */ - struct rcu_head *nocb_follower_head; /* CBs ready to invoke. */ - struct rcu_head **nocb_follower_tail; -- wait_queue_head_t nocb_wq; /* For nocb kthreads to sleep on. */ -+ struct swait_head nocb_wq; /* For nocb kthreads to sleep on. */ - struct task_struct *nocb_kthread; - int nocb_defer_wakeup; /* Defer wakeup of nocb_kthread. */ - -@@ -472,7 +473,7 @@ struct rcu_state { - unsigned long gpnum; /* Current gp number. */ - unsigned long completed; /* # of last completed gp. */ - struct task_struct *gp_kthread; /* Task for grace periods. */ -- wait_queue_head_t gp_wq; /* Where GP task waits. */ -+ struct swait_head gp_wq; /* Where GP task waits. */ - short gp_flags; /* Commands for GP task. */ - short gp_state; /* GP kthread sleep state. */ - -@@ -504,7 +505,7 @@ struct rcu_state { - atomic_long_t expedited_workdone3; /* # done by others #3. */ - atomic_long_t expedited_normal; /* # fallbacks to normal. */ - atomic_t expedited_need_qs; /* # CPUs left to check in. */ -- wait_queue_head_t expedited_wq; /* Wait for check-ins. */ -+ struct swait_head expedited_wq; /* Wait for check-ins. */ - int ncpus_snap; /* # CPUs seen last time. */ - - unsigned long jiffies_force_qs; /* Time at which to invoke */ ---- a/kernel/rcu/tree_plugin.h -+++ b/kernel/rcu/tree_plugin.h -@@ -1830,7 +1830,7 @@ early_param("rcu_nocb_poll", parse_rcu_n - */ - static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp) - { -- wake_up_all(&rnp->nocb_gp_wq[rnp->completed & 0x1]); -+ swait_wake_all(&rnp->nocb_gp_wq[rnp->completed & 0x1]); - } - - /* -@@ -1848,8 +1848,8 @@ static void rcu_nocb_gp_set(struct rcu_n - - static void rcu_init_one_nocb(struct rcu_node *rnp) - { -- init_waitqueue_head(&rnp->nocb_gp_wq[0]); -- init_waitqueue_head(&rnp->nocb_gp_wq[1]); -+ init_swait_head(&rnp->nocb_gp_wq[0]); -+ init_swait_head(&rnp->nocb_gp_wq[1]); - } - - #ifndef CONFIG_RCU_NOCB_CPU_ALL -@@ -1874,7 +1874,7 @@ static void wake_nocb_leader(struct rcu_ - if (READ_ONCE(rdp_leader->nocb_leader_sleep) || force) { - /* Prior smp_mb__after_atomic() orders against prior enqueue. */ - WRITE_ONCE(rdp_leader->nocb_leader_sleep, false); -- wake_up(&rdp_leader->nocb_wq); -+ swait_wake(&rdp_leader->nocb_wq); - } - } - -@@ -2087,7 +2087,7 @@ static void rcu_nocb_wait_gp(struct rcu_ - */ - trace_rcu_future_gp(rnp, rdp, c, TPS("StartWait")); - for (;;) { -- wait_event_interruptible( -+ swait_event_interruptible( - rnp->nocb_gp_wq[c & 0x1], - (d = ULONG_CMP_GE(READ_ONCE(rnp->completed), c))); - if (likely(d)) -@@ -2115,7 +2115,7 @@ static void nocb_leader_wait(struct rcu_ - /* Wait for callbacks to appear. */ - if (!rcu_nocb_poll) { - trace_rcu_nocb_wake(my_rdp->rsp->name, my_rdp->cpu, "Sleep"); -- wait_event_interruptible(my_rdp->nocb_wq, -+ swait_event_interruptible(my_rdp->nocb_wq, - !READ_ONCE(my_rdp->nocb_leader_sleep)); - /* Memory barrier handled by smp_mb() calls below and repoll. */ - } else if (firsttime) { -@@ -2190,7 +2190,7 @@ static void nocb_leader_wait(struct rcu_ - * List was empty, wake up the follower. - * Memory barriers supplied by atomic_long_add(). - */ -- wake_up(&rdp->nocb_wq); -+ swait_wake(&rdp->nocb_wq); - } - } - -@@ -2211,7 +2211,7 @@ static void nocb_follower_wait(struct rc - if (!rcu_nocb_poll) { - trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, - "FollowerSleep"); -- wait_event_interruptible(rdp->nocb_wq, -+ swait_event_interruptible(rdp->nocb_wq, - READ_ONCE(rdp->nocb_follower_head)); - } else if (firsttime) { - /* Don't drown trace log with "Poll"! */ -@@ -2370,7 +2370,7 @@ void __init rcu_init_nohz(void) - static void __init rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp) - { - rdp->nocb_tail = &rdp->nocb_head; -- init_waitqueue_head(&rdp->nocb_wq); -+ init_swait_head(&rdp->nocb_wq); - rdp->nocb_follower_tail = &rdp->nocb_follower_head; - } - diff --git a/patches/rtmutex--Handle-non-enqueued-waiters-gracefully b/patches/rtmutex--Handle-non-enqueued-waiters-gracefully.patch index 7223153e73cff7..7223153e73cff7 100644 --- a/patches/rtmutex--Handle-non-enqueued-waiters-gracefully +++ b/patches/rtmutex--Handle-non-enqueued-waiters-gracefully.patch diff --git a/patches/series b/patches/series index 2e8d0bca9d4233..075616db0f1863 100644 --- a/patches/series +++ b/patches/series @@ -7,6 +7,26 @@ ############################################################ rtmutex-Make-wait_lock-irq-safe.patch arm64-replace-read_lock-to-rcu-lock-in-call_step_hoo.patch +# AT91 queue in ARM-SOC +0001-clk-at91-make-use-of-syscon-to-share-PMC-registers-i.patch +0002-clk-at91-make-use-of-syscon-regmap-internally.patch +0003-clk-at91-remove-IRQ-handling-and-use-polling.patch +0004-clk-at91-pmc-merge-at91_pmc_init-in-atmel_pmc_probe.patch +0005-clk-at91-pmc-move-pmc-structures-to-C-file.patch +0006-ARM-at91-pm-simply-call-at91_pm_init.patch +0007-ARM-at91-pm-find-and-remap-the-pmc.patch +0008-ARM-at91-pm-move-idle-functions-to-pm.c.patch +0009-ARM-at91-remove-useless-includes-and-function-protot.patch +0010-usb-gadget-atmel-access-the-PMC-using-regmap.patch +0011-clk-at91-pmc-drop-at91_pmc_base.patch +0012-clk-at91-pmc-remove-useless-capacities-handling.patch +0013-clk-at91-remove-useless-includes.patch +# SWAIT queue in TIP +0001-wait.-ch-Introduce-the-simple-waitqueue-swait-implem.patch +0002-kbuild-Add-option-to-turn-incompatible-pointer-check.patch +0003-KVM-Use-simple-waitqueue-for-vcpu-wq.patch +0004-rcu-Do-not-call-rcu_nocb_gp_cleanup-while-holding-rn.patch +0005-rcu-Use-simple-wait-queues-where-possible-in-rcutree.patch ############################################################ # UPSTREAM FIXES, patches pending @@ -21,6 +41,7 @@ drivers-cpuidle-coupled-fix-warning-cpuidle_coupled_.patch drivers-media-vsp1_video-fix-compile-error.patch sc16is7xx_Drop_bogus_use_of_IRQF_ONESHOT.patch f2fs_Mutex_cant_be_used_by_down_write_nest_lock().patch +at91_dont_enable_disable_clock.patch ############################################################ # Stuff which needs addressing upstream, but requires more @@ -31,7 +52,7 @@ rfc-arm-smp-__cpu_disable-fix-sleeping-function-called-from-invalid-context.patc ############################################################ # Stuff broken upstream, need to be sent ############################################################ -rtmutex--Handle-non-enqueued-waiters-gracefully +rtmutex--Handle-non-enqueued-waiters-gracefully.patch kernel-sched-fix-preempt_disable_ip-recodring-for-pr.patch # Wants a different fix for upstream @@ -366,9 +387,7 @@ rt-serial-warn-fix.patch # SIMPLE WAITQUEUE wait.h-include-atomic.h.patch -wait-simple-implementation.patch work-simple-Simple-work-queue-implemenation.patch -rcu-more-swait-conversions.patch completion-use-simple-wait-queues.patch fs-aio-simple-simple-work.patch @@ -430,7 +449,7 @@ jump-label-rt.patch # NETWORKING sunrpc-make-svc_xprt_do_enqueue-use-get_cpu_light.patch -net__Make_synchronize-rcu_expedited_conditional-on-non-rt +net__Make_synchronize-rcu_expedited_conditional-on-non-rt.patch skbufhead-raw-lock.patch net-core-cpuhotplug-drain-input_pkt_queue-lockless.patch net-move-xmit_recursion-to-per-task-variable-on-RT.patch @@ -478,7 +497,7 @@ sysfs-realtime-entry.patch power-disable-highmem-on-rt.patch mips-disable-highmem-on-rt.patch mm-rt-kmap-atomic-scheduling.patch -mm--rt--Fix-generic-kmap_atomic-for-RT +mm--rt--Fix-generic-kmap_atomic-for-RT.patch x86-highmem-add-a-already-used-pte-check.patch arm-highmem-flush-tlb-on-unmap.patch arm-enable-highmem-for-rt.patch @@ -491,7 +510,6 @@ ipc-sem-rework-semaphore-wakeups.patch # KVM require constant freq TSC (smp function call -> cpufreq) x86-kvm-require-const-tsc-for-rt.patch KVM-lapic-mark-LAPIC-timer-handler-as-irqsafe.patch -KVM-use-simple-waitqueue-for-vcpu-wq.patch # SCSI/FCOE scsi-fcoe-rt-aware.patch diff --git a/patches/wait-simple-implementation.patch b/patches/wait-simple-implementation.patch deleted file mode 100644 index 199b44b0acd01c..00000000000000 --- a/patches/wait-simple-implementation.patch +++ /dev/null @@ -1,362 +0,0 @@ -From: Thomas Gleixner <tglx@linutronix.de> -Date: Mon Dec 12 12:29:04 2011 +0100 -Subject: wait-simple: Simple waitqueue implementation - -wait_queue is a swiss army knife and in most of the cases the -complexity is not needed. For RT waitqueues are a constant source of -trouble as we can't convert the head lock to a raw spinlock due to -fancy and long lasting callbacks. - -Provide a slim version, which allows RT to replace wait queues. This -should go mainline as well, as it lowers memory consumption and -runtime overhead. - -Signed-off-by: Thomas Gleixner <tglx@linutronix.de> - -smp_mb() added by Steven Rostedt to fix a race condition with swait -wakeups vs adding items to the list. ---- - include/linux/wait-simple.h | 207 ++++++++++++++++++++++++++++++++++++++++++++ - kernel/sched/Makefile | 2 - kernel/sched/wait-simple.c | 115 ++++++++++++++++++++++++ - 3 files changed, 323 insertions(+), 1 deletion(-) - ---- /dev/null -+++ b/include/linux/wait-simple.h -@@ -0,0 +1,207 @@ -+#ifndef _LINUX_WAIT_SIMPLE_H -+#define _LINUX_WAIT_SIMPLE_H -+ -+#include <linux/spinlock.h> -+#include <linux/list.h> -+ -+#include <asm/current.h> -+ -+struct swaiter { -+ struct task_struct *task; -+ struct list_head node; -+}; -+ -+#define DEFINE_SWAITER(name) \ -+ struct swaiter name = { \ -+ .task = current, \ -+ .node = LIST_HEAD_INIT((name).node), \ -+ } -+ -+struct swait_head { -+ raw_spinlock_t lock; -+ struct list_head list; -+}; -+ -+#define SWAIT_HEAD_INITIALIZER(name) { \ -+ .lock = __RAW_SPIN_LOCK_UNLOCKED(name.lock), \ -+ .list = LIST_HEAD_INIT((name).list), \ -+ } -+ -+#define DEFINE_SWAIT_HEAD(name) \ -+ struct swait_head name = SWAIT_HEAD_INITIALIZER(name) -+ -+extern void __init_swait_head(struct swait_head *h, struct lock_class_key *key); -+ -+#define init_swait_head(swh) \ -+ do { \ -+ static struct lock_class_key __key; \ -+ \ -+ __init_swait_head((swh), &__key); \ -+ } while (0) -+ -+/* -+ * Waiter functions -+ */ -+extern void swait_prepare_locked(struct swait_head *head, struct swaiter *w); -+extern void swait_prepare(struct swait_head *head, struct swaiter *w, int state); -+extern void swait_finish_locked(struct swait_head *head, struct swaiter *w); -+extern void swait_finish(struct swait_head *head, struct swaiter *w); -+ -+/* Check whether a head has waiters enqueued */ -+static inline bool swaitqueue_active(struct swait_head *h) -+{ -+ /* Make sure the condition is visible before checking list_empty() */ -+ smp_mb(); -+ return !list_empty(&h->list); -+} -+ -+/* -+ * Wakeup functions -+ */ -+extern unsigned int __swait_wake(struct swait_head *head, unsigned int state, unsigned int num); -+extern unsigned int __swait_wake_locked(struct swait_head *head, unsigned int state, unsigned int num); -+ -+#define swait_wake(head) __swait_wake(head, TASK_NORMAL, 1) -+#define swait_wake_interruptible(head) __swait_wake(head, TASK_INTERRUPTIBLE, 1) -+#define swait_wake_all(head) __swait_wake(head, TASK_NORMAL, 0) -+#define swait_wake_all_interruptible(head) __swait_wake(head, TASK_INTERRUPTIBLE, 0) -+ -+/* -+ * Event API -+ */ -+#define __swait_event(wq, condition) \ -+do { \ -+ DEFINE_SWAITER(__wait); \ -+ \ -+ for (;;) { \ -+ swait_prepare(&wq, &__wait, TASK_UNINTERRUPTIBLE); \ -+ if (condition) \ -+ break; \ -+ schedule(); \ -+ } \ -+ swait_finish(&wq, &__wait); \ -+} while (0) -+ -+/** -+ * swait_event - sleep until a condition gets true -+ * @wq: the waitqueue to wait on -+ * @condition: a C expression for the event to wait for -+ * -+ * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the -+ * @condition evaluates to true. The @condition is checked each time -+ * the waitqueue @wq is woken up. -+ * -+ * wake_up() has to be called after changing any variable that could -+ * change the result of the wait condition. -+ */ -+#define swait_event(wq, condition) \ -+do { \ -+ if (condition) \ -+ break; \ -+ __swait_event(wq, condition); \ -+} while (0) -+ -+#define __swait_event_interruptible(wq, condition, ret) \ -+do { \ -+ DEFINE_SWAITER(__wait); \ -+ \ -+ for (;;) { \ -+ swait_prepare(&wq, &__wait, TASK_INTERRUPTIBLE); \ -+ if (condition) \ -+ break; \ -+ if (signal_pending(current)) { \ -+ ret = -ERESTARTSYS; \ -+ break; \ -+ } \ -+ schedule(); \ -+ } \ -+ swait_finish(&wq, &__wait); \ -+} while (0) -+ -+#define __swait_event_interruptible_timeout(wq, condition, ret) \ -+do { \ -+ DEFINE_SWAITER(__wait); \ -+ \ -+ for (;;) { \ -+ swait_prepare(&wq, &__wait, TASK_INTERRUPTIBLE); \ -+ if (condition) \ -+ break; \ -+ if (signal_pending(current)) { \ -+ ret = -ERESTARTSYS; \ -+ break; \ -+ } \ -+ ret = schedule_timeout(ret); \ -+ if (!ret) \ -+ break; \ -+ } \ -+ swait_finish(&wq, &__wait); \ -+} while (0) -+ -+/** -+ * swait_event_interruptible - sleep until a condition gets true -+ * @wq: the waitqueue to wait on -+ * @condition: a C expression for the event to wait for -+ * -+ * The process is put to sleep (TASK_INTERRUPTIBLE) until the -+ * @condition evaluates to true. The @condition is checked each time -+ * the waitqueue @wq is woken up. -+ * -+ * wake_up() has to be called after changing any variable that could -+ * change the result of the wait condition. -+ */ -+#define swait_event_interruptible(wq, condition) \ -+({ \ -+ int __ret = 0; \ -+ if (!(condition)) \ -+ __swait_event_interruptible(wq, condition, __ret); \ -+ __ret; \ -+}) -+ -+#define swait_event_interruptible_timeout(wq, condition, timeout) \ -+({ \ -+ int __ret = timeout; \ -+ if (!(condition)) \ -+ __swait_event_interruptible_timeout(wq, condition, __ret); \ -+ __ret; \ -+}) -+ -+#define __swait_event_timeout(wq, condition, ret) \ -+do { \ -+ DEFINE_SWAITER(__wait); \ -+ \ -+ for (;;) { \ -+ swait_prepare(&wq, &__wait, TASK_UNINTERRUPTIBLE); \ -+ if (condition) \ -+ break; \ -+ ret = schedule_timeout(ret); \ -+ if (!ret) \ -+ break; \ -+ } \ -+ swait_finish(&wq, &__wait); \ -+} while (0) -+ -+/** -+ * swait_event_timeout - sleep until a condition gets true or a timeout elapses -+ * @wq: the waitqueue to wait on -+ * @condition: a C expression for the event to wait for -+ * @timeout: timeout, in jiffies -+ * -+ * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the -+ * @condition evaluates to true. The @condition is checked each time -+ * the waitqueue @wq is woken up. -+ * -+ * wake_up() has to be called after changing any variable that could -+ * change the result of the wait condition. -+ * -+ * The function returns 0 if the @timeout elapsed, and the remaining -+ * jiffies if the condition evaluated to true before the timeout elapsed. -+ */ -+#define swait_event_timeout(wq, condition, timeout) \ -+({ \ -+ long __ret = timeout; \ -+ if (!(condition)) \ -+ __swait_event_timeout(wq, condition, __ret); \ -+ __ret; \ -+}) -+ -+#endif ---- a/kernel/sched/Makefile -+++ b/kernel/sched/Makefile -@@ -13,7 +13,7 @@ endif - - obj-y += core.o loadavg.o clock.o cputime.o - obj-y += idle_task.o fair.o rt.o deadline.o stop_task.o --obj-y += wait.o completion.o idle.o -+obj-y += wait.o wait-simple.o completion.o idle.o - obj-$(CONFIG_SMP) += cpupri.o cpudeadline.o - obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o - obj-$(CONFIG_SCHEDSTATS) += stats.o ---- /dev/null -+++ b/kernel/sched/wait-simple.c -@@ -0,0 +1,115 @@ -+/* -+ * Simple waitqueues without fancy flags and callbacks -+ * -+ * (C) 2011 Thomas Gleixner <tglx@linutronix.de> -+ * -+ * Based on kernel/wait.c -+ * -+ * For licencing details see kernel-base/COPYING -+ */ -+#include <linux/init.h> -+#include <linux/export.h> -+#include <linux/sched.h> -+#include <linux/wait-simple.h> -+ -+/* Adds w to head->list. Must be called with head->lock locked. */ -+static inline void __swait_enqueue(struct swait_head *head, struct swaiter *w) -+{ -+ list_add(&w->node, &head->list); -+ /* We can't let the condition leak before the setting of head */ -+ smp_mb(); -+} -+ -+/* Removes w from head->list. Must be called with head->lock locked. */ -+static inline void __swait_dequeue(struct swaiter *w) -+{ -+ list_del_init(&w->node); -+} -+ -+void __init_swait_head(struct swait_head *head, struct lock_class_key *key) -+{ -+ raw_spin_lock_init(&head->lock); -+ lockdep_set_class(&head->lock, key); -+ INIT_LIST_HEAD(&head->list); -+} -+EXPORT_SYMBOL(__init_swait_head); -+ -+void swait_prepare_locked(struct swait_head *head, struct swaiter *w) -+{ -+ w->task = current; -+ if (list_empty(&w->node)) -+ __swait_enqueue(head, w); -+} -+ -+void swait_prepare(struct swait_head *head, struct swaiter *w, int state) -+{ -+ unsigned long flags; -+ -+ raw_spin_lock_irqsave(&head->lock, flags); -+ swait_prepare_locked(head, w); -+ __set_current_state(state); -+ raw_spin_unlock_irqrestore(&head->lock, flags); -+} -+EXPORT_SYMBOL(swait_prepare); -+ -+void swait_finish_locked(struct swait_head *head, struct swaiter *w) -+{ -+ __set_current_state(TASK_RUNNING); -+ if (w->task) -+ __swait_dequeue(w); -+} -+ -+void swait_finish(struct swait_head *head, struct swaiter *w) -+{ -+ unsigned long flags; -+ -+ __set_current_state(TASK_RUNNING); -+ if (w->task) { -+ raw_spin_lock_irqsave(&head->lock, flags); -+ __swait_dequeue(w); -+ raw_spin_unlock_irqrestore(&head->lock, flags); -+ } -+} -+EXPORT_SYMBOL(swait_finish); -+ -+unsigned int -+__swait_wake_locked(struct swait_head *head, unsigned int state, unsigned int num) -+{ -+ struct swaiter *curr, *next; -+ int woken = 0; -+ -+ list_for_each_entry_safe(curr, next, &head->list, node) { -+ if (wake_up_state(curr->task, state)) { -+ __swait_dequeue(curr); -+ /* -+ * The waiting task can free the waiter as -+ * soon as curr->task = NULL is written, -+ * without taking any locks. A memory barrier -+ * is required here to prevent the following -+ * store to curr->task from getting ahead of -+ * the dequeue operation. -+ */ -+ smp_wmb(); -+ curr->task = NULL; -+ if (++woken == num) -+ break; -+ } -+ } -+ return woken; -+} -+ -+unsigned int -+__swait_wake(struct swait_head *head, unsigned int state, unsigned int num) -+{ -+ unsigned long flags; -+ int woken; -+ -+ if (!swaitqueue_active(head)) -+ return 0; -+ -+ raw_spin_lock_irqsave(&head->lock, flags); -+ woken = __swait_wake_locked(head, state, num); -+ raw_spin_unlock_irqrestore(&head->lock, flags); -+ return woken; -+} -+EXPORT_SYMBOL(__swait_wake); diff --git a/patches/work-simple-Simple-work-queue-implemenation.patch b/patches/work-simple-Simple-work-queue-implemenation.patch index 74de1a1a9ebaa5..04f9a3a81fee19 100644 --- a/patches/work-simple-Simple-work-queue-implemenation.patch +++ b/patches/work-simple-Simple-work-queue-implemenation.patch @@ -50,8 +50,8 @@ Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de> obj-y += core.o loadavg.o clock.o cputime.o obj-y += idle_task.o fair.o rt.o deadline.o stop_task.o --obj-y += wait.o wait-simple.o completion.o idle.o -+obj-y += wait.o wait-simple.o work-simple.o completion.o idle.o +-obj-y += wait.o swait.o completion.o idle.o ++obj-y += wait.o swait.o work-simple.o completion.o idle.o obj-$(CONFIG_SMP) += cpupri.o cpudeadline.o obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o obj-$(CONFIG_SCHEDSTATS) += stats.o @@ -65,7 +65,7 @@ Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de> + * PREEMPT_RT_FULL safe. The callbacks are executed in kthread context. + */ + -+#include <linux/wait-simple.h> ++#include <linux/swait.h> +#include <linux/work-simple.h> +#include <linux/kthread.h> +#include <linux/slab.h> @@ -79,7 +79,7 @@ Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de> + +struct sworker { + struct list_head events; -+ struct swait_head wq; ++ struct swait_queue_head wq; + + raw_spinlock_t lock; + @@ -140,7 +140,7 @@ Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de> + + INIT_LIST_HEAD(&worker->events); + raw_spin_lock_init(&worker->lock); -+ init_swait_head(&worker->wq); ++ init_swait_queue_head(&worker->wq); + + worker->task = kthread_run(swork_kthread, worker, "kswork"); + if (IS_ERR(worker->task)) { @@ -177,7 +177,7 @@ Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de> + list_add_tail(&sev->item, &glob_worker->events); + raw_spin_unlock_irqrestore(&glob_worker->lock, flags); + -+ swait_wake(&glob_worker->wq); ++ swake_up(&glob_worker->wq); + return true; +} +EXPORT_SYMBOL_GPL(swork_queue); |