add mpcore_wdt fixes
SVN-Revision: 27557
This commit is contained in:
parent
9a560e48dd
commit
b3b0f0e49a
4 changed files with 178 additions and 0 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
|
@ -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;
|
|
@ -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)
|
Loading…
Reference in a new issue