aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog/booke_wdt.c
diff options
context:
space:
mode:
authorChris Friesen <cfriesen@nortel.com>2009-08-12 14:02:46 -0400
committerWim Van Sebroeck <wim@iguana.be>2009-09-18 04:37:21 -0400
commitdcfb748422d01245b6e89c94d85fcdb3c71a56a0 (patch)
tree19c99c7c3ec245de6610cf1e0e6f8cf9023a5e98 /drivers/watchdog/booke_wdt.c
parent9fd868f440c3d722199a14200b2a64a0a5e70221 (diff)
[WATCHDOG] fix book E watchdog to take WDIOC_SETTIMEOUT arg in seconds
The WDIOC_SETTIMEOUT argument is supposed to be a "seconds" value. However, the book E wdt currently treats it as a "period" which is interpreted in a board-specific way. This patch allows the user to pass in a "seconds" value and the driver will set the smallest timeout that is at least as large as specified by the user. It's been tested on e500 hardware and works as expected. The patch only modifies the CONFIG_FSL_BOOKE case, the CONFIG_4xx case is left unmodified as I don't have any hardware to test it on. Signed-off-by: Chris Friesen <cfriesen@nortel.com> Cc: Kumar Gala <galak@gate.crashing.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/watchdog/booke_wdt.c')
-rw-r--r--drivers/watchdog/booke_wdt.c57
1 files changed, 53 insertions, 4 deletions
diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c
index 225398fd5049..e8380ef65c1c 100644
--- a/drivers/watchdog/booke_wdt.c
+++ b/drivers/watchdog/booke_wdt.c
@@ -22,6 +22,8 @@
22 22
23#include <asm/reg_booke.h> 23#include <asm/reg_booke.h>
24#include <asm/system.h> 24#include <asm/system.h>
25#include <asm/time.h>
26#include <asm/div64.h>
25 27
26/* If the kernel parameter wdt=1, the watchdog will be enabled at boot. 28/* If the kernel parameter wdt=1, the watchdog will be enabled at boot.
27 * Also, the wdt_period sets the watchdog timer period timeout. 29 * Also, the wdt_period sets the watchdog timer period timeout.
@@ -32,7 +34,7 @@
32 */ 34 */
33 35
34#ifdef CONFIG_FSL_BOOKE 36#ifdef CONFIG_FSL_BOOKE
35#define WDT_PERIOD_DEFAULT 63 /* Ex. wdt_period=28 bus=333Mhz,reset=~40sec */ 37#define WDT_PERIOD_DEFAULT 38 /* Ex. wdt_period=28 bus=333Mhz,reset=~40sec */
36#else 38#else
37#define WDT_PERIOD_DEFAULT 3 /* Refer to the PPC40x and PPC4xx manuals */ 39#define WDT_PERIOD_DEFAULT 3 /* Refer to the PPC40x and PPC4xx manuals */
38#endif /* for timing information */ 40#endif /* for timing information */
@@ -41,7 +43,7 @@ u32 booke_wdt_enabled;
41u32 booke_wdt_period = WDT_PERIOD_DEFAULT; 43u32 booke_wdt_period = WDT_PERIOD_DEFAULT;
42 44
43#ifdef CONFIG_FSL_BOOKE 45#ifdef CONFIG_FSL_BOOKE
44#define WDTP(x) ((((63-x)&0x3)<<30)|(((63-x)&0x3c)<<15)) 46#define WDTP(x) ((((x)&0x3)<<30)|(((x)&0x3c)<<15))
45#define WDTP_MASK (WDTP(0)) 47#define WDTP_MASK (WDTP(0))
46#else 48#else
47#define WDTP(x) (TCR_WP(x)) 49#define WDTP(x) (TCR_WP(x))
@@ -50,6 +52,45 @@ u32 booke_wdt_period = WDT_PERIOD_DEFAULT;
50 52
51static DEFINE_SPINLOCK(booke_wdt_lock); 53static DEFINE_SPINLOCK(booke_wdt_lock);
52 54
55/* For the specified period, determine the number of seconds
56 * corresponding to the reset time. There will be a watchdog
57 * exception at approximately 3/5 of this time.
58 *
59 * The formula to calculate this is given by:
60 * 2.5 * (2^(63-period+1)) / timebase_freq
61 *
62 * In order to simplify things, we assume that period is
63 * at least 1. This will still result in a very long timeout.
64 */
65static unsigned long long period_to_sec(unsigned int period)
66{
67 unsigned long long tmp = 1ULL << (64 - period);
68 unsigned long tmp2 = ppc_tb_freq;
69
70 /* tmp may be a very large number and we don't want to overflow,
71 * so divide the timebase freq instead of multiplying tmp
72 */
73 tmp2 = tmp2 / 5 * 2;
74
75 do_div(tmp, tmp2);
76 return tmp;
77}
78
79/*
80 * This procedure will find the highest period which will give a timeout
81 * greater than the one required. e.g. for a bus speed of 66666666 and
82 * and a parameter of 2 secs, then this procedure will return a value of 38.
83 */
84static unsigned int sec_to_period(unsigned int secs)
85{
86 unsigned int period;
87 for (period = 63; period > 0; period--) {
88 if (period_to_sec(period) >= secs)
89 return period;
90 }
91 return 0;
92}
93
53static void __booke_wdt_ping(void *data) 94static void __booke_wdt_ping(void *data)
54{ 95{
55 mtspr(SPRN_TSR, TSR_ENW|TSR_WIS); 96 mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
@@ -93,7 +134,7 @@ static long booke_wdt_ioctl(struct file *file,
93 134
94 switch (cmd) { 135 switch (cmd) {
95 case WDIOC_GETSUPPORT: 136 case WDIOC_GETSUPPORT:
96 if (copy_to_user(arg, &ident, sizeof(struct watchdog_info))) 137 if (copy_to_user((void *)arg, &ident, sizeof(ident)))
97 return -EFAULT; 138 return -EFAULT;
98 case WDIOC_GETSTATUS: 139 case WDIOC_GETSTATUS:
99 return put_user(ident.options, p); 140 return put_user(ident.options, p);
@@ -115,8 +156,16 @@ static long booke_wdt_ioctl(struct file *file,
115 booke_wdt_ping(); 156 booke_wdt_ping();
116 return 0; 157 return 0;
117 case WDIOC_SETTIMEOUT: 158 case WDIOC_SETTIMEOUT:
118 if (get_user(booke_wdt_period, p)) 159 if (get_user(tmp, p))
119 return -EFAULT; 160 return -EFAULT;
161#ifdef CONFIG_FSL_BOOKE
162 /* period of 1 gives the largest possible timeout */
163 if (tmp > period_to_sec(1))
164 return -EINVAL;
165 booke_wdt_period = sec_to_period(tmp);
166#else
167 booke_wdt_period = tmp;
168#endif
120 mtspr(SPRN_TCR, (mfspr(SPRN_TCR) & ~WDTP_MASK) | 169 mtspr(SPRN_TCR, (mfspr(SPRN_TCR) & ~WDTP_MASK) |
121 WDTP(booke_wdt_period)); 170 WDTP(booke_wdt_period));
122 return 0; 171 return 0;