aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
authorAtsushi Nemoto <anemo@mba.ocn.ne.jp>2009-12-15 19:46:04 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-16 10:19:59 -0500
commit3151520d88b27b9dd4fb1c1f89a94807f0ad7ef1 (patch)
tree4a53759581236789ba294ffc3adc3256e1282b30 /drivers/rtc
parentac18eb622f4d8cdd544222e56230db850259cd37 (diff)
rtc-stk17ta8: fix races around device registration
- Call dev_set_drvdata before rtc device creation. - Use its own spinlock instead of rtc->irq_lock. Because pdata->rtc must be initialized to use the irq_lock (pdata->rtc->irq_lock). There is a small window which rtc methods can be called before pdata->rtc is initialized. And there is no need use the irq_lock to protect hardware registers. The driver's own spinlock shoule be enough. - Check pdata->rtc before calling rtc_update_irq. - Use alarm_irq_enable and remove ioctl routine. - Use devres APIs and simplify error/remove path. These fixes are ported from ds1553 driver and just compile-tested only. Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp> Cc: Alessandro Zummo <alessandro.zummo@towertech.it> Cc: Thomas Hommel <thomas.hommel@gefanuc.com> Cc: David Brownell <david-b@pacbell.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/rtc-stk17ta8.c114
1 files changed, 45 insertions, 69 deletions
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c
index 62c2969436a..31ea22070e3 100644
--- a/drivers/rtc/rtc-stk17ta8.c
+++ b/drivers/rtc/rtc-stk17ta8.c
@@ -62,7 +62,6 @@
62struct rtc_plat_data { 62struct rtc_plat_data {
63 struct rtc_device *rtc; 63 struct rtc_device *rtc;
64 void __iomem *ioaddr; 64 void __iomem *ioaddr;
65 unsigned long baseaddr;
66 unsigned long last_jiffies; 65 unsigned long last_jiffies;
67 int irq; 66 int irq;
68 unsigned int irqen; 67 unsigned int irqen;
@@ -70,6 +69,7 @@ struct rtc_plat_data {
70 int alrm_min; 69 int alrm_min;
71 int alrm_hour; 70 int alrm_hour;
72 int alrm_mday; 71 int alrm_mday;
72 spinlock_t lock;
73}; 73};
74 74
75static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm) 75static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm)
@@ -142,7 +142,7 @@ static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata)
142 unsigned long irqflags; 142 unsigned long irqflags;
143 u8 flags; 143 u8 flags;
144 144
145 spin_lock_irqsave(&pdata->rtc->irq_lock, irqflags); 145 spin_lock_irqsave(&pdata->lock, irqflags);
146 146
147 flags = readb(ioaddr + RTC_FLAGS); 147 flags = readb(ioaddr + RTC_FLAGS);
148 writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS); 148 writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS);
@@ -162,7 +162,7 @@ static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata)
162 writeb(pdata->irqen ? RTC_INTS_AIE : 0, ioaddr + RTC_INTERRUPTS); 162 writeb(pdata->irqen ? RTC_INTS_AIE : 0, ioaddr + RTC_INTERRUPTS);
163 readb(ioaddr + RTC_FLAGS); /* clear interrupts */ 163 readb(ioaddr + RTC_FLAGS); /* clear interrupts */
164 writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS); 164 writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS);
165 spin_unlock_irqrestore(&pdata->rtc->irq_lock, irqflags); 165 spin_unlock_irqrestore(&pdata->lock, irqflags);
166} 166}
167 167
168static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 168static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
@@ -202,48 +202,45 @@ static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id)
202 struct platform_device *pdev = dev_id; 202 struct platform_device *pdev = dev_id;
203 struct rtc_plat_data *pdata = platform_get_drvdata(pdev); 203 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
204 void __iomem *ioaddr = pdata->ioaddr; 204 void __iomem *ioaddr = pdata->ioaddr;
205 unsigned long events = RTC_IRQF; 205 unsigned long events = 0;
206 206
207 spin_lock(&pdata->lock);
207 /* read and clear interrupt */ 208 /* read and clear interrupt */
208 if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF)) 209 if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF) {
209 return IRQ_NONE; 210 events = RTC_IRQF;
210 if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) 211 if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80)
211 events |= RTC_UF; 212 events |= RTC_UF;
212 else 213 else
213 events |= RTC_AF; 214 events |= RTC_AF;
214 rtc_update_irq(pdata->rtc, 1, events); 215 if (likely(pdata->rtc))
215 return IRQ_HANDLED; 216 rtc_update_irq(pdata->rtc, 1, events);
217 }
218 spin_unlock(&pdata->lock);
219 return events ? IRQ_HANDLED : IRQ_NONE;
216} 220}
217 221
218static int stk17ta8_rtc_ioctl(struct device *dev, unsigned int cmd, 222static int stk17ta8_rtc_alarm_irq_enable(struct device *dev,
219 unsigned long arg) 223 unsigned int enabled)
220{ 224{
221 struct platform_device *pdev = to_platform_device(dev); 225 struct platform_device *pdev = to_platform_device(dev);
222 struct rtc_plat_data *pdata = platform_get_drvdata(pdev); 226 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
223 227
224 if (pdata->irq <= 0) 228 if (pdata->irq <= 0)
225 return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ 229 return -EINVAL;
226 switch (cmd) { 230 if (enabled)
227 case RTC_AIE_OFF:
228 pdata->irqen &= ~RTC_AF;
229 stk17ta8_rtc_update_alarm(pdata);
230 break;
231 case RTC_AIE_ON:
232 pdata->irqen |= RTC_AF; 231 pdata->irqen |= RTC_AF;
233 stk17ta8_rtc_update_alarm(pdata); 232 else
234 break; 233 pdata->irqen &= ~RTC_AF;
235 default: 234 stk17ta8_rtc_update_alarm(pdata);
236 return -ENOIOCTLCMD;
237 }
238 return 0; 235 return 0;
239} 236}
240 237
241static const struct rtc_class_ops stk17ta8_rtc_ops = { 238static const struct rtc_class_ops stk17ta8_rtc_ops = {
242 .read_time = stk17ta8_rtc_read_time, 239 .read_time = stk17ta8_rtc_read_time,
243 .set_time = stk17ta8_rtc_set_time, 240 .set_time = stk17ta8_rtc_set_time,
244 .read_alarm = stk17ta8_rtc_read_alarm, 241 .read_alarm = stk17ta8_rtc_read_alarm,
245 .set_alarm = stk17ta8_rtc_set_alarm, 242 .set_alarm = stk17ta8_rtc_set_alarm,
246 .ioctl = stk17ta8_rtc_ioctl, 243 .alarm_irq_enable = stk17ta8_rtc_alarm_irq_enable,
247}; 244};
248 245
249static ssize_t stk17ta8_nvram_read(struct kobject *kobj, 246static ssize_t stk17ta8_nvram_read(struct kobject *kobj,
@@ -292,26 +289,22 @@ static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev)
292 unsigned int cal; 289 unsigned int cal;
293 unsigned int flags; 290 unsigned int flags;
294 struct rtc_plat_data *pdata; 291 struct rtc_plat_data *pdata;
295 void __iomem *ioaddr = NULL; 292 void __iomem *ioaddr;
296 int ret = 0; 293 int ret = 0;
297 294
298 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 295 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
299 if (!res) 296 if (!res)
300 return -ENODEV; 297 return -ENODEV;
301 298
302 pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); 299 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
303 if (!pdata) 300 if (!pdata)
304 return -ENOMEM; 301 return -ENOMEM;
305 if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) { 302 if (!devm_request_mem_region(&pdev->dev, res->start, RTC_REG_SIZE,
306 ret = -EBUSY; 303 pdev->name))
307 goto out; 304 return -EBUSY;
308 } 305 ioaddr = devm_ioremap(&pdev->dev, res->start, RTC_REG_SIZE);
309 pdata->baseaddr = res->start; 306 if (!ioaddr)
310 ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE); 307 return -ENOMEM;
311 if (!ioaddr) {
312 ret = -ENOMEM;
313 goto out;
314 }
315 pdata->ioaddr = ioaddr; 308 pdata->ioaddr = ioaddr;
316 pdata->irq = platform_get_irq(pdev, 0); 309 pdata->irq = platform_get_irq(pdev, 0);
317 310
@@ -327,9 +320,13 @@ static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev)
327 if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF) 320 if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF)
328 dev_warn(&pdev->dev, "voltage-low detected.\n"); 321 dev_warn(&pdev->dev, "voltage-low detected.\n");
329 322
323 spin_lock_init(&pdata->lock);
324 pdata->last_jiffies = jiffies;
325 platform_set_drvdata(pdev, pdata);
330 if (pdata->irq > 0) { 326 if (pdata->irq > 0) {
331 writeb(0, ioaddr + RTC_INTERRUPTS); 327 writeb(0, ioaddr + RTC_INTERRUPTS);
332 if (request_irq(pdata->irq, stk17ta8_rtc_interrupt, 328 if (devm_request_irq(&pdev->dev, pdata->irq,
329 stk17ta8_rtc_interrupt,
333 IRQF_DISABLED | IRQF_SHARED, 330 IRQF_DISABLED | IRQF_SHARED,
334 pdev->name, pdev) < 0) { 331 pdev->name, pdev) < 0) {
335 dev_warn(&pdev->dev, "interrupt not available.\n"); 332 dev_warn(&pdev->dev, "interrupt not available.\n");
@@ -337,30 +334,14 @@ static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev)
337 } 334 }
338 } 335 }
339 336
340 pdata->last_jiffies = jiffies;
341 platform_set_drvdata(pdev, pdata);
342
343 pdata->rtc = rtc_device_register(pdev->name, &pdev->dev, 337 pdata->rtc = rtc_device_register(pdev->name, &pdev->dev,
344 &stk17ta8_rtc_ops, THIS_MODULE); 338 &stk17ta8_rtc_ops, THIS_MODULE);
345 if (IS_ERR(pdata->rtc)) { 339 if (IS_ERR(pdata->rtc))
346 ret = PTR_ERR(pdata->rtc); 340 return PTR_ERR(pdata->rtc);
347 goto out;
348 }
349 341
350 ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); 342 ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
351 if (ret) { 343 if (ret)
352 rtc_device_unregister(pdata->rtc); 344 rtc_device_unregister(pdata->rtc);
353 goto out;
354 }
355 return 0;
356 out:
357 if (pdata->irq > 0)
358 free_irq(pdata->irq, pdev);
359 if (ioaddr)
360 iounmap(ioaddr);
361 if (pdata->baseaddr)
362 release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
363 kfree(pdata);
364 return ret; 345 return ret;
365} 346}
366 347
@@ -370,13 +351,8 @@ static int __devexit stk17ta8_rtc_remove(struct platform_device *pdev)
370 351
371 sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); 352 sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
372 rtc_device_unregister(pdata->rtc); 353 rtc_device_unregister(pdata->rtc);
373 if (pdata->irq > 0) { 354 if (pdata->irq > 0)
374 writeb(0, pdata->ioaddr + RTC_INTERRUPTS); 355 writeb(0, pdata->ioaddr + RTC_INTERRUPTS);
375 free_irq(pdata->irq, pdev);
376 }
377 iounmap(pdata->ioaddr);
378 release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
379 kfree(pdata);
380 return 0; 356 return 0;
381} 357}
382 358