diff options
Diffstat (limited to 'drivers/watchdog/iop_wdt.c')
-rw-r--r-- | drivers/watchdog/iop_wdt.c | 62 |
1 files changed, 32 insertions, 30 deletions
diff --git a/drivers/watchdog/iop_wdt.c b/drivers/watchdog/iop_wdt.c index 1946dd06d815..96eb2cbe5874 100644 --- a/drivers/watchdog/iop_wdt.c +++ b/drivers/watchdog/iop_wdt.c | |||
@@ -37,6 +37,7 @@ | |||
37 | static int nowayout = WATCHDOG_NOWAYOUT; | 37 | static int nowayout = WATCHDOG_NOWAYOUT; |
38 | static unsigned long wdt_status; | 38 | static unsigned long wdt_status; |
39 | static unsigned long boot_status; | 39 | static unsigned long boot_status; |
40 | static spinlock_t wdt_lock; | ||
40 | 41 | ||
41 | #define WDT_IN_USE 0 | 42 | #define WDT_IN_USE 0 |
42 | #define WDT_OK_TO_CLOSE 1 | 43 | #define WDT_OK_TO_CLOSE 1 |
@@ -68,8 +69,10 @@ static void wdt_enable(void) | |||
68 | /* Arm and enable the Timer to starting counting down from 0xFFFF.FFFF | 69 | /* Arm and enable the Timer to starting counting down from 0xFFFF.FFFF |
69 | * Takes approx. 10.7s to timeout | 70 | * Takes approx. 10.7s to timeout |
70 | */ | 71 | */ |
72 | spin_lock(&wdt_lock); | ||
71 | write_wdtcr(IOP_WDTCR_EN_ARM); | 73 | write_wdtcr(IOP_WDTCR_EN_ARM); |
72 | write_wdtcr(IOP_WDTCR_EN); | 74 | write_wdtcr(IOP_WDTCR_EN); |
75 | spin_unlock(&wdt_lock); | ||
73 | } | 76 | } |
74 | 77 | ||
75 | /* returns 0 if the timer was successfully disabled */ | 78 | /* returns 0 if the timer was successfully disabled */ |
@@ -77,9 +80,11 @@ static int wdt_disable(void) | |||
77 | { | 80 | { |
78 | /* Stop Counting */ | 81 | /* Stop Counting */ |
79 | if (wdt_supports_disable()) { | 82 | if (wdt_supports_disable()) { |
83 | spin_lock(&wdt_lock); | ||
80 | write_wdtcr(IOP_WDTCR_DIS_ARM); | 84 | write_wdtcr(IOP_WDTCR_DIS_ARM); |
81 | write_wdtcr(IOP_WDTCR_DIS); | 85 | write_wdtcr(IOP_WDTCR_DIS); |
82 | clear_bit(WDT_ENABLED, &wdt_status); | 86 | clear_bit(WDT_ENABLED, &wdt_status); |
87 | spin_unlock(&wdt_lock); | ||
83 | printk(KERN_INFO "WATCHDOG: Disabled\n"); | 88 | printk(KERN_INFO "WATCHDOG: Disabled\n"); |
84 | return 0; | 89 | return 0; |
85 | } else | 90 | } else |
@@ -92,16 +97,12 @@ static int iop_wdt_open(struct inode *inode, struct file *file) | |||
92 | return -EBUSY; | 97 | return -EBUSY; |
93 | 98 | ||
94 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); | 99 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); |
95 | |||
96 | wdt_enable(); | 100 | wdt_enable(); |
97 | |||
98 | set_bit(WDT_ENABLED, &wdt_status); | 101 | set_bit(WDT_ENABLED, &wdt_status); |
99 | |||
100 | return nonseekable_open(inode, file); | 102 | return nonseekable_open(inode, file); |
101 | } | 103 | } |
102 | 104 | ||
103 | static ssize_t | 105 | static ssize_t iop_wdt_write(struct file *file, const char *data, size_t len, |
104 | iop_wdt_write(struct file *file, const char *data, size_t len, | ||
105 | loff_t *ppos) | 106 | loff_t *ppos) |
106 | { | 107 | { |
107 | if (len) { | 108 | if (len) { |
@@ -121,46 +122,35 @@ iop_wdt_write(struct file *file, const char *data, size_t len, | |||
121 | } | 122 | } |
122 | wdt_enable(); | 123 | wdt_enable(); |
123 | } | 124 | } |
124 | |||
125 | return len; | 125 | return len; |
126 | } | 126 | } |
127 | 127 | ||
128 | static struct watchdog_info ident = { | 128 | static const struct watchdog_info ident = { |
129 | .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, | 129 | .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, |
130 | .identity = "iop watchdog", | 130 | .identity = "iop watchdog", |
131 | }; | 131 | }; |
132 | 132 | ||
133 | static int | 133 | static long iop_wdt_ioctl(struct file *file, |
134 | iop_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 134 | unsigned int cmd, unsigned long arg) |
135 | unsigned long arg) | ||
136 | { | 135 | { |
137 | int options; | 136 | int options; |
138 | int ret = -ENOTTY; | 137 | int ret = -ENOTTY; |
138 | int __user *argp = (int __user *)arg; | ||
139 | 139 | ||
140 | switch (cmd) { | 140 | switch (cmd) { |
141 | case WDIOC_GETSUPPORT: | 141 | case WDIOC_GETSUPPORT: |
142 | if (copy_to_user | 142 | if (copy_to_user(argp, &ident, sizeof ident)) |
143 | ((struct watchdog_info *)arg, &ident, sizeof ident)) | ||
144 | ret = -EFAULT; | 143 | ret = -EFAULT; |
145 | else | 144 | else |
146 | ret = 0; | 145 | ret = 0; |
147 | break; | 146 | break; |
148 | 147 | ||
149 | case WDIOC_GETSTATUS: | 148 | case WDIOC_GETSTATUS: |
150 | ret = put_user(0, (int *)arg); | 149 | ret = put_user(0, argp); |
151 | break; | 150 | break; |
152 | 151 | ||
153 | case WDIOC_GETBOOTSTATUS: | 152 | case WDIOC_GETBOOTSTATUS: |
154 | ret = put_user(boot_status, (int *)arg); | 153 | ret = put_user(boot_status, argp); |
155 | break; | ||
156 | |||
157 | case WDIOC_GETTIMEOUT: | ||
158 | ret = put_user(iop_watchdog_timeout(), (int *)arg); | ||
159 | break; | ||
160 | |||
161 | case WDIOC_KEEPALIVE: | ||
162 | wdt_enable(); | ||
163 | ret = 0; | ||
164 | break; | 154 | break; |
165 | 155 | ||
166 | case WDIOC_SETOPTIONS: | 156 | case WDIOC_SETOPTIONS: |
@@ -177,14 +167,21 @@ iop_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
177 | } else | 167 | } else |
178 | ret = 0; | 168 | ret = 0; |
179 | } | 169 | } |
180 | |||
181 | if (options & WDIOS_ENABLECARD) { | 170 | if (options & WDIOS_ENABLECARD) { |
182 | wdt_enable(); | 171 | wdt_enable(); |
183 | ret = 0; | 172 | ret = 0; |
184 | } | 173 | } |
185 | break; | 174 | break; |
186 | } | ||
187 | 175 | ||
176 | case WDIOC_KEEPALIVE: | ||
177 | wdt_enable(); | ||
178 | ret = 0; | ||
179 | break; | ||
180 | |||
181 | case WDIOC_GETTIMEOUT: | ||
182 | ret = put_user(iop_watchdog_timeout(), argp); | ||
183 | break; | ||
184 | } | ||
188 | return ret; | 185 | return ret; |
189 | } | 186 | } |
190 | 187 | ||
@@ -214,7 +211,7 @@ static const struct file_operations iop_wdt_fops = { | |||
214 | .owner = THIS_MODULE, | 211 | .owner = THIS_MODULE, |
215 | .llseek = no_llseek, | 212 | .llseek = no_llseek, |
216 | .write = iop_wdt_write, | 213 | .write = iop_wdt_write, |
217 | .ioctl = iop_wdt_ioctl, | 214 | .unlocked_ioctl = iop_wdt_ioctl, |
218 | .open = iop_wdt_open, | 215 | .open = iop_wdt_open, |
219 | .release = iop_wdt_release, | 216 | .release = iop_wdt_release, |
220 | }; | 217 | }; |
@@ -229,10 +226,8 @@ static int __init iop_wdt_init(void) | |||
229 | { | 226 | { |
230 | int ret; | 227 | int ret; |
231 | 228 | ||
232 | ret = misc_register(&iop_wdt_miscdev); | 229 | spin_lock_init(&wdt_lock); |
233 | if (ret == 0) | 230 | |
234 | printk("iop watchdog timer: timeout %lu sec\n", | ||
235 | iop_watchdog_timeout()); | ||
236 | 231 | ||
237 | /* check if the reset was caused by the watchdog timer */ | 232 | /* check if the reset was caused by the watchdog timer */ |
238 | boot_status = (read_rcsr() & IOP_RCSR_WDT) ? WDIOF_CARDRESET : 0; | 233 | boot_status = (read_rcsr() & IOP_RCSR_WDT) ? WDIOF_CARDRESET : 0; |
@@ -242,6 +237,13 @@ static int __init iop_wdt_init(void) | |||
242 | */ | 237 | */ |
243 | write_wdtsr(IOP13XX_WDTCR_IB_RESET); | 238 | write_wdtsr(IOP13XX_WDTCR_IB_RESET); |
244 | 239 | ||
240 | /* Register after we have the device set up so we cannot race | ||
241 | with an open */ | ||
242 | ret = misc_register(&iop_wdt_miscdev); | ||
243 | if (ret == 0) | ||
244 | printk(KERN_INFO "iop watchdog timer: timeout %lu sec\n", | ||
245 | iop_watchdog_timeout()); | ||
246 | |||
245 | return ret; | 247 | return ret; |
246 | } | 248 | } |
247 | 249 | ||