From eb811c73b69f18cefb7a63f22fe07212c6575650 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 27 Jul 2015 15:00:12 +0100 Subject: CLOCKSOURCE: mips-gic: Enable the clock before using it For the clock to be used (e.g. get its rate through clk_get_rate) it should be prepared and enabled first. Also, while the clock is enabled the driver must hold a reference to it, so let's remove the call to clk_put. Reviewed-by: Andrew Bresticker Signed-off-by: Ezequiel Garcia Acked-by: Daniel Lezcano Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: Thomas Gleixner Cc: James Hartley Cc: Govindraj Raja Cc: Damien Horsley Cc: James Hogan Cc: Ezequiel Garcia Patchwork: https://patchwork.linux-mips.org/patch/10779/ Signed-off-by: Ralf Baechle --- drivers/clocksource/mips-gic-timer.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/clocksource/mips-gic-timer.c') diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index b81ed1a5342d..913585d93466 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -158,8 +158,13 @@ static void __init gic_clocksource_of_init(struct device_node *node) clk = of_clk_get(node, 0); if (!IS_ERR(clk)) { + if (clk_prepare_enable(clk) < 0) { + pr_err("GIC failed to enable clock\n"); + clk_put(clk); + return; + } + gic_frequency = clk_get_rate(clk); - clk_put(clk); } else if (of_property_read_u32(node, "clock-frequency", &gic_frequency)) { pr_err("GIC frequency not specified.\n"); -- cgit v1.2.1 From f95ac8558b88a5e9ae2b1d580a5cc55bffa512fa Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 27 Jul 2015 15:00:13 +0100 Subject: CLOCKSOURCE: mips-gic: Add missing error returns checks This commit adds the required checks on the functions that return an error. Some of them are not critical, so only a warning is printed. Signed-off-by: Ezequiel Garcia Reviewed-by: Andrew Bresticker Acked-by: Daniel Lezcano Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: Thomas Gleixner Cc: James Hartley Cc: Govindraj Raja Cc: Damien Horsley Cc: James Hogan Cc: Ezequiel Garcia Patchwork: https://patchwork.linux-mips.org/patch/10780/ Signed-off-by: Ralf Baechle --- drivers/clocksource/mips-gic-timer.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers/clocksource/mips-gic-timer.c') diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index 913585d93466..c4352f078492 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -100,12 +100,18 @@ static struct notifier_block gic_cpu_nb = { static int gic_clockevent_init(void) { + int ret; + if (!cpu_has_counter || !gic_frequency) return -ENXIO; - setup_percpu_irq(gic_timer_irq, &gic_compare_irqaction); + ret = setup_percpu_irq(gic_timer_irq, &gic_compare_irqaction); + if (ret < 0) + return ret; - register_cpu_notifier(&gic_cpu_nb); + ret = register_cpu_notifier(&gic_cpu_nb); + if (ret < 0) + pr_warn("GIC: Unable to register CPU notifier\n"); gic_clockevent_cpu_init(this_cpu_ptr(&gic_clockevent_device)); @@ -125,13 +131,17 @@ static struct clocksource gic_clocksource = { static void __init __gic_clocksource_init(void) { + int ret; + /* Set clocksource mask. */ gic_clocksource.mask = CLOCKSOURCE_MASK(gic_get_count_width()); /* Calculate a somewhat reasonable rating value. */ gic_clocksource.rating = 200 + gic_frequency / 10000000; - clocksource_register_hz(&gic_clocksource, gic_frequency); + ret = clocksource_register_hz(&gic_clocksource, gic_frequency); + if (ret < 0) + pr_warn("GIC: Unable to register clocksource\n"); gic_clockevent_init(); -- cgit v1.2.1 From 67d4e669c1e504a491e44737f3561eaba919b304 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 27 Jul 2015 15:00:14 +0100 Subject: CLOCKSOURCE: mips-gic: Split clocksource and clockevent initialization This is preparation work for the introduction of clockevent frequency update with a clock notifier. This is only possible when the device is passed a clk struct, so let's split the legacy and devicetree initialization. Reviewed-by: Andrew Bresticker Signed-off-by: Ezequiel Garcia Acked-by: Daniel Lezcano Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: Thomas Gleixner Cc: James Hartley Cc: Govindraj Raja Cc: Damien Horsley Cc: James Hogan Cc: Ezequiel Garcia Patchwork: https://patchwork.linux-mips.org/patch/10781/ Signed-off-by: Ralf Baechle --- drivers/clocksource/mips-gic-timer.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/clocksource/mips-gic-timer.c') diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index c4352f078492..22a4daf5f0c8 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -142,11 +142,6 @@ static void __init __gic_clocksource_init(void) ret = clocksource_register_hz(&gic_clocksource, gic_frequency); if (ret < 0) pr_warn("GIC: Unable to register clocksource\n"); - - gic_clockevent_init(); - - /* And finally start the counter */ - gic_start_count(); } void __init gic_clocksource_init(unsigned int frequency) @@ -156,6 +151,10 @@ void __init gic_clocksource_init(unsigned int frequency) GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_COMPARE); __gic_clocksource_init(); + gic_clockevent_init(); + + /* And finally start the counter */ + gic_start_count(); } static void __init gic_clocksource_of_init(struct device_node *node) @@ -187,6 +186,10 @@ static void __init gic_clocksource_of_init(struct device_node *node) } __gic_clocksource_init(); + gic_clockevent_init(); + + /* And finally start the counter */ + gic_start_count(); } CLOCKSOURCE_OF_DECLARE(mips_gic_timer, "mti,gic-timer", gic_clocksource_of_init); -- cgit v1.2.1 From fc6a6772f888ee8ab4c5428854f7f1d3abda13df Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 27 Jul 2015 15:00:15 +0100 Subject: CLOCKSOURCE: mips-gic: Update clockevent frequency on clock rate changes This commit introduces the clockevent frequency update, using a clock notifier. It will be used to support CPUFreq on platforms using MIPS GIC based clockevents. Signed-off-by: Ezequiel Garcia Acked-by: Daniel Lezcano Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: Thomas Gleixner Cc: Andrew Bresticker Cc: James Hartley Cc: Govindraj Raja Cc: Damien Horsley Cc: James Hogan Cc: Ezequiel Garcia Patchwork: https://patchwork.linux-mips.org/patch/10782/ Signed-off-by: Ralf Baechle --- drivers/clocksource/mips-gic-timer.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'drivers/clocksource/mips-gic-timer.c') diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index 22a4daf5f0c8..a155bec06d18 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -79,6 +79,13 @@ static void gic_clockevent_cpu_exit(struct clock_event_device *cd) disable_percpu_irq(gic_timer_irq); } +static void gic_update_frequency(void *data) +{ + unsigned long rate = (unsigned long)data; + + clockevents_update_freq(this_cpu_ptr(&gic_clockevent_device), rate); +} + static int gic_cpu_notifier(struct notifier_block *nb, unsigned long action, void *data) { @@ -94,10 +101,26 @@ static int gic_cpu_notifier(struct notifier_block *nb, unsigned long action, return NOTIFY_OK; } +static int gic_clk_notifier(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct clk_notifier_data *cnd = data; + + if (action == POST_RATE_CHANGE) + on_each_cpu(gic_update_frequency, (void *)cnd->new_rate, 1); + + return NOTIFY_OK; +} + + static struct notifier_block gic_cpu_nb = { .notifier_call = gic_cpu_notifier, }; +static struct notifier_block gic_clk_nb = { + .notifier_call = gic_clk_notifier, +}; + static int gic_clockevent_init(void) { int ret; @@ -160,6 +183,7 @@ void __init gic_clocksource_init(unsigned int frequency) static void __init gic_clocksource_of_init(struct device_node *node) { struct clk *clk; + int ret; if (WARN_ON(!gic_present || !node->parent || !of_device_is_compatible(node->parent, "mti,gic"))) @@ -186,7 +210,12 @@ static void __init gic_clocksource_of_init(struct device_node *node) } __gic_clocksource_init(); - gic_clockevent_init(); + + ret = gic_clockevent_init(); + if (!ret && !IS_ERR(clk)) { + if (clk_notifier_register(clk, &gic_clk_nb) < 0) + pr_warn("GIC: Unable to register clock notifier\n"); + } /* And finally start the counter */ gic_start_count(); -- cgit v1.2.1