Deactivating the use of interrupts here fixes a crash on early boot with
RT-Preempt.

Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = c0004000
[00000000] *pgd=00000000
Internal error: Oops: 5 [#1] PREEMPT ARM
Modules linked in:
CPU: 0 PID: 0 Comm: swapper Not tainted 4.0.0-rt4+ #197
Hardware name: Atmel SAMA5
task: c068f338 ti: c068a000 task.ti: c068a000
PC is at wake_up_process+0x8/0x4c
LR is at kthread_create_on_node+0xa0/0x148
pc : [<c0037478>]    lr : [<c00317b0>]    psr: 600001d3
sp : c068bec0  ip : 00000000  fp : 00100100
r10: 00000000  r9 : cf402380  r8 : ffffffff
r7 : c0047ae0  r6 : c068bedc  r5 : c06926b4  r4 : 00000000
r3 : c06bbf1c  r2 : c068becc  r1 : c068f338  r0 : 00000000
Flags: nZCv  IRQs off  FIQs off  Mode SVC_32  ISA ARM  Segment kernel
Control: 10c53c7d  Table: 20004059  DAC: 00000015
Process swapper (pid: 0, stack limit = 0xc068a210)
Stack: (0xc068bec0 to 0xc068c000)
bec0: c06bbf1c cf402700 00100100 c00317b0 00000010 c068bf00 fefffc00 00000000
bee0: c068bee0 c068bee0 00000001 cf404c00 cf4026c0 cf404c00 00000010 00000010
bf00: c00481c0 c05b05bc 00000010 c05f52fc cfdaa47c cf4026c0 00040080 cf404c00
bf20: c037286c 00000010 cf402380 c004858c cfdaa47c c050d548 fefffc00 00000010
bf40: cf402380 c06d2a1c cf402388 c0676b70 c05f52fc cf402380 00000001 cfdaa47c
bf60: cf4023c0 00000000 c06b450c cf402400 00200200 c0676888 00000000 00000001
bf80: 00000000 00000000 00000000 00000001 c06bb280 00000001 ffffffff c068c000
bfa0: c06bb280 c0682808 cfffcb40 c0660264 00000001 c065cb10 ffffffff ffffffff
bfc0: c065c66c 00000000 00000000 c0682808 00000000 c06bb454 c068c050 c0682804
bfe0: c0690550 20004059 410fc051 00000000 00000000 20008070 00000000 00000000
Code: eb1238c0 eafffff3 e92d4818 e1a04000 (e5903000)
---[ end trace 0000000000000001 ]---

Signed-off-by: David Dueck <davidcdu...@googlemail.com>
---
 drivers/clk/Kconfig           |  1 +
 drivers/clk/at91/Kconfig      |  4 ++++
 drivers/clk/at91/clk-main.c   | 34 ++++++++++++++++++++++++++++++++++
 drivers/clk/at91/clk-master.c | 11 +++++++++++
 drivers/clk/at91/clk-pll.c    | 11 ++++++++++-
 drivers/clk/at91/clk-system.c | 11 +++++++++++
 drivers/clk/at91/clk-utmi.c   | 10 ++++++++++
 drivers/clk/at91/pmc.c        |  6 ++++++
 8 files changed, 87 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/at91/Kconfig

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 0b474a0..b1a56f3 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -147,6 +147,7 @@ source "drivers/clk/qcom/Kconfig"
 
 endmenu
 
+source "drivers/clk/at91/Kconfig"
 source "drivers/clk/bcm/Kconfig"
 source "drivers/clk/mvebu/Kconfig"
 
diff --git a/drivers/clk/at91/Kconfig b/drivers/clk/at91/Kconfig
new file mode 100644
index 0000000..343c758
--- /dev/null
+++ b/drivers/clk/at91/Kconfig
@@ -0,0 +1,4 @@
+config AT91_CLK_POLLING
+       bool "AT91 clk polling"
+       help
+               Poll clocks instead of using interrupts
diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
index 59fa3cc..11033ae 100644
--- a/drivers/clk/at91/clk-main.c
+++ b/drivers/clk/at91/clk-main.c
@@ -69,6 +69,7 @@ struct clk_sam9x5_main {
 
 #define to_clk_sam9x5_main(hw) container_of(hw, struct clk_sam9x5_main, hw)
 
+#ifndef CONFIG_AT91_CLK_POLLING
 static irqreturn_t clk_main_osc_irq_handler(int irq, void *dev_id)
 {
        struct clk_main_osc *osc = dev_id;
@@ -78,6 +79,7 @@ static irqreturn_t clk_main_osc_irq_handler(int irq, void 
*dev_id)
 
        return IRQ_HANDLED;
 }
+#endif
 
 static int clk_main_osc_prepare(struct clk_hw *hw)
 {
@@ -95,9 +97,13 @@ static int clk_main_osc_prepare(struct clk_hw *hw)
        }
 
        while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS)) {
+#ifdef CONFIG_AT91_CLK_POLLING
+               cpu_relax();
+#else
                enable_irq(osc->irq);
                wait_event(osc->wait,
                           pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS);
+#endif
        }
 
        return 0;
@@ -145,7 +151,9 @@ at91_clk_register_main_osc(struct at91_pmc *pmc,
                           const char *parent_name,
                           bool bypass)
 {
+#ifndef CONFIG_AT91_CLK_POLLING
        int ret;
+#endif
        struct clk_main_osc *osc;
        struct clk *clk = NULL;
        struct clk_init_data init;
@@ -169,11 +177,13 @@ at91_clk_register_main_osc(struct at91_pmc *pmc,
 
        init_waitqueue_head(&osc->wait);
        irq_set_status_flags(osc->irq, IRQ_NOAUTOEN);
+#ifndef CONFIG_AT91_CLK_POLLING
        ret = request_irq(osc->irq, clk_main_osc_irq_handler,
                          IRQF_TRIGGER_HIGH, name, osc);
        if (ret)
                return ERR_PTR(ret);
 
+#endif
        if (bypass)
                pmc_write(pmc, AT91_CKGR_MOR,
                          (pmc_read(pmc, AT91_CKGR_MOR) &
@@ -213,6 +223,7 @@ void __init of_at91rm9200_clk_main_osc_setup(struct 
device_node *np,
        of_clk_add_provider(np, of_clk_src_simple_get, clk);
 }
 
+#ifndef CONFIG_AT91_CLK_POLLING
 static irqreturn_t clk_main_rc_osc_irq_handler(int irq, void *dev_id)
 {
        struct clk_main_rc_osc *osc = dev_id;
@@ -222,6 +233,7 @@ static irqreturn_t clk_main_rc_osc_irq_handler(int irq, 
void *dev_id)
 
        return IRQ_HANDLED;
 }
+#endif
 
 static int clk_main_rc_osc_prepare(struct clk_hw *hw)
 {
@@ -237,9 +249,13 @@ static int clk_main_rc_osc_prepare(struct clk_hw *hw)
        }
 
        while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCRCS)) {
+#ifdef CONFIG_AT91_CLK_POLLING
+               cpu_relax();
+#else
                enable_irq(osc->irq);
                wait_event(osc->wait,
                           pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCRCS);
+#endif
        }
 
        return 0;
@@ -297,7 +313,9 @@ at91_clk_register_main_rc_osc(struct at91_pmc *pmc,
                              const char *name,
                              u32 frequency, u32 accuracy)
 {
+#ifndef CONFIG_AT91_CLK_POLLING
        int ret;
+#endif
        struct clk_main_rc_osc *osc;
        struct clk *clk = NULL;
        struct clk_init_data init;
@@ -323,11 +341,13 @@ at91_clk_register_main_rc_osc(struct at91_pmc *pmc,
 
        init_waitqueue_head(&osc->wait);
        irq_set_status_flags(osc->irq, IRQ_NOAUTOEN);
+#ifndef CONFIG_AT91_CLK_POLLING
        ret = request_irq(osc->irq, clk_main_rc_osc_irq_handler,
                          IRQF_TRIGGER_HIGH, name, osc);
        if (ret)
                return ERR_PTR(ret);
 
+#endif
        clk = clk_register(NULL, &osc->hw);
        if (IS_ERR(clk)) {
                free_irq(irq, osc);
@@ -476,6 +496,7 @@ void __init of_at91rm9200_clk_main_setup(struct device_node 
*np,
        of_clk_add_provider(np, of_clk_src_simple_get, clk);
 }
 
+#ifndef CONFIG_AT91_CLK_POLLING
 static irqreturn_t clk_sam9x5_main_irq_handler(int irq, void *dev_id)
 {
        struct clk_sam9x5_main *clkmain = dev_id;
@@ -485,6 +506,7 @@ static irqreturn_t clk_sam9x5_main_irq_handler(int irq, 
void *dev_id)
 
        return IRQ_HANDLED;
 }
+#endif
 
 static int clk_sam9x5_main_prepare(struct clk_hw *hw)
 {
@@ -492,9 +514,13 @@ static int clk_sam9x5_main_prepare(struct clk_hw *hw)
        struct at91_pmc *pmc = clkmain->pmc;
 
        while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS)) {
+#ifdef CONFIG_AT91_CLK_POLLING
                enable_irq(clkmain->irq);
                wait_event(clkmain->wait,
                           pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS);
+#else
+               cpu_relax();
+#endif
        }
 
        return clk_main_probe_frequency(pmc);
@@ -532,9 +558,13 @@ static int clk_sam9x5_main_set_parent(struct clk_hw *hw, 
u8 index)
                pmc_write(pmc, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL);
 
        while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS)) {
+#ifdef CONFIG_AT91_CLK_POLLING
+               cpu_relax();
+#else
                enable_irq(clkmain->irq);
                wait_event(clkmain->wait,
                           pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS);
+#endif
        }
 
        return 0;
@@ -562,7 +592,9 @@ at91_clk_register_sam9x5_main(struct at91_pmc *pmc,
                              const char **parent_names,
                              int num_parents)
 {
+#ifndef CONFIG_AT91_CLK_POLLING
        int ret;
+#endif
        struct clk_sam9x5_main *clkmain;
        struct clk *clk = NULL;
        struct clk_init_data init;
@@ -590,10 +622,12 @@ at91_clk_register_sam9x5_main(struct at91_pmc *pmc,
                             AT91_PMC_MOSCEN);
        init_waitqueue_head(&clkmain->wait);
        irq_set_status_flags(clkmain->irq, IRQ_NOAUTOEN);
+#ifndef CONFIG_AT91_CLK_POLLING
        ret = request_irq(clkmain->irq, clk_sam9x5_main_irq_handler,
                          IRQF_TRIGGER_HIGH, name, clkmain);
        if (ret)
                return ERR_PTR(ret);
+#endif
 
        clk = clk_register(NULL, &clkmain->hw);
        if (IS_ERR(clk)) {
diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c
index c1af80b..8cd7c57 100644
--- a/drivers/clk/at91/clk-master.c
+++ b/drivers/clk/at91/clk-master.c
@@ -51,6 +51,7 @@ struct clk_master {
        const struct clk_master_characteristics *characteristics;
 };
 
+#ifndef CONFIG_AT91_CLK_POLLING
 static irqreturn_t clk_master_irq_handler(int irq, void *dev_id)
 {
        struct clk_master *master = (struct clk_master *)dev_id;
@@ -60,15 +61,21 @@ static irqreturn_t clk_master_irq_handler(int irq, void 
*dev_id)
 
        return IRQ_HANDLED;
 }
+#endif
+
 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)) {
+#ifdef CONFIG_AT91_CLK_POLLING
+               cpu_relax();
+#else
                enable_irq(master->irq);
                wait_event(master->wait,
                           pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY);
+#endif
        }
 
        return 0;
@@ -138,7 +145,9 @@ at91_clk_register_master(struct at91_pmc *pmc, unsigned int 
irq,
                const struct clk_master_layout *layout,
                const struct clk_master_characteristics *characteristics)
 {
+#ifndef CONFIG_AT91_CLK_POLLING
        int ret;
+#endif
        struct clk_master *master;
        struct clk *clk = NULL;
        struct clk_init_data init;
@@ -163,10 +172,12 @@ at91_clk_register_master(struct at91_pmc *pmc, unsigned 
int irq,
        master->irq = irq;
        init_waitqueue_head(&master->wait);
        irq_set_status_flags(master->irq, IRQ_NOAUTOEN);
+#ifndef CONFIG_AT91_CLK_POLLING
        ret = request_irq(master->irq, clk_master_irq_handler,
                          IRQF_TRIGGER_HIGH, "clk-master", master);
        if (ret)
                return ERR_PTR(ret);
+#endif
 
        clk = clk_register(NULL, &master->hw);
        if (IS_ERR(clk))
diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c
index 6ec79db..a8b3cc5 100644
--- a/drivers/clk/at91/clk-pll.c
+++ b/drivers/clk/at91/clk-pll.c
@@ -69,6 +69,7 @@ struct clk_pll {
        const struct clk_pll_characteristics *characteristics;
 };
 
+#ifndef CONFIG_AT91_CLK_POLLING
 static irqreturn_t clk_pll_irq_handler(int irq, void *dev_id)
 {
        struct clk_pll *pll = (struct clk_pll *)dev_id;
@@ -78,6 +79,7 @@ static irqreturn_t clk_pll_irq_handler(int irq, void *dev_id)
 
        return IRQ_HANDLED;
 }
+#endif
 
 static int clk_pll_prepare(struct clk_hw *hw)
 {
@@ -119,9 +121,13 @@ static int clk_pll_prepare(struct clk_hw *hw)
        pmc_write(pmc, offset, pllr);
 
        while (!(pmc_read(pmc, AT91_PMC_SR) & mask)) {
+#ifdef CONFIG_AT91_CLK_POLLING
+               cpu_relax();
+#else
                enable_irq(pll->irq);
                wait_event(pll->wait,
                           pmc_read(pmc, AT91_PMC_SR) & mask);
+#endif
        }
 
        return 0;
@@ -308,7 +314,9 @@ at91_clk_register_pll(struct at91_pmc *pmc, unsigned int 
irq, const char *name,
        struct clk_pll *pll;
        struct clk *clk = NULL;
        struct clk_init_data init;
+#ifndef CONFIG_AT91_CLK_POLLING
        int ret;
+#endif
        int offset = PLL_REG(id);
        u32 tmp;
 
@@ -336,11 +344,12 @@ at91_clk_register_pll(struct at91_pmc *pmc, unsigned int 
irq, const char *name,
        pll->mul = PLL_MUL(tmp, layout);
        init_waitqueue_head(&pll->wait);
        irq_set_status_flags(pll->irq, IRQ_NOAUTOEN);
+#ifndef CONFIG_AT91_CLK_POLLING
        ret = request_irq(pll->irq, clk_pll_irq_handler, IRQF_TRIGGER_HIGH,
                          id ? "clk-pllb" : "clk-plla", pll);
        if (ret)
                return ERR_PTR(ret);
-
+#endif
        clk = clk_register(NULL, &pll->hw);
        if (IS_ERR(clk))
                kfree(pll);
diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c
index a76d03f..bb7c82a 100644
--- a/drivers/clk/at91/clk-system.c
+++ b/drivers/clk/at91/clk-system.c
@@ -39,6 +39,8 @@ static inline int is_pck(int id)
 {
        return (id >= 8) && (id <= 15);
 }
+
+#ifndef CONFIG_AT91_CLK_POLLING
 static irqreturn_t clk_system_irq_handler(int irq, void *dev_id)
 {
        struct clk_system *sys = (struct clk_system *)dev_id;
@@ -48,6 +50,7 @@ static irqreturn_t clk_system_irq_handler(int irq, void 
*dev_id)
 
        return IRQ_HANDLED;
 }
+#endif
 
 static int clk_system_prepare(struct clk_hw *hw)
 {
@@ -61,12 +64,16 @@ static int clk_system_prepare(struct clk_hw *hw)
                return 0;
 
        while (!(pmc_read(pmc, AT91_PMC_SR) & mask)) {
+#ifdef CONFIG_AT91_CLK_POLLING
                if (sys->irq) {
                        enable_irq(sys->irq);
                        wait_event(sys->wait,
                                   pmc_read(pmc, AT91_PMC_SR) & mask);
                } else
                        cpu_relax();
+#else
+               cpu_relax();
+#endif
        }
        return 0;
 }
@@ -106,7 +113,9 @@ at91_clk_register_system(struct at91_pmc *pmc, const char 
*name,
        struct clk_system *sys;
        struct clk *clk = NULL;
        struct clk_init_data init;
+#ifndef CONFIG_AT91_CLK_POLLING
        int ret;
+#endif
 
        if (!parent_name || id > SYSTEM_MAX_ID)
                return ERR_PTR(-EINVAL);
@@ -128,10 +137,12 @@ at91_clk_register_system(struct at91_pmc *pmc, const char 
*name,
        if (irq) {
                init_waitqueue_head(&sys->wait);
                irq_set_status_flags(sys->irq, IRQ_NOAUTOEN);
+#ifndef CONFIG_AT91_CLK_POLLING
                ret = request_irq(sys->irq, clk_system_irq_handler,
                                IRQF_TRIGGER_HIGH, name, sys);
                if (ret)
                        return ERR_PTR(ret);
+#endif
        }
 
        clk = clk_register(NULL, &sys->hw);
diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c
index ae3263b..60fdf30 100644
--- a/drivers/clk/at91/clk-utmi.c
+++ b/drivers/clk/at91/clk-utmi.c
@@ -33,6 +33,7 @@ struct clk_utmi {
 
 #define to_clk_utmi(hw) container_of(hw, struct clk_utmi, hw)
 
+#ifndef CONFIG_AT91_CLK_POLLING
 static irqreturn_t clk_utmi_irq_handler(int irq, void *dev_id)
 {
        struct clk_utmi *utmi = (struct clk_utmi *)dev_id;
@@ -42,6 +43,7 @@ static irqreturn_t clk_utmi_irq_handler(int irq, void *dev_id)
 
        return IRQ_HANDLED;
 }
+#endif
 
 static int clk_utmi_prepare(struct clk_hw *hw)
 {
@@ -53,9 +55,13 @@ static int clk_utmi_prepare(struct clk_hw *hw)
        pmc_write(pmc, AT91_CKGR_UCKR, tmp);
 
        while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU)) {
+#ifdef CONFIG_AT91_CLK_POLLING
+               cpu_relax();
+#else
                enable_irq(utmi->irq);
                wait_event(utmi->wait,
                           pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU);
+#endif
        }
 
        return 0;
@@ -96,7 +102,9 @@ static struct clk * __init
 at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int irq,
                       const char *name, const char *parent_name)
 {
+#ifndef CONFIG_AT91_CLK_POLLING
        int ret;
+#endif
        struct clk_utmi *utmi;
        struct clk *clk = NULL;
        struct clk_init_data init;
@@ -116,11 +124,13 @@ at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int 
irq,
        utmi->irq = irq;
        init_waitqueue_head(&utmi->wait);
        irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN);
+#ifndef CONFIG_AT91_CLK_POLLING
        ret = request_irq(utmi->irq, clk_utmi_irq_handler,
                          IRQF_TRIGGER_HIGH, "clk-utmi", utmi);
        if (ret)
                return ERR_PTR(ret);
 
+#endif
        clk = clk_register(NULL, &utmi->hw);
        if (IS_ERR(clk))
                kfree(utmi);
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index 3f27d21..3c592bc 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -158,6 +158,7 @@ static struct irq_domain_ops pmc_irq_ops = {
        .xlate  = pmc_irq_domain_xlate,
 };
 
+#ifndef CONFIG_AT91_CLK_POLLING
 static irqreturn_t pmc_irq_handler(int irq, void *data)
 {
        struct at91_pmc *pmc = (struct at91_pmc *)data;
@@ -173,6 +174,7 @@ static irqreturn_t pmc_irq_handler(int irq, void *data)
 
        return IRQ_HANDLED;
 }
+#endif
 
 static const struct at91_pmc_caps at91rm9200_caps = {
        .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB |
@@ -241,14 +243,18 @@ static struct at91_pmc *__init at91_pmc_init(struct 
device_node *np,
                goto out_free_pmc;
 
        pmc_write(pmc, AT91_PMC_IDR, 0xffffffff);
+#ifndef CONFIG_AT91_CLK_POLLING
        if (request_irq(pmc->virq, pmc_irq_handler,
                        IRQF_SHARED | IRQF_COND_SUSPEND, "pmc", pmc))
                goto out_remove_irqdomain;
+#endif
 
        return pmc;
 
+#ifndef CONFIG_AT91_CLK_POLLING
 out_remove_irqdomain:
        irq_domain_remove(pmc->irqdomain);
+#endif
 out_free_pmc:
        kfree(pmc);
 
-- 
2.4.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to