mirror of
https://github.com/openwrt/openwrt.git
synced 2025-01-31 16:35:44 +00:00
add mpcore_wdt fixes
SVN-Revision: 27557
This commit is contained in:
parent
9a560e48dd
commit
b3b0f0e49a
@ -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…
x
Reference in New Issue
Block a user