diff options
| -rw-r--r-- | drivers/watchdog/orion5x_wdt.c | 57 |
1 files changed, 42 insertions, 15 deletions
diff --git a/drivers/watchdog/orion5x_wdt.c b/drivers/watchdog/orion5x_wdt.c index e81441f103dd..7529616739d2 100644 --- a/drivers/watchdog/orion5x_wdt.c +++ b/drivers/watchdog/orion5x_wdt.c | |||
| @@ -42,7 +42,17 @@ static unsigned int wdt_tclk; | |||
| 42 | static unsigned long wdt_status; | 42 | static unsigned long wdt_status; |
| 43 | static spinlock_t wdt_lock; | 43 | static spinlock_t wdt_lock; |
| 44 | 44 | ||
| 45 | static void wdt_enable(void) | 45 | static void orion5x_wdt_ping(void) |
| 46 | { | ||
| 47 | spin_lock(&wdt_lock); | ||
| 48 | |||
| 49 | /* Reload watchdog duration */ | ||
| 50 | writel(wdt_tclk * heartbeat, WDT_VAL); | ||
| 51 | |||
| 52 | spin_unlock(&wdt_lock); | ||
| 53 | } | ||
| 54 | |||
| 55 | static void orion5x_wdt_enable(void) | ||
| 46 | { | 56 | { |
| 47 | u32 reg; | 57 | u32 reg; |
| 48 | 58 | ||
| @@ -69,7 +79,7 @@ static void wdt_enable(void) | |||
| 69 | spin_unlock(&wdt_lock); | 79 | spin_unlock(&wdt_lock); |
| 70 | } | 80 | } |
| 71 | 81 | ||
| 72 | static void wdt_disable(void) | 82 | static void orion5x_wdt_disable(void) |
| 73 | { | 83 | { |
| 74 | u32 reg; | 84 | u32 reg; |
| 75 | 85 | ||
| @@ -101,7 +111,7 @@ static int orion5x_wdt_open(struct inode *inode, struct file *file) | |||
| 101 | if (test_and_set_bit(WDT_IN_USE, &wdt_status)) | 111 | if (test_and_set_bit(WDT_IN_USE, &wdt_status)) |
| 102 | return -EBUSY; | 112 | return -EBUSY; |
| 103 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); | 113 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); |
| 104 | wdt_enable(); | 114 | orion5x_wdt_enable(); |
| 105 | return nonseekable_open(inode, file); | 115 | return nonseekable_open(inode, file); |
| 106 | } | 116 | } |
| 107 | 117 | ||
| @@ -122,18 +132,28 @@ static ssize_t orion5x_wdt_write(struct file *file, const char *data, | |||
| 122 | set_bit(WDT_OK_TO_CLOSE, &wdt_status); | 132 | set_bit(WDT_OK_TO_CLOSE, &wdt_status); |
| 123 | } | 133 | } |
| 124 | } | 134 | } |
| 125 | wdt_enable(); | 135 | orion5x_wdt_ping(); |
| 126 | } | 136 | } |
| 127 | return len; | 137 | return len; |
| 128 | } | 138 | } |
| 129 | 139 | ||
| 130 | static struct watchdog_info ident = { | 140 | static int orion5x_wdt_settimeout(int new_time) |
| 141 | { | ||
| 142 | if ((new_time <= 0) || (new_time > wdt_max_duration)) | ||
| 143 | return -EINVAL; | ||
| 144 | |||
| 145 | /* Set new watchdog time to be used when | ||
| 146 | * orion5x_wdt_enable() or orion5x_wdt_ping() is called. */ | ||
| 147 | heartbeat = new_time; | ||
| 148 | return 0; | ||
| 149 | } | ||
| 150 | |||
| 151 | static const struct watchdog_info ident = { | ||
| 131 | .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | | 152 | .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | |
| 132 | WDIOF_KEEPALIVEPING, | 153 | WDIOF_KEEPALIVEPING, |
| 133 | .identity = "Orion5x Watchdog", | 154 | .identity = "Orion5x Watchdog", |
| 134 | }; | 155 | }; |
| 135 | 156 | ||
| 136 | |||
| 137 | static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd, | 157 | static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd, |
| 138 | unsigned long arg) | 158 | unsigned long arg) |
| 139 | { | 159 | { |
| @@ -152,7 +172,7 @@ static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd, | |||
| 152 | break; | 172 | break; |
| 153 | 173 | ||
| 154 | case WDIOC_KEEPALIVE: | 174 | case WDIOC_KEEPALIVE: |
| 155 | wdt_enable(); | 175 | orion5x_wdt_ping(); |
| 156 | ret = 0; | 176 | ret = 0; |
| 157 | break; | 177 | break; |
| 158 | 178 | ||
| @@ -161,12 +181,11 @@ static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd, | |||
| 161 | if (ret) | 181 | if (ret) |
| 162 | break; | 182 | break; |
| 163 | 183 | ||
| 164 | if (time <= 0 || time > wdt_max_duration) { | 184 | if (orion5x_wdt_settimeout(time)) { |
| 165 | ret = -EINVAL; | 185 | ret = -EINVAL; |
| 166 | break; | 186 | break; |
| 167 | } | 187 | } |
| 168 | heartbeat = time; | 188 | orion5x_wdt_ping(); |
| 169 | wdt_enable(); | ||
| 170 | /* Fall through */ | 189 | /* Fall through */ |
| 171 | 190 | ||
| 172 | case WDIOC_GETTIMEOUT: | 191 | case WDIOC_GETTIMEOUT: |
| @@ -187,7 +206,7 @@ static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd, | |||
| 187 | static int orion5x_wdt_release(struct inode *inode, struct file *file) | 206 | static int orion5x_wdt_release(struct inode *inode, struct file *file) |
| 188 | { | 207 | { |
| 189 | if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) | 208 | if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) |
| 190 | wdt_disable(); | 209 | orion5x_wdt_disable(); |
| 191 | else | 210 | else |
| 192 | printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " | 211 | printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " |
| 193 | "timer will not stop\n"); | 212 | "timer will not stop\n"); |
| @@ -230,7 +249,7 @@ static int __devinit orion5x_wdt_probe(struct platform_device *pdev) | |||
| 230 | orion5x_wdt_miscdev.parent = &pdev->dev; | 249 | orion5x_wdt_miscdev.parent = &pdev->dev; |
| 231 | 250 | ||
| 232 | wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk; | 251 | wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk; |
| 233 | if (heartbeat <= 0 || heartbeat > wdt_max_duration) | 252 | if (orion5x_wdt_settimeout(heartbeat)) |
| 234 | heartbeat = wdt_max_duration; | 253 | heartbeat = wdt_max_duration; |
| 235 | 254 | ||
| 236 | ret = misc_register(&orion5x_wdt_miscdev); | 255 | ret = misc_register(&orion5x_wdt_miscdev); |
| @@ -247,7 +266,7 @@ static int __devexit orion5x_wdt_remove(struct platform_device *pdev) | |||
| 247 | int ret; | 266 | int ret; |
| 248 | 267 | ||
| 249 | if (test_bit(WDT_IN_USE, &wdt_status)) { | 268 | if (test_bit(WDT_IN_USE, &wdt_status)) { |
| 250 | wdt_disable(); | 269 | orion5x_wdt_disable(); |
| 251 | clear_bit(WDT_IN_USE, &wdt_status); | 270 | clear_bit(WDT_IN_USE, &wdt_status); |
| 252 | } | 271 | } |
| 253 | 272 | ||
| @@ -258,9 +277,16 @@ static int __devexit orion5x_wdt_remove(struct platform_device *pdev) | |||
| 258 | return ret; | 277 | return ret; |
| 259 | } | 278 | } |
| 260 | 279 | ||
| 280 | static void orion5x_wdt_shutdown(struct platform_device *pdev) | ||
| 281 | { | ||
| 282 | if (test_bit(WDT_IN_USE, &wdt_status)) | ||
| 283 | orion5x_wdt_disable(); | ||
| 284 | } | ||
| 285 | |||
| 261 | static struct platform_driver orion5x_wdt_driver = { | 286 | static struct platform_driver orion5x_wdt_driver = { |
| 262 | .probe = orion5x_wdt_probe, | 287 | .probe = orion5x_wdt_probe, |
| 263 | .remove = __devexit_p(orion5x_wdt_remove), | 288 | .remove = __devexit_p(orion5x_wdt_remove), |
| 289 | .shutdown = orion5x_wdt_shutdown, | ||
| 264 | .driver = { | 290 | .driver = { |
| 265 | .owner = THIS_MODULE, | 291 | .owner = THIS_MODULE, |
| 266 | .name = "orion5x_wdt", | 292 | .name = "orion5x_wdt", |
| @@ -285,10 +311,11 @@ MODULE_AUTHOR("Sylver Bruneau <sylver.bruneau@googlemail.com>"); | |||
| 285 | MODULE_DESCRIPTION("Orion5x Processor Watchdog"); | 311 | MODULE_DESCRIPTION("Orion5x Processor Watchdog"); |
| 286 | 312 | ||
| 287 | module_param(heartbeat, int, 0); | 313 | module_param(heartbeat, int, 0); |
| 288 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds"); | 314 | MODULE_PARM_DESC(heartbeat, "Initial watchdog heartbeat in seconds"); |
| 289 | 315 | ||
| 290 | module_param(nowayout, int, 0); | 316 | module_param(nowayout, int, 0); |
| 291 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); | 317 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" |
| 318 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
| 292 | 319 | ||
| 293 | MODULE_LICENSE("GPL"); | 320 | MODULE_LICENSE("GPL"); |
| 294 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | 321 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |
