[generic/3.0]: add mpcore_wdt fixes
authorImre Kaloz <kaloz@openwrt.org>
Fri, 8 Jul 2011 09:33:13 +0000 (09:33 +0000)
committerImre Kaloz <kaloz@openwrt.org>
Fri, 8 Jul 2011 09:33:13 +0000 (09:33 +0000)
SVN-Revision: 27557

target/linux/generic/patches-3.0/991-arm_smp_twd_fix_typo.patch [new file with mode: 0644]
target/linux/generic/patches-3.0/992-mpcore_wdt_fix_watchdog_counter_loading.patch [new file with mode: 0644]
target/linux/generic/patches-3.0/993-mpcore_wdt_fix_wdioc_setoptions_handling.patch [new file with mode: 0644]
target/linux/generic/patches-3.0/994-mpcore_wdt_fix_timer_mode_setup.patch [new file with mode: 0644]

diff --git a/target/linux/generic/patches-3.0/991-arm_smp_twd_fix_typo.patch b/target/linux/generic/patches-3.0/991-arm_smp_twd_fix_typo.patch
new file mode 100644 (file)
index 0000000..9574757
--- /dev/null
@@ -0,0 +1,28 @@
+To get hundredths of MHz the rate needs to be divided by 10'000.
+Here is an example:
+ twd_timer_rate = 123456789
+ Before the patch:
+    twd_timer_rate / 1000000 = 123
+    (twd_timer_rate / 1000000) % 100 = 23
+    Result: 123.23MHz.
+ After being fixed:
+    twd_timer_rate / 1000000 = 123
+    (twd_timer_rate / 10000) % 100 = 45
+    Result: 123.45MHz.
+
+Signed-off-by: Vitaly Kuzmichev <vkuzmichev@mvista.com>
+---
+ arch/arm/kernel/smp_twd.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+--- a/arch/arm/kernel/smp_twd.c
++++ b/arch/arm/kernel/smp_twd.c
+@@ -115,7 +115,7 @@ static void __cpuinit twd_calibrate_rate
+               twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);
+               printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000,
+-                      (twd_timer_rate / 1000000) % 100);
++                      (twd_timer_rate / 10000) % 100);
+       }
+ }
diff --git a/target/linux/generic/patches-3.0/992-mpcore_wdt_fix_watchdog_counter_loading.patch b/target/linux/generic/patches-3.0/992-mpcore_wdt_fix_watchdog_counter_loading.patch
new file mode 100644 (file)
index 0000000..87c1c02
--- /dev/null
@@ -0,0 +1,64 @@
+Although the commit "98af057092f8f0dabe63c5df08adc2bbfbddb1d2
+ ARM: 6126/1: ARM mpcore_wdt: fix build failure and other fixes"
+resolved long standing mpcore_wdt driver build problems, it
+introduced an error in the relationship between the MPcore watchdog
+timer clock rate and mpcore_margin, "MPcore timer margin in seconds",
+such that watchdog timeouts are now arbitrary rather than the number
+of seconds specified by mpcore_margin.
+
+This change restores mpcore_wdt_keepalive() to its equivalent
+implementation prior to commit 98af057 such that watchdog timeouts now
+occur as specified by mpcore_margin.
+
+The variable 'mpcore_timer_rate' which caused that build failure was
+replaced by 'twd_timer_rate'. Adding exported function to obtain
+'twd_timer_rate' value in mpcore_wdt driver.
+
+MPCORE_WATCHDOG needed to build 'mpcore_wdt' already depends on
+HAVE_ARM_TWD needed to build 'smp_twd', so from the point of view of
+'mpcore_wdt' driver the exported function will always exist.
+
+Signed-off-by: Valentine Barshak <vbarshak@mvista.com>
+Signed-off-by: Vitaly Kuzmichev <vkuzmichev@mvista.com>
+---
+
+ arch/arm/include/asm/smp_twd.h |    1 +
+ arch/arm/kernel/smp_twd.c      |    7 +++++++
+ drivers/watchdog/mpcore_wdt.c  |    4 +---
+ 3 files changed, 9 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/include/asm/smp_twd.h
++++ b/arch/arm/include/asm/smp_twd.h
+@@ -24,5 +24,6 @@ extern void __iomem *twd_base;
+ int twd_timer_ack(void);
+ void twd_timer_setup(struct clock_event_device *);
++unsigned long twd_timer_get_rate(void);
+ #endif
+--- a/arch/arm/kernel/smp_twd.c
++++ b/arch/arm/kernel/smp_twd.c
+@@ -142,3 +142,10 @@ void __cpuinit twd_timer_setup(struct cl
+       clockevents_register_device(clk);
+ }
++
++/* Needed by mpcore_wdt */
++unsigned long twd_timer_get_rate(void)
++{
++      return twd_timer_rate;
++}
++EXPORT_SYMBOL_GPL(twd_timer_get_rate);
+--- a/drivers/watchdog/mpcore_wdt.c
++++ b/drivers/watchdog/mpcore_wdt.c
+@@ -99,9 +99,7 @@ static void mpcore_wdt_keepalive(struct
+       spin_lock(&wdt_lock);
+       /* Assume prescale is set to 256 */
+-      count =  __raw_readl(wdt->base + TWD_WDOG_COUNTER);
+-      count = (0xFFFFFFFFU - count) * (HZ / 5);
+-      count = (count / 256) * mpcore_margin;
++      count = (twd_timer_get_rate() / 256) * mpcore_margin;
+       /* Reload the counter */
+       writel(count + wdt->perturb, wdt->base + TWD_WDOG_LOAD);
diff --git a/target/linux/generic/patches-3.0/993-mpcore_wdt_fix_wdioc_setoptions_handling.patch b/target/linux/generic/patches-3.0/993-mpcore_wdt_fix_wdioc_setoptions_handling.patch
new file mode 100644 (file)
index 0000000..fa261ce
--- /dev/null
@@ -0,0 +1,29 @@
+According to the include/linux/watchdog.h WDIOC_SETOPTIONS is
+classified as 'read from device' ioctl call:
+  #define WDIOC_SETOPTIONS        _IOR(WATCHDOG_IOCTL_BASE, 4, int)
+
+However, the driver 'mpcore_wdt' performs 'copy_from_user' only if
+_IOC_WRITE is set, thus the local variable 'uarg' which is used in
+WDIOC_SETOPTIONS handling remains uninitialized.
+
+The proper way to fix this is to bind WDIOC_SETOPTIONS to _IOW,
+but this will break compatibility.
+So adding additional condition for performing 'copy_from_user'.
+
+Signed-off-by: Vitaly Kuzmichev <vkuzmichev@mvista.com>
+---
+ drivers/watchdog/mpcore_wdt.c |    3 ++-
+ 1 files changed, 2 insertions(+), 1 deletions(-)
+
+--- a/drivers/watchdog/mpcore_wdt.c
++++ b/drivers/watchdog/mpcore_wdt.c
+@@ -233,7 +233,8 @@ static long mpcore_wdt_ioctl(struct file
+       if (_IOC_DIR(cmd) && _IOC_SIZE(cmd) > sizeof(uarg))
+               return -ENOTTY;
+-      if (_IOC_DIR(cmd) & _IOC_WRITE) {
++      if ((_IOC_DIR(cmd) & _IOC_WRITE)
++                      || cmd == WDIOC_SETOPTIONS) {
+               ret = copy_from_user(&uarg, (void __user *)arg, _IOC_SIZE(cmd));
+               if (ret)
+                       return -EFAULT;
diff --git a/target/linux/generic/patches-3.0/994-mpcore_wdt_fix_timer_mode_setup.patch b/target/linux/generic/patches-3.0/994-mpcore_wdt_fix_timer_mode_setup.patch
new file mode 100644 (file)
index 0000000..0090923
--- /dev/null
@@ -0,0 +1,57 @@
+Allow watchdog to set its iterrupt as pending when it is configured
+for timer mode (in other words, allow emitting interrupt).
+Also add macros for all Watchdog Control Register flags.
+
+Signed-off-by: Vitaly Kuzmichev <vkuzmichev@mvista.com>
+---
+ arch/arm/include/asm/smp_twd.h |    6 ++++++
+ drivers/watchdog/mpcore_wdt.c  |   15 +++++++++++----
+ 2 files changed, 17 insertions(+), 4 deletions(-)
+
+--- a/arch/arm/include/asm/smp_twd.h
++++ b/arch/arm/include/asm/smp_twd.h
+@@ -18,6 +18,12 @@
+ #define TWD_TIMER_CONTROL_PERIODIC    (1 << 1)
+ #define TWD_TIMER_CONTROL_IT_ENABLE   (1 << 2)
++#define TWD_WDOG_CONTROL_ENABLE               (1 << 0)
++#define TWD_WDOG_CONTROL_PERIODIC     (1 << 1)
++#define TWD_WDOG_CONTROL_IT_ENABLE    (1 << 2)
++#define TWD_WDOG_CONTROL_TIMER_MODE   (0 << 3)
++#define TWD_WDOG_CONTROL_WATCHDOG_MODE        (1 << 3)
++
+ struct clock_event_device;
+ extern void __iomem *twd_base;
+--- a/drivers/watchdog/mpcore_wdt.c
++++ b/drivers/watchdog/mpcore_wdt.c
+@@ -118,18 +118,25 @@ static void mpcore_wdt_stop(struct mpcor
+ static void mpcore_wdt_start(struct mpcore_wdt *wdt)
+ {
++      u32 mode;
++
+       dev_printk(KERN_INFO, wdt->dev, "enabling watchdog.\n");
+       /* This loads the count register but does NOT start the count yet */
+       mpcore_wdt_keepalive(wdt);
++      /* Setup watchdog - prescale=256, enable=1 */
++      mode = (255 << 8) | TWD_WDOG_CONTROL_ENABLE;
++
+       if (mpcore_noboot) {
+-              /* Enable watchdog - prescale=256, watchdog mode=0, enable=1 */
+-              writel(0x0000FF01, wdt->base + TWD_WDOG_CONTROL);
++              /* timer mode, send interrupt */
++              mode |= TWD_WDOG_CONTROL_TIMER_MODE |
++                              TWD_WDOG_CONTROL_IT_ENABLE;
+       } else {
+-              /* Enable watchdog - prescale=256, watchdog mode=1, enable=1 */
+-              writel(0x0000FF09, wdt->base + TWD_WDOG_CONTROL);
++              /* watchdog mode */
++              mode |= TWD_WDOG_CONTROL_WATCHDOG_MODE;
+       }
++      writel(mode, wdt->base + TWD_WDOG_CONTROL);
+ }
+ static int mpcore_wdt_set_heartbeat(int t)