aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
authorAtsushi Nemoto <anemo@mba.ocn.ne.jp>2009-12-15 19:45:58 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-16 10:19:59 -0500
commitba4f3e47cb9ef72f864f1b5548688e0a195011e9 (patch)
tree1a115124e4923e85754c28c8773be67b586ec5b9 /drivers/rtc
parenta8462ef63c961639a743f9fcddf408da46641281 (diff)
rtc-ds1511: 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,update}_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: Andrew Sharp <andy.sharp@lsi.com> Cc: Thomas Hommel <thomas.hommel@gefanuc.com> Cc: David Brownell <david-b@pacbell.net> Cc: Alessandro Zummo <a.zummo@towertech.it> 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-ds1511.c148
1 files changed, 60 insertions, 88 deletions
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
index 539676e25fd8..4166b84cb514 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -87,7 +87,6 @@ enum ds1511reg {
87struct rtc_plat_data { 87struct rtc_plat_data {
88 struct rtc_device *rtc; 88 struct rtc_device *rtc;
89 void __iomem *ioaddr; /* virtual base address */ 89 void __iomem *ioaddr; /* virtual base address */
90 unsigned long baseaddr; /* physical base address */
91 int size; /* amount of memory mapped */ 90 int size; /* amount of memory mapped */
92 int irq; 91 int irq;
93 unsigned int irqen; 92 unsigned int irqen;
@@ -95,6 +94,7 @@ struct rtc_plat_data {
95 int alrm_min; 94 int alrm_min;
96 int alrm_hour; 95 int alrm_hour;
97 int alrm_mday; 96 int alrm_mday;
97 spinlock_t lock;
98}; 98};
99 99
100static DEFINE_SPINLOCK(ds1511_lock); 100static DEFINE_SPINLOCK(ds1511_lock);
@@ -302,7 +302,7 @@ ds1511_rtc_update_alarm(struct rtc_plat_data *pdata)
302{ 302{
303 unsigned long flags; 303 unsigned long flags;
304 304
305 spin_lock_irqsave(&pdata->rtc->irq_lock, flags); 305 spin_lock_irqsave(&pdata->lock, flags);
306 rtc_write(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ? 306 rtc_write(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
307 0x80 : bin2bcd(pdata->alrm_mday) & 0x3f, 307 0x80 : bin2bcd(pdata->alrm_mday) & 0x3f,
308 RTC_ALARM_DATE); 308 RTC_ALARM_DATE);
@@ -317,7 +317,7 @@ ds1511_rtc_update_alarm(struct rtc_plat_data *pdata)
317 RTC_ALARM_SEC); 317 RTC_ALARM_SEC);
318 rtc_write(rtc_read(RTC_CMD) | (pdata->irqen ? RTC_TIE : 0), RTC_CMD); 318 rtc_write(rtc_read(RTC_CMD) | (pdata->irqen ? RTC_TIE : 0), RTC_CMD);
319 rtc_read(RTC_CMD1); /* clear interrupts */ 319 rtc_read(RTC_CMD1); /* clear interrupts */
320 spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags); 320 spin_unlock_irqrestore(&pdata->lock, flags);
321} 321}
322 322
323 static int 323 static int
@@ -362,61 +362,63 @@ ds1511_interrupt(int irq, void *dev_id)
362{ 362{
363 struct platform_device *pdev = dev_id; 363 struct platform_device *pdev = dev_id;
364 struct rtc_plat_data *pdata = platform_get_drvdata(pdev); 364 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
365 unsigned long events = RTC_IRQF; 365 unsigned long events = 0;
366 366
367 spin_lock(&pdata->lock);
367 /* 368 /*
368 * read and clear interrupt 369 * read and clear interrupt
369 */ 370 */
370 if (!(rtc_read(RTC_CMD1) & DS1511_IRQF)) { 371 if (rtc_read(RTC_CMD1) & DS1511_IRQF) {
371 return IRQ_NONE; 372 events = RTC_IRQF;
372 } 373 if (rtc_read(RTC_ALARM_SEC) & 0x80)
373 if (rtc_read(RTC_ALARM_SEC) & 0x80) { 374 events |= RTC_UF;
374 events |= RTC_UF; 375 else
375 } else { 376 events |= RTC_AF;
376 events |= RTC_AF; 377 if (likely(pdata->rtc))
377 } 378 rtc_update_irq(pdata->rtc, 1, events);
378 rtc_update_irq(pdata->rtc, 1, events); 379 }
379 return IRQ_HANDLED; 380 spin_unlock(&pdata->lock);
381 return events ? IRQ_HANDLED : IRQ_NONE;
380} 382}
381 383
382 static int 384static int ds1511_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
383ds1511_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
384{ 385{
385 struct platform_device *pdev = to_platform_device(dev); 386 struct platform_device *pdev = to_platform_device(dev);
386 struct rtc_plat_data *pdata = platform_get_drvdata(pdev); 387 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
387 388
388 if (pdata->irq <= 0) { 389 if (pdata->irq <= 0)
389 return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ 390 return -EINVAL;
390 } 391 if (enabled)
391 switch (cmd) {
392 case RTC_AIE_OFF:
393 pdata->irqen &= ~RTC_AF;
394 ds1511_rtc_update_alarm(pdata);
395 break;
396 case RTC_AIE_ON:
397 pdata->irqen |= RTC_AF; 392 pdata->irqen |= RTC_AF;
398 ds1511_rtc_update_alarm(pdata); 393 else
399 break; 394 pdata->irqen &= ~RTC_AF;
400 case RTC_UIE_OFF: 395 ds1511_rtc_update_alarm(pdata);
401 pdata->irqen &= ~RTC_UF; 396 return 0;
402 ds1511_rtc_update_alarm(pdata); 397}
403 break; 398
404 case RTC_UIE_ON: 399static int ds1511_rtc_update_irq_enable(struct device *dev,
400 unsigned int enabled)
401{
402 struct platform_device *pdev = to_platform_device(dev);
403 struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
404
405 if (pdata->irq <= 0)
406 return -EINVAL;
407 if (enabled)
405 pdata->irqen |= RTC_UF; 408 pdata->irqen |= RTC_UF;
406 ds1511_rtc_update_alarm(pdata); 409 else
407 break; 410 pdata->irqen &= ~RTC_UF;
408 default: 411 ds1511_rtc_update_alarm(pdata);
409 return -ENOIOCTLCMD;
410 }
411 return 0; 412 return 0;
412} 413}
413 414
414static const struct rtc_class_ops ds1511_rtc_ops = { 415static const struct rtc_class_ops ds1511_rtc_ops = {
415 .read_time = ds1511_rtc_read_time, 416 .read_time = ds1511_rtc_read_time,
416 .set_time = ds1511_rtc_set_time, 417 .set_time = ds1511_rtc_set_time,
417 .read_alarm = ds1511_rtc_read_alarm, 418 .read_alarm = ds1511_rtc_read_alarm,
418 .set_alarm = ds1511_rtc_set_alarm, 419 .set_alarm = ds1511_rtc_set_alarm,
419 .ioctl = ds1511_rtc_ioctl, 420 .alarm_irq_enable = ds1511_rtc_alarm_irq_enable,
421 .update_irq_enable = ds1511_rtc_update_irq_enable,
420}; 422};
421 423
422 static ssize_t 424 static ssize_t
@@ -492,29 +494,23 @@ ds1511_rtc_probe(struct platform_device *pdev)
492{ 494{
493 struct rtc_device *rtc; 495 struct rtc_device *rtc;
494 struct resource *res; 496 struct resource *res;
495 struct rtc_plat_data *pdata = NULL; 497 struct rtc_plat_data *pdata;
496 int ret = 0; 498 int ret = 0;
497 499
498 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 500 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
499 if (!res) { 501 if (!res) {
500 return -ENODEV; 502 return -ENODEV;
501 } 503 }
502 pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); 504 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
503 if (!pdata) { 505 if (!pdata)
504 return -ENOMEM; 506 return -ENOMEM;
505 }
506 pdata->size = res->end - res->start + 1; 507 pdata->size = res->end - res->start + 1;
507 if (!request_mem_region(res->start, pdata->size, pdev->name)) { 508 if (!devm_request_mem_region(&pdev->dev, res->start, pdata->size,
508 ret = -EBUSY; 509 pdev->name))
509 goto out; 510 return -EBUSY;
510 } 511 ds1511_base = devm_ioremap(&pdev->dev, res->start, pdata->size);
511 pdata->baseaddr = res->start; 512 if (!ds1511_base)
512 pdata->size = pdata->size; 513 return -ENOMEM;
513 ds1511_base = ioremap(pdata->baseaddr, pdata->size);
514 if (!ds1511_base) {
515 ret = -ENOMEM;
516 goto out;
517 }
518 pdata->ioaddr = ds1511_base; 514 pdata->ioaddr = ds1511_base;
519 pdata->irq = platform_get_irq(pdev, 0); 515 pdata->irq = platform_get_irq(pdev, 0);
520 516
@@ -540,13 +536,15 @@ ds1511_rtc_probe(struct platform_device *pdev)
540 dev_warn(&pdev->dev, "voltage-low detected.\n"); 536 dev_warn(&pdev->dev, "voltage-low detected.\n");
541 } 537 }
542 538
539 spin_lock_init(&pdata->lock);
540 platform_set_drvdata(pdev, pdata);
543 /* 541 /*
544 * if the platform has an interrupt in mind for this device, 542 * if the platform has an interrupt in mind for this device,
545 * then by all means, set it 543 * then by all means, set it
546 */ 544 */
547 if (pdata->irq > 0) { 545 if (pdata->irq > 0) {
548 rtc_read(RTC_CMD1); 546 rtc_read(RTC_CMD1);
549 if (request_irq(pdata->irq, ds1511_interrupt, 547 if (devm_request_irq(&pdev->dev, pdata->irq, ds1511_interrupt,
550 IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) { 548 IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) {
551 549
552 dev_warn(&pdev->dev, "interrupt not available.\n"); 550 dev_warn(&pdev->dev, "interrupt not available.\n");
@@ -556,33 +554,13 @@ ds1511_rtc_probe(struct platform_device *pdev)
556 554
557 rtc = rtc_device_register(pdev->name, &pdev->dev, &ds1511_rtc_ops, 555 rtc = rtc_device_register(pdev->name, &pdev->dev, &ds1511_rtc_ops,
558 THIS_MODULE); 556 THIS_MODULE);
559 if (IS_ERR(rtc)) { 557 if (IS_ERR(rtc))
560 ret = PTR_ERR(rtc); 558 return PTR_ERR(rtc);
561 goto out;
562 }
563 pdata->rtc = rtc; 559 pdata->rtc = rtc;
564 platform_set_drvdata(pdev, pdata); 560
565 ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr); 561 ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
566 if (ret) { 562 if (ret)
567 goto out;
568 }
569 return 0;
570 out:
571 if (pdata->rtc) {
572 rtc_device_unregister(pdata->rtc); 563 rtc_device_unregister(pdata->rtc);
573 }
574 if (pdata->irq > 0) {
575 free_irq(pdata->irq, pdev);
576 }
577 if (ds1511_base) {
578 iounmap(ds1511_base);
579 ds1511_base = NULL;
580 }
581 if (pdata->baseaddr) {
582 release_mem_region(pdata->baseaddr, pdata->size);
583 }
584
585 kfree(pdata);
586 return ret; 564 return ret;
587} 565}
588 566
@@ -593,19 +571,13 @@ ds1511_rtc_remove(struct platform_device *pdev)
593 571
594 sysfs_remove_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr); 572 sysfs_remove_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
595 rtc_device_unregister(pdata->rtc); 573 rtc_device_unregister(pdata->rtc);
596 pdata->rtc = NULL;
597 if (pdata->irq > 0) { 574 if (pdata->irq > 0) {
598 /* 575 /*
599 * disable the alarm interrupt 576 * disable the alarm interrupt
600 */ 577 */
601 rtc_write(rtc_read(RTC_CMD) & ~RTC_TIE, RTC_CMD); 578 rtc_write(rtc_read(RTC_CMD) & ~RTC_TIE, RTC_CMD);
602 rtc_read(RTC_CMD1); 579 rtc_read(RTC_CMD1);
603 free_irq(pdata->irq, pdev);
604 } 580 }
605 iounmap(pdata->ioaddr);
606 ds1511_base = NULL;
607 release_mem_region(pdata->baseaddr, pdata->size);
608 kfree(pdata);
609 return 0; 581 return 0;
610} 582}
611 583