linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] rtc: tps6586x: fix possible race condition
@ 2018-05-17 20:48 Alexandre Belloni
  2018-05-17 20:48 ` [PATCH 2/2] rtc: tps6586x: let the core handle rtc range Alexandre Belloni
  0 siblings, 1 reply; 2+ messages in thread
From: Alexandre Belloni @ 2018-05-17 20:48 UTC (permalink / raw)
  To: linux-rtc; +Cc: linux-kernel, Alexandre Belloni

The probe function is not allowed to fail after the RTC is registered
because the following may happen:

CPU0:                                CPU1:
sys_load_module()
 do_init_module()
  do_one_initcall()
   cmos_do_probe()
    rtc_device_register()
     __register_chrdev()
     cdev->owner = struct module*
                                     open("/dev/rtc0")
    rtc_device_unregister()
  module_put()
  free_module()
   module_free(mod->module_core)
   /* struct module *module is now
      freed */
                                      chrdev_open()
                                       spin_lock(cdev_lock)
                                       cdev_get()
                                        try_module_get()
                                         module_is_live()
                                         /* dereferences already
                                            freed struct module* */

Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
---
 drivers/rtc/rtc-tps6586x.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c
index 46a19adf9a96..9b741143f131 100644
--- a/drivers/rtc/rtc-tps6586x.c
+++ b/drivers/rtc/rtc-tps6586x.c
@@ -276,14 +276,15 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
 	device_init_wakeup(&pdev->dev, 1);
 
 	platform_set_drvdata(pdev, rtc);
-	rtc->rtc = devm_rtc_device_register(&pdev->dev, dev_name(&pdev->dev),
-				       &tps6586x_rtc_ops, THIS_MODULE);
+	rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
 	if (IS_ERR(rtc->rtc)) {
 		ret = PTR_ERR(rtc->rtc);
-		dev_err(&pdev->dev, "RTC device register: ret %d\n", ret);
+		dev_err(&pdev->dev, "RTC allocate device: ret %d\n", ret);
 		goto fail_rtc_register;
 	}
 
+	rtc->rtc->ops = &tps6586x_rtc_ops;
+
 	ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
 				tps6586x_rtc_irq,
 				IRQF_ONESHOT,
@@ -294,6 +295,13 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
 		goto fail_rtc_register;
 	}
 	disable_irq(rtc->irq);
+
+	ret = rtc_register_device(rtc->rtc);
+	if (ret) {
+		dev_err(&pdev->dev, "RTC device register: ret %d\n", ret);
+		goto fail_rtc_register;
+	}
+
 	return 0;
 
 fail_rtc_register:
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [PATCH 2/2] rtc: tps6586x: let the core handle rtc range
  2018-05-17 20:48 [PATCH 1/2] rtc: tps6586x: fix possible race condition Alexandre Belloni
@ 2018-05-17 20:48 ` Alexandre Belloni
  0 siblings, 0 replies; 2+ messages in thread
From: Alexandre Belloni @ 2018-05-17 20:48 UTC (permalink / raw)
  To: linux-rtc; +Cc: linux-kernel, Alexandre Belloni

Let the core handle offsetting and windowing the RTC range.

The RTC has a 40-bit counter counting at 1024 Hz. So its maximum value is
2^(40-10) - 1. Also, let the core handle the offset instead of coding it in
the callbacks. Keep the default epoch at the beginning of 2009 (this will
fail in 2043).

Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
---
 drivers/rtc/rtc-tps6586x.c | 27 +++++----------------------
 1 file changed, 5 insertions(+), 22 deletions(-)

diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c
index 9b741143f131..d6434e514a52 100644
--- a/drivers/rtc/rtc-tps6586x.c
+++ b/drivers/rtc/rtc-tps6586x.c
@@ -58,7 +58,6 @@ struct tps6586x_rtc {
 	struct rtc_device	*rtc;
 	int			irq;
 	bool			irq_en;
-	time64_t		epoch_start;
 };
 
 static inline struct device *to_tps6586x_dev(struct device *dev)
@@ -68,7 +67,6 @@ static inline struct device *to_tps6586x_dev(struct device *dev)
 
 static int tps6586x_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
-	struct tps6586x_rtc *rtc = dev_get_drvdata(dev);
 	struct device *tps_dev = to_tps6586x_dev(dev);
 	unsigned long long ticks = 0;
 	time64_t seconds;
@@ -88,14 +86,13 @@ static int tps6586x_rtc_read_time(struct device *dev, struct rtc_time *tm)
 	}
 
 	seconds = ticks >> 10;
-	seconds += rtc->epoch_start;
-	rtc_time_to_tm(seconds, tm);
+	rtc_time64_to_tm(seconds, tm);
+
 	return 0;
 }
 
 static int tps6586x_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
-	struct tps6586x_rtc *rtc = dev_get_drvdata(dev);
 	struct device *tps_dev = to_tps6586x_dev(dev);
 	unsigned long long ticks;
 	time64_t seconds;
@@ -103,11 +100,6 @@ static int tps6586x_rtc_set_time(struct device *dev, struct rtc_time *tm)
 	int ret;
 
 	seconds = rtc_tm_to_time64(tm);
-	if (seconds < rtc->epoch_start) {
-		dev_err(dev, "requested time unsupported\n");
-		return -EINVAL;
-	}
-	seconds -= rtc->epoch_start;
 
 	ticks = (unsigned long long)seconds << 10;
 	buff[0] = (ticks >> 32) & 0xff;
@@ -155,7 +147,6 @@ static int tps6586x_rtc_alarm_irq_enable(struct device *dev,
 
 static int tps6586x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
-	struct tps6586x_rtc *rtc = dev_get_drvdata(dev);
 	struct device *tps_dev = to_tps6586x_dev(dev);
 	time64_t seconds;
 	unsigned long ticks;
@@ -168,18 +159,12 @@ static int tps6586x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 
 	seconds = rtc_tm_to_time64(&alrm->time);
 
-	if (alrm->enabled && (seconds < rtc->epoch_start)) {
-		dev_err(dev, "can't set alarm to requested time\n");
-		return -EINVAL;
-	}
-
 	ret = tps6586x_rtc_alarm_irq_enable(dev, alrm->enabled);
 	if (ret < 0) {
 		dev_err(dev, "can't set alarm irq, err %d\n", ret);
 		return ret;
 	}
 
-	seconds -= rtc->epoch_start;
 	ret = tps6586x_reads(tps_dev, RTC_COUNT4_DUMMYREAD,
 			sizeof(rbuff), rbuff);
 	if (ret < 0) {
@@ -210,7 +195,6 @@ static int tps6586x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 
 static int tps6586x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
-	struct tps6586x_rtc *rtc = dev_get_drvdata(dev);
 	struct device *tps_dev = to_tps6586x_dev(dev);
 	unsigned long ticks;
 	time64_t seconds;
@@ -225,7 +209,6 @@ static int tps6586x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 
 	ticks = (buff[0] << 16) | (buff[1] << 8) | buff[2];
 	seconds = ticks >> 10;
-	seconds += rtc->epoch_start;
 
 	rtc_time64_to_tm(seconds, &alrm->time);
 	return 0;
@@ -260,9 +243,6 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
 	rtc->dev = &pdev->dev;
 	rtc->irq = platform_get_irq(pdev, 0);
 
-	/* Set epoch start as 00:00:00:01:01:2009 */
-	rtc->epoch_start = mktime64(2009, 1, 1, 0, 0, 0);
-
 	/* 1 kHz tick mode, enable tick counting */
 	ret = tps6586x_update(tps_dev, RTC_CTRL,
 		RTC_ENABLE | OSC_SRC_SEL |
@@ -284,6 +264,9 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
 	}
 
 	rtc->rtc->ops = &tps6586x_rtc_ops;
+	rtc->rtc->range_max = (1ULL << 30) - 1; /* 30-bit seconds */
+	rtc->rtc->start_secs = mktime64(2009, 1, 1, 0, 0, 0);
+	rtc->rtc->set_start_time = true;
 
 	ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
 				tps6586x_rtc_irq,
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2018-05-17 20:48 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-17 20:48 [PATCH 1/2] rtc: tps6586x: fix possible race condition Alexandre Belloni
2018-05-17 20:48 ` [PATCH 2/2] rtc: tps6586x: let the core handle rtc range Alexandre Belloni

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).