diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/watchdog/booke_wdt.c | 57 |
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; | |||
41 | u32 booke_wdt_period = WDT_PERIOD_DEFAULT; | 43 | u32 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 | ||
51 | static DEFINE_SPINLOCK(booke_wdt_lock); | 53 | static 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 | */ | ||
65 | static 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 | */ | ||
84 | static 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 | |||
53 | static void __booke_wdt_ping(void *data) | 94 | static 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; |