Armada 370/XP watchdog support
Subsystems (7)
v2 cover Armada 370/XP watchdog support
The second patchset to extend Orion watchdog driver adding support for Armada 370/XP SoC.
On this series I've tried to address all the issues raised when the previous patchset was submitted. See here [1] for the previous thread.
I suggest that you go through the above thread to get the full picture. Anyway, long story short, the main two issues are the ones preventing multiplatform building:
* Watchdog RSTOUT enable.
While v1 enabled the RSTOUT at each machine initialization, Jason Gunthorpe later pointed out [2] that such enabling might lead to a spurious watchdog trigger, in the event of the watchdog expired event not being cleared.
Therefore, the current patchset adds RSTOUT as a second address resource (or 'reg' entry in devicetree words) to allow different platforms specify the corresponding address of the register. This change allows to build the driver on multiplatforms builds as helps remove a mach-specific header.
The drawback of this is that the DT backwards compatibility gets broken; this was timely discussed but no better solution was achieved or proposed.
* BRIDGE CAUSE clear removal
The watchdog cause clear should be done by the bridge irqchip driver, so it's fine to remove it from the watchdog driver and instead request the interruption.
However, there are still a few platforms (orion5x, and legacy kirkwood/dove) that doesn't have this bridge irqchip support enabled. On these platforms the bridge cause clear is simply *not* done.
If we are paranoid about this, maybe we can simply add the clear on each mach-xxx/irq.c, together with the other irq is initialization.
The rest of the work is mostly the same as v1.
Patches 1-3 introduces the Atomic I/O API needed to access shared registers; this patch has been properly discussed elsewhere and has been submitted to the ARM patch tracker for its inclusion in v3.14.
Patches 2-3 uses the atomic I/O API on the clocksource and watchdog drivers. The orion clocksource patch is submitted here because the register is shared with the watchdog.
Patch 4 adds the interrupt handling as already explained above. Patch 5-6 peform the already discussed RSTOUT and BRIDGE CAUSE changes and allows multiplatform build.
Patches 7-10 extends the orion_wdt driver to support other SoCs. Patch 11 adds the Armada 370/XP support.
Patches 12-13 updates the devicetree files, patch 14 allows to build the driver on any Orion platform and finally patch 15 updates the defconfig.
This series is based on v3.13-rc8 and has been tested on:
* Kirkwood Openblocks A6
* Armada 370 Reference Design
[1] http://comments.gmane.org/gmane.linux.ports.arm.kernel/263459
[2] http://permalink.gmane.org/gmane.linux.ports.arm.kernel/263544
Ezequiel Garcia (15):
ARM: Introduce atomic MMIO modify
clocksource: orion: Use atomic access for shared registers
watchdog: orion: Use atomic access for shared registers
watchdog: orion: Handle IRQ
watchdog: orion: Make RSTOUT register a separate resource
watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
watchdog: orion: Introduce an orion_watchdog device structure
watchdog: orion: Introduce per-compatible of_device_id data
watchdog: orion: Add per-compatible clock initialization
watchdog: orion: Add per-compatible watchdog start implementation
watchdog: orion: Add support for Armada 370 and Armada XP SoC
ARM: mvebu: Enable Armada 370/XP watchdog in the devicetree
ARM: kirkwood: Add RSTOUT 'reg' entry to devicetree
watchdog: orion: Allow to build on any Orion platform
ARM: mvebu: Enable watchdog support in defconfig
.../devicetree/bindings/watchdog/marvel.txt | 8 +- arch/arm/boot/dts/armada-370-xp.dtsi | 4 + arch/arm/boot/dts/armada-370.dtsi | 5 + arch/arm/boot/dts/armada-xp.dtsi | 6 + arch/arm/boot/dts/kirkwood.dtsi | 2 +- arch/arm/configs/mvebu_defconfig | 2 + arch/arm/include/asm/io.h | 6 + arch/arm/kernel/io.c | 35 +++ arch/arm/mach-dove/include/mach/bridge-regs.h | 1 + arch/arm/mach-kirkwood/include/mach/bridge-regs.h | 1 + arch/arm/mach-mv78xx0/include/mach/bridge-regs.h | 1 + arch/arm/mach-orion5x/include/mach/bridge-regs.h | 1 + arch/arm/plat-orion/common.c | 10 +- drivers/clocksource/time-orion.c | 28 +- drivers/watchdog/Kconfig | 2 +- drivers/watchdog/orion_wdt.c | 316 ++++++++++++++++----- 16 files changed, 333 insertions(+), 95 deletions(-)
Signature · 1 line
1.8.1.5
PATCH v2 1/15 ARM: Introduce atomic MMIO modify
Some SoC have MMIO regions that are shared across orthogonal subsystems. This commit implements a possible solution for the thread-safe access of such regions through a spinlock-protected API.
Concurrent access is protected with a single spinlock for the entire MMIO address space. While this protects shared-registers, it also serializes access to unrelated/unshared registers.
We add relaxed and non-relaxed variants, by using writel_relaxed and writel, respectively. The rationale for this is that some users may not require register write completion but only thread-safe access to a register.
---
Submitted to ARM patch tracker:
http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=7930/1
arch/arm/include/asm/io.h | 6 ++++++ arch/arm/kernel/io.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+)
arch/arm/include/asm/io.h +6 -0
@@ -38,6 +38,12 @@#define isa_bus_to_virt phys_to_virt/* +* Atomic MMIO-wide IO modify +*/ +extern void atomic_io_modify (void __iomem *reg,u32 mask,u32 set); +extern void atomic_io_modify_relaxed (void __iomem *reg,u32 mask,u32 set); + +/* * Generic IO read/write. These perform native-endian accesses. Note * that some architectures will want to re-define __raw_{read,write}w. */
arch/arm/kernel/io.c +35 -0
@@ -1,6 +1,41 @@#include <linux/export.h> #include <linux/types.h> #include <linux/io.h> +#include <linux/spinlock.h> + +static DEFINE_RAW_SPINLOCK (__io_lock); + +/* +* Generic atomic MMIO modify. +* +* Allows thread-safe access to registers shared by unrelated subsystems. +* The access is protected by a single MMIO-wide lock. +*/ +void atomic_io_modify_relaxed (void __iomem *reg,u32 mask,u32 set) +{ +unsigned long flags; +u32 value; + +raw_spin_lock_irqsave (&__io_lock, flags); + value =readl_relaxed (reg) & ~mask; + value |= (set & mask); +writel_relaxed (value, reg); +raw_spin_unlock_irqrestore (&__io_lock, flags); +} +EXPORT_SYMBOL (atomic_io_modify_relaxed); + +void atomic_io_modify (void __iomem *reg,u32 mask,u32 set) +{ +unsigned long flags; +u32 value; + +raw_spin_lock_irqsave (&__io_lock, flags); + value =readl_relaxed (reg) & ~mask; + value |= (set & mask); +writel (value, reg); +raw_spin_unlock_irqrestore (&__io_lock, flags); +} +EXPORT_SYMBOL (atomic_io_modify);/* * Copy data from IO memory space to "real" memory space.
Signature · 1 line
1.8.1.5
PATCH v2 1/15 ARM: Introduce atomic MMIO modify
Quoted 8 lines · On Tuesday 21 January 2014 06:12:27 Ezequiel Garcia wrote:
Some SoC have MMIO regions that are shared across orthogonal subsystems. This commit implements a possible solution for the thread-safe access of such regions through a spinlock-protected API.
Concurrent access is protected with a single spinlock for the entire MMIO address space. While this protects shared-registers, it also serializes access to unrelated/unshared registers.
Quoted 5 lines
We add relaxed and non-relaxed variants, by using
writel_relaxedand writel, respectively. The rationale for this is that some users may not require register write completion but only thread-safe access to a register.Signed-off-by Ezequiel Garcia <[email protected]>
You add the new atomic mmio interfaces in an ARM global header file, but at the same time make them ARM-only. I'm not opposed to having interfaces like that, but I'm not convinced they are actually needed for this case and if we go there, it needs to be done more carefully and should be available for all architectures so that portable drivers can use them.
It also seems to duplicate functionality that is already present in regmap-mmio.
Arnd
PATCH v2 1/15 ARM: Introduce atomic MMIO modify
Quoted 13 lines · Arnd Bergmann
Quoted 12 lines · On Tuesday 21 January 2014 06:12:27 Ezequiel Garcia wrote:
Some SoC have MMIO regions that are shared across orthogonal subsystems. This commit implements a possible solution for the thread-safe access of such regions through a spinlock-protected API.
Concurrent access is protected with a single spinlock for the entire MMIO address space. While this protects shared-registers, it also serializes access to unrelated/unshared registers.
We add relaxed and non-relaxed variants, by using
writel_relaxedand writel, respectively. The rationale for this is that some users may not require register write completion but only thread-safe access to a register.
Quoted 9 lines
Quoted 1 line
Signed-off-by Ezequiel Garcia <[email protected]>You add the new atomic mmio interfaces in an ARM global header file, but at the same time make them ARM-only. I'm not opposed to having interfaces like that, but I'm not convinced they are actually needed for this case and if we go there, it needs to be done more carefully and should be available for all architectures so that portable drivers can use them.
Yes, true. We've discussed about this and even post an arch-generic API:
http://lwn.net/Articles/564709/
In the end it was decided to keep it ARM-specific for now:
http://www.spinics.net/lists/arm-kernel/msg271773.html
Just for reference, the last posted patchset for the atomic I/O API is this:
http://www.spinics.net/lists/arm-kernel/msg292775.html
Quoted 3 lines
It also seems to duplicate functionality that is already present in regmap-mmio.
Yes, this is true. We tried to use regmap-mmio/syscon but we need this to initialize the clocksource which is too early for that to work:
https://www.mail-archive.com/[email protected]/msg484535.html
Signature · 7 lines
Ezequiel García, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com -- To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 2/15 clocksource: orion: Use atomic access for shared registers
In reply to Ezequiel GarciaReplace the driver-specific thread-safe shared register API by the recently introduced atomic_io_clear_set().
--- drivers/clocksource/time-orion.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-)
drivers/clocksource/time-orion.c +10 -18
@@ -35,20 +35,6 @@#define ORION_ONESHOT_MAX 0xfffffffestatic void __iomem *timer_base; -static DEFINE_SPINLOCK (timer_ctrl_lock); - -/* -* Thread-safe access to TIMER_CTRL register -* (shared with watchdog timer) -*/ -void orion_timer_ctrl_clrset (u32 clr,u32 set) -{ -spin_lock (&timer_ctrl_lock); -writel ((readl (timer_base +TIMER_CTRL ) & ~clr) | set, - timer_base +TIMER_CTRL ); -spin_unlock (&timer_ctrl_lock); -} -EXPORT_SYMBOL (orion_timer_ctrl_clrset);/* * Free-running clocksource handling.
@@ -68,7 +54,8 @@ static int orion_clkevt_next_event(unsigned long delta, {/* setup and enable one-shot timer */ writel (delta, timer_base +TIMER1_VAL ); -orion_timer_ctrl_clrset (TIMER1_RELOAD_EN ,TIMER1_EN ); +atomic_io_modify (timer_base +TIMER_CTRL , +TIMER1_RELOAD_EN |TIMER1_EN ,TIMER1_EN );return 0 ; }
@@ -80,10 +67,13 @@ static void orion_clkevt_mode(enum clock_event_mode mode,/* setup and enable periodic timer at 1/HZ intervals */ writel (ticks_per_jiffy -1 , timer_base +TIMER1_RELOAD );writel (ticks_per_jiffy -1 , timer_base +TIMER1_VAL ); -orion_timer_ctrl_clrset (0 ,TIMER1_RELOAD_EN |TIMER1_EN ); +atomic_io_modify (timer_base +TIMER_CTRL , +TIMER1_RELOAD_EN |TIMER1_EN , +TIMER1_RELOAD_EN |TIMER1_EN ); }else {/* disable timer */ -orion_timer_ctrl_clrset (TIMER1_RELOAD_EN |TIMER1_EN ,0 ); +atomic_io_modify (timer_base +TIMER_CTRL , +TIMER1_RELOAD_EN |TIMER1_EN ,0 ); } }
@@ -131,7 +121,9 @@ static void __init orion_timer_init(struct device_node *np)/* setup timer0 as free-running clocksource */ writel (~0 , timer_base +TIMER0_VAL );writel (~0 , timer_base +TIMER0_RELOAD ); -orion_timer_ctrl_clrset (0 ,TIMER0_RELOAD_EN |TIMER0_EN ); +atomic_io_modify (timer_base +TIMER_CTRL , +TIMER0_RELOAD_EN |TIMER0_EN , +TIMER0_RELOAD_EN |TIMER0_EN );clocksource_mmio_init (timer_base +TIMER0_VAL ,"orion_clocksource" ,clk_get_rate (clk),300 ,32 , clocksource_mmio_readl_down);
Signature · 1 line
1.8.1.5
PATCH v2 2/15 clocksource: orion: Use atomic access for shared registers
drivers/clocksource/time-orion.c line 51
Quoted 12 lines · On Tuesday 21 January 2014 06:12:28 Ezequiel Garcia wrote:
drivers/clocksource/time-orion.c +0
-12-/* -* Thread-safe access to TIMER_CTRL register -* (shared with watchdog timer) -*/ -void orion_timer_ctrl_clrset (u32 clr,u32 set) -{ -spin_lock (&timer_ctrl_lock); -writel ((readl (timer_base +TIMER_CTRL ) & ~clr) | set, - timer_base +TIMER_CTRL ); -spin_unlock (&timer_ctrl_lock); -} -EXPORT_SYMBOL (orion_timer_ctrl_clrset);
I don't understand what's wrong with this function, it seems like a cleaner approach than touching the register directly from two different drivers. Is this something that would only work on orion but not on armadaxp?
Arnd
Sebastian Hesselbarth
maintainerPATCH v2 2/15 clocksource: orion: Use atomic access for shared registers
Quoted 10 lines · Arnd Bergmann
Quoted 9 lines · On Tuesday 21 January 2014 06:12:28 Ezequiel Garcia wrote:
drivers/clocksource/time-orion.c +0
-9-/* -* Thread-safe access to TIMER_CTRL register -* (shared with watchdog timer) -*/ -void orion_timer_ctrl_clrset (u32 clr,u32 set) -{ -spin_lock (&timer_ctrl_lock); -writel ((readl (timer_base +TIMER_CTRL ) & ~clr) | set, - timer_base +TIMER_CTRL );
Quoted 8 lines
drivers/clocksource/time-orion.c line 51
Quoted 3 lines
drivers/clocksource/time-orion.c +0
-3-spin_unlock (&timer_ctrl_lock); -} -EXPORT_SYMBOL (orion_timer_ctrl_clrset);I don't understand what's wrong with this function, it seems like a cleaner approach than touching the register directly from two different drivers. Is this something that would only work on orion but not on armadaxp?
The real problem with this is that it resides in orion-time.c which is fine for Orion SoCs. Armada 370/XP use a different timer and therefore the _common_ watchdog driver cannot call this function.
Moreover, Dove (out of Orion) and Armada 370/XP will happily live in one V7 kernel with both time-orion and time-armada-370-xp compiled in.
The idea of the atomic readl/writel was to have something lightweight and _early_ to allow such locking even for timers.
IIRC, there was some kind of consensus that it is okay to have atomic readl/writel here.
Sebastian
PATCH v2 2/15 clocksource: orion: Use atomic access for shared registers
Quoted 20 lines · On Tuesday 21 January 2014 10:58:17 Sebastian Hesselbarth wrote:
Quoted 10 lines · Arnd Bergmann
Quoted 9 lines · On Tuesday 21 January 2014 06:12:28 Ezequiel Garcia wrote:
drivers/clocksource/time-orion.c +0
-9-/* -* Thread-safe access to TIMER_CTRL register -* (shared with watchdog timer) -*/ -void orion_timer_ctrl_clrset (u32 clr,u32 set) -{ -spin_lock (&timer_ctrl_lock); -writel ((readl (timer_base +TIMER_CTRL ) & ~clr) | set, - timer_base +TIMER_CTRL );Quoted 8 lines
drivers/clocksource/time-orion.c line 51
Quoted 3 lines
drivers/clocksource/time-orion.c +0
-3-spin_unlock (&timer_ctrl_lock); -} -EXPORT_SYMBOL (orion_timer_ctrl_clrset);I don't understand what's wrong with this function, it seems like a cleaner approach than touching the register directly from two different drivers. Is this something that would only work on orion but not on armadaxp?
Quoted 3 lines
The real problem with this is that it resides in
orion-time.cwhich is fine for Orion SoCs. Armada 370/XP use a different timer and therefore the _common_ watchdog driver cannot call this function.
Right, I had missed this part.
Quoted 2 lines
Moreover, Dove (out of Orion) and Armada 370/XP will happily live in one V7 kernel with both time-orion and time-armada-370-xp compiled in.
It still wouldn't be too hard to do: both clock drivers could export functions with different identifiers, and the wdt driver can use conditional compilation (#ifdef or if(IS_ENABLED())) to only call those functions when the respective clocksource drivers are enabled.
I think the part where it went wrong is the fact that we have two device nodes in DT that claim the same register range, which should not have happened, but seems too hard to fix now without breaking one part or another.
Quoted 5 lines
The idea of the atomic readl/writel was to have something lightweight and _early_ to allow such locking even for timers.
IIRC, there was some kind of consensus that it is okay to have atomic readl/writel here.
Ok, Ezequiel pointed me to that discussion now, seems ok then.
Arnd
Andrew Lunn
maintainerPATCH v2 2/15 clocksource: orion: Use atomic access for shared registers
Quoted 6 lines
Quoted 3 lines
The real problem with this is that it resides in
orion-time.cwhich is fine for Orion SoCs. Armada 370/XP use a different timer and therefore the _common_ watchdog driver cannot call this function.Right, I had missed this part.
Quoted 7 lines
Quoted 2 lines
Moreover, Dove (out of Orion) and Armada 370/XP will happily live in one V7 kernel with both time-orion and time-armada-370-xp compiled in.
It still wouldn't be too hard to do: both clock drivers could export functions with different identifiers, and the wdt driver can use conditional compilation (#ifdef or if(IS_ENABLED())) to only call those functions when the respective clocksource drivers are enabled.
Hi Arnd.
The plan is to make dove part of MULTI_V7. At that point, you have both dove and armada-370-xp in the same kernel. Conditional compilation does not work, the watchdog driver would need to know at runtime which timer is in use, and call the right timer function.
I'm working on making DT Kirkwood part of MULTI_V5. The changes needed are mostly trivial. I expect making Dove part of MULTI_V7 is also trivial, so could happen during the next cycle. So this mix of Dove and Armada 370 XP is not a theoretical problem, it is something which needs to be solved ready for merging during the next window.
Andrew
PATCH v2 2/15 clocksource: orion: Use atomic access for shared registers
In reply to Ezequiel GarciaQuoted 4 lines · Ezequiel Garcia
Replace the driver-specific thread-safe shared register API by the recently introduced
atomic_io_clear_set().Signed-off-by Ezequiel Garcia <[email protected]>
Hi Ezequiel,
in the future, put me in Cc when modifying files in clocksource that will make my life easier to track the changes.
Thanks.
-- Daniel
Quoted 29 lines
--- drivers/clocksource/time-orion.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-)drivers/clocksource/time-orion.c +0
-14@@ -35,20 +35,6 @@#define ORION_ONESHOT_MAX 0xfffffffestatic void __iomem *timer_base; -static DEFINE_SPINLOCK (timer_ctrl_lock); - -/* -* Thread-safe access to TIMER_CTRL register -* (shared with watchdog timer) -*/ -void orion_timer_ctrl_clrset (u32 clr,u32 set) -{ -spin_lock (&timer_ctrl_lock); -writel ((readl (timer_base +TIMER_CTRL ) & ~clr) | set, - timer_base +TIMER_CTRL ); -spin_unlock (&timer_ctrl_lock); -} -EXPORT_SYMBOL (orion_timer_ctrl_clrset);/* * Free-running clocksource handling.
drivers/clocksource/time-orion.c static int orion_clkevt_next_event(unsigned long delta, · line 58
Quoted 6 lines
drivers/clocksource/time-orion.c +2
-1@@ -68,7 +54,8 @@ static int orion_clkevt_next_event(unsigned long delta, {/* setup and enable one-shot timer */ writel (delta, timer_base +TIMER1_VAL ); -orion_timer_ctrl_clrset (TIMER1_RELOAD_EN ,TIMER1_EN ); +atomic_io_modify (timer_base +TIMER_CTRL , +TIMER1_RELOAD_EN |TIMER1_EN ,TIMER1_EN );
I am not convinced this change is worth.
Could you elaborate the race the spinlock should prevent ?
Quoted 31 lines
drivers/clocksource/time-orion.c +8
-3return 0 ; }@@ -80,10 +67,13 @@ static void orion_clkevt_mode(enum clock_event_mode mode,/* setup and enable periodic timer at 1/HZ intervals */ writel (ticks_per_jiffy -1 , timer_base +TIMER1_RELOAD );writel (ticks_per_jiffy -1 , timer_base +TIMER1_VAL ); -orion_timer_ctrl_clrset (0 ,TIMER1_RELOAD_EN |TIMER1_EN ); +atomic_io_modify (timer_base +TIMER_CTRL , +TIMER1_RELOAD_EN |TIMER1_EN , +TIMER1_RELOAD_EN |TIMER1_EN ); }else {/* disable timer */ -orion_timer_ctrl_clrset (TIMER1_RELOAD_EN |TIMER1_EN ,0 ); +atomic_io_modify (timer_base +TIMER_CTRL , +TIMER1_RELOAD_EN |TIMER1_EN ,0 ); } }@@ -131,7 +121,9 @@ static void __init orion_timer_init(struct device_node *np)/* setup timer0 as free-running clocksource */ writel (~0 , timer_base +TIMER0_VAL );writel (~0 , timer_base +TIMER0_RELOAD ); -orion_timer_ctrl_clrset (0 ,TIMER0_RELOAD_EN |TIMER0_EN ); +atomic_io_modify (timer_base +TIMER_CTRL , +TIMER0_RELOAD_EN |TIMER0_EN , +TIMER0_RELOAD_EN |TIMER0_EN );clocksource_mmio_init (timer_base +TIMER0_VAL ,"orion_clocksource" ,clk_get_rate (clk),300 ,32 , clocksource_mmio_readl_down);
Signature · 5 lines
<http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook | <http://twitter.com/#!/linaroorg> Twitter | <http://www.linaro.org/linaro-blog/> Blog
PATCH v2 2/15 clocksource: orion: Use atomic access for shared registers
Hello Daniel,
Quoted 9 lines · Daniel Lezcano
Quoted 4 lines · Ezequiel Garcia
Replace the driver-specific thread-safe shared register API by the recently introduced
atomic_io_clear_set().Signed-off-by Ezequiel Garcia <[email protected]>in the future, put me in Cc when modifying files in clocksource that will make my life easier to track the changes.
Ouch, sorry about that.
[..]
Quoted 12 lines
drivers/clocksource/time-orion.c static int orion_clkevt_next_event(unsigned long delta, · line 58
Quoted 9 lines
/*
* Free-running clocksource handling.drivers/clocksource/time-orion.c +2
-1@@ -68,7 +54,8 @@ static int orion_clkevt_next_event(unsigned long delta, {/* setup and enable one-shot timer */ writel (delta, timer_base +TIMER1_VAL ); -orion_timer_ctrl_clrset (TIMER1_RELOAD_EN ,TIMER1_EN ); +atomic_io_modify (timer_base +TIMER_CTRL , +TIMER1_RELOAD_EN |TIMER1_EN ,TIMER1_EN );I am not convinced this change is worth.
Quoted 2 lines
Could you elaborate the race the spinlock should prevent ?
Sure. Take a look to the patchset that adds the atomic I/O (sorry again for not Ccing you on that one):
http://www.spinics.net/lists/arm-kernel/msg292775.html
The TIMER_CTRL register provides clocksource and watchdog control, so we need a safe way to access the register, since we're sharing it on two completely unrelated drivers.
Signature · 7 lines
Ezequiel García, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com -- To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 3/15 watchdog: orion: Use atomic access for shared registers
In reply to Ezequiel GarciaSince the timer control register is shared with the clocksource driver, use the recently introduced atomic_io_clear_set() to access such register.
--- drivers/watchdog/orion_wdt.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-)
drivers/watchdog/orion_wdt.c +4 -16
@@ -61,8 +61,6 @@ static int orion_wdt_ping(struct watchdog_device *wdt_dev)static int orion_wdt_start (struct watchdog_device *wdt_dev) { -u32 reg; -spin_lock (&wdt_lock);/* Set watchdog duration */
@@ -72,14 +70,10 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)writel (~WDT_INT_REQ ,BRIDGE_CAUSE );/* Enable watchdog timer */ - reg =readl (wdt_reg +TIMER_CTRL ); - reg |=WDT_EN ; -writel (reg, wdt_reg +TIMER_CTRL ); +atomic_io_modify (wdt_reg +TIMER_CTRL ,WDT_EN ,WDT_EN );/* Enable reset on watchdog */ - reg =readl (RSTOUTn_MASK); - reg |=WDT_RESET_OUT_EN ; -writel (reg, RSTOUTn_MASK); +atomic_io_modify (RSTOUTn_MASK,WDT_RESET_OUT_EN ,WDT_RESET_OUT_EN );spin_unlock (&wdt_lock);return 0 ;
@@ -87,19 +81,13 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)static int orion_wdt_stop (struct watchdog_device *wdt_dev) { -u32 reg; -spin_lock (&wdt_lock);/* Disable reset on watchdog */ - reg =readl (RSTOUTn_MASK); - reg &= ~WDT_RESET_OUT_EN ; -writel (reg, RSTOUTn_MASK); +atomic_io_modify (RSTOUTn_MASK,WDT_RESET_OUT_EN ,0 );/* Disable watchdog timer */ - reg =readl (wdt_reg +TIMER_CTRL ); - reg &= ~WDT_EN ; -writel (reg, wdt_reg +TIMER_CTRL ); +atomic_io_modify (wdt_reg +TIMER_CTRL ,WDT_EN ,0 );spin_unlock (&wdt_lock);return 0 ;
Signature · 1 line
1.8.1.5
PATCH v2 3/15 watchdog: orion: Use atomic access for shared registers
Quoted 13 lines · Ezequiel Garcia
Since the timer control register is shared with the clocksource driver, use the recently introduced
atomic_io_clear_set()to access such register.Signed-off-by Ezequiel Garcia <[email protected]>--- drivers/watchdog/orion_wdt.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-)drivers/watchdog/orion_wdt.c +0
-0
drivers/watchdog/orion_wdt.c static int orion_wdt_ping(struct watchdog_device *wdt_dev) · line 64
Quoted 6 lines
drivers/watchdog/orion_wdt.c +0
-2@@ -61,8 +61,6 @@ static int orion_wdt_ping(struct watchdog_device *wdt_dev)static int orion_wdt_start (struct watchdog_device *wdt_dev) { -u32 reg; -spin_lock (&wdt_lock);
Shouldn't this spin_lock be dropped now?
Regards,
Fabio Estevam
PATCH v2 3/15 watchdog: orion: Use atomic access for shared registers
Quoted 16 lines · Fabio Estevam
Quoted 14 lines · Ezequiel Garcia
Since the timer control register is shared with the clocksource driver, use the recently introduced
atomic_io_clear_set()to access such register.Signed-off-by Ezequiel Garcia <[email protected]>--- drivers/watchdog/orion_wdt.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-)drivers/watchdog/orion_wdt.c +0
-0@@ -61,8 +61,6 @@ static int orion_wdt_ping(struct watchdog_device *wdt_dev)
Quoted 8 lines
drivers/watchdog/orion_wdt.c static int orion_wdt_ping(struct watchdog_device *wdt_dev) · line 64
Quoted 5 lines
drivers/watchdog/orion_wdt.c +0
-2static int orion_wdt_start (struct watchdog_device *wdt_dev) { -u32 reg; -spin_lock (&wdt_lock);Shouldn't this
spin_lockbe dropped now?
Hm... yes. The watchdog core uses a mutex to serialize all the watchdog hooks:
start, stop, ping, set_timeout, etc. So it seems you're right, the spinlock should be dropped entirely as I see no need for it.
Thanks for the feedback,
Signature · 3 lines
Ezequiel Garc?a, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com
PATCH v2 3/15 watchdog: orion: Use atomic access for shared registers
In reply to Ezequiel Garciadrivers/watchdog/orion_wdt.c static int orion_wdt_start(struct watchdog_device *wdt_dev) · line 73
Quoted 7 lines · On Tuesday 21 January 2014 06:12:29 Ezequiel Garcia wrote:
writel(~WDT_INT_REQ, BRIDGE_CAUSE); /* Enable watchdog timer */drivers/watchdog/orion_wdt.c +1
-3- reg =readl (wdt_reg +TIMER_CTRL ); - reg |=WDT_EN ; -writel (reg, wdt_reg +TIMER_CTRL ); +atomic_io_modify (wdt_reg +TIMER_CTRL ,WDT_EN ,WDT_EN );
As mentioned in my comment for patch 2, it seems that the exported orion_timer_ctrl_clrset() function would be more appropriate for this.
drivers/watchdog/orion_wdt.c static int orion_wdt_start(struct watchdog_device *wdt_dev) · line 76
Quoted 5 lines
/* Enable reset on watchdog */drivers/watchdog/orion_wdt.c +1
-3- reg =readl (RSTOUTn_MASK); - reg |=WDT_RESET_OUT_EN ; -writel (reg, RSTOUTn_MASK); +atomic_io_modify (RSTOUTn_MASK,WDT_RESET_OUT_EN ,WDT_RESET_OUT_EN );
And this register already has an abstraction in arch/arm/mach-mvebu/system-controller.c. I would prefer to find a way to generalize that. I can see multiple ways to do that:
* Turn the "marvell,armada-370-xp-system-controller" device into a "syscon" device that can be used through regmap from other parts of the kernel.
* Move arch/arm/mach-mvebu/system-controller.c into drivers/soc (we don't have this directory yet, but have discussed it in the past) to export soc-specific functions from there.
* Move all of the system-controller implementation into the wdt driver and require that this driver be enabled in order to do regular system reset. The system-controller can register itself as a reboot hook, so you can remove the ".restart = mvebu_restart" part from mach-mvebu.
Arnd
Andrew Lunn
maintainerPATCH v2 3/15 watchdog: orion: Use atomic access for shared registers
Quoted 11 lines · Arnd Bergmann
drivers/watchdog/orion_wdt.c static int orion_wdt_start(struct watchdog_device *wdt_dev) · line 73
Quoted 7 lines · On Tuesday 21 January 2014 06:12:29 Ezequiel Garcia wrote:
writel(~WDT_INT_REQ, BRIDGE_CAUSE); /* Enable watchdog timer */drivers/watchdog/orion_wdt.c +1
-3- reg =readl (wdt_reg +TIMER_CTRL ); - reg |=WDT_EN ; -writel (reg, wdt_reg +TIMER_CTRL ); +atomic_io_modify (wdt_reg +TIMER_CTRL ,WDT_EN ,WDT_EN );As mentioned in my comment for patch 2, it seems that the exported
orion_timer_ctrl_clrset()function would be more appropriate for this.
Hi Arnd
As Sebastian points out, Armada 370 XP does not have this function.
Quoted 10 lines
drivers/watchdog/orion_wdt.c static int orion_wdt_start(struct watchdog_device *wdt_dev) · line 76
Quoted 6 lines
/* Enable reset on watchdog */drivers/watchdog/orion_wdt.c +1
-3- reg =readl (RSTOUTn_MASK); - reg |=WDT_RESET_OUT_EN ; -writel (reg, RSTOUTn_MASK); +atomic_io_modify (RSTOUTn_MASK,WDT_RESET_OUT_EN ,WDT_RESET_OUT_EN );And this register already has an abstraction in
arch/arm/mach-mvebu/system-controller.c. I would prefer to find a way to generalize that. I can see multiple ways to do that:
Please be aware that arch/arm/mach-mvebu/system-controller.c is currently DT only. We need a solution which works for both with DT and without DT, since orion5x and mv78xx0 none DT boards are not going away soon.
Andrew
PATCH v2 4/15 watchdog: orion: Handle IRQ
In reply to Ezequiel GarciaDT-enabled where an irqchip driver for the brigde interrupt controller is available can handle the watchdog IRQ properly. Therefore, we request the interruption and add a dummy handler that merely calls panic().
This is done in order to have an initial 'ack' of the interruption, which clears the watchdog state.
Furthermore, since some platforms don't have such IRQ, this commit makes the interruption specification optional.
--- .../devicetree/bindings/watchdog/marvel.txt | 2 ++ drivers/watchdog/orion_wdt.c | 22 +++++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/watchdog/marvel.txt +2 -0
@@ -7,6 +7,7 @@ Required Properties: Optional properties: +- interrupts : Contains the IRQ for watchdog expiration - timeout-sec : Contains the watchdog timeout in seconds Example:
@@ -14,6 +15,7 @@ Example: wdt at 20300 { compatible = "marvell,orion-wdt"; reg = <0x20300 0x28>; + interrupts = <3>; timeout-sec = <10>; status = "okay"; };
drivers/watchdog/orion_wdt.c +21 -1
@@ -19,6 +19,7 @@#include <linux/platform_device.h> #include <linux/watchdog.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/io.h> #include <linux/spinlock.h> #include <linux/clk.h>
@@ -131,10 +132,16 @@ static struct watchdog_device orion_wdt = { .min_timeout = 1, }; +static irqreturn_t orion_wdt_irq (int irq,void *devid) +{ +panic ("Watchdog Timeout" ); +return IRQ_HANDLED ; +} +static int orion_wdt_probe (struct platform_device *pdev) {struct resource *res; -int ret; +int ret, irq; clk =devm_clk_get (&pdev->dev,NULL );if (IS_ERR (clk)) {
@@ -151,6 +158,19 @@ static int orion_wdt_probe(struct platform_device *pdev)if (!wdt_reg)return -ENOMEM ; + irq =platform_get_irq (pdev,0 ); +if (irq >0 ) { +/* +* Not all supported platforms specify an interruption for the +* watchdog, so let's make it optional. +*/ + ret =request_irq (irq, orion_wdt_irq,0 , pdev->name,NULL ); +if (ret <0 ) { +dev_err (&pdev->dev,"failed to request IRQ\n" ); +return ret; + } + } + wdt_max_duration =WDT_MAX_CYCLE_COUNT / wdt_tclk; orion_wdt.timeout = wdt_max_duration;
Signature · 1 line
1.8.1.5
PATCH v2 5/15 watchdog: orion: Make RSTOUT register a separate resource
In reply to Ezequiel GarciaIn order to support other SoC, it's required to distinguish the 'control' timer register, from the 'rstout' register that enables system reset on watchdog expiration.
--- Documentation/devicetree/bindings/watchdog/marvel.txt | 6 ++++-- arch/arm/mach-dove/include/mach/bridge-regs.h | 1 + arch/arm/mach-kirkwood/include/mach/bridge-regs.h | 1 + arch/arm/mach-mv78xx0/include/mach/bridge-regs.h | 1 + arch/arm/mach-orion5x/include/mach/bridge-regs.h | 1 + arch/arm/plat-orion/common.c | 10 ++++++---- drivers/watchdog/orion_wdt.c | 12 ++++++++++-- 7 files changed, 24 insertions(+), 8 deletions(-)
Documentation/devicetree/bindings/watchdog/marvel.txt +4 -2
@@ -3,7 +3,9 @@ Required Properties: - Compatibility : "marvell,orion-wdt" -- reg : Address of the timer registers +- reg : Should contain two entries: first one with the + timer control address, second one with the + rstout enable address. Optional properties:
@@ -14,7 +16,7 @@ Example: wdt at 20300 { compatible = "marvell,orion-wdt"; - reg = <0x20300 0x28>; + reg = <0x20300 0x28>, <0x20108 0x4>; interrupts = <3>; timeout-sec = <10>; status = "okay";
arch/arm/mach-dove/include/mach/bridge-regs.h +1 -0
@@ -21,6 +21,7 @@#define CPU_CTRL_PCIE1_LINK 0x00000008#define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108) +#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108)#define SOFT_RESET_OUT_EN 0x00000004#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c)
arch/arm/mach-kirkwood/include/mach/bridge-regs.h +1 -0
@@ -21,6 +21,7 @@#define CPU_RESET 0x00000002#define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108) +#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108)#define SOFT_RESET_OUT_EN 0x00000004#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c)
arch/arm/mach-mv78xx0/include/mach/bridge-regs.h +1 -0
@@ -15,6 +15,7 @@#define L2_WRITETHROUGH 0x00020000#define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108) +#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108)#define SOFT_RESET_OUT_EN 0x00000004#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c)
arch/arm/mach-orion5x/include/mach/bridge-regs.h +1 -0
@@ -18,6 +18,7 @@#define CPU_CTRL (ORION5X_BRIDGE_VIRT_BASE + 0x104)#define RSTOUTn_MASK (ORION5X_BRIDGE_VIRT_BASE + 0x108) +#define RSTOUTn_MASK_PHYS (ORION5X_BRIDGE_PHYS_BASE + 0x108)#define CPU_SOFT_RESET (ORION5X_BRIDGE_VIRT_BASE + 0x10c)
arch/arm/plat-orion/common.c +6 -4
@@ -594,14 +594,16 @@ void __init orion_spi_1_init(unsigned long mapbase)/***************************************************************************** * Watchdog ****************************************************************************/ -static struct resource orion_wdt_resource = -DEFINE_RES_MEM (TIMER_PHYS_BASE ,0x28 ); +static struct resource orion_wdt_resource[] = { +DEFINE_RES_MEM (TIMER_PHYS_BASE ,0x04 ), +DEFINE_RES_MEM (RSTOUTn_MASK_PHYS,0x04 ), +};static struct platform_device orion_wdt_device = { .name ="orion_wdt" , .id =-1 , - .num_resources =1 , - .resource = &orion_wdt_resource, + .num_resources =ARRAY_SIZE (orion_wdt_resource), + .resource = orion_wdt_resource, };void __init orion_wdt_init (void )
drivers/watchdog/orion_wdt.c +10 -2
@@ -47,6 +47,7 @@ static unsigned int wdt_max_duration; /* (seconds) */static struct clk *clk;static unsigned int wdt_tclk;static void __iomem *wdt_reg; +static void __iomem *wdt_rstout;static DEFINE_SPINLOCK (wdt_lock);static int orion_wdt_ping (struct watchdog_device *wdt_dev)
@@ -74,7 +75,7 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)atomic_io_modify (wdt_reg +TIMER_CTRL ,WDT_EN ,WDT_EN );/* Enable reset on watchdog */ -atomic_io_modify (RSTOUTn_MASK,WDT_RESET_OUT_EN ,WDT_RESET_OUT_EN ); +atomic_io_modify (wdt_rstout,WDT_RESET_OUT_EN ,WDT_RESET_OUT_EN );spin_unlock (&wdt_lock);return 0 ;
@@ -85,7 +86,7 @@ static int orion_wdt_stop(struct watchdog_device *wdt_dev)spin_lock (&wdt_lock);/* Disable reset on watchdog */ -atomic_io_modify (RSTOUTn_MASK,WDT_RESET_OUT_EN ,0 ); +atomic_io_modify (wdt_rstout,WDT_RESET_OUT_EN ,0 );/* Disable watchdog timer */ atomic_io_modify (wdt_reg +TIMER_CTRL ,WDT_EN ,0 );
@@ -158,6 +159,13 @@ static int orion_wdt_probe(struct platform_device *pdev)if (!wdt_reg)return -ENOMEM ; + res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); +if (!res) +return -ENODEV ; + wdt_rstout =devm_ioremap (&pdev->dev, res->start,resource_size (res)); +if (!wdt_rstout) +return -ENOMEM ; + irq =platform_get_irq (pdev,0 );if (irq >0 ) {/*
Signature · 1 line
1.8.1.5
PATCH v2 5/15 watchdog: orion: Make RSTOUT register a separate resource
drivers/watchdog/orion_wdt.c static int orion_wdt_probe(struct platform_device *pdev) · line 164
Quoted 7 lines · Ezequiel Garcia
In order to support other SoC, it's required to distinguish the 'control' timer register, from the 'rstout' register that enables system reset on watchdog expiration.
drivers/watchdog/orion_wdt.c +3
-0+ res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); +if (!res) +return -ENODEV ;
^^^^^^^^^^^^^^^^^^^^^^
This change seems to break compatibility with existing DT files that have only a single entry in reg?
Can the value be defaulted some how if missing?
Regards,
Jason
PATCH v2 5/15 watchdog: orion: Make RSTOUT register a separate resource
Quoted 8 lines · On Tuesday 21 January 2014 16:33:21 Jason Gunthorpe wrote:
drivers/watchdog/orion_wdt.c static int orion_wdt_probe(struct platform_device *pdev) · line 164
Quoted 7 lines · Ezequiel Garcia
In order to support other SoC, it's required to distinguish the 'control' timer register, from the 'rstout' register that enables system reset on watchdog expiration.
drivers/watchdog/orion_wdt.c +3
-0+ res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); +if (!res) +return -ENODEV ;
Quoted 6 lines
^^^^^^^^^^^^^^^^^^^^^^This change seems to break compatibility with existing DT files that have only a single entry in reg?
Can the value be defaulted some how if missing?
I think this is a direct consequence of the attempt to remove the header file dependency, since the RSTOUTn_MASK macro is defined in mach/bridge-regs.h.
I don't see a good way out that would preserve backwards compatibility, other than hardcoding the physical address in the driver, which seems just as bad as breaking compatibility. That said, it is always the same constant (0xf1000000 + 0x20000 + 0x0108) on Dove, Kirkwood and Orion5x (not on mv78xx0, but that doesn't use the wdt), so hardcoding a fallback would technically work, but we should print a fat warning at boot time if we actually fall back to that.
Arnd
PATCH v2 5/15 watchdog: orion: Make RSTOUT register a separate resource
Jason, Arnd:
Quoted 11 lines · Arnd Bergmann
Quoted 10 lines · On Tuesday 21 January 2014 16:33:21 Jason Gunthorpe wrote:
drivers/watchdog/orion_wdt.c static int orion_wdt_probe(struct platform_device *pdev) · line 164
Quoted 7 lines · Ezequiel Garcia
In order to support other SoC, it's required to distinguish the 'control' timer register, from the 'rstout' register that enables system reset on watchdog expiration.
drivers/watchdog/orion_wdt.c +3
-0+ res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); +if (!res) +return -ENODEV ;^^^^^^^^^^^^^^^^^^^^^^
Quoted 9 lines
Quoted 4 lines
This change seems to break compatibility with existing DT files that have only a single entry in reg?
Can the value be defaulted some how if missing?
I think this is a direct consequence of the attempt to remove the header file dependency, since the
RSTOUTn_MASKmacro is defined inmach/bridge-regs.h.
Exactly. Just for the record, I warned about this a while back:
http://www.spinics.net/lists/arm-kernel/msg270163.html
That said, it truly sucks to break compatibility so finding a way to keep backwards compatibility would be certainly desirable.
Quoted 8 lines
I don't see a good way out that would preserve backwards compatibility, other than hardcoding the physical address in the driver, which seems just as bad as breaking compatibility. That said, it is always the same constant (
0xf1000000+0x20000+0x0108) on Dove, Kirkwood and Orion5x (not on mv78xx0, but that doesn't use the wdt), so hardcoding a fallback would technically work, but we should print a fat warning at boot time if we actually fall back to that.
Yes, I was thinking just about this. Namely:
If the second resource is missing *and* the compatible-string is "orion-watchdog" (or it's not DT-registered), then use a hardcoded RSTOUTn_MASK address. And pr_warn() something.
Thanks for the feedback,
Signature · 7 lines
Ezequiel García, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com -- To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 5/15 watchdog: orion: Make RSTOUT register a separate resource
Quoted 11 lines · Ezequiel Garcia
Quoted 8 lines
I don't see a good way out that would preserve backwards compatibility, other than hardcoding the physical address in the driver, which seems just as bad as breaking compatibility. That said, it is always the same constant (
0xf1000000+0x20000+0x0108) on Dove, Kirkwood and Orion5x (not on mv78xx0, but that doesn't use the wdt), so hardcoding a fallback would technically work, but we should print a fat warning at boot time if we actually fall back to that.Yes, I was thinking just about this. Namely:
[..]
How about something like this?
drivers/watchdog/orion_wdt.c +28 -4
@@ -26,6 +26,9 @@#include <linux/of.h> #include <mach/bridge-regs.h> +/* RSTOUT mask register physical address for Orion5x, Kirkwood and Dove */ +#define ORION_RSTOUT_MASK 0xf1020108 +/* * Watchdog timer block registers. */
@@ -119,6 +122,30 @@ static irqreturn_t orion_wdt_irq(int irq, void *devid)return IRQ_HANDLED ; } +/* +* The original devicetree binding for this driver specified only +* one memory resource, so in order to keep DT backwards compatibility +* we try to fallback to a hardcoded register address, if the resource +* is missing from the devicetree. +*/ +static void __iomem *try_compat_rstout_ioremap (struct platform_device *pdev) +{ +struct resource *res; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); +if (res) +return devm_ioremap (&pdev->dev, res->start, +resource_size (res)); + +/* This workaround works only for "orion-wdt", DT-enabled */ +if (!of_device_is_compatible (pdev->dev.of_node,"marvell,orion-wdt" )) +return NULL ; + +dev_warn (&pdev->dev,"falling back to harcoded RSTOUT reg 0x%x\n" , +ORION_RSTOUT_MASK ); +return devm_ioremap (&pdev->dev,ORION_RSTOUT_MASK ,0x4 ); +} +static int orion_wdt_probe (struct platform_device *pdev) {struct resource *res;
@@ -139,10 +166,7 @@ static int orion_wdt_probe(struct platform_device *pdev)if (!wdt_reg)return -ENOMEM ; - res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); -if (!res) -return -ENODEV ; - wdt_rstout =devm_ioremap (&pdev->dev, res->start,resource_size (res)); + wdt_rstout =try_compat_rstout_ioremap (pdev);if (!wdt_rstout)return -ENOMEM ;
Signature · 7 lines
Ezequiel García, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com -- To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 5/15 watchdog: orion: Make RSTOUT register a separate resource
Quoted 10 lines · Ezequiel Garcia
Quoted 9 lines · Ezequiel Garcia
Quoted 8 lines
I don't see a good way out that would preserve backwards compatibility, other than hardcoding the physical address in the driver, which seems just as bad as breaking compatibility. That said, it is always the same constant (
0xf1000000+0x20000+0x0108) on Dove, Kirkwood and Orion5x (not on mv78xx0, but that doesn't use the wdt), so hardcoding a fallback would technically work, but we should print a fat warning at boot time if we actually fall back to that.
Quoted 5 lines
Quoted 2 lines
Yes, I was thinking just about this. Namely:
[..]
How about something like this?
I liked Arnd's idea to use an offset from the first register. With the mbus driver we can now actually change the 0xF1.. prefix via the DT.
drivers/watchdog/orion_wdt.c static irqreturn_t orion_wdt_irq(int irq, void *devid) · line 145
Quoted 2 lines
drivers/watchdog/orion_wdt.c +2
-0+dev_warn (&pdev->dev,"falling back to harcoded RSTOUT reg 0x%x\n" , +ORION_RSTOUT_MASK );
Maybe:
dev_warn(&pdev->dev, FW_BUG "falling back to harcoded RSTOUT reg 0x%x\n",
?
drivers/watchdog/orion_wdt.c static int orion_wdt_probe(struct platform_device *pdev) · line 171
Quoted 11 lines
drivers/watchdog/orion_wdt.c +1
-4@@ -139,10 +166,7 @@ static int orion_wdt_probe(struct platform_device *pdev)if (!wdt_reg)return -ENOMEM ; - res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); -if (!res) -return -ENODEV ; - wdt_rstout =devm_ioremap (&pdev->dev, res->start,resource_size (res)); + wdt_rstout =try_compat_rstout_ioremap (pdev);if (!wdt_rstout)return -ENOMEM ;
ENOMEM is probably not the right errno? Is there a standard errno for malformed DT?
Jason
PATCH v2 5/15 watchdog: orion: Make RSTOUT register a separate resource
Quoted 11 lines · On Wednesday 22 January 2014 11:14:09 Jason Gunthorpe wrote:
Quoted 10 lines · Ezequiel Garcia
Quoted 9 lines · Ezequiel Garcia
Quoted 8 lines
I don't see a good way out that would preserve backwards compatibility, other than hardcoding the physical address in the driver, which seems just as bad as breaking compatibility. That said, it is always the same constant (
0xf1000000+0x20000+0x0108) on Dove, Kirkwood and Orion5x (not on mv78xx0, but that doesn't use the wdt), so hardcoding a fallback would technically work, but we should print a fat warning at boot time if we actually fall back to that.
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
Yes, I was thinking just about this. Namely:
[..]
How about something like this?
I liked Arnd's idea to use an offset from the first register. With the mbus driver we can now actually change the
0xF1.. prefix via the DT.
That wasn't actually my idea, but it does sound reasonable.
Quoted 5 lines
drivers/watchdog/orion_wdt.c static irqreturn_t orion_wdt_irq(int irq, void *devid) · line 145
Quoted 2 lines
drivers/watchdog/orion_wdt.c +2
-0+dev_warn (&pdev->dev,"falling back to harcoded RSTOUT reg 0x%x\n" , +ORION_RSTOUT_MASK );Maybe:
dev_warn(&pdev->dev,FW_BUG"falling back to harcoded RSTOUT reg 0x%x\n",
I was thinking of WARN_ON(), i.e. something that users will actually notice ;-)
Quoted 4 lines
Quoted 4 lines
drivers/watchdog/orion_wdt.c +0
-0@@ -139,10 +166,7 @@ static int orion_wdt_probe(struct platform_device *pdev)if (!wdt_reg)return -ENOMEM ;
Quoted 10 lines
drivers/watchdog/orion_wdt.c static int orion_wdt_probe(struct platform_device *pdev) · line 171
Quoted 7 lines
drivers/watchdog/orion_wdt.c +1
-4- res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); -if (!res) -return -ENODEV ; - wdt_rstout =devm_ioremap (&pdev->dev, res->start,resource_size (res)); + wdt_rstout =try_compat_rstout_ioremap (pdev);if (!wdt_rstout)return -ENOMEM ;ENOMEM is probably not the right errno? Is there a standard errno for malformed DT?
I don't think so. I'd probably use ENODEV, but it's not ideal.
Arnd
PATCH v2 5/15 watchdog: orion: Make RSTOUT register a separate resource
In reply to Jason GunthorpeQuoted 11 lines · Jason Gunthorpe
Quoted 10 lines · Ezequiel Garcia
Quoted 9 lines · Ezequiel Garcia
Quoted 8 lines
I don't see a good way out that would preserve backwards compatibility, other than hardcoding the physical address in the driver, which seems just as bad as breaking compatibility. That said, it is always the same constant (
0xf1000000+0x20000+0x0108) on Dove, Kirkwood and Orion5x (not on mv78xx0, but that doesn't use the wdt), so hardcoding a fallback would technically work, but we should print a fat warning at boot time if we actually fall back to that.
Quoted 9 lines
Quoted 5 lines
Quoted 2 lines
Yes, I was thinking just about this. Namely:
[..]
How about something like this?
I liked Arnd's idea to use an offset from the first register. With the mbus driver we can now actually change the
0xF1.. prefix via the DT.
Good idea. Maybe extracting the base address from the timer control
register: wdt_reg & 0xff000000 ?
Signature · 7 lines
Ezequiel García, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com -- To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 6/15 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
In reply to Ezequiel GarciaAfter adding the IRQ request, the BRIDGE_CAUSE bit should be cleared by the bridge interrupt controller. There's no longer a need to do it in the watchdog driver, so we can simply remove it.
--- drivers/watchdog/orion_wdt.c | 5 ----- 1 file changed, 5 deletions(-)
drivers/watchdog/orion_wdt.c +0 -5
@@ -25,7 +25,6 @@#include <linux/clk.h> #include <linux/err.h> #include <linux/of.h> -#include <mach/bridge-regs.h> /* * Watchdog timer block registers.
@@ -39,7 +38,6 @@#define WDT_OK_TO_CLOSE 1#define WDT_RESET_OUT_EN BIT(1) -#define WDT_INT_REQ BIT(3)static bool nowayout =WATCHDOG_NOWAYOUT ;static int heartbeat =-1 ;/* module parameter (seconds) */
@@ -68,9 +66,6 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)/* Set watchdog duration */ writel (wdt_tclk * wdt_dev->timeout, wdt_reg +WDT_VAL ); -/* Clear watchdog timer interrupt */ -writel (~WDT_INT_REQ ,BRIDGE_CAUSE ); -/* Enable watchdog timer */ atomic_io_modify (wdt_reg +TIMER_CTRL ,WDT_EN ,WDT_EN );
Signature · 1 line
1.8.1.5
PATCH v2 6/15 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
Quoted 3 lines · Ezequiel Garcia
After adding the IRQ request, the
BRIDGE_CAUSEbit should be cleared by the bridge interrupt controller. There's no longer a need to do it in the watchdog driver, so we can simply remove it.
When we talked about this before I pointed out that sequence here is important:
- Disable WDT
- Clear bridge
- Enable WDT
Looking at this patch in isolation it looks to me like the clear bridge lines should be replaced with a request_irq (as that does the clear) - is the request_irq in the wrong spot?
drivers/watchdog/orion_wdt.c static int orion_wdt_start(struct watchdog_device *wdt_dev) · line 71
Quoted 10 lines
drivers/watchdog/orion_wdt.c +0
-3@@ -68,9 +66,6 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)/* Set watchdog duration */ writel (wdt_tclk * wdt_dev->timeout, wdt_reg +WDT_VAL ); -/* Clear watchdog timer interrupt */ -writel (~WDT_INT_REQ ,BRIDGE_CAUSE ); -/* Enable watchdog timer */ atomic_io_modify (wdt_reg +TIMER_CTRL ,WDT_EN ,WDT_EN );
Regards,
Jason
PATCH v2 6/15 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
Quoted 5 lines · Jason Gunthorpe
Quoted 3 lines · Ezequiel Garcia
After adding the IRQ request, the
BRIDGE_CAUSEbit should be cleared by the bridge interrupt controller. There's no longer a need to do it in the watchdog driver, so we can simply remove it.
Quoted 7 lines
When we talked about this before I pointed out that sequence here is important:
- Disable WDT
- Clear bridge
- Enable WDT
Sure, I wrote this series with that in mind and made some tests to ensure that no spurious trigger was possible.
Quoted 4 lines
Looking at this patch in isolation it looks to me like the clear bridge lines should be replaced with a
request_irq(as that does the clear) - is therequest_irqin the wrong spot?
First of all, it seems to me that the first item "Disable WDT" is not currently true on this driver. orion_wdt_start() seem to reset the counter, but doesn't clear the WDT_EN bit. Do you think we should enforce a "true" disable?
As an example, s3c2410wdt calls stop() from start(). Maybe we should do something like it?
Regarding the sequence. Let me see if I got this problem right. The concern here is about the bootloader leaving the registers in a weird-state, right?
In that case, I thought that requesting the IRQ at probe time was enough to ensure the BRIDGE_CAUSE would be cleared by the time the watchdog is started. However, after reading through the irqchip code again, I'm no longer sure this is the case.
It looks like the BRIDGE_CAUSE register is cleared when the interruption is acked (which happens in the handler if I understood the code right). So requesting the IRQ is useless...
I'll trace the code to confirm this.
Sebastian: If the above is correct, do you think we can add a cause clear to the orion irqchip? (supposing it's harmful) Something like this:
drivers/irqchip/irq-orion.c +3 -0
@@ -180,6 +180,9 @@ static int __init orion_bridge_irq_init(struct device_node *np, gc->chip_types[0 ].chip.irq_mask = irq_gc_mask_clr_bit; gc->chip_types[0 ].chip.irq_unmask = irq_gc_mask_set_bit; +/* clear pending interrupts */ +writel (0 , gc->reg_base +ORION_BRIDGE_IRQ_CAUSE ); +/* mask all interrupts */ writel (0 , gc->reg_base +ORION_BRIDGE_IRQ_MASK );
Signature · 7 lines
Ezequiel García, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com -- To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 6/15 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
Quoted 8 lines · Ezequiel Garcia
Quoted 3 lines
Looking at this patch in isolation it looks to me like the clear bridge lines should be replaced with a
request_irq(as that does the clear) - is therequest_irqin the wrong spot?First of all, it seems to me that the first item "Disable WDT" is not currently true on this driver.
orion_wdt_start()seem to reset the counter, but doesn't clear theWDT_ENbit. Do you think we should enforce a "true" disable?
I think so.
Quoted 3 lines
Regarding the sequence. Let me see if I got this problem right. The concern here is about the bootloader leaving the registers in a weird-state, right?
It isn't just bootloaders to worry about, but also things like kexec..
Quoted 4 lines
In that case, I thought that requesting the IRQ at probe time was enough to ensure the
BRIDGE_CAUSEwould be cleared by the time the watchdog is started. However, after reading through the irqchip code again, I'm no longer sure this is the case.
The watchdog should ideally be fully stopped before request_irq so there is no possible race.
Quoted 3 lines
It looks like the
BRIDGE_CAUSEregister is cleared when the interruption is acked (which happens in the handler if I understood the code right). So requesting the IRQ is useless...
IMHO, the IRQ stuff should clear out pending edge triggered interrupts at request_irq time. It makes no sense to take an interrupt for a stale edge event.
I had always assumed the core code did this via irq_gc_ack_clr_bit - but I don't see an obvious path..
Quoted 2 lines
Sebastian: If the above is correct, do you think we can add a cause clear to the orion irqchip? (supposing it's harmful) Something like this:
Hrm, irq_startup looks like the right hook to put something like this in.
Jason
PATCH v2 6/15 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
Quoted 18 lines · Jason Gunthorpe
Quoted 8 lines · Ezequiel Garcia
Quoted 3 lines
Looking at this patch in isolation it looks to me like the clear bridge lines should be replaced with a
request_irq(as that does the clear) - is therequest_irqin the wrong spot?First of all, it seems to me that the first item "Disable WDT" is not currently true on this driver.
orion_wdt_start()seem to reset the counter, but doesn't clear theWDT_ENbit. Do you think we should enforce a "true" disable?I think so.
Quoted 3 lines
Regarding the sequence. Let me see if I got this problem right. The concern here is about the bootloader leaving the registers in a weird-state, right?
It isn't just bootloaders to worry about, but also things like kexec..
Quoted 8 lines
Quoted 4 lines
In that case, I thought that requesting the IRQ at probe time was enough to ensure the
BRIDGE_CAUSEwould be cleared by the time the watchdog is started. However, after reading through the irqchip code again, I'm no longer sure this is the case.The watchdog should ideally be fully stopped before
request_irqso there is no possible race.
Agreed. So, let's assume we can guarantee that request_irq() does the job of clearing the cause register (clearing pending irqs).
So, your suggestion is to put request_irq() in the watchdog start()?
Otherwise, we can ensure a watchdog full stop at probe(), before requesting the IRQ. Both solutions should work, uh?
I don't have a strong opinion. It's not like the watchdog is going to be frequently started/stopped (right?) so we can easily do the request_irq() in the start() without worrying.
Signature · 7 lines
Ezequiel García, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com -- To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 6/15 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
Quoted 7 lines · Ezequiel Garcia
Agreed. So, let's assume we can guarantee that
request_irq()does the job of clearing the cause register (clearing pending irqs).So, your suggestion is to put
request_irq()in the watchdogstart()?Otherwise, we can ensure a watchdog full stop at
probe(), before requesting the IRQ. Both solutions should work, uh?
Right, I would keep the request_irq in probe, just because that feels more idiomatic..
Jason
PATCH v2 6/15 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
Quoted 5 lines · Jason Gunthorpe
Quoted 3 lines · Ezequiel Garcia
Agreed. So, let's assume we can guarantee that
request_irq()does the job of clearing the cause register (clearing pending irqs).
Quoted 8 lines
Quoted 4 lines
So, your suggestion is to put
request_irq()in the watchdogstart()?Otherwise, we can ensure a watchdog full stop at
probe(), before requesting the IRQ. Both solutions should work, uh?Right, I would keep the
request_irqin probe, just because that feels more idiomatic..
Done. Baking v4...
Signature · 7 lines
Ezequiel García, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com -- To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Sebastian Hesselbarth
maintainerPATCH v2 6/15 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
In reply to Jason GunthorpeQuoted 17 lines · Jason Gunthorpe
Quoted 8 lines · Ezequiel Garcia
Quoted 3 lines
Looking at this patch in isolation it looks to me like the clear bridge lines should be replaced with a
request_irq(as that does the clear) - is therequest_irqin the wrong spot?In that case, I thought that requesting the IRQ at probe time was enough to ensure the
BRIDGE_CAUSEwould be cleared by the time the watchdog is started. However, after reading through the irqchip code again, I'm no longer sure this is the case.The watchdog should ideally be fully stopped before
request_irqso there is no possible race.Quoted 3 lines
It looks like the
BRIDGE_CAUSEregister is cleared when the interruption is acked (which happens in the handler if I understood the code right). So requesting the IRQ is useless...
Quoted 9 lines
IMHO, the IRQ stuff should clear out pending edge triggered interrupts at
request_irqtime. It makes no sense to take an interrupt for a stale edge event.I had always assumed the core code did this via
irq_gc_ack_clr_bit- but I don't see an obvious path..Quoted 2 lines
Sebastian: If the above is correct, do you think we can add a cause clear to the orion irqchip? (supposing it's harmful) Something like this:
Ezequiel,
irqchip/irq-orion.c does mask all interrupts but you are right, it should also clear pending interrupts right after that.
So
/* mask all interrupts */ writel(0, gc->reg_base + ORION_BRIDGE_IRQ_MASK);
should become
/* mask and clear all interrupts */ writel(0, gc->reg_base + ORION_BRIDGE_IRQ_MASK); writel(~0, gc->reg_base + ORION_BRIDGE_IRQ_CAUSE);
Could also be clear on write 0, I'll check that. I already had some beer, so I'll postpone any patches till tomorrow.
Clearing BRIDGE_CAUSE will only clear all currently pending upstream IRQs, of course. If WDT IRQ will be re-raised right after that in BRIDGE_CAUSE depends on the actual HW implementation, i.e. we do no clear the causing IRQ itself but just what it raised in BRIDGE_CAUSE.
So, you should also clear WDT's irq in the driver yourself to clear a possible pending upstream BRIDGE_CAUSE.
Sebastian
PATCH v2 6/15 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
Quoted 4 lines
Clearing
BRIDGE_CAUSEwill only clear all currently pending upstream IRQs, of course. If WDT IRQ will be re-raised right after that inBRIDGE_CAUSEdepends on the actual HW implementation, i.e. we do no clear the causing IRQ itself but just what it raised inBRIDGE_CAUSE.
Which is why it makes no sense to clear it one time at kernel start.
Either you only get new edge triggered interrupts after request_irq (sane behavior) or you might sometimes get an old pending edge triggered interrupt after request_irq (crazy behavior).
Clearing BRIDGE_CAUSE at kernel start only shortens the racy window it doesn't eliminate it.
In the more familiar level triggered world the driver would go to the device and ensure it wasn't asserting an IRQ level and then do the request_irq. This guarentees it won't get an interrupt callback.
In a edge triggered world the driver should go to the device an ensure that it won't create a new IRQ, then do request_irq - confident that there will NEVER be a call to the IRQ handler, under any circumstances.
So I think edge triggered interrupts need to ack any possible old edge trigger in the cause register before the first unmask - eg in the setup callback.
Quoted 2 lines
So, you should also clear WDT's irq in the driver yourself to clear a possible pending upstream
BRIDGE_CAUSE.
Which isn't possible - the BRIDGE_CAUSE is owned by the irq driver and it must be cleared there, and it must only be cleared after the wdt has been stopped so it doesn't set it again.
Notice that Ezequiel has added an IRQ handler that just calls panic, so a spurious interrupt call is VERY VERY BAD.
Jason
PATCH v2 6/15 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
Quoted 7 lines · Jason Gunthorpe
Quoted 4 lines
Clearing
BRIDGE_CAUSEwill only clear all currently pending upstream IRQs, of course. If WDT IRQ will be re-raised right after that inBRIDGE_CAUSEdepends on the actual HW implementation, i.e. we do no clear the causing IRQ itself but just what it raised inBRIDGE_CAUSE.Which is why it makes no sense to clear it one time at kernel start.
So, it seems we need to handle irq_startup(), as you suggested. I've just tested the attached patch, and it's working fine: the driver's probe() fully stops the watchdog, and then request_irq() acks and pending interrupts, through the added irq_startup().
How does it look?
drivers/irqchip/irq-orion.c +11 -0
@@ -108,6 +108,16 @@ IRQCHIP_DECLARE(orion_intc, "marvell,orion-intc", orion_irq_init);#define ORION_BRIDGE_IRQ_CAUSE 0x00#define ORION_BRIDGE_IRQ_MASK 0x04 +static unsigned int orion_bridge_irq_startup (struct irq_data *data) +{ +/* Ack pending interrupts */ + data->chip->irq_ack (data); + +/* Unmask the interrupt */ + data->chip->irq_unmask (data); +return 0 ; +} +static void orion_bridge_irq_handler (unsigned int irq,struct irq_desc *desc) {struct irq_domain *d =irq_get_handler_data (irq);
@@ -176,6 +186,7 @@ static int __init orion_bridge_irq_init(struct device_node *np, gc->chip_types[0 ].regs.ack =ORION_BRIDGE_IRQ_CAUSE ; gc->chip_types[0 ].regs.mask =ORION_BRIDGE_IRQ_MASK ; + gc->chip_types[0 ].chip.irq_startup = orion_bridge_irq_startup; gc->chip_types[0 ].chip.irq_ack = irq_gc_ack_clr_bit; gc->chip_types[0 ].chip.irq_mask = irq_gc_mask_clr_bit; gc->chip_types[0 ].chip.irq_unmask = irq_gc_mask_set_bit;
Signature · 7 lines
Ezequiel García, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com -- To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 6/15 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
Quoted 9 lines · Ezequiel Garcia
Quoted 7 lines · Jason Gunthorpe
Quoted 4 lines
Clearing
BRIDGE_CAUSEwill only clear all currently pending upstream IRQs, of course. If WDT IRQ will be re-raised right after that inBRIDGE_CAUSEdepends on the actual HW implementation, i.e. we do no clear the causing IRQ itself but just what it raised inBRIDGE_CAUSE.Which is why it makes no sense to clear it one time at kernel start.
Quoted 6 lines
So, it seems we need to handle
irq_startup(), as you suggested. I've just tested the attached patch, and it's working fine: the driver'sprobe()fully stops the watchdog, and thenrequest_irq()acks and pending interrupts, through the addedirq_startup().How does it look?
Looks sane to me.
I looked some more and there are other drivers (eg irq-metag-ext) that take this same approach.
Sebastian:
I looked at the irq-orion driver a bit more and noticed this:
ret = irq_alloc_domain_generic_chips(domain, nrirqs, 1, np->name,
handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE);
^^^^^^^^^^^^^^^^^^^^^Shouldn't it be handle_edge_irq? Otherwise who is calling irq_ack? How does this work at all? :)
Jason
PATCH v2 6/15 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
Quoted 15 lines · Jason Gunthorpe
Quoted 14 lines · Ezequiel Garcia
Quoted 7 lines · Jason Gunthorpe
Quoted 4 lines
Clearing
BRIDGE_CAUSEwill only clear all currently pending upstream IRQs, of course. If WDT IRQ will be re-raised right after that inBRIDGE_CAUSEdepends on the actual HW implementation, i.e. we do no clear the causing IRQ itself but just what it raised inBRIDGE_CAUSE.Which is why it makes no sense to clear it one time at kernel start.
So, it seems we need to handle
irq_startup(), as you suggested. I've just tested the attached patch, and it's working fine: the driver'sprobe()fully stops the watchdog, and thenrequest_irq()acks and pending interrupts, through the addedirq_startup().
Quoted 7 lines
Quoted 1 line
How does it look?
Looks sane to me.
I looked some more and there are other drivers (eg irq-metag-ext) that take this same approach.
Yup, I took that one as a starting point.
[..]
Quoted 8 lines
I looked at the irq-orion driver a bit more and noticed this:
ret = irq_alloc_domain_generic_chips(domain, nrirqs, 1, np->name, handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE); ^^^^^^^^^^^^^^^^^^^^^Shouldn't it be
handle_edge_irq? Otherwise who is callingirq_ack? How does this work at all? :)
I'm not familiar with the differences between handle_level_irq and handle_edge_irq, but -AFAICS- both seem to ack the IRQ.
In fact handle_level_irq(), masks and acks the IRQ as the first thing.
Signature · 7 lines
Ezequiel García, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com -- To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Sebastian Hesselbarth
maintainerPATCH v2 6/15 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
In reply to Jason GunthorpeQuoted 22 lines · Jason Gunthorpe
Quoted 9 lines · Ezequiel Garcia
Quoted 7 lines · Jason Gunthorpe
Quoted 4 lines
Clearing
BRIDGE_CAUSEwill only clear all currently pending upstream IRQs, of course. If WDT IRQ will be re-raised right after that inBRIDGE_CAUSEdepends on the actual HW implementation, i.e. we do no clear the causing IRQ itself but just what it raised inBRIDGE_CAUSE.Which is why it makes no sense to clear it one time at kernel start.
Quoted 6 lines
So, it seems we need to handle
irq_startup(), as you suggested. I've just tested the attached patch, and it's working fine: the driver'sprobe()fully stops the watchdog, and thenrequest_irq()acks and pending interrupts, through the addedirq_startup().How does it look?
Looks sane to me.
I looked some more and there are other drivers (eg irq-metag-ext) that take this same approach.
Quoted 8 lines
Sebastian:
I looked at the irq-orion driver a bit more and noticed this:ret = irq_alloc_domain_generic_chips(domain, nrirqs, 1, np->name, handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE); ^^^^^^^^^^^^^^^^^^^^^Shouldn't it be
handle_edge_irq? Otherwise who is callingirq_ack? How does this work at all? :)
I can tell you that it comes from arch/arm/plat-orion/irq.c and I blindly copied it. I never really checked the differences in handling level/edge irqs. Besides, if it wasn't working, we wouldn't get far in booting the kernel without timer irqs.
From a HW point-of-view, I'd say the difference is that an
edge-triggered irq samples level transitions from e.g. low to high. It also remains asserted if you clear the actual cause of the interrupt and is only asserted again on the next low-to-high transition.
A level-triggered irq will be asserted as long as the cause of the irq is asserted. If you clear the cause, you'll also clear that bit in the upstream controller.
*BUT*, I will double-check how Linux deals with level/edge irqs and if Orion SoCs have edge or level triggered cause registers. That should reveal, if it is more sane to use handle_edge_irq here and possibly in the main interrupt controller, too.
Sebastian
PATCH v2 6/15 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
Quoted 9 lines · Sebastian Hesselbarth
Quoted 8 lines
Sebastian:
I looked at the irq-orion driver a bit more and noticed this:ret = irq_alloc_domain_generic_chips(domain, nrirqs, 1, np->name, handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE); ^^^^^^^^^^^^^^^^^^^^^Shouldn't it be
handle_edge_irq? Otherwise who is callingirq_ack? How does this work at all? :)
Quoted 4 lines
I can tell you that it comes from
arch/arm/plat-orion/irq.cand I blindly copied it. I never really checked the differences in handling level/edge irqs. Besides, if it wasn't working, we wouldn't get far in booting the kernel without timer irqs.
Ezequiel found the ack call I missed, so it makes sense it works.
I think the difference in routines only starts to matter when you can get another incoming edge IRQ while already handling one (due to SMP? threaded interrupts? RealTime? not sure)
Quoted 2 lines
It also remains asserted if you clear the actual cause of the interrupt and is only asserted again on the next low-to-high transition.
Which is why Ezequiel's patch is the right approach: we need to clear the interrupt latched in the cause register after the watchdog driver disable but before enabling/unmasking the interrupt.
Remember, the BRIDGE_MASK register has no effect on the BRIDGE_CAUSE, it only effects which bits propogate to the main cause register.
Quoted 4 lines
*BUT*, I will double-check how Linux deals with level/edge irqs and if Orion SoCs have edge or level triggered cause registers. That should reveal, if it is more sane to use
handle_edge_irqhere and possibly in the main interrupt controller, too.
There is a mixture.
Any cause bit documented to be clearable is edge triggered, all others are level.
On Kirkwood this means all of the main interrupt controller bits are level and all the bridge bits are edge. Which means edge is definitely correct for the bridge handler, and level correct for the main handler.
Jason
Sebastian Hesselbarth
maintainerPATCH v2 6/15 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
Quoted 24 lines · Jason Gunthorpe
Quoted 9 lines · Sebastian Hesselbarth
Quoted 8 lines
Sebastian:
I looked at the irq-orion driver a bit more and noticed this:ret = irq_alloc_domain_generic_chips(domain, nrirqs, 1, np->name, handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE); ^^^^^^^^^^^^^^^^^^^^^Shouldn't it be
handle_edge_irq? Otherwise who is callingirq_ack? How does this work at all? :)Quoted 4 lines
I can tell you that it comes from
arch/arm/plat-orion/irq.cand I blindly copied it. I never really checked the differences in handling level/edge irqs. Besides, if it wasn't working, we wouldn't get far in booting the kernel without timer irqs.Ezequiel found the ack call I missed, so it makes sense it works.
I think the difference in routines only starts to matter when you can get another incoming edge IRQ while already handling one (due to SMP? threaded interrupts? RealTime? not sure)
Quoted 2 lines
It also remains asserted if you clear the actual cause of the interrupt and is only asserted again on the next low-to-high transition.
Quoted 6 lines
Which is why Ezequiel's patch is the right approach: we need to clear the interrupt latched in the cause register after the watchdog driver disable but before enabling/unmasking the interrupt.
Remember, the
BRIDGE_MASKregister has no effect on theBRIDGE_CAUSE, it only effects which bits propogate to the main cause register.
Yeah, I know. But you don't get new ones if mask them. At least for edge triggered irqs, you can also clear them without clearing the cause of the interrupt. Nevertheless, I think we agree here.
Quoted 7 lines
Quoted 4 lines
*BUT*, I will double-check how Linux deals with level/edge irqs and if Orion SoCs have edge or level triggered cause registers. That should reveal, if it is more sane to use
handle_edge_irqhere and possibly in the main interrupt controller, too.There is a mixture.
Quoted 7 lines
Any cause bit documented to be clearable is edge triggered, all others are level.
On Kirkwood this means all of the main interrupt controller bits are level and all the bridge bits are edge. Which means edge is definitely correct for the bridge handler, and level correct for the main handler.
Just checked that for Dove, it is the same there. Main IRQ_CAUSE is RO, BRIDGE_CAUSE is RW0C, and PMU_CAUSE is RW *sigh*.
I need to remember that when Dove moves over to mach-mvebu, as we need a different chained irq handler for PMU that deals with that broken RW register.
Sebastian
PATCH v2 6/15 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
In reply to Jason GunthorpeOn Wed, Jan 22, 2014 at 05:19:34PM -0700, Jason Gunthorpe wrote:
[..]
Quoted 6 lines
On Kirkwood this means all of the main interrupt controller bits are level and all the bridge bits are edge. Which means edge is definitely correct for the bridge handler, and level correct for the main handler.
Which means we should change the bridge handler to edge?
Is there any _noticeable_ side-effect in doing the handling via level?
Signature · 7 lines
Ezequiel García, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com -- To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Sebastian Hesselbarth
maintainerPATCH v2 6/15 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
In reply to Jason GunthorpeQuoted 5 lines · Jason Gunthorpe
Quoted 4 lines
Clearing
BRIDGE_CAUSEwill only clear all currently pending upstream IRQs, of course. If WDT IRQ will be re-raised right after that inBRIDGE_CAUSEdepends on the actual HW implementation, i.e. we do no clear the causing IRQ itself but just what it raised inBRIDGE_CAUSE.
Quoted 8 lines
Which is why it makes no sense to clear it one time at kernel start.
Either you only get new edge triggered interrupts after
request_irq(sane behavior) or you might sometimes get an old pending edge triggered interrupt afterrequest_irq(crazy behavior).Clearing
BRIDGE_CAUSEat kernel start only shortens the racy window it doesn't eliminate it.
Actually, I missed that we mask all BRIDGE irqs in orion_bridge_irq_init. If we now also clear already pending irqs, that will not raise any old interrupts as long as watchdog clears all reasons for upstream irqs before requesting a BRIDGE irq.
Quoted 13 lines
In the more familiar level triggered world the driver would go to the device and ensure it wasn't asserting an IRQ level and then do the
request_irq. This guarentees it won't get an interrupt callback.In a edge triggered world the driver should go to the device an ensure that it won't create a new IRQ, then do
request_irq- confident that there will NEVER be a call to the IRQ handler, under any circumstances.So I think edge triggered interrupts need to ack any possible old edge trigger in the cause register before the first unmask - eg in the setup callback.
Quoted 6 lines
Quoted 2 lines
So, you should also clear WDT's irq in the driver yourself to clear a possible pending upstream
BRIDGE_CAUSE.Which isn't possible - the
BRIDGE_CAUSEis owned by the irq driver and it must be cleared there, and it must only be cleared after the wdt has been stopped so it doesn't set it again.
I should have been more precise here: I meant watchdog driver should clear all sources of possible upstream interrupts in its _own_ registers.
Quoted 2 lines
Notice that Ezequiel has added an IRQ handler that just calls panic, so a spurious interrupt call is VERY VERY BAD.
And I understand that he now clears watchdog's register before requesting an irq. All that is missing is bridge_irq driver clearing CAUSE register after masking all irqs, right?
I'll stich a patch for that hopefully tomorrow.
Sebastian
PATCH v2 6/15 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
On Thu, Jan 23, 2014 at 12:49:50AM +0100, Sebastian Hesselbarth wrote:
[..]
Quoted 7 lines
Quoted 2 lines
Notice that Ezequiel has added an IRQ handler that just calls panic, so a spurious interrupt call is VERY VERY BAD.
And I understand that he now clears watchdog's register before requesting an irq. All that is missing is
bridge_irqdriver clearing CAUSE register after masking all irqs, right?
Are you sure clearing the CAUSE register after masking the IRQs will be enough?
AFAICS, until now nobody unmasks the watchdog IRQ (at least the orion_wdt driver didn't request the interruption) but *still* the CAUSE register is set upon watchdog expiration. So I would guessed a masked interrupt still raises a bit in the CAUSE register.
Although I'm no sure I'm making sense here or just noise...
Signature · 7 lines
Ezequiel García, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com -- To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 6/15 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
Sebastian,
Quoted 10 lines · Ezequiel Garcia
On Thu, Jan 23, 2014 at 12:49:50AM +0100, Sebastian Hesselbarth wrote:
[..]Quoted 7 lines
Quoted 2 lines
Notice that Ezequiel has added an IRQ handler that just calls panic, so a spurious interrupt call is VERY VERY BAD.
And I understand that he now clears watchdog's register before requesting an irq. All that is missing is
bridge_irqdriver clearing CAUSE register after masking all irqs, right?
Quoted 7 lines
Are you sure clearing the CAUSE register after masking the IRQs will be enough?
AFAICS, until now nobody unmasks the watchdog IRQ (at least the
orion_wdtdriver didn't request the interruption) but *still* the CAUSE register is set upon watchdog expiration. So I would guessed a masked interrupt still raises a bit in the CAUSE register.
Let me add some real information instead of my speculations. Taken from the Kirkwood specification:
Table 136: Mbus-L to Mbus Bridge Interrupt Mask Register
Offset: 0x00020114
Field: Mask
Type/InitVal: RW 0x0
Description: There is a mask bit per each cause bit. Mask only affects the
assertion of interrupt pins. It does not affect the setting of bits in the Cause register.
So I guess this is why Jason has been insisting with the introduction of the irq_startup.
(Just for reference, the little patch I attached yesterday proved to work here.)
Signature · 7 lines
Ezequiel García, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com -- To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Sebastian Hesselbarth
maintainerPATCH v2 6/15 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
Jason, Ezequiel,
Quoted 32 lines · Ezequiel Garcia
Sebastian,
Quoted 10 lines · Ezequiel Garcia
On Thu, Jan 23, 2014 at 12:49:50AM +0100, Sebastian Hesselbarth wrote:
[..]Quoted 7 lines
Quoted 2 lines
Notice that Ezequiel has added an IRQ handler that just calls panic, so a spurious interrupt call is VERY VERY BAD.
And I understand that he now clears watchdog's register before requesting an irq. All that is missing is
bridge_irqdriver clearing CAUSE register after masking all irqs, right?Quoted 7 lines
Are you sure clearing the CAUSE register after masking the IRQs will be enough?
AFAICS, until now nobody unmasks the watchdog IRQ (at least the
orion_wdtdriver didn't request the interruption) but *still* the CAUSE register is set upon watchdog expiration. So I would guessed a masked interrupt still raises a bit in the CAUSE register.Let me add some real information instead of my speculations. Taken from the Kirkwood specification:
Table 136: Mbus-L to Mbus Bridge Interrupt Mask Register
Offset:0x00020114
Field: Mask
Type/InitVal: RW0x0
Description: There is a mask bit per each cause bit. Mask only affects the
assertion of interrupt pins. It does not affect the setting of bits in the Cause register.
Quoted 4 lines
So I guess this is why Jason has been insisting with the introduction of the
irq_startup.(Just for reference, the little patch I attached yesterday proved to work here.)
You guys were so right ;)
I just tested your v4 of the watchdog patches and forced a stale watchdog irq. It will cause a watchdog reset as you predicted.
I have some fixes for irq-orion.c's bridge irq that take care of:
- handle_edge_irq
- mask _and_ clear irqs on init
- use irq_enable to ensure stale irqs are acked before unmask
With the last one, the stale watchdog irq will not raise watchdog's irq handler anymore.
BTW, during my test, it looks like RSTOUT wasn't set, so I'll add my Tested-by on v4 when I have investigated that.
Sebastian
PATCH v2 7/15 watchdog: orion: Introduce an orion_watchdog device structure
In reply to Ezequiel GarciaIn order to prepare to support multiple compatible-strings, this commit adds a device structure to hold the driver's state.
--- drivers/watchdog/orion_wdt.c | 114 ++++++++++++++++++++++++++----------------- 1 file changed, 68 insertions(+), 46 deletions(-)
drivers/watchdog/orion_wdt.c +68 -46
@@ -41,62 +41,71 @@static bool nowayout =WATCHDOG_NOWAYOUT ;static int heartbeat =-1 ;/* module parameter (seconds) */ -static unsigned int wdt_max_duration;/* (seconds) */ -static struct clk *clk; -static unsigned int wdt_tclk; -static void __iomem *wdt_reg; -static void __iomem *wdt_rstout; -static DEFINE_SPINLOCK (wdt_lock); + +struct orion_watchdog { +struct watchdog_device wdt; +void __iomem *reg; +void __iomem *rstout; +spinlock_t lock; +unsigned long clk_rate; +struct clk *clk; +};static int orion_wdt_ping (struct watchdog_device *wdt_dev) { -spin_lock (&wdt_lock); +struct orion_watchdog *dev =watchdog_get_drvdata (wdt_dev); +spin_lock (&dev->lock);/* Reload watchdog duration */ -writel (wdt_tclk * wdt_dev->timeout, wdt_reg +WDT_VAL ); +writel (dev->clk_rate * wdt_dev->timeout, dev->reg +WDT_VAL ); -spin_unlock (&wdt_lock); +spin_unlock (&dev->lock);return 0 ; }static int orion_wdt_start (struct watchdog_device *wdt_dev) { -spin_lock (&wdt_lock); +struct orion_watchdog *dev =watchdog_get_drvdata (wdt_dev); + +spin_lock (&dev->lock);/* Set watchdog duration */ -writel (wdt_tclk * wdt_dev->timeout, wdt_reg +WDT_VAL ); +writel (dev->clk_rate * wdt_dev->timeout, dev->reg +WDT_VAL );/* Enable watchdog timer */ -atomic_io_modify (wdt_reg +TIMER_CTRL ,WDT_EN ,WDT_EN ); +atomic_io_modify (dev->reg +TIMER_CTRL ,WDT_EN ,WDT_EN );/* Enable reset on watchdog */ -atomic_io_modify (wdt_rstout,WDT_RESET_OUT_EN ,WDT_RESET_OUT_EN ); +atomic_io_modify (dev->rstout,WDT_RESET_OUT_EN ,WDT_RESET_OUT_EN ); -spin_unlock (&wdt_lock); +spin_unlock (&dev->lock);return 0 ; }static int orion_wdt_stop (struct watchdog_device *wdt_dev) { -spin_lock (&wdt_lock); +struct orion_watchdog *dev =watchdog_get_drvdata (wdt_dev); + +spin_lock (&dev->lock);/* Disable reset on watchdog */ -atomic_io_modify (wdt_rstout,WDT_RESET_OUT_EN ,0 ); +atomic_io_modify (dev->rstout,WDT_RESET_OUT_EN ,0 );/* Disable watchdog timer */ -atomic_io_modify (wdt_reg +TIMER_CTRL ,WDT_EN ,0 ); +atomic_io_modify (dev->reg +TIMER_CTRL ,WDT_EN ,0 ); -spin_unlock (&wdt_lock); +spin_unlock (&dev->lock);return 0 ; }static unsigned int orion_wdt_get_timeleft (struct watchdog_device *wdt_dev) { +struct orion_watchdog *dev =watchdog_get_drvdata (wdt_dev);unsigned int time_left; -spin_lock (&wdt_lock); - time_left =readl (wdt_reg +WDT_VAL ) / wdt_tclk; -spin_unlock (&wdt_lock); +spin_lock (&dev->lock); + time_left =readl (dev->reg +WDT_VAL ) / dev->clk_rate; +spin_unlock (&dev->lock);return time_left; }
@@ -122,12 +131,6 @@ static const struct watchdog_ops orion_wdt_ops = { .get_timeleft = orion_wdt_get_timeleft, }; -static struct watchdog_device orion_wdt = { - .info = &orion_wdt_info, - .ops = &orion_wdt_ops, - .min_timeout =1 , -}; -static irqreturn_t orion_wdt_irq (int irq,void *devid) {panic ("Watchdog Timeout" );
@@ -136,29 +139,42 @@ static irqreturn_t orion_wdt_irq(int irq, void *devid)static int orion_wdt_probe (struct platform_device *pdev) { +struct orion_watchdog *dev; +unsigned int wdt_max_duration;/* (seconds) */ struct resource *res;int ret, irq; - clk =devm_clk_get (&pdev->dev,NULL ); -if (IS_ERR (clk)) { + dev =devm_kzalloc (&pdev->dev,sizeof (struct orion_watchdog ), +GFP_KERNEL ); +if (!dev) +return -ENOMEM ; + + dev->wdt.info = &orion_wdt_info; + dev->wdt.ops = &orion_wdt_ops; + dev->wdt.min_timeout =1 ; + + dev->clk =devm_clk_get (&pdev->dev,NULL ); +if (IS_ERR (dev->clk)) {dev_err (&pdev->dev,"Orion Watchdog missing clock\n" );return -ENODEV ; } -clk_prepare_enable (clk); - wdt_tclk =clk_get_rate (clk); +clk_prepare_enable (dev->clk); + dev->clk_rate =clk_get_rate (dev->clk); +spin_lock_init (&dev->lock); res =platform_get_resource (pdev,IORESOURCE_MEM ,0 );if (!res)return -ENODEV ; - wdt_reg =devm_ioremap (&pdev->dev, res->start,resource_size (res)); -if (!wdt_reg) + dev->reg =devm_ioremap (&pdev->dev, res->start, +resource_size (res)); +if (!dev->reg)return -ENOMEM ; res =platform_get_resource (pdev,IORESOURCE_MEM ,1 );if (!res)return -ENODEV ; - wdt_rstout =devm_ioremap (&pdev->dev, res->start,resource_size (res)); -if (!wdt_rstout) + dev->rstout =devm_ioremap (&pdev->dev, res->start,resource_size (res)); +if (!dev->rstout)return -ENOMEM ; irq =platform_get_irq (pdev,0 );
@@ -174,34 +190,40 @@ static int orion_wdt_probe(struct platform_device *pdev) } } - wdt_max_duration =WDT_MAX_CYCLE_COUNT / wdt_tclk; + wdt_max_duration =WDT_MAX_CYCLE_COUNT / dev->clk_rate; - orion_wdt.timeout = wdt_max_duration; - orion_wdt.max_timeout = wdt_max_duration; -watchdog_init_timeout (&orion_wdt, heartbeat, &pdev->dev); + dev->wdt.timeout = wdt_max_duration; + dev->wdt.max_timeout = wdt_max_duration; +watchdog_init_timeout (&dev->wdt, heartbeat, &pdev->dev); -watchdog_set_nowayout (&orion_wdt, nowayout); - ret =watchdog_register_device (&orion_wdt); +platform_set_drvdata (pdev, &dev->wdt); +watchdog_set_drvdata (&dev->wdt, dev); +watchdog_set_nowayout (&dev->wdt, nowayout); + ret =watchdog_register_device (&dev->wdt);if (ret) { -clk_disable_unprepare (clk); +clk_disable_unprepare (dev->clk);return ret; }pr_info ("Initial timeout %d sec%s\n" , - orion_wdt.timeout, nowayout ?", nowayout" :"" ); + dev->wdt.timeout, nowayout ?", nowayout" :"" );return 0 ; }static int orion_wdt_remove (struct platform_device *pdev) { -watchdog_unregister_device (&orion_wdt); -clk_disable_unprepare (clk); +struct watchdog_device *wdt_dev =platform_get_drvdata (pdev); +struct orion_watchdog *dev =watchdog_get_drvdata (wdt_dev); + +watchdog_unregister_device (wdt_dev); +clk_disable_unprepare (dev->clk);return 0 ; }static void orion_wdt_shutdown (struct platform_device *pdev) { -orion_wdt_stop (&orion_wdt); +struct watchdog_device *wdt_dev =platform_get_drvdata (pdev); +orion_wdt_stop (wdt_dev); }static const struct of_device_id orion_wdt_of_match_table[] = {
Signature · 1 line
1.8.1.5
PATCH v2 8/15 watchdog: orion: Introduce per-compatible of_device_id data
In reply to Ezequiel GarciaThis commit adds an orion_watchdog_data structure to holda compatible-data information. This allows to remove the driver-wide definition and to future add support for multiple compatible-strings.
--- drivers/watchdog/orion_wdt.c | 63 +++++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 16 deletions(-)
drivers/watchdog/orion_wdt.c +47 -16
@@ -25,23 +25,32 @@#include <linux/clk.h> #include <linux/err.h> #include <linux/of.h> +#include <linux/of_device.h> /* * Watchdog timer block registers. */ #define TIMER_CTRL 0x0000 -#define WDT_EN 0x0010 -#define WDT_VAL 0x0024#define WDT_MAX_CYCLE_COUNT 0xffffffff#define WDT_IN_USE 0#define WDT_OK_TO_CLOSE 1 -#define WDT_RESET_OUT_EN BIT(1) +#define WDT_A370_RATIO_MASK (v) ((v) << 16) +#define WDT_A370_RATIO_SHIFT 5 +#define WDT_A370_RATIO (1 << WDT_A370_RATIO_SHIFT) + +#define WDT_AXP_FIXED_ENABLE_BIT BIT(10)static bool nowayout =WATCHDOG_NOWAYOUT ;static int heartbeat =-1 ;/* module parameter (seconds) */ +struct orion_watchdog_data { +int wdt_counter_offset; +int wdt_enable_bit; +int rstout_enable_bit; +}; +struct orion_watchdog {struct watchdog_device wdt;void __iomem *reg;
@@ -49,6 +58,7 @@ struct orion_watchdog {spinlock_t lock;unsigned long clk_rate;struct clk *clk; +struct orion_watchdog_data *data; };static int orion_wdt_ping (struct watchdog_device *wdt_dev)
@@ -57,7 +67,8 @@ static int orion_wdt_ping(struct watchdog_device *wdt_dev)spin_lock (&dev->lock);/* Reload watchdog duration */ -writel (dev->clk_rate * wdt_dev->timeout, dev->reg +WDT_VAL ); +writel (dev->clk_rate * wdt_dev->timeout, + dev->reg + dev->data->wdt_counter_offset);spin_unlock (&dev->lock);return 0 ;
@@ -70,13 +81,16 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)spin_lock (&dev->lock);/* Set watchdog duration */ -writel (dev->clk_rate * wdt_dev->timeout, dev->reg +WDT_VAL ); +writel (dev->clk_rate * wdt_dev->timeout, + dev->reg + dev->data->wdt_counter_offset);/* Enable watchdog timer */ -atomic_io_modify (dev->reg +TIMER_CTRL ,WDT_EN ,WDT_EN ); +atomic_io_modify (dev->reg +TIMER_CTRL , dev->data->wdt_enable_bit, + dev->data->wdt_enable_bit);/* Enable reset on watchdog */ -atomic_io_modify (dev->rstout,WDT_RESET_OUT_EN ,WDT_RESET_OUT_EN ); +atomic_io_modify (dev->rstout, dev->data->rstout_enable_bit, + dev->data->rstout_enable_bit);spin_unlock (&dev->lock);return 0 ;
@@ -89,10 +103,10 @@ static int orion_wdt_stop(struct watchdog_device *wdt_dev)spin_lock (&dev->lock);/* Disable reset on watchdog */ -atomic_io_modify (dev->rstout,WDT_RESET_OUT_EN ,0 ); +atomic_io_modify (dev->rstout, dev->data->rstout_enable_bit,0 );/* Disable watchdog timer */ -atomic_io_modify (dev->reg +TIMER_CTRL ,WDT_EN ,0 ); +atomic_io_modify (dev->reg +TIMER_CTRL , dev->data->wdt_enable_bit,0 );spin_unlock (&dev->lock);return 0 ;
@@ -104,7 +118,8 @@ static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev)unsigned int time_left;spin_lock (&dev->lock); - time_left =readl (dev->reg +WDT_VAL ) / dev->clk_rate; + time_left =readl (dev->reg + dev->data->wdt_counter_offset); + time_left /= dev->clk_rate;spin_unlock (&dev->lock);return time_left;
@@ -137,9 +152,25 @@ static irqreturn_t orion_wdt_irq(int irq, void *devid)return IRQ_HANDLED ; } +static const struct orion_watchdog_data orion_data = { + .rstout_enable_bit =BIT (1 ), + .wdt_enable_bit =BIT (4 ), + .wdt_counter_offset =0x24 , +}; + +static const struct of_device_id orion_wdt_of_match_table[] = { + { + .compatible ="marvell,orion-wdt" , + .data = &orion_data, + }, + {}, +}; +MODULE_DEVICE_TABLE (of, orion_wdt_of_match_table); +static int orion_wdt_probe (struct platform_device *pdev) {struct orion_watchdog *dev; +const struct of_device_id *match;unsigned int wdt_max_duration;/* (seconds) */ struct resource *res;int ret, irq;
@@ -149,9 +180,15 @@ static int orion_wdt_probe(struct platform_device *pdev)if (!dev)return -ENOMEM ; + match =of_match_device (orion_wdt_of_match_table, &pdev->dev); +if (!match) +/* Default legacy match */ + match = &orion_wdt_of_match_table[0 ]; + dev->wdt.info = &orion_wdt_info; dev->wdt.ops = &orion_wdt_ops; dev->wdt.min_timeout =1 ; + dev->data = (struct orion_watchdog_data *)match->data; dev->clk =devm_clk_get (&pdev->dev,NULL );if (IS_ERR (dev->clk)) {
@@ -226,12 +263,6 @@ static void orion_wdt_shutdown(struct platform_device *pdev)orion_wdt_stop (wdt_dev); } -static const struct of_device_id orion_wdt_of_match_table[] = { - { .compatible ="marvell,orion-wdt" , }, - {}, -}; -MODULE_DEVICE_TABLE (of, orion_wdt_of_match_table); -static struct platform_driver orion_wdt_driver = { .probe = orion_wdt_probe, .remove = orion_wdt_remove,
Signature · 1 line
1.8.1.5
PATCH v2 9/15 watchdog: orion: Add per-compatible clock initialization
In reply to Ezequiel GarciaFollowing the introduction of the compatible-data field, it's now possible to further abstract the clock initialization. This will allow to support SoC with a different clock setup.
--- drivers/watchdog/orion_wdt.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-)
drivers/watchdog/orion_wdt.c +22 -7
@@ -45,10 +45,14 @@static bool nowayout =WATCHDOG_NOWAYOUT ;static int heartbeat =-1 ;/* module parameter (seconds) */ +struct orion_watchdog ; +struct orion_watchdog_data {int wdt_counter_offset;int wdt_enable_bit;int rstout_enable_bit; +int (*clock_init) (struct platform_device *, +struct orion_watchdog *); };struct orion_watchdog {
@@ -61,6 +65,17 @@ struct orion_watchdog {struct orion_watchdog_data *data; }; +static int orion_wdt_clock_init (struct platform_device *pdev, +struct orion_watchdog *dev) +{ + dev->clk =devm_clk_get (&pdev->dev,NULL ); +if (IS_ERR (dev->clk)) +return -ENODEV ; +clk_prepare_enable (dev->clk); + dev->clk_rate =clk_get_rate (dev->clk); +return 0 ; +} +static int orion_wdt_ping (struct watchdog_device *wdt_dev) {struct orion_watchdog *dev =watchdog_get_drvdata (wdt_dev);
@@ -156,6 +171,7 @@ static const struct orion_watchdog_data orion_data = { .rstout_enable_bit = BIT(1), .wdt_enable_bit = BIT(4), .wdt_counter_offset = 0x24, + .clock_init = orion_wdt_clock_init, };static const struct of_device_id orion_wdt_of_match_table[] = {
@@ -190,13 +206,6 @@ static int orion_wdt_probe(struct platform_device *pdev) dev->wdt.min_timeout =1 ; dev->data = (struct orion_watchdog_data *)match->data; - dev->clk =devm_clk_get (&pdev->dev,NULL ); -if (IS_ERR (dev->clk)) { -dev_err (&pdev->dev,"Orion Watchdog missing clock\n" ); -return -ENODEV ; - } -clk_prepare_enable (dev->clk); - dev->clk_rate =clk_get_rate (dev->clk);spin_lock_init (&dev->lock); res =platform_get_resource (pdev,IORESOURCE_MEM ,0 );
@@ -214,6 +223,12 @@ static int orion_wdt_probe(struct platform_device *pdev)if (!dev->rstout)return -ENOMEM ; + ret = dev->data->clock_init (pdev, dev); +if (ret) { +dev_err (&pdev->dev,"cannot initialize clock\n" ); +return ret; + } + irq =platform_get_irq (pdev,0 );if (irq >0 ) {/*
Signature · 1 line
1.8.1.5
PATCH v2 9/15 watchdog: orion: Add per-compatible clock initialization
drivers/watchdog/orion_wdt.c struct orion_watchdog { · line 73
Quoted 6 lines · Ezequiel Garcia
drivers/watchdog/orion_wdt.c +6
-0+static int orion_wdt_clock_init (struct platform_device *pdev, +struct orion_watchdog *dev) +{ + dev->clk =devm_clk_get (&pdev->dev,NULL ); +if (IS_ERR (dev->clk)) +return -ENODEV ;
Shouldn't it be 'return PTR_ERR(dev->clk)' instead?
Quoted 1 line
+
clk_prepare_enable(dev->clk);
clk_prepare_enable may fail, so better check its return value.
Regards,
Fabio Estevam
PATCH v2 9/15 watchdog: orion: Add per-compatible clock initialization
Quoted 13 lines · Fabio Estevam
drivers/watchdog/orion_wdt.c struct orion_watchdog { · line 73
Quoted 6 lines · Ezequiel Garcia
drivers/watchdog/orion_wdt.c +6
-0+static int orion_wdt_clock_init (struct platform_device *pdev, +struct orion_watchdog *dev) +{ + dev->clk =devm_clk_get (&pdev->dev,NULL ); +if (IS_ERR (dev->clk)) +return -ENODEV ;Shouldn't it be 'return
PTR_ERR(dev->clk)' instead?
[..]
Quoted 4 lines
Quoted 1 line
+
clk_prepare_enable(dev->clk);
clk_prepare_enablemay fail, so better check its return value.
Indeed.
Thanks!
Signature · 3 lines
Ezequiel Garc?a, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com
PATCH v2 10/15 watchdog: orion: Add per-compatible watchdog start implementation
In reply to Ezequiel GarciaTo handle differences between SoCs this commit adds per-compatible string start() function for the watchdog kick-off. This is preparation work and makes no functionality changes to the current driver.
--- drivers/watchdog/orion_wdt.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
drivers/watchdog/orion_wdt.c +11 -1
@@ -53,6 +53,7 @@ struct orion_watchdog_data {int rstout_enable_bit;int (*clock_init) (struct platform_device *,struct orion_watchdog *); +int (*start) (struct watchdog_device *); };struct orion_watchdog {
@@ -89,7 +90,7 @@ static int orion_wdt_ping(struct watchdog_device *wdt_dev)return 0 ; } -static int orion_wdt_start (struct watchdog_device *wdt_dev) +static int orion_start (struct watchdog_device *wdt_dev) {struct orion_watchdog *dev =watchdog_get_drvdata (wdt_dev);
@@ -111,6 +112,14 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)return 0 ; } +static int orion_wdt_start (struct watchdog_device *wdt_dev) +{ +struct orion_watchdog *dev =watchdog_get_drvdata (wdt_dev); + +/* There are some per-SoC quirks to handle */ +return dev->data->start (wdt_dev); +} +static int orion_wdt_stop (struct watchdog_device *wdt_dev) {struct orion_watchdog *dev =watchdog_get_drvdata (wdt_dev);
@@ -172,6 +181,7 @@ static const struct orion_watchdog_data orion_data = { .wdt_enable_bit = BIT(4), .wdt_counter_offset = 0x24, .clock_init = orion_wdt_clock_init, + .start = orion_start, };static const struct of_device_id orion_wdt_of_match_table[] = {
Signature · 1 line
1.8.1.5
PATCH v2 11/15 watchdog: orion: Add support for Armada 370 and Armada XP SoC
In reply to Ezequiel GarciaUsing the added infrastructure for handling SoC differences, this commit adds support for the watchdog controller available in Armada 370 and Armada XP SoCs.
--- drivers/watchdog/orion_wdt.c | 89 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+)
drivers/watchdog/orion_wdt.c +89 -0
@@ -31,6 +31,7 @@* Watchdog timer block registers. */ #define TIMER_CTRL 0x0000 +#define TIMER_A370_STATUS 0x04#define WDT_MAX_CYCLE_COUNT 0xffffffff#define WDT_IN_USE 0
@@ -42,6 +43,12 @@#define WDT_AXP_FIXED_ENABLE_BIT BIT(10) +#define WDT_A370_RATIO_MASK (v) ((v) << 16) +#define WDT_A370_RATIO_SHIFT 5 +#define WDT_A370_RATIO (1 << WDT_A370_RATIO_SHIFT) + +#define WDT_A370_EXPIRED BIT(31) +static bool nowayout =WATCHDOG_NOWAYOUT ;static int heartbeat =-1 ;/* module parameter (seconds) */
@@ -77,6 +84,40 @@ static int orion_wdt_clock_init(struct platform_device *pdev,return 0 ; } +static int armada370_wdt_clock_init (struct platform_device *pdev, +struct orion_watchdog *dev) +{ + dev->clk =devm_clk_get (&pdev->dev,NULL ); +if (IS_ERR (dev->clk)) +return -ENODEV ; +clk_prepare_enable (dev->clk); + +/* Setup watchdog input clock */ +atomic_io_modify (dev->reg +TIMER_CTRL , +WDT_A370_RATIO_MASK (WDT_A370_RATIO_SHIFT ), +WDT_A370_RATIO_MASK (WDT_A370_RATIO_SHIFT )); + + dev->clk_rate =clk_get_rate (dev->clk) /WDT_A370_RATIO ; +return 0 ; +} + +static int armadaxp_wdt_clock_init (struct platform_device *pdev, +struct orion_watchdog *dev) +{ + dev->clk =of_clk_get_by_name (pdev->dev.of_node,"fixed" ); +if (IS_ERR (dev->clk)) +return -ENODEV ; +clk_prepare_enable (dev->clk); + +/* Enable the fixed watchdog clock input */ +atomic_io_modify (dev->reg +TIMER_CTRL , +WDT_AXP_FIXED_ENABLE_BIT , +WDT_AXP_FIXED_ENABLE_BIT ); + + dev->clk_rate =clk_get_rate (dev->clk); +return 0 ; +} +static int orion_wdt_ping (struct watchdog_device *wdt_dev) {struct orion_watchdog *dev =watchdog_get_drvdata (wdt_dev);
@@ -90,6 +131,30 @@ static int orion_wdt_ping(struct watchdog_device *wdt_dev)return 0 ; } +static int armada370_start (struct watchdog_device *wdt_dev) +{ +struct orion_watchdog *dev =watchdog_get_drvdata (wdt_dev); + +spin_lock (&dev->lock); + +/* Set watchdog duration */ +writel (dev->clk_rate * wdt_dev->timeout, + dev->reg + dev->data->wdt_counter_offset); + +/* Clear the watchdog expiration bit */ +atomic_io_modify (dev->reg +TIMER_A370_STATUS ,WDT_A370_EXPIRED ,0 ); + +/* Enable watchdog timer */ +atomic_io_modify (dev->reg +TIMER_CTRL , dev->data->wdt_enable_bit, + dev->data->wdt_enable_bit); + +atomic_io_modify (dev->rstout, dev->data->rstout_enable_bit, + dev->data->rstout_enable_bit); + +spin_unlock (&dev->lock); +return 0 ; +} +static int orion_start (struct watchdog_device *wdt_dev) {struct orion_watchdog *dev =watchdog_get_drvdata (wdt_dev);
@@ -184,11 +249,35 @@ static const struct orion_watchdog_data orion_data = { .start = orion_start, }; +static const struct orion_watchdog_data armada370_data = { + .rstout_enable_bit =BIT (8 ), + .wdt_enable_bit =BIT (8 ), + .wdt_counter_offset =0x34 , + .clock_init = armada370_wdt_clock_init, + .start = armada370_start, +}; + +static const struct orion_watchdog_data armadaxp_data = { + .rstout_enable_bit =BIT (8 ), + .wdt_enable_bit =BIT (8 ), + .wdt_counter_offset =0x34 , + .clock_init = armadaxp_wdt_clock_init, + .start = armada370_start, +}; +static const struct of_device_id orion_wdt_of_match_table[] = { { .compatible ="marvell,orion-wdt" , .data = &orion_data, }, + { + .compatible ="marvell,armada-370-wdt" , + .data = &armada370_data, + }, + { + .compatible ="marvell,armada-xp-wdt" , + .data = &armadaxp_data, + }, {}, };MODULE_DEVICE_TABLE (of, orion_wdt_of_match_table);
Signature · 1 line
1.8.1.5
PATCH v2 12/15 ARM: mvebu: Enable Armada 370/XP watchdog in the devicetree
In reply to Ezequiel GarciaAdd the DT nodes to enable watchdog support available in Armada 370 and Armada XP SoCs.
--- arch/arm/boot/dts/armada-370-xp.dtsi | 4 ++++ arch/arm/boot/dts/armada-370.dtsi | 5 +++++ arch/arm/boot/dts/armada-xp.dtsi | 6 ++++++ 3 files changed, 15 insertions(+)
arch/arm/boot/dts/armada-370-xp.dtsi +4 -0
@@ -151,6 +151,10 @@ interrupts = <37>, <38>, <39>, <40>, <5>, <6>; }; + watchdog at 20300 { + reg = <0x20300 0x34>, <0x20704 0x4>; + }; + sata at a0000 { compatible = "marvell,orion-sata"; reg = <0xa0000 0x5000>;
arch/arm/boot/dts/armada-370.dtsi +5 -0
@@ -168,6 +168,11 @@ clocks = <&coreclk 2>; }; + watchdog at 20300 { + compatible = "marvell,armada-370-wdt"; + clocks = <&coreclk 2>; + }; + coreclk: mvebu-sar at 18230 { compatible = "marvell,armada-370-core-clock"; reg = <0x18230 0x08>;
arch/arm/boot/dts/armada-xp.dtsi +6 -0
@@ -74,6 +74,12 @@ clock-names = "nbclk", "fixed"; }; + watchdog at 20300 { + compatible = "marvell,armada-xp-wdt"; + clocks = <&coreclk 2>, <&refclk>; + clock-names = "nbclk", "fixed"; + }; + coreclk: mvebu-sar at 18230 { compatible = "marvell,armada-xp-core-clock"; reg = <0x18230 0x08>;
Signature · 1 line
1.8.1.5
PATCH v2 13/15 ARM: kirkwood: Add RSTOUT 'reg' entry to devicetree
In reply to Ezequiel GarciaIn order to support multiplatform builds the watchdog devicetree binding was modified and now the 'reg' property is specified to need two entries. This commit adds the second entry as-per the new specification.
--- arch/arm/boot/dts/kirkwood.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm/boot/dts/kirkwood.dtsi +1 -1
@@ -165,7 +165,7 @@ wdt: watchdog-timer at 20300 { compatible = "marvell,orion-wdt"; - reg = <0x20300 0x28>; + reg = <0x20300 0x28>, <0x20108 0x4>; interrupt-parent = <&bridge_intc>; interrupts = <3>; clocks = <&gate_clk 7>;
Signature · 1 line
1.8.1.5
PATCH v2 14/15 watchdog: orion: Allow to build on any Orion platform
In reply to Ezequiel GarciaAfter getting rid of all the mach-specific code, it's now possible to allow builds in any Orion platform.
--- drivers/watchdog/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/watchdog/Kconfig +1 -1
@@ -282,7 +282,7 @@ config DAVINCI_WATCHDOG config ORION_WATCHDOG tristate "Orion watchdog" - depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE + depends on PLAT_ORION select WATCHDOG_CORE help Say Y here if to include support for the watchdog timer
Signature · 1 line
1.8.1.5
Sebastian Hesselbarth
maintainerPATCH v2 14/15 watchdog: orion: Allow to build on any Orion platform
Quoted 13 lines · Ezequiel Garcia
After getting rid of all the mach-specific code, it's now possible to allow builds in any Orion platform.
Signed-off-by Ezequiel Garcia <[email protected]>--- drivers/watchdog/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/watchdog/Kconfig +0
-0
drivers/watchdog/Kconfig config DAVINCI_WATCHDOG · line 285
Quoted 5 lines
drivers/watchdog/Kconfig +1
-1@@ -282,7 +282,7 @@ config DAVINCI_WATCHDOG config ORION_WATCHDOG tristate "Orion watchdog" - depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE + depends on PLAT_ORION
Ezequiel,
while above is true now, I tend to rather have ARCH_MVEBU added here. We really want to get rid of both !ARCH_MVEBU and PLAT_ORION and this unnecessarily will make it more complicated.
I haven't checked why ARCH_MVEBU at all added PLAT_ORION as dependency, but IIRC it was just because of a missing mbus driver? If it is just this, we should also remove PLAT_ORION from ARCH_MVEBU to have a clean cut between new common arch and existing sub-archs.
Sebastian
Quoted 4 lines
drivers/watchdog/Kconfig +0
-0select WATCHDOG_CORE help Say Y here if to include support for the watchdog timer
Andrew Lunn
maintainerPATCH v2 14/15 watchdog: orion: Allow to build on any Orion platform
Quoted 22 lines · Sebastian Hesselbarth
Quoted 13 lines · Ezequiel Garcia
After getting rid of all the mach-specific code, it's now possible to allow builds in any Orion platform.
Signed-off-by Ezequiel Garcia <[email protected]>--- drivers/watchdog/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/watchdog/Kconfig +0
-0drivers/watchdog/Kconfig config DAVINCI_WATCHDOG · line 285
Quoted 5 lines
drivers/watchdog/Kconfig +1
-1@@ -282,7 +282,7 @@ config DAVINCI_WATCHDOG config ORION_WATCHDOG tristate "Orion watchdog" - depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE + depends on PLAT_ORIONEzequiel,
Quoted 8 lines
while above is true now, I tend to rather have
ARCH_MVEBUadded here. We really want to get rid of both !ARCH_MVEBU andPLAT_ORIONand this unnecessarily will make it more complicated.I haven't checked why
ARCH_MVEBUat all addedPLAT_ORIONas dependency, but IIRC it was just because of a missing mbus driver? If it is just this, we should also removePLAT_ORIONfromARCH_MVEBUto have a clean cut between new common arch and existing sub-archs.
I took a look at this when moving DT kirkwood into mach-mvebu. There is nothing in plat-orion which ARCH_MVEBU needs. So i agree with Sebastian, it should be PLAT_ORION || ARCH_MVEBU.
Andrew
PATCH v2 14/15 watchdog: orion: Allow to build on any Orion platform
Hi Andrew, Sebastian:
Quoted 20 lines · Andrew Lunn
Quoted 19 lines · Sebastian Hesselbarth
Quoted 18 lines · Ezequiel Garcia
After getting rid of all the mach-specific code, it's now possible to allow builds in any Orion platform.
Signed-off-by Ezequiel Garcia <[email protected]>--- drivers/watchdog/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/watchdog/Kconfig +1
-1@@ -282,7 +282,7 @@ config DAVINCI_WATCHDOG config ORION_WATCHDOG tristate "Orion watchdog" - depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE + depends on PLAT_ORION
[..]
Quoted 10 lines
Quoted 9 lines
while above is true now, I tend to rather have
ARCH_MVEBUadded here. We really want to get rid of both !ARCH_MVEBU andPLAT_ORIONand this unnecessarily will make it more complicated.I haven't checked why
ARCH_MVEBUat all addedPLAT_ORIONas dependency, but IIRC it was just because of a missing mbus driver? If it is just this, we should also removePLAT_ORIONfromARCH_MVEBUto have a clean cut between new common arch and existing sub-archs.
Hm... not sure why we depend on PLAT_ORION. I'll take a look.
Quoted 4 lines
I took a look at this when moving DT kirkwood into mach-mvebu. There is nothing in plat-orion which
ARCH_MVEBUneeds. So i agree with Sebastian, it should bePLAT_ORION||ARCH_MVEBU.
OK, will do.
Thanks!
Signature · 7 lines
Ezequiel García, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com -- To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Removing PLAT_ORION dependency from ARCH_MVEBU (Was Re: [PATCH v2 14/15] watchdog: orion: Allow to build on any Orion platform)
In reply to Sebastian HesselbarthSebastian,
I'm picking on this discussion, with a new Subject.
Quoted 19 lines · Sebastian Hesselbarth
Quoted 18 lines · Ezequiel Garcia
After getting rid of all the mach-specific code, it's now possible to allow builds in any Orion platform.
Signed-off-by Ezequiel Garcia <[email protected]>--- drivers/watchdog/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/watchdog/Kconfig +1
-1@@ -282,7 +282,7 @@ config DAVINCI_WATCHDOG config ORION_WATCHDOG tristate "Orion watchdog" - depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE + depends on PLAT_ORION
[..]
Quoted 6 lines
I haven't checked why
ARCH_MVEBUat all addedPLAT_ORIONas dependency, but IIRC it was just because of a missing mbus driver? If it is just this, we should also removePLAT_ORIONfromARCH_MVEBUto have a clean cut between new common arch and existing sub-archs.
Well, I'm not sure if I'm following you. Many drivers currently depend on PLAT_ORION, so if we remove PLAT_ORION from ARCH_MVEBU we would have to replace: s/PLAT_ORION/ARCH_{MVEBU, KIRKWOOD, DOVE, ...}.
Is this the suggested roadmap or I've completely misunderstood it?
Signature · 7 lines
Ezequiel García, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com -- To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Sebastian Hesselbarth
maintainerRemoving PLAT_ORION dependency from ARCH_MVEBU (Was Re: [PATCH v2 14/15] watchdog: orion: Allow to build on any Orion platform)
Quoted 32 lines · Ezequiel Garcia
Sebastian,
I'm picking on this discussion, with a new Subject.
Quoted 19 lines · Sebastian Hesselbarth
Quoted 18 lines · Ezequiel Garcia
After getting rid of all the mach-specific code, it's now possible to allow builds in any Orion platform.
Signed-off-by Ezequiel Garcia <[email protected]>--- drivers/watchdog/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/watchdog/Kconfig +1
-1@@ -282,7 +282,7 @@ config DAVINCI_WATCHDOG config ORION_WATCHDOG tristate "Orion watchdog" - depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE + depends on PLAT_ORION[..]
Quoted 6 lines
I haven't checked why
ARCH_MVEBUat all addedPLAT_ORIONas dependency, but IIRC it was just because of a missing mbus driver? If it is just this, we should also removePLAT_ORIONfromARCH_MVEBUto have a clean cut between new common arch and existing sub-archs.
Quoted 5 lines
Well, I'm not sure if I'm following you. Many drivers currently depend on
PLAT_ORION, so if we removePLAT_ORIONfromARCH_MVEBUwe would have to replace: s/PLAT_ORION/ARCH_{MVEBU, KIRKWOOD, DOVE, ...}.Is this the suggested roadmap or I've completely misunderstood it?
Actually, you are right, PLAT_ORION is dependency for a bunch of drivers. But as PLAT_ORION - code-wise - almost only contains non-DT stuff, I'd prefer to use ARCH_MVEBU for DT enabled Marvell SoCs where possible.
So for the above, just add ARCH_MVEBU and remove ARCH_KIRKWOOD, ARCH_DOVE later when we kill them, instead of hiding all behind PLAT_ORION. Also remove the dependency of ARCH_MVEBU to PLAT_ORION where possible or replace it with ARCH_MVEBU directly.
This way we would have a clean ARCH_MVEBU config for DT-enabled SoCs and PLAT_ORION for non-DT ones. BTW, there is also PLAT_ORION_LEGACY which is just selecting PLAT_ORION. IIRC, I added that to distinguish non-DT and DT earlier, but ARCH_MVEBU selecting PLAT_ORION made that redundant.
Sebastian
PATCH v2 15/15 ARM: mvebu: Enable watchdog support in defconfig
In reply to Ezequiel GarciaNow that we have proper support for Armada 370/XP watchdog let's enable it in the defconfig.
--- arch/arm/configs/mvebu_defconfig | 2 ++ 1 file changed, 2 insertions(+)
arch/arm/configs/mvebu_defconfig +2 -0
@@ -60,6 +60,8 @@ CONFIG_GPIOLIB=y CONFIG_GPIO_SYSFS=y CONFIG_THERMAL=y CONFIG_ARMADA_THERMAL=y +CONFIG_WATCHDOG=y +CONFIG_ORION_WATCHDOG=y CONFIG_USB_SUPPORT=y CONFIG_USB=y CONFIG_USB_EHCI_HCD=y
Signature · 1 line
1.8.1.5
PATCH v2 15/15 ARM: mvebu: Enable watchdog support in defconfig
Quoted 7 lines · Ezequiel Garcia
Now that we have proper support for Armada 370/XP watchdog let's enable it in the defconfig.
Signed-off-by Ezequiel Garcia <[email protected]>--- arch/arm/configs/mvebu_defconfig | 2 ++ 1 file changed, 2 insertions(+)
Just a note to myself more than anything: I need to square up multi_v7 with mvebu. As we make these changes next cycle, we need to be able to easily test that we aren't breaking multiplat build or boot.
Hopefully I can get some defconfig changes in for -rc1? :)
thx,
Jason.
Quoted 16 lines
arch/arm/configs/mvebu_defconfig +2
-0@@ -60,6 +60,8 @@ CONFIG_GPIOLIB=y CONFIG_GPIO_SYSFS=y CONFIG_THERMAL=y CONFIG_ARMADA_THERMAL=y +CONFIG_WATCHDOG=y +CONFIG_ORION_WATCHDOG=y CONFIG_USB_SUPPORT=y CONFIG_USB=y CONFIG_USB_EHCI_HCD=ySignature · 1 line
1.8.1.5
Andrew Lunn
maintainerPATCH v2 15/15 ARM: mvebu: Enable watchdog support in defconfig
Quoted 4 lines · Jason Cooper
Quoted 3 lines · Ezequiel Garcia
Now that we have proper support for Armada 370/XP watchdog let's enable it in the defconfig.
Quoted 8 lines
Quoted 4 lines
Signed-off-by Ezequiel Garcia <[email protected]>--- arch/arm/configs/mvebu_defconfig | 2 ++ 1 file changed, 2 insertions(+)Just a note to myself more than anything: I need to square up
multi_v7with mvebu. As we make these changes next cycle, we need to be able to easily test that we aren't breaking multiplat build or boot.
Hi Jason
Hopefully you can also tackle multi_v5 as well, once DT kirkwood moves into mach-mvebu.
To check for breaking boot, you need some other hardware platform. Nomadik was breaking kirkwood multi_v5, and you would not see the problem on Nomadik.
Andrew
PATCH v2 15/15 ARM: mvebu: Enable watchdog support in defconfig
Quoted 10 lines · Andrew Lunn
Quoted 9 lines · Jason Cooper
Quoted 7 lines · Ezequiel Garcia
Now that we have proper support for Armada 370/XP watchdog let's enable it in the defconfig.
Signed-off-by Ezequiel Garcia <[email protected]>--- arch/arm/configs/mvebu_defconfig | 2 ++ 1 file changed, 2 insertions(+)
Quoted 8 lines
Quoted 3 lines
Just a note to myself more than anything: I need to square up
multi_v7with mvebu. As we make these changes next cycle, we need to be able to easily test that we aren't breaking multiplat build or boot.Hi Jason
Hopefully you can also tackle
multi_v5as well, once DT kirkwood moves into mach-mvebu.
Yes.
Quoted 3 lines
To check for breaking boot, you need some other hardware platform. Nomadik was breaking kirkwood
multi_v5, and you would not see the problem on Nomadik.
Yes, I was more specifically looking to leverage arm-buildbot...
thx,
Jason.