add mpcore_wdt fixes

SVN-Revision: 27557
This commit is contained in:
Imre Kaloz 2011-07-08 09:33:13 +00:00
parent 9a560e48dd
commit b3b0f0e49a
4 changed files with 178 additions and 0 deletions

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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;

View file

@ -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)