From dc11bae78529526605c5c45c369c9512fd012093 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 5 Jun 2017 00:18:43 +0200 Subject: clocksource/drivers: Add timer-of common init routine The different drivers are all using the same pattern when initializing. 1. Get the base address 2. Get the irq number 3. Get the clock 4. Prepare and enable the clock 5. Get the rate 6. Request an interrupt Instead of repeating again and again these steps in all the drivers, let's provide a common init routine to give the opportunity to factor all of them out. We can expect a significant kernel size improvement when the common routine will be used in all the drivers. Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-of.c | 172 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 drivers/clocksource/timer-of.c (limited to 'drivers/clocksource/timer-of.c') diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c new file mode 100644 index 000000000000..be1dbee11c20 --- /dev/null +++ b/drivers/clocksource/timer-of.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2017, Linaro Ltd. All rights reserved. + * + * Author: Daniel Lezcano + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include +#include +#include +#include + +#include "timer-of.h" + +static __init void timer_irq_exit(struct of_timer_irq *of_irq) +{ + struct timer_of *to = container_of(of_irq, struct timer_of, of_irq); + + struct clock_event_device *clkevt = &to->clkevt; + + of_irq->percpu ? free_percpu_irq(of_irq->irq, clkevt) : + free_irq(of_irq->irq, clkevt); +} + +static __init int timer_irq_init(struct device_node *np, + struct of_timer_irq *of_irq) +{ + int ret; + struct timer_of *to = container_of(of_irq, struct timer_of, of_irq); + struct clock_event_device *clkevt = &to->clkevt; + + of_irq->irq = of_irq->name ? of_irq_get_byname(np, of_irq->name): + irq_of_parse_and_map(np, of_irq->index); + if (!of_irq->irq) { + pr_err("Failed to map interrupt for %s\n", np->full_name); + return -EINVAL; + } + + ret = of_irq->percpu ? + request_percpu_irq(of_irq->irq, of_irq->handler, + np->full_name, clkevt) : + request_irq(of_irq->irq, of_irq->handler, + of_irq->flags ? of_irq->flags : IRQF_TIMER, + np->full_name, clkevt); + if (ret) { + pr_err("Failed to request irq %d for %s\n", of_irq->irq, + np->full_name); + return ret; + } + + clkevt->irq = of_irq->irq; + + return 0; +} + +static __init void timer_clk_exit(struct of_timer_clk *of_clk) +{ + of_clk->rate = 0; + clk_disable_unprepare(of_clk->clk); + clk_put(of_clk->clk); +} + +static __init int timer_clk_init(struct device_node *np, + struct of_timer_clk *of_clk) +{ + int ret; + + of_clk->clk = of_clk->name ? of_clk_get_by_name(np, of_clk->name) : + of_clk_get(np, of_clk->index); + if (IS_ERR(of_clk->clk)) { + pr_err("Failed to get clock for %s\n", np->full_name); + return PTR_ERR(of_clk->clk); + } + + ret = clk_prepare_enable(of_clk->clk); + if (ret) { + pr_err("Failed for enable clock for %s\n", np->full_name); + goto out_clk_put; + } + + of_clk->rate = clk_get_rate(of_clk->clk); + if (!of_clk->rate) { + ret = -EINVAL; + pr_err("Failed to get clock rate for %s\n", np->full_name); + goto out_clk_disable; + } + + of_clk->period = DIV_ROUND_UP(of_clk->rate, HZ); +out: + return ret; + +out_clk_disable: + clk_disable_unprepare(of_clk->clk); +out_clk_put: + clk_put(of_clk->clk); + + goto out; +} + +static __init void timer_base_exit(struct of_timer_base *of_base) +{ + iounmap(of_base->base); +} + +static __init int timer_base_init(struct device_node *np, + struct of_timer_base *of_base) +{ + const char *name = of_base->name ? of_base->name : np->full_name; + + of_base->base = of_io_request_and_map(np, of_base->index, name); + if (of_base->base) { + pr_err("Failed to iomap (%s)\n", name); + return -ENXIO; + } + + return 0; +} + +int __init timer_of_init(struct device_node *np, struct timer_of *to) +{ + int ret; + int flags = 0; + + if (to->flags & TIMER_OF_BASE) { + ret = timer_base_init(np, &to->of_base); + if (ret) + goto out_fail; + flags |= TIMER_OF_BASE; + } + + if (to->flags & TIMER_OF_CLOCK) { + ret = timer_clk_init(np, &to->of_clk); + if (ret) + goto out_fail; + flags |= TIMER_OF_CLOCK; + } + + if (to->flags & TIMER_OF_IRQ) { + ret = timer_irq_init(np, &to->of_irq); + if (ret) + goto out_fail; + flags |= TIMER_OF_IRQ; + } + + if (!to->clkevt.name) + to->clkevt.name = np->name; +out: + return ret; + +out_fail: + if (flags & TIMER_OF_IRQ) + timer_irq_exit(&to->of_irq); + + if (flags & TIMER_OF_CLOCK) + timer_clk_exit(&to->of_clk); + + if (flags & TIMER_OF_BASE) + timer_base_exit(&to->of_base); + goto out; +} -- cgit v1.2.3 From b7dcc4eacc45263ac5d3a0bd78c64e9ff7c94c13 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 21 Jun 2017 23:49:54 +0200 Subject: clocksource/drivers: Fix uninitialized variable use in timer_of_init If none of the flags are set, 'ret' is uninitialized as pointed out by gcc: drivers/clocksource/timer-of.c: In function 'timer_of_init': drivers/clocksource/timer-of.c:160:9: error: 'ret' may be used uninitialized in this function [-Werror=maybe-uninitialized] Since calling the function without any of the flags is an error, set the return value to -EINVAL for that case. [ tglx: Get rid of the silly backwards goto while at it ] Fixes: dc11bae78529 ("clocksource/drivers: Add timer-of common init routine") Signed-off-by: Arnd Bergmann Signed-off-by: Thomas Gleixner Cc: Daniel Lezcano Link: http://lkml.kernel.org/r/20170621215005.3870011-1-arnd@arndb.de --- drivers/clocksource/timer-of.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/clocksource/timer-of.c') diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c index be1dbee11c20..64b1c2081a67 100644 --- a/drivers/clocksource/timer-of.c +++ b/drivers/clocksource/timer-of.c @@ -130,7 +130,7 @@ static __init int timer_base_init(struct device_node *np, int __init timer_of_init(struct device_node *np, struct timer_of *to) { - int ret; + int ret = -EINVAL; int flags = 0; if (to->flags & TIMER_OF_BASE) { @@ -156,7 +156,6 @@ int __init timer_of_init(struct device_node *np, struct timer_of *to) if (!to->clkevt.name) to->clkevt.name = np->name; -out: return ret; out_fail: @@ -168,5 +167,5 @@ out_fail: if (flags & TIMER_OF_BASE) timer_base_exit(&to->of_base); - goto out; + return ret; } -- cgit v1.2.3 From 22ece4e3df6335e691207de1198a609e761b8640 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 20 Jun 2017 07:51:11 +0200 Subject: clocksource/drivers/timer-of: Fix invalid iomap check A typo in the code checks the return value of iomap against !NULL and, thus, fails everytime the mapping succeed. Fix this by inverting the condition in the check. Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/clocksource/timer-of.c') diff --git a/drivers/clocksource/timer-of.c b/drivers/clocksource/timer-of.c index 64b1c2081a67..f6e7491c873c 100644 --- a/drivers/clocksource/timer-of.c +++ b/drivers/clocksource/timer-of.c @@ -120,7 +120,7 @@ static __init int timer_base_init(struct device_node *np, const char *name = of_base->name ? of_base->name : np->full_name; of_base->base = of_io_request_and_map(np, of_base->index, name); - if (of_base->base) { + if (!of_base->base) { pr_err("Failed to iomap (%s)\n", name); return -ENXIO; } -- cgit v1.2.3