diff options
Diffstat (limited to 'drivers/watchdog/ixp4xx_wdt.c')
-rw-r--r-- | drivers/watchdog/ixp4xx_wdt.c | 67 |
1 files changed, 29 insertions, 38 deletions
diff --git a/drivers/watchdog/ixp4xx_wdt.c b/drivers/watchdog/ixp4xx_wdt.c index 2313fad0dbb1..41264a5f1731 100644 --- a/drivers/watchdog/ixp4xx_wdt.c +++ b/drivers/watchdog/ixp4xx_wdt.c | |||
@@ -22,48 +22,47 @@ | |||
22 | #include <linux/watchdog.h> | 22 | #include <linux/watchdog.h> |
23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
24 | #include <linux/bitops.h> | 24 | #include <linux/bitops.h> |
25 | 25 | #include <linux/uaccess.h> | |
26 | #include <mach/hardware.h> | 26 | #include <mach/hardware.h> |
27 | #include <asm/uaccess.h> | ||
28 | 27 | ||
29 | static int nowayout = WATCHDOG_NOWAYOUT; | 28 | static int nowayout = WATCHDOG_NOWAYOUT; |
30 | static int heartbeat = 60; /* (secs) Default is 1 minute */ | 29 | static int heartbeat = 60; /* (secs) Default is 1 minute */ |
31 | static unsigned long wdt_status; | 30 | static unsigned long wdt_status; |
32 | static unsigned long boot_status; | 31 | static unsigned long boot_status; |
32 | static spin_lock_t wdt_lock; | ||
33 | 33 | ||
34 | #define WDT_TICK_RATE (IXP4XX_PERIPHERAL_BUS_CLOCK * 1000000UL) | 34 | #define WDT_TICK_RATE (IXP4XX_PERIPHERAL_BUS_CLOCK * 1000000UL) |
35 | 35 | ||
36 | #define WDT_IN_USE 0 | 36 | #define WDT_IN_USE 0 |
37 | #define WDT_OK_TO_CLOSE 1 | 37 | #define WDT_OK_TO_CLOSE 1 |
38 | 38 | ||
39 | static void | 39 | static void wdt_enable(void) |
40 | wdt_enable(void) | ||
41 | { | 40 | { |
41 | spin_lock(&wdt_lock); | ||
42 | *IXP4XX_OSWK = IXP4XX_WDT_KEY; | 42 | *IXP4XX_OSWK = IXP4XX_WDT_KEY; |
43 | *IXP4XX_OSWE = 0; | 43 | *IXP4XX_OSWE = 0; |
44 | *IXP4XX_OSWT = WDT_TICK_RATE * heartbeat; | 44 | *IXP4XX_OSWT = WDT_TICK_RATE * heartbeat; |
45 | *IXP4XX_OSWE = IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE; | 45 | *IXP4XX_OSWE = IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE; |
46 | *IXP4XX_OSWK = 0; | 46 | *IXP4XX_OSWK = 0; |
47 | spin_unlock(&wdt_lock); | ||
47 | } | 48 | } |
48 | 49 | ||
49 | static void | 50 | static void wdt_disable(void) |
50 | wdt_disable(void) | ||
51 | { | 51 | { |
52 | spin_lock(&wdt_lock); | ||
52 | *IXP4XX_OSWK = IXP4XX_WDT_KEY; | 53 | *IXP4XX_OSWK = IXP4XX_WDT_KEY; |
53 | *IXP4XX_OSWE = 0; | 54 | *IXP4XX_OSWE = 0; |
54 | *IXP4XX_OSWK = 0; | 55 | *IXP4XX_OSWK = 0; |
56 | spin_unlock(&wdt_lock); | ||
55 | } | 57 | } |
56 | 58 | ||
57 | static int | 59 | static int ixp4xx_wdt_open(struct inode *inode, struct file *file) |
58 | ixp4xx_wdt_open(struct inode *inode, struct file *file) | ||
59 | { | 60 | { |
60 | if (test_and_set_bit(WDT_IN_USE, &wdt_status)) | 61 | if (test_and_set_bit(WDT_IN_USE, &wdt_status)) |
61 | return -EBUSY; | 62 | return -EBUSY; |
62 | 63 | ||
63 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); | 64 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); |
64 | |||
65 | wdt_enable(); | 65 | wdt_enable(); |
66 | |||
67 | return nonseekable_open(inode, file); | 66 | return nonseekable_open(inode, file); |
68 | } | 67 | } |
69 | 68 | ||
@@ -87,7 +86,6 @@ ixp4xx_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) | |||
87 | } | 86 | } |
88 | wdt_enable(); | 87 | wdt_enable(); |
89 | } | 88 | } |
90 | |||
91 | return len; | 89 | return len; |
92 | } | 90 | } |
93 | 91 | ||
@@ -98,9 +96,8 @@ static struct watchdog_info ident = { | |||
98 | }; | 96 | }; |
99 | 97 | ||
100 | 98 | ||
101 | static int | 99 | static long ixp4xx_wdt_ioctl(struct file *file, unsigned int cmd, |
102 | ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 100 | unsigned long arg) |
103 | unsigned long arg) | ||
104 | { | 101 | { |
105 | int ret = -ENOTTY; | 102 | int ret = -ENOTTY; |
106 | int time; | 103 | int time; |
@@ -119,6 +116,11 @@ ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
119 | ret = put_user(boot_status, (int *)arg); | 116 | ret = put_user(boot_status, (int *)arg); |
120 | break; | 117 | break; |
121 | 118 | ||
119 | case WDIOC_KEEPALIVE: | ||
120 | wdt_enable(); | ||
121 | ret = 0; | ||
122 | break; | ||
123 | |||
122 | case WDIOC_SETTIMEOUT: | 124 | case WDIOC_SETTIMEOUT: |
123 | ret = get_user(time, (int *)arg); | 125 | ret = get_user(time, (int *)arg); |
124 | if (ret) | 126 | if (ret) |
@@ -136,25 +138,17 @@ ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
136 | case WDIOC_GETTIMEOUT: | 138 | case WDIOC_GETTIMEOUT: |
137 | ret = put_user(heartbeat, (int *)arg); | 139 | ret = put_user(heartbeat, (int *)arg); |
138 | break; | 140 | break; |
139 | |||
140 | case WDIOC_KEEPALIVE: | ||
141 | wdt_enable(); | ||
142 | ret = 0; | ||
143 | break; | ||
144 | } | 141 | } |
145 | return ret; | 142 | return ret; |
146 | } | 143 | } |
147 | 144 | ||
148 | static int | 145 | static int ixp4xx_wdt_release(struct inode *inode, struct file *file) |
149 | ixp4xx_wdt_release(struct inode *inode, struct file *file) | ||
150 | { | 146 | { |
151 | if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) { | 147 | if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) |
152 | wdt_disable(); | 148 | wdt_disable(); |
153 | } else { | 149 | else |
154 | printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " | 150 | printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " |
155 | "timer will not stop\n"); | 151 | "timer will not stop\n"); |
156 | } | ||
157 | |||
158 | clear_bit(WDT_IN_USE, &wdt_status); | 152 | clear_bit(WDT_IN_USE, &wdt_status); |
159 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); | 153 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); |
160 | 154 | ||
@@ -162,18 +156,16 @@ ixp4xx_wdt_release(struct inode *inode, struct file *file) | |||
162 | } | 156 | } |
163 | 157 | ||
164 | 158 | ||
165 | static const struct file_operations ixp4xx_wdt_fops = | 159 | static const struct file_operations ixp4xx_wdt_fops = { |
166 | { | ||
167 | .owner = THIS_MODULE, | 160 | .owner = THIS_MODULE, |
168 | .llseek = no_llseek, | 161 | .llseek = no_llseek, |
169 | .write = ixp4xx_wdt_write, | 162 | .write = ixp4xx_wdt_write, |
170 | .ioctl = ixp4xx_wdt_ioctl, | 163 | .unlocked_ioctl = ixp4xx_wdt_ioctl, |
171 | .open = ixp4xx_wdt_open, | 164 | .open = ixp4xx_wdt_open, |
172 | .release = ixp4xx_wdt_release, | 165 | .release = ixp4xx_wdt_release, |
173 | }; | 166 | }; |
174 | 167 | ||
175 | static struct miscdevice ixp4xx_wdt_miscdev = | 168 | static struct miscdevice ixp4xx_wdt_miscdev = { |
176 | { | ||
177 | .minor = WATCHDOG_MINOR, | 169 | .minor = WATCHDOG_MINOR, |
178 | .name = "watchdog", | 170 | .name = "watchdog", |
179 | .fops = &ixp4xx_wdt_fops, | 171 | .fops = &ixp4xx_wdt_fops, |
@@ -186,19 +178,18 @@ static int __init ixp4xx_wdt_init(void) | |||
186 | 178 | ||
187 | asm("mrc p15, 0, %0, cr0, cr0, 0;" : "=r"(processor_id) :); | 179 | asm("mrc p15, 0, %0, cr0, cr0, 0;" : "=r"(processor_id) :); |
188 | if (!(processor_id & 0xf) && !cpu_is_ixp46x()) { | 180 | if (!(processor_id & 0xf) && !cpu_is_ixp46x()) { |
189 | printk("IXP4XXX Watchdog: Rev. A0 IXP42x CPU detected - " | 181 | printk(KERN_ERR "IXP4XXX Watchdog: Rev. A0 IXP42x CPU detected" |
190 | "watchdog disabled\n"); | 182 | " - watchdog disabled\n"); |
191 | 183 | ||
192 | return -ENODEV; | 184 | return -ENODEV; |
193 | } | 185 | } |
194 | 186 | spin_lock_init(&wdt_lock); | |
195 | ret = misc_register(&ixp4xx_wdt_miscdev); | ||
196 | if (ret == 0) | ||
197 | printk("IXP4xx Watchdog Timer: heartbeat %d sec\n", heartbeat); | ||
198 | |||
199 | boot_status = (*IXP4XX_OSST & IXP4XX_OSST_TIMER_WARM_RESET) ? | 187 | boot_status = (*IXP4XX_OSST & IXP4XX_OSST_TIMER_WARM_RESET) ? |
200 | WDIOF_CARDRESET : 0; | 188 | WDIOF_CARDRESET : 0; |
201 | 189 | ret = misc_register(&ixp4xx_wdt_miscdev); | |
190 | if (ret == 0) | ||
191 | printk(KERN_INFO "IXP4xx Watchdog Timer: heartbeat %d sec\n", | ||
192 | heartbeat); | ||
202 | return ret; | 193 | return ret; |
203 | } | 194 | } |
204 | 195 | ||