* [PATCH 0/3] rtc: rtc-hid-sensor-time @ 2013-04-19 15:14 Alexander Holler 2013-04-19 15:14 ` [PATCH 1/3 RESEND] rtc: rtc-hid-sensor-time: allow full years (16bit) in HID reports Alexander Holler ` (3 more replies) 0 siblings, 4 replies; 78+ messages in thread From: Alexander Holler @ 2013-04-19 15:14 UTC (permalink / raw) To: linux-kernel Cc: rtc-linux, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina Hello, as I'm not sure if the maintainer of the RTC subsystem is active again, I've added the people which where involved with rtc-hid-sensor-time before to cc too. That might be a good idea even he is active again, as the driver depends on hid-sensor-hub and as such works a bit outside the stuff other RTC drivers do use. This small series of patches do extend the driver a bit. They make the driver more standard (draft) compliant and I've added a replacement for the usual hctosys, because that isn't usable with this driver. I've already send the first patch two weeks before (unchanged) therefor I've marked it as RESEND (see https://lkml.org/lkml/2013/4/5/177 ). Actually I wanted to have added another patch to adjust the system time too (when the clock sends HID reports which are including milliseconds regulary by itself), but I have to read about the in-kernel timekeeping (kernel/time/timekeeping.c, kernel/time/ntp.c) for that and I don't know if I will find the time without missing the next merge window. Personally I would like if they went into 3.9 too, but beeing realistic, I'm happy if they end up in 3.11. ;) If someone is curious about my other side of that driver, I've setup a website with explanations and source which should make it easy build a similiar hot-pluggable RTC: http://ahsoftware.de/dcf77-hid-usb-rtc/ Regards, Alexander ^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 1/3 RESEND] rtc: rtc-hid-sensor-time: allow full years (16bit) in HID reports 2013-04-19 15:14 [PATCH 0/3] rtc: rtc-hid-sensor-time Alexander Holler @ 2013-04-19 15:14 ` Alexander Holler 2013-04-19 15:14 ` [PATCH 2/3] rtc: rtc-hid-sensor-time: allow 16 and 32 bit values for all attributes Alexander Holler ` (2 subsequent siblings) 3 siblings, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-04-19 15:14 UTC (permalink / raw) To: linux-kernel Cc: rtc-linux, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina, Alexander Holler The draft for HID-sensors (HUTRR39) currently doesn't define the range for the attribute year. Asking one of the authors revealed that full years (e.g. 2013 instead of just 13) were meant. So we now allow both, 8 bit and 16 bit values for the attribute year and assuming full years when the value is 16 bits wide. We will still support 8 bit values until the specification gets final (and maybe defines a way to set the time too). Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- drivers/rtc/rtc-hid-sensor-time.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index 31c5728..f3ef38a 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -85,10 +85,13 @@ static int hid_time_capture_sample(struct hid_sensor_hub_device *hsdev, switch (usage_id) { case HID_USAGE_SENSOR_TIME_YEAR: - time_buf->tm_year = *(u8 *)raw_data; - if (time_buf->tm_year < 70) - /* assume we are in 1970...2069 */ - time_buf->tm_year += 100; + if (raw_len == 1) { + time_buf->tm_year = *(u8 *)raw_data; + if (time_buf->tm_year < 70) + /* assume we are in 1970...2069 */ + time_buf->tm_year += 100; + } else + time_buf->tm_year = *(u16 *)raw_data-1900; break; case HID_USAGE_SENSOR_TIME_MONTH: /* sensor sending the month as 1-12, we need 0-11 */ @@ -151,11 +154,27 @@ static int hid_time_parse_report(struct platform_device *pdev, return -EINVAL; } if (time_state->info[i].size != 1) { - dev_err(&pdev->dev, - "attribute '%s' not 8 bits wide!\n", + /* + * The draft for HID-sensors (HUTRR39) currently + * doesn't define the range for the year attribute. + * Therefor we support both 8 bit (0-99) and 16 bit + * (full) as size for the year. + */ + if (time_state->info[i].attrib_id != + HID_USAGE_SENSOR_TIME_YEAR) { + dev_err(&pdev->dev, + "attribute '%s' not 8 bits wide!\n", hid_time_attrib_name( time_state->info[i].attrib_id)); - return -EINVAL; + return -EINVAL; + } + if (time_state->info[i].size != 2) { + dev_err(&pdev->dev, + "attribute '%s' not 8 or 16 bits wide!\n", + hid_time_attrib_name( + time_state->info[i].attrib_id)); + return -EINVAL; + } } if (time_state->info[i].units != HID_USAGE_SENSOR_UNITS_NOT_SPECIFIED && -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 2/3] rtc: rtc-hid-sensor-time: allow 16 and 32 bit values for all attributes. 2013-04-19 15:14 [PATCH 0/3] rtc: rtc-hid-sensor-time Alexander Holler 2013-04-19 15:14 ` [PATCH 1/3 RESEND] rtc: rtc-hid-sensor-time: allow full years (16bit) in HID reports Alexander Holler @ 2013-04-19 15:14 ` Alexander Holler 2013-04-19 15:14 ` [PATCH 3/3] rtc: rtc-hid-sensor-time; add option hctosys to set time at boot Alexander Holler 2013-04-20 23:46 ` [PATCH 0/3] rtc: rtc-hid-sensor-time Jiri Kosina 3 siblings, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-04-19 15:14 UTC (permalink / raw) To: linux-kernel Cc: rtc-linux, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina, Alexander Holler There is no real reason to not support 16 or 32 bit values too. Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- drivers/rtc/rtc-hid-sensor-time.c | 59 +++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index f3ef38a..10fc0f0 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -76,6 +76,20 @@ static int hid_time_proc_event(struct hid_sensor_hub_device *hsdev, return 0; } +static u32 hid_time_value(size_t raw_len, char *raw_data) +{ + switch (raw_len) { + case 1: + return *(u8 *)raw_data; + case 2: + return *(u16 *)raw_data; + case 4: + return *(u32 *)raw_data; + default: + return (u32)(~0U); /* 0xff... or -1 to denote an error */ + } +} + static int hid_time_capture_sample(struct hid_sensor_hub_device *hsdev, unsigned usage_id, size_t raw_len, char *raw_data, void *priv) @@ -85,29 +99,35 @@ static int hid_time_capture_sample(struct hid_sensor_hub_device *hsdev, switch (usage_id) { case HID_USAGE_SENSOR_TIME_YEAR: + /* + * The draft for HID-sensors (HUTRR39) currently doesn't define + * the range for the year attribute. Therefor we support + * 8 bit (0-99) and 16 or 32 bits (full) as size for the year. + */ if (raw_len == 1) { time_buf->tm_year = *(u8 *)raw_data; if (time_buf->tm_year < 70) /* assume we are in 1970...2069 */ time_buf->tm_year += 100; } else - time_buf->tm_year = *(u16 *)raw_data-1900; + time_buf->tm_year = + (int)hid_time_value(raw_len, raw_data)-1900; break; case HID_USAGE_SENSOR_TIME_MONTH: - /* sensor sending the month as 1-12, we need 0-11 */ - time_buf->tm_mon = *(u8 *)raw_data-1; + /* sensors are sending the month as 1-12, we need 0-11 */ + time_buf->tm_mon = (int)hid_time_value(raw_len, raw_data)-1; break; case HID_USAGE_SENSOR_TIME_DAY: - time_buf->tm_mday = *(u8 *)raw_data; + time_buf->tm_mday = (int)hid_time_value(raw_len, raw_data); break; case HID_USAGE_SENSOR_TIME_HOUR: - time_buf->tm_hour = *(u8 *)raw_data; + time_buf->tm_hour = (int)hid_time_value(raw_len, raw_data); break; case HID_USAGE_SENSOR_TIME_MINUTE: - time_buf->tm_min = *(u8 *)raw_data; + time_buf->tm_min = (int)hid_time_value(raw_len, raw_data); break; case HID_USAGE_SENSOR_TIME_SECOND: - time_buf->tm_sec = *(u8 *)raw_data; + time_buf->tm_sec = (int)hid_time_value(raw_len, raw_data); break; default: return -EINVAL; @@ -153,28 +173,13 @@ static int hid_time_parse_report(struct platform_device *pdev, "not all needed attributes inside the same report!\n"); return -EINVAL; } - if (time_state->info[i].size != 1) { - /* - * The draft for HID-sensors (HUTRR39) currently - * doesn't define the range for the year attribute. - * Therefor we support both 8 bit (0-99) and 16 bit - * (full) as size for the year. - */ - if (time_state->info[i].attrib_id != - HID_USAGE_SENSOR_TIME_YEAR) { - dev_err(&pdev->dev, - "attribute '%s' not 8 bits wide!\n", - hid_time_attrib_name( - time_state->info[i].attrib_id)); - return -EINVAL; - } - if (time_state->info[i].size != 2) { - dev_err(&pdev->dev, - "attribute '%s' not 8 or 16 bits wide!\n", + if (time_state->info[i].size == 3 || + time_state->info[i].size > 4) { + dev_err(&pdev->dev, + "attribute '%s' not 8, 16 or 32 bits wide!\n", hid_time_attrib_name( time_state->info[i].attrib_id)); - return -EINVAL; - } + return -EINVAL; } if (time_state->info[i].units != HID_USAGE_SENSOR_UNITS_NOT_SPECIFIED && -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 3/3] rtc: rtc-hid-sensor-time; add option hctosys to set time at boot 2013-04-19 15:14 [PATCH 0/3] rtc: rtc-hid-sensor-time Alexander Holler 2013-04-19 15:14 ` [PATCH 1/3 RESEND] rtc: rtc-hid-sensor-time: allow full years (16bit) in HID reports Alexander Holler 2013-04-19 15:14 ` [PATCH 2/3] rtc: rtc-hid-sensor-time: allow 16 and 32 bit values for all attributes Alexander Holler @ 2013-04-19 15:14 ` Alexander Holler 2013-04-22 23:38 ` Andrew Morton 2013-04-20 23:46 ` [PATCH 0/3] rtc: rtc-hid-sensor-time Jiri Kosina 3 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-04-19 15:14 UTC (permalink / raw) To: linux-kernel Cc: rtc-linux, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina, Alexander Holler drivers/rtc/hctosys (CONFIG_RTC_HCTOSYS) doesn't work for rtc-hid-sensor-time because it will be called in late_init, and thus before rtc-hid-sensor-time gets loaded. To set the time through rtc-hid-sensor-time at startup, the module now checks by default if the system time is before 1970-01-02 and sets the system time (once) if this is the case. To disable this behaviour, set the module option hctosys to zero, e.g. by using rtc-hid-sensor-time.hctosys=0 at the kernel command line if the driver is statically linked into the kernel. Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- drivers/rtc/rtc-hid-sensor-time.c | 72 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index 10fc0f0..3184729 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -27,6 +27,12 @@ /* Usage ID from spec for Time: 0x2000A0 */ #define DRIVER_NAME "HID-SENSOR-2000a0" /* must be lowercase */ +static bool hid_time_hctosys_enabled = 1; +module_param_named(hctosys, hid_time_hctosys_enabled, bool, 0644); +MODULE_PARM_DESC(hctosys, + "set the system time (once) if it is before 1970-01-02"); +static bool hid_time_time_set_once; + enum hid_time_channel { CHANNEL_SCAN_INDEX_YEAR, CHANNEL_SCAN_INDEX_MONTH, @@ -62,6 +68,38 @@ static const char * const hid_time_channel_names[TIME_RTC_CHANNEL_MAX] = { "year", "month", "day", "hour", "minute", "second", }; +static void hid_time_hctosys(struct hid_time_state *time_state) +{ + struct timeval tv; + struct timespec ts; + int rc = rtc_valid_tm(&time_state->last_time); + if (rc) { + dev_err(time_state->rtc->dev.parent, + "hctosys: invalid date/time\n"); + return; + } + do_gettimeofday(&tv); + if (tv.tv_sec >= 86400) /* 1970-01-02 00:00:00 UTC */ + /* + * Security: don't let a hot-pluggable device change + * a valid system time. + */ + return; + ts.tv_nsec = NSEC_PER_SEC >> 1; + rtc_tm_to_time(&time_state->last_time, &ts.tv_sec); + rc = do_settimeofday(&ts); + dev_info(time_state->rtc->dev.parent, + "hctosys: setting system clock to " + "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", + time_state->last_time.tm_year + 1900, + time_state->last_time.tm_mon + 1, + time_state->last_time.tm_mday, + time_state->last_time.tm_hour, + time_state->last_time.tm_min, + time_state->last_time.tm_sec, + (unsigned int) ts.tv_sec); +} + /* Callback handler to send event after all samples are received and captured */ static int hid_time_proc_event(struct hid_sensor_hub_device *hsdev, unsigned usage_id, void *priv) @@ -73,6 +111,10 @@ static int hid_time_proc_event(struct hid_sensor_hub_device *hsdev, time_state->last_time = time_state->time_buf; spin_unlock_irqrestore(&time_state->lock_last_time, flags); complete(&time_state->comp_last_time); + if (unlikely(!hid_time_time_set_once && hid_time_hctosys_enabled)) { + hid_time_time_set_once = 1; + hid_time_hctosys(time_state); + } return 0; } @@ -237,6 +279,22 @@ static const struct rtc_class_ops hid_time_rtc_ops = { .read_time = hid_rtc_read_time, }; +struct hid_time_work_time_state { + struct work_struct work; + struct hid_time_state *time_state; +}; + +static void hid_time_request_report_work(struct work_struct *work) +{ + struct hid_time_state *time_state = + ((struct hid_time_work_time_state *)work)->time_state; + /* get a report with all values through requesting one value */ + sensor_hub_input_attr_get_raw_value( + time_state->common_attributes.hsdev, HID_USAGE_SENSOR_TIME, + hid_time_addresses[0], time_state->info[0].report_id); + kfree(work); +} + static int hid_time_probe(struct platform_device *pdev) { int ret = 0; @@ -287,6 +345,20 @@ static int hid_time_probe(struct platform_device *pdev) return PTR_ERR(time_state->rtc); } + if (!hid_time_time_set_once && hid_time_hctosys_enabled) { + /* + * Request a HID report to set the time. + * Calling sensor_hub_..._get_raw_value() here directly + * doesn't work, therefor we have to use a work. + */ + struct hid_time_work_time_state *hdwork = + kmalloc(sizeof(struct hid_time_work_time_state), + GFP_KERNEL); + hdwork->time_state = time_state; + INIT_WORK(&hdwork->work, hid_time_request_report_work); + schedule_work(&hdwork->work); + } + return ret; } -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* Re: [PATCH 3/3] rtc: rtc-hid-sensor-time; add option hctosys to set time at boot 2013-04-19 15:14 ` [PATCH 3/3] rtc: rtc-hid-sensor-time; add option hctosys to set time at boot Alexander Holler @ 2013-04-22 23:38 ` Andrew Morton 2013-04-23 8:51 ` Alexander Holler 0 siblings, 1 reply; 78+ messages in thread From: Andrew Morton @ 2013-04-22 23:38 UTC (permalink / raw) To: Alexander Holler Cc: linux-kernel, rtc-linux, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina On Fri, 19 Apr 2013 17:14:12 +0200 Alexander Holler <holler@ahsoftware.de> wrote: > drivers/rtc/hctosys (CONFIG_RTC_HCTOSYS) doesn't work for > rtc-hid-sensor-time because it will be called in late_init, and thus before > rtc-hid-sensor-time gets loaded. Isn't that true of all RTC drivers which are built as modules? There's nothing special about hid-sensor-time here? I assume the standard answer here is "your RTC driver should be built into vmlinux". If we wish to make things work for modular RTC drivers then we should find a solution which addresses *all* RTC drivers? > To set the time through rtc-hid-sensor-time > at startup, the module now checks by default if the system time is before > 1970-01-02 and sets the system time (once) if this is the case. > > To disable this behaviour, set the module option hctosys to zero, e.g. by > using rtc-hid-sensor-time.hctosys=0 at the kernel command line if the > driver is statically linked into the kernel. Is a bit hacky, no? > @@ -237,6 +279,22 @@ static const struct rtc_class_ops hid_time_rtc_ops = { > .read_time = hid_rtc_read_time, > }; > > +struct hid_time_work_time_state { > + struct work_struct work; > + struct hid_time_state *time_state; > +}; > + > +static void hid_time_request_report_work(struct work_struct *work) > +{ > + struct hid_time_state *time_state = > + ((struct hid_time_work_time_state *)work)->time_state; Yikes. Use container_of() here. Also, you don't *have* to initialise things at their definition site. So struct hid_time_state *time_state = some-ginormous-expression-which-overflows-80-columns; becomes struct hid_time_state *time_state; time_state = some-ginormous-expression-which-no-longer-overflows-80-columns; Simple, no? > + /* get a report with all values through requesting one value */ > + sensor_hub_input_attr_get_raw_value( > + time_state->common_attributes.hsdev, HID_USAGE_SENSOR_TIME, > + hid_time_addresses[0], time_state->info[0].report_id); > + kfree(work); > +} > + > static int hid_time_probe(struct platform_device *pdev) > { > int ret = 0; > @@ -287,6 +345,20 @@ static int hid_time_probe(struct platform_device *pdev) > return PTR_ERR(time_state->rtc); > } > > + if (!hid_time_time_set_once && hid_time_hctosys_enabled) { > + /* > + * Request a HID report to set the time. > + * Calling sensor_hub_..._get_raw_value() here directly > + * doesn't work, therefor we have to use a work. > + */ > + struct hid_time_work_time_state *hdwork = > + kmalloc(sizeof(struct hid_time_work_time_state), > + GFP_KERNEL); looky: struct hid_time_work_time_state *hdwork; hdwork = kmalloc(sizeof(*hdwork), GFP_KERNEL); > + hdwork->time_state = time_state; Forgot to check for kmalloc() failure. > + INIT_WORK(&hdwork->work, hid_time_request_report_work); > + schedule_work(&hdwork->work); The patch adds a schedule_work() but no flush_scheduled_work(), etc. So if the driver is shut down or rmmodded while the work is still pending, the kernel will go kapow. > + } > + > return ret; > } ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 3/3] rtc: rtc-hid-sensor-time; add option hctosys to set time at boot 2013-04-22 23:38 ` Andrew Morton @ 2013-04-23 8:51 ` Alexander Holler 2013-04-23 10:08 ` Alexander Holler 0 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-04-23 8:51 UTC (permalink / raw) To: Andrew Morton Cc: linux-kernel, rtc-linux, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina Am 23.04.2013 01:38, schrieb Andrew Morton: > On Fri, 19 Apr 2013 17:14:12 +0200 Alexander Holler <holler@ahsoftware.de> wrote: > >> drivers/rtc/hctosys (CONFIG_RTC_HCTOSYS) doesn't work for >> rtc-hid-sensor-time because it will be called in late_init, and thus before >> rtc-hid-sensor-time gets loaded. > > Isn't that true of all RTC drivers which are built as modules? There's > nothing special about hid-sensor-time here? > > I assume the standard answer here is "your RTC driver should be built > into vmlinux". If we wish to make things work for modular RTC drivers > then we should find a solution which addresses *all* RTC drivers? No. I having rtc-hid-sensor-time, hid-sensor-hub (and USB) statically linked in doesn't help. Here is what happens here with such an configuration: -- [ 7.638970] drivers/rtc/hctosys.c: unable to open rtc device (rtc0) [ 7.645639] Waiting 180sec before mounting root device... [ 16.598759] HID-SENSOR-2000a0 HID-SENSOR-2000a0.0: rtc core: registered hid-sensor-time as rtc0 [ 16.608712] HID-SENSOR-2000a0 HID-SENSOR-2000a0.0: hctosys: setting system clock to 2013-04-19 16:45:06 UTC (1366389906) -- I havent't looked in detail at why rtc-hid-sensor-time gets loaded that late, but I assume it's because the USB stack (and/or the device or the communication inbetween) needs some time (and I assume that's why rootwait and rootdelay got invented too). > >> To set the time through rtc-hid-sensor-time >> at startup, the module now checks by default if the system time is before >> 1970-01-02 and sets the system time (once) if this is the case. >> >> To disable this behaviour, set the module option hctosys to zero, e.g. by >> using rtc-hid-sensor-time.hctosys=0 at the kernel command line if the >> driver is statically linked into the kernel. > > Is a bit hacky, no? I didn't have any other idea to prevent an USB (or any other hot-pluggable HID) device to change the time while still beeing able (by default) to set the time by such an device at boot. But I'm open to suggestions. (E.g. one of the scenarios I want to prevent is, that a computer gets it's time by NTP and someone is able to change the time later on by simply plugging in some HID device.) > >> @@ -237,6 +279,22 @@ static const struct rtc_class_ops hid_time_rtc_ops = { >> .read_time = hid_rtc_read_time, >> }; >> >> +struct hid_time_work_time_state { >> + struct work_struct work; >> + struct hid_time_state *time_state; >> +}; >> + >> +static void hid_time_request_report_work(struct work_struct *work) >> +{ >> + struct hid_time_state *time_state = >> + ((struct hid_time_work_time_state *)work)->time_state; > > Yikes. Use container_of() here. Ok, will do. > > Also, you don't *have* to initialise things at their definition site. So > > struct hid_time_state *time_state = > some-ginormous-expression-which-overflows-80-columns; > > becomes > > struct hid_time_state *time_state; > time_state = some-ginormous-expression-which-no-longer-overflows-80-columns; > > Simple, no? Depends on which maintainer one might end up. Everyone has it's own preferred style and I've seen discussions about more silly things. ;) Will change it. > >> + /* get a report with all values through requesting one value */ >> + sensor_hub_input_attr_get_raw_value( >> + time_state->common_attributes.hsdev, HID_USAGE_SENSOR_TIME, >> + hid_time_addresses[0], time_state->info[0].report_id); >> + kfree(work); >> +} >> + >> static int hid_time_probe(struct platform_device *pdev) >> { >> int ret = 0; >> @@ -287,6 +345,20 @@ static int hid_time_probe(struct platform_device *pdev) >> return PTR_ERR(time_state->rtc); >> } >> >> + if (!hid_time_time_set_once && hid_time_hctosys_enabled) { >> + /* >> + * Request a HID report to set the time. >> + * Calling sensor_hub_..._get_raw_value() here directly >> + * doesn't work, therefor we have to use a work. >> + */ >> + struct hid_time_work_time_state *hdwork = >> + kmalloc(sizeof(struct hid_time_work_time_state), >> + GFP_KERNEL); > > looky: > > struct hid_time_work_time_state *hdwork; > > hdwork = kmalloc(sizeof(*hdwork), GFP_KERNEL); > >> + hdwork->time_state = time_state; > > Forgot to check for kmalloc() failure. > >> + INIT_WORK(&hdwork->work, hid_time_request_report_work); >> + schedule_work(&hdwork->work); > > The patch adds a schedule_work() but no flush_scheduled_work(), etc. > So if the driver is shut down or rmmodded while the work is still > pending, the kernel will go kapow. > Yes, I've forgotten those two things. Will fix them with a v2, if there will be an agreement about the first two points. Thanks for the review. Alexander ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 3/3] rtc: rtc-hid-sensor-time; add option hctosys to set time at boot 2013-04-23 8:51 ` Alexander Holler @ 2013-04-23 10:08 ` Alexander Holler 2013-04-23 10:13 ` Alexander Holler 0 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-04-23 10:08 UTC (permalink / raw) To: Andrew Morton Cc: linux-kernel, rtc-linux, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina Am 23.04.2013 10:51, schrieb Alexander Holler: > Am 23.04.2013 01:38, schrieb Andrew Morton: >> On Fri, 19 Apr 2013 17:14:12 +0200 Alexander Holler >> <holler@ahsoftware.de> wrote: >> >>> drivers/rtc/hctosys (CONFIG_RTC_HCTOSYS) doesn't work for >>> rtc-hid-sensor-time because it will be called in late_init, and thus >>> before >>> rtc-hid-sensor-time gets loaded. >> >> Isn't that true of all RTC drivers which are built as modules? There's >> nothing special about hid-sensor-time here? >> >> I assume the standard answer here is "your RTC driver should be built >> into vmlinux". If we wish to make things work for modular RTC drivers >> then we should find a solution which addresses *all* RTC drivers? > > No. I having rtc-hid-sensor-time, hid-sensor-hub (and USB) statically > linked in doesn't help. Here is what happens here with such an > configuration: > > -- > [ 7.638970] drivers/rtc/hctosys.c: unable to open rtc device (rtc0) > [ 7.645639] Waiting 180sec before mounting root device... > [ 16.598759] HID-SENSOR-2000a0 HID-SENSOR-2000a0.0: rtc core: > registered hid-sensor-time as rtc0 > [ 16.608712] HID-SENSOR-2000a0 HID-SENSOR-2000a0.0: hctosys: setting > system clock to 2013-04-19 16:45:06 UTC (1366389906) > -- > > I havent't looked in detail at why rtc-hid-sensor-time gets loaded that > late, but I assume it's because the USB stack (and/or the device or the > communication inbetween) needs some time (and I assume that's why > rootwait and rootdelay got invented too). > >> >>> To set the time through rtc-hid-sensor-time >>> at startup, the module now checks by default if the system time is >>> before >>> 1970-01-02 and sets the system time (once) if this is the case. >>> >>> To disable this behaviour, set the module option hctosys to zero, >>> e.g. by >>> using rtc-hid-sensor-time.hctosys=0 at the kernel command line if the >>> driver is statically linked into the kernel. >> >> Is a bit hacky, no? > > I didn't have any other idea to prevent an USB (or any other > hot-pluggable HID) device to change the time while still beeing able (by > default) to set the time by such an device at boot. But I'm open to > suggestions. (E.g. one of the scenarios I want to prevent is, that a > computer gets it's time by NTP and someone is able to change the time > later on by simply plugging in some HID device.) > To add something more: I use the system time as a bool "time_was_set_once" and have choosen one day just in case something needs really long to boot (e.g. because of some lengthy fsck or whatever else). A solution to both problems might be to change the logic for hctosys completly to read the time when the first RTC device appears (or when the device mentioned in CONFIG_RTC_HCTOSYS_DEVICE appears). But that would require a change to hctosys or the RTC subsystem, which would involve more patches and discussion. As rtc-hid-sensor-time currently seems to be the only RTC with the above problems, I've gone the easy route and only modified this driver. Regards, Alexander ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 3/3] rtc: rtc-hid-sensor-time; add option hctosys to set time at boot 2013-04-23 10:08 ` Alexander Holler @ 2013-04-23 10:13 ` Alexander Holler 2013-04-23 10:17 ` Alexander Holler 0 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-04-23 10:13 UTC (permalink / raw) To: Andrew Morton Cc: linux-kernel, rtc-linux, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina Am 23.04.2013 12:08, schrieb Alexander Holler: > Am 23.04.2013 10:51, schrieb Alexander Holler: >> Am 23.04.2013 01:38, schrieb Andrew Morton: >>> On Fri, 19 Apr 2013 17:14:12 +0200 Alexander Holler >>> <holler@ahsoftware.de> wrote: >>> >>>> drivers/rtc/hctosys (CONFIG_RTC_HCTOSYS) doesn't work for >>>> rtc-hid-sensor-time because it will be called in late_init, and thus >>>> before >>>> rtc-hid-sensor-time gets loaded. >>> >>> Isn't that true of all RTC drivers which are built as modules? There's >>> nothing special about hid-sensor-time here? >>> >>> I assume the standard answer here is "your RTC driver should be built >>> into vmlinux". If we wish to make things work for modular RTC drivers >>> then we should find a solution which addresses *all* RTC drivers? >> >> No. I having rtc-hid-sensor-time, hid-sensor-hub (and USB) statically >> linked in doesn't help. Here is what happens here with such an >> configuration: >> >> -- >> [ 7.638970] drivers/rtc/hctosys.c: unable to open rtc device (rtc0) >> [ 7.645639] Waiting 180sec before mounting root device... >> [ 16.598759] HID-SENSOR-2000a0 HID-SENSOR-2000a0.0: rtc core: >> registered hid-sensor-time as rtc0 >> [ 16.608712] HID-SENSOR-2000a0 HID-SENSOR-2000a0.0: hctosys: setting >> system clock to 2013-04-19 16:45:06 UTC (1366389906) >> -- >> >> I havent't looked in detail at why rtc-hid-sensor-time gets loaded that >> late, but I assume it's because the USB stack (and/or the device or the >> communication inbetween) needs some time (and I assume that's why >> rootwait and rootdelay got invented too). >> >>> >>>> To set the time through rtc-hid-sensor-time >>>> at startup, the module now checks by default if the system time is >>>> before >>>> 1970-01-02 and sets the system time (once) if this is the case. >>>> >>>> To disable this behaviour, set the module option hctosys to zero, >>>> e.g. by >>>> using rtc-hid-sensor-time.hctosys=0 at the kernel command line if the >>>> driver is statically linked into the kernel. >>> >>> Is a bit hacky, no? >> >> I didn't have any other idea to prevent an USB (or any other >> hot-pluggable HID) device to change the time while still beeing able (by >> default) to set the time by such an device at boot. But I'm open to >> suggestions. (E.g. one of the scenarios I want to prevent is, that a >> computer gets it's time by NTP and someone is able to change the time >> later on by simply plugging in some HID device.) >> > > To add something more: I use the system time as a bool > "time_was_set_once" and have choosen one day just in case something > needs really long to boot (e.g. because of some lengthy fsck or whatever > else). > > A solution to both problems might be to change the logic for hctosys > completly to read the time when the first RTC device appears (or when > the device mentioned in CONFIG_RTC_HCTOSYS_DEVICE appears). But that > would require a change to hctosys or the RTC subsystem, which would > involve more patches and discussion. As rtc-hid-sensor-time currently > seems to be the only RTC with the above problems, I've gone the easy > route and only modified this driver. Oh, damn. I've forgotten my example above with NTP. In that case setting the time when the first RTC appears doesn't work. Regards, Alexander ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 3/3] rtc: rtc-hid-sensor-time; add option hctosys to set time at boot 2013-04-23 10:13 ` Alexander Holler @ 2013-04-23 10:17 ` Alexander Holler 2013-04-23 15:47 ` Alexander Holler 2013-05-05 11:21 ` [PATCH 0/4] rtc: rtc-hid-sensor-time: some changes Alexander Holler 0 siblings, 2 replies; 78+ messages in thread From: Alexander Holler @ 2013-04-23 10:17 UTC (permalink / raw) To: Andrew Morton Cc: linux-kernel, rtc-linux, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina Am 23.04.2013 12:13, schrieb Alexander Holler: > Am 23.04.2013 12:08, schrieb Alexander Holler: >> Am 23.04.2013 10:51, schrieb Alexander Holler: >>> Am 23.04.2013 01:38, schrieb Andrew Morton: >>>> On Fri, 19 Apr 2013 17:14:12 +0200 Alexander Holler >>>> <holler@ahsoftware.de> wrote: >>>> >>>>> drivers/rtc/hctosys (CONFIG_RTC_HCTOSYS) doesn't work for >>>>> rtc-hid-sensor-time because it will be called in late_init, and thus >>>>> before >>>>> rtc-hid-sensor-time gets loaded. >>>> >>>> Isn't that true of all RTC drivers which are built as modules? There's >>>> nothing special about hid-sensor-time here? >>>> >>>> I assume the standard answer here is "your RTC driver should be built >>>> into vmlinux". If we wish to make things work for modular RTC drivers >>>> then we should find a solution which addresses *all* RTC drivers? >>> >>> No. I having rtc-hid-sensor-time, hid-sensor-hub (and USB) statically >>> linked in doesn't help. Here is what happens here with such an >>> configuration: >>> >>> -- >>> [ 7.638970] drivers/rtc/hctosys.c: unable to open rtc device (rtc0) >>> [ 7.645639] Waiting 180sec before mounting root device... >>> [ 16.598759] HID-SENSOR-2000a0 HID-SENSOR-2000a0.0: rtc core: >>> registered hid-sensor-time as rtc0 >>> [ 16.608712] HID-SENSOR-2000a0 HID-SENSOR-2000a0.0: hctosys: setting >>> system clock to 2013-04-19 16:45:06 UTC (1366389906) >>> -- >>> >>> I havent't looked in detail at why rtc-hid-sensor-time gets loaded that >>> late, but I assume it's because the USB stack (and/or the device or the >>> communication inbetween) needs some time (and I assume that's why >>> rootwait and rootdelay got invented too). >>> >>>> >>>>> To set the time through rtc-hid-sensor-time >>>>> at startup, the module now checks by default if the system time is >>>>> before >>>>> 1970-01-02 and sets the system time (once) if this is the case. >>>>> >>>>> To disable this behaviour, set the module option hctosys to zero, >>>>> e.g. by >>>>> using rtc-hid-sensor-time.hctosys=0 at the kernel command line if the >>>>> driver is statically linked into the kernel. >>>> >>>> Is a bit hacky, no? >>> >>> I didn't have any other idea to prevent an USB (or any other >>> hot-pluggable HID) device to change the time while still beeing able (by >>> default) to set the time by such an device at boot. But I'm open to >>> suggestions. (E.g. one of the scenarios I want to prevent is, that a >>> computer gets it's time by NTP and someone is able to change the time >>> later on by simply plugging in some HID device.) >>> >> >> To add something more: I use the system time as a bool >> "time_was_set_once" and have choosen one day just in case something >> needs really long to boot (e.g. because of some lengthy fsck or whatever >> else). >> >> A solution to both problems might be to change the logic for hctosys >> completly to read the time when the first RTC device appears (or when >> the device mentioned in CONFIG_RTC_HCTOSYS_DEVICE appears). But that >> would require a change to hctosys or the RTC subsystem, which would >> involve more patches and discussion. As rtc-hid-sensor-time currently >> seems to be the only RTC with the above problems, I've gone the easy >> route and only modified this driver. > > Oh, damn. I've forgotten my example above with NTP. In that case setting > the time when the first RTC appears doesn't work. So a general solution might be to set the system time when the first RTC (or the one mentioned in CONFIG_RTC_HCTOSYS_DEVICE) appears AND nothing else did set the time before. Regards, Alexander ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 3/3] rtc: rtc-hid-sensor-time; add option hctosys to set time at boot 2013-04-23 10:17 ` Alexander Holler @ 2013-04-23 15:47 ` Alexander Holler 2013-04-24 21:14 ` Andrew Morton 2013-05-05 11:21 ` [PATCH 0/4] rtc: rtc-hid-sensor-time: some changes Alexander Holler 1 sibling, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-04-23 15:47 UTC (permalink / raw) To: Andrew Morton Cc: linux-kernel, rtc-linux, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina Am 23.04.2013 12:17, schrieb Alexander Holler: > Am 23.04.2013 12:13, schrieb Alexander Holler: >> Am 23.04.2013 12:08, schrieb Alexander Holler: >>> Am 23.04.2013 10:51, schrieb Alexander Holler: >>>> Am 23.04.2013 01:38, schrieb Andrew Morton: >>>>> On Fri, 19 Apr 2013 17:14:12 +0200 Alexander Holler >>>>> <holler@ahsoftware.de> wrote: >>>>> >>>>>> drivers/rtc/hctosys (CONFIG_RTC_HCTOSYS) doesn't work for >>>>>> rtc-hid-sensor-time because it will be called in late_init, and thus >>>>>> before >>>>>> rtc-hid-sensor-time gets loaded. >>>>> >>>>> Isn't that true of all RTC drivers which are built as modules? >>>>> There's >>>>> nothing special about hid-sensor-time here? >>>>> >>>>> I assume the standard answer here is "your RTC driver should be built >>>>> into vmlinux". If we wish to make things work for modular RTC drivers >>>>> then we should find a solution which addresses *all* RTC drivers? >>>> >>>> No. I having rtc-hid-sensor-time, hid-sensor-hub (and USB) statically >>>> linked in doesn't help. Here is what happens here with such an >>>> configuration: >>>> >>>> -- >>>> [ 7.638970] drivers/rtc/hctosys.c: unable to open rtc device (rtc0) >>>> [ 7.645639] Waiting 180sec before mounting root device... >>>> [ 16.598759] HID-SENSOR-2000a0 HID-SENSOR-2000a0.0: rtc core: >>>> registered hid-sensor-time as rtc0 >>>> [ 16.608712] HID-SENSOR-2000a0 HID-SENSOR-2000a0.0: hctosys: setting >>>> system clock to 2013-04-19 16:45:06 UTC (1366389906) >>>> -- >>>> >>>> I havent't looked in detail at why rtc-hid-sensor-time gets loaded that >>>> late, but I assume it's because the USB stack (and/or the device or the >>>> communication inbetween) needs some time (and I assume that's why >>>> rootwait and rootdelay got invented too). >>>> >>>>> >>>>>> To set the time through rtc-hid-sensor-time >>>>>> at startup, the module now checks by default if the system time is >>>>>> before >>>>>> 1970-01-02 and sets the system time (once) if this is the case. >>>>>> >>>>>> To disable this behaviour, set the module option hctosys to zero, >>>>>> e.g. by >>>>>> using rtc-hid-sensor-time.hctosys=0 at the kernel command line if the >>>>>> driver is statically linked into the kernel. >>>>> >>>>> Is a bit hacky, no? >>>> >>>> I didn't have any other idea to prevent an USB (or any other >>>> hot-pluggable HID) device to change the time while still beeing able >>>> (by >>>> default) to set the time by such an device at boot. But I'm open to >>>> suggestions. (E.g. one of the scenarios I want to prevent is, that a >>>> computer gets it's time by NTP and someone is able to change the time >>>> later on by simply plugging in some HID device.) >>>> >>> >>> To add something more: I use the system time as a bool >>> "time_was_set_once" and have choosen one day just in case something >>> needs really long to boot (e.g. because of some lengthy fsck or whatever >>> else). >>> >>> A solution to both problems might be to change the logic for hctosys >>> completly to read the time when the first RTC device appears (or when >>> the device mentioned in CONFIG_RTC_HCTOSYS_DEVICE appears). But that >>> would require a change to hctosys or the RTC subsystem, which would >>> involve more patches and discussion. As rtc-hid-sensor-time currently >>> seems to be the only RTC with the above problems, I've gone the easy >>> route and only modified this driver. >> >> Oh, damn. I've forgotten my example above with NTP. In that case setting >> the time when the first RTC appears doesn't work. > > So a general solution might be to set the system time when the first RTC > (or the one mentioned in CONFIG_RTC_HCTOSYS_DEVICE) appears AND nothing > else did set the time before. To extend that idea a bit further, I think an option timewait (similiar to rootwait) would be a nice to have. If just time wouldn't be that rare ... ;) Regards, Alexander ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 3/3] rtc: rtc-hid-sensor-time; add option hctosys to set time at boot 2013-04-23 15:47 ` Alexander Holler @ 2013-04-24 21:14 ` Andrew Morton 2013-04-25 6:55 ` Alexander Holler 0 siblings, 1 reply; 78+ messages in thread From: Andrew Morton @ 2013-04-24 21:14 UTC (permalink / raw) To: Alexander Holler Cc: linux-kernel, rtc-linux, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina On Tue, 23 Apr 2013 17:47:20 +0200 Alexander Holler <holler@ahsoftware.de> wrote: > >>> "time_was_set_once" and have choosen one day just in case something > >>> needs really long to boot (e.g. because of some lengthy fsck or whatever > >>> else). > >>> > >>> A solution to both problems might be to change the logic for hctosys > >>> completly to read the time when the first RTC device appears (or when > >>> the device mentioned in CONFIG_RTC_HCTOSYS_DEVICE appears). But that > >>> would require a change to hctosys or the RTC subsystem, which would > >>> involve more patches and discussion. As rtc-hid-sensor-time currently > >>> seems to be the only RTC with the above problems, I've gone the easy > >>> route and only modified this driver. > >> > >> Oh, damn. I've forgotten my example above with NTP. In that case setting > >> the time when the first RTC appears doesn't work. > > > > So a general solution might be to set the system time when the first RTC > > (or the one mentioned in CONFIG_RTC_HCTOSYS_DEVICE) appears AND nothing > > else did set the time before. > > To extend that idea a bit further, I think an option timewait (similiar > to rootwait) would be a nice to have. > > If just time wouldn't be that rare ... ;) Yes, some sort of notifier callout when the CONFIG_RTC_HCTOSYS_DEVICE device is registered seems appropriate. I didn't understand why that is problematic for NTP. Getting all the lifetime/reference stuff right will be tricky :( Can't shut down or unload a driver when it is on that notification list. And it assumes that the CONFIG_RTC_HCTOSYS_DEVICE driver is all ready to go when it registers itself. Hopefully that is true, but they should be reviewed. Adding the timewait thing sounds unpleasant - how to reliably tune the interval for all possible users of your distro? We should aim to make things synchronous, deterministic and stuff-happens-in-the-correct-order. It all sounds like a moderate amount of work, but it would be great to be able to fix this for all drivers, not just hid-sensor-time. That's assuming that other drivers have the same issue - perhaps they don't, but perhaps things can go wrong if the module loading order is wrong? ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 3/3] rtc: rtc-hid-sensor-time; add option hctosys to set time at boot 2013-04-24 21:14 ` Andrew Morton @ 2013-04-25 6:55 ` Alexander Holler 0 siblings, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-04-25 6:55 UTC (permalink / raw) To: Andrew Morton Cc: linux-kernel, rtc-linux, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina, John Stultz Am 24.04.2013 23:14, schrieb Andrew Morton: > On Tue, 23 Apr 2013 17:47:20 +0200 Alexander Holler <holler@ahsoftware.de> wrote: > >>>>> "time_was_set_once" and have choosen one day just in case something >>>>> needs really long to boot (e.g. because of some lengthy fsck or whatever >>>>> else). >>>>> >>>>> A solution to both problems might be to change the logic for hctosys >>>>> completly to read the time when the first RTC device appears (or when >>>>> the device mentioned in CONFIG_RTC_HCTOSYS_DEVICE appears). But that >>>>> would require a change to hctosys or the RTC subsystem, which would >>>>> involve more patches and discussion. As rtc-hid-sensor-time currently >>>>> seems to be the only RTC with the above problems, I've gone the easy >>>>> route and only modified this driver. >>>> >>>> Oh, damn. I've forgotten my example above with NTP. In that case setting >>>> the time when the first RTC appears doesn't work. >>> >>> So a general solution might be to set the system time when the first RTC >>> (or the one mentioned in CONFIG_RTC_HCTOSYS_DEVICE) appears AND nothing >>> else did set the time before. >> >> To extend that idea a bit further, I think an option timewait (similiar >> to rootwait) would be a nice to have. >> >> If just time wouldn't be that rare ... ;) > > Yes, some sort of notifier callout when the CONFIG_RTC_HCTOSYS_DEVICE > device is registered seems appropriate. I didn't understand why that > is problematic for NTP. > > Getting all the lifetime/reference stuff right will be tricky :( Can't > shut down or unload a driver when it is on that notification list. > > And it assumes that the CONFIG_RTC_HCTOSYS_DEVICE driver is all ready > to go when it registers itself. Hopefully that is true, but they > should be reviewed. > > Adding the timewait thing sounds unpleasant - how to reliably tune the > interval for all possible users of your distro? We should aim to make > things synchronous, deterministic and > stuff-happens-in-the-correct-order. > > It all sounds like a moderate amount of work, but it would be great > to be able to fix this for all drivers, not just hid-sensor-time. That's > assuming that other drivers have the same issue - perhaps they don't, > but perhaps things can go wrong if the module loading order is wrong? > I've added John Stultz to cc as he seems to work on a similiar problem (to not set the time twice on resume). I'm not sure what you meant with the notifiers, but wouldn't be a function which sets the time if nothing else did that before a solution? I think about something like that (not real code): static bool timeWasSet; // = 0 int setTimeIfNotSet(time, devicename) { if (timeWasSet || (devicename && CONFIG_RTC_HCTOSYS_DEVICE && devicename != CONFIG_RTC_HCTOSYS_DEVICE ) return -1; timeWasSet = 1; do_settimeofday(time); return 0; } That "timewait" kernel option I mentioned above then would be easy too: void timewait(void) { while (!timeWasSet) sleepOrSimiliar(); } That setTimeIfNotSet() function could be called by the RTC subsystem whenever a new RTC will be registered and CONFIG_RTC_HCTOSYS is enabled (or on resume). In regard to the persistent_clocks on x86 I know almost nothing. I didn't even knew they do exist before I've seen a discussion about HCTOSYS yesterday. I thought the RTC_CMOS driver is responsible for the time on x86. ;) Therfor I can't say anything about how things do work there. Whats missing above is something which sets timeWasSet to 1 if userland (NTP or similiar) does set the time. That could be done always (in do_settimeofday) or e.g. by using a function pointer to do_settimeofday() which first points to a function which sets timeWasSet and later on points to do_settimeofday() directly. Maybe it's all silly (I'm missing the big overview over time in the kernel), but thats what first entered my mind while thinking about how to avoid changing a time by an HID device if it was already set by userland/NTP or another clock (besides that trick in testing for system date < 1970-01-02 I've then used in my patch because it was easy to implement while not doing changes to timekeeping itself). Regards, Alexander ^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 0/4] rtc: rtc-hid-sensor-time: some changes 2013-04-23 10:17 ` Alexander Holler 2013-04-23 15:47 ` Alexander Holler @ 2013-05-05 11:21 ` Alexander Holler 2013-05-05 11:21 ` [PATCH 1/4] rtc: rtc-hid-sensor-time: allow full years (16bit) in HID reports Alexander Holler ` (3 more replies) 1 sibling, 4 replies; 78+ messages in thread From: Alexander Holler @ 2013-05-05 11:21 UTC (permalink / raw) To: linux-kernel Cc: rtc-linux, Andrew Morton, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina, John Stultz Changes to the first series: - Patch 1 and 2 are unchanged, - Patch 3 uses getnstimeofday() instead of do_gettimeofday() which spares a variable and it should include all changes requested through the review by Andrew Morton. I left in the "hacky" part but included a more verbose comment in the source why the "hacky" looking part is there, - Patch 4 is new and adds support for milliseconds (currently only used if the system time will be set by the driver). Regards, Alexander Holler ^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 1/4] rtc: rtc-hid-sensor-time: allow full years (16bit) in HID reports 2013-05-05 11:21 ` [PATCH 0/4] rtc: rtc-hid-sensor-time: some changes Alexander Holler @ 2013-05-05 11:21 ` Alexander Holler 2013-05-05 11:21 ` [PATCH 2/4] rtc: rtc-hid-sensor-time: allow 16 and 32 bit values for all attributes Alexander Holler ` (2 subsequent siblings) 3 siblings, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-05-05 11:21 UTC (permalink / raw) To: linux-kernel Cc: rtc-linux, Andrew Morton, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina, John Stultz, Alexander Holler The draft for HID-sensors (HUTRR39) currently doesn't define the range for the attribute year. Asking one of the authors revealed that full years (e.g. 2013 instead of just 13) were meant. So we now allow both, 8 bit and 16 bit values for the attribute year and assuming full years when the value is 16 bits wide. We will still support 8 bit values until the specification gets final (and maybe defines a way to set the time too). Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- drivers/rtc/rtc-hid-sensor-time.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index 6302450..b8c1b10 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -85,10 +85,13 @@ static int hid_time_capture_sample(struct hid_sensor_hub_device *hsdev, switch (usage_id) { case HID_USAGE_SENSOR_TIME_YEAR: - time_buf->tm_year = *(u8 *)raw_data; - if (time_buf->tm_year < 70) - /* assume we are in 1970...2069 */ - time_buf->tm_year += 100; + if (raw_len == 1) { + time_buf->tm_year = *(u8 *)raw_data; + if (time_buf->tm_year < 70) + /* assume we are in 1970...2069 */ + time_buf->tm_year += 100; + } else + time_buf->tm_year = *(u16 *)raw_data-1900; break; case HID_USAGE_SENSOR_TIME_MONTH: /* sensor sending the month as 1-12, we need 0-11 */ @@ -151,11 +154,27 @@ static int hid_time_parse_report(struct platform_device *pdev, return -EINVAL; } if (time_state->info[i].size != 1) { - dev_err(&pdev->dev, - "attribute '%s' not 8 bits wide!\n", + /* + * The draft for HID-sensors (HUTRR39) currently + * doesn't define the range for the year attribute. + * Therefor we support both 8 bit (0-99) and 16 bit + * (full) as size for the year. + */ + if (time_state->info[i].attrib_id != + HID_USAGE_SENSOR_TIME_YEAR) { + dev_err(&pdev->dev, + "attribute '%s' not 8 bits wide!\n", hid_time_attrib_name( time_state->info[i].attrib_id)); - return -EINVAL; + return -EINVAL; + } + if (time_state->info[i].size != 2) { + dev_err(&pdev->dev, + "attribute '%s' not 8 or 16 bits wide!\n", + hid_time_attrib_name( + time_state->info[i].attrib_id)); + return -EINVAL; + } } if (time_state->info[i].units != HID_USAGE_SENSOR_UNITS_NOT_SPECIFIED && -- 1.8.1.5 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 2/4] rtc: rtc-hid-sensor-time: allow 16 and 32 bit values for all attributes. 2013-05-05 11:21 ` [PATCH 0/4] rtc: rtc-hid-sensor-time: some changes Alexander Holler 2013-05-05 11:21 ` [PATCH 1/4] rtc: rtc-hid-sensor-time: allow full years (16bit) in HID reports Alexander Holler @ 2013-05-05 11:21 ` Alexander Holler 2013-05-05 11:21 ` [PATCH 3/4] rtc: rtc-hid-sensor-time: add option hctosys to set time at boot Alexander Holler 2013-05-05 11:21 ` [PATCH 4/4] rtc: rtc-hid-sensor-time: add support for milliseconds Alexander Holler 3 siblings, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-05-05 11:21 UTC (permalink / raw) To: linux-kernel Cc: rtc-linux, Andrew Morton, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina, John Stultz, Alexander Holler There is no real reason to not support 16 or 32 bit values too. Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- drivers/rtc/rtc-hid-sensor-time.c | 59 +++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index b8c1b10..7273b01 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -76,6 +76,20 @@ static int hid_time_proc_event(struct hid_sensor_hub_device *hsdev, return 0; } +static u32 hid_time_value(size_t raw_len, char *raw_data) +{ + switch (raw_len) { + case 1: + return *(u8 *)raw_data; + case 2: + return *(u16 *)raw_data; + case 4: + return *(u32 *)raw_data; + default: + return (u32)(~0U); /* 0xff... or -1 to denote an error */ + } +} + static int hid_time_capture_sample(struct hid_sensor_hub_device *hsdev, unsigned usage_id, size_t raw_len, char *raw_data, void *priv) @@ -85,29 +99,35 @@ static int hid_time_capture_sample(struct hid_sensor_hub_device *hsdev, switch (usage_id) { case HID_USAGE_SENSOR_TIME_YEAR: + /* + * The draft for HID-sensors (HUTRR39) currently doesn't define + * the range for the year attribute. Therefor we support + * 8 bit (0-99) and 16 or 32 bits (full) as size for the year. + */ if (raw_len == 1) { time_buf->tm_year = *(u8 *)raw_data; if (time_buf->tm_year < 70) /* assume we are in 1970...2069 */ time_buf->tm_year += 100; } else - time_buf->tm_year = *(u16 *)raw_data-1900; + time_buf->tm_year = + (int)hid_time_value(raw_len, raw_data)-1900; break; case HID_USAGE_SENSOR_TIME_MONTH: - /* sensor sending the month as 1-12, we need 0-11 */ - time_buf->tm_mon = *(u8 *)raw_data-1; + /* sensors are sending the month as 1-12, we need 0-11 */ + time_buf->tm_mon = (int)hid_time_value(raw_len, raw_data)-1; break; case HID_USAGE_SENSOR_TIME_DAY: - time_buf->tm_mday = *(u8 *)raw_data; + time_buf->tm_mday = (int)hid_time_value(raw_len, raw_data); break; case HID_USAGE_SENSOR_TIME_HOUR: - time_buf->tm_hour = *(u8 *)raw_data; + time_buf->tm_hour = (int)hid_time_value(raw_len, raw_data); break; case HID_USAGE_SENSOR_TIME_MINUTE: - time_buf->tm_min = *(u8 *)raw_data; + time_buf->tm_min = (int)hid_time_value(raw_len, raw_data); break; case HID_USAGE_SENSOR_TIME_SECOND: - time_buf->tm_sec = *(u8 *)raw_data; + time_buf->tm_sec = (int)hid_time_value(raw_len, raw_data); break; default: return -EINVAL; @@ -153,28 +173,13 @@ static int hid_time_parse_report(struct platform_device *pdev, "not all needed attributes inside the same report!\n"); return -EINVAL; } - if (time_state->info[i].size != 1) { - /* - * The draft for HID-sensors (HUTRR39) currently - * doesn't define the range for the year attribute. - * Therefor we support both 8 bit (0-99) and 16 bit - * (full) as size for the year. - */ - if (time_state->info[i].attrib_id != - HID_USAGE_SENSOR_TIME_YEAR) { - dev_err(&pdev->dev, - "attribute '%s' not 8 bits wide!\n", - hid_time_attrib_name( - time_state->info[i].attrib_id)); - return -EINVAL; - } - if (time_state->info[i].size != 2) { - dev_err(&pdev->dev, - "attribute '%s' not 8 or 16 bits wide!\n", + if (time_state->info[i].size == 3 || + time_state->info[i].size > 4) { + dev_err(&pdev->dev, + "attribute '%s' not 8, 16 or 32 bits wide!\n", hid_time_attrib_name( time_state->info[i].attrib_id)); - return -EINVAL; - } + return -EINVAL; } if (time_state->info[i].units != HID_USAGE_SENSOR_UNITS_NOT_SPECIFIED && -- 1.8.1.5 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 3/4] rtc: rtc-hid-sensor-time: add option hctosys to set time at boot 2013-05-05 11:21 ` [PATCH 0/4] rtc: rtc-hid-sensor-time: some changes Alexander Holler 2013-05-05 11:21 ` [PATCH 1/4] rtc: rtc-hid-sensor-time: allow full years (16bit) in HID reports Alexander Holler 2013-05-05 11:21 ` [PATCH 2/4] rtc: rtc-hid-sensor-time: allow 16 and 32 bit values for all attributes Alexander Holler @ 2013-05-05 11:21 ` Alexander Holler 2013-05-21 21:42 ` Andrew Morton ` (2 more replies) 2013-05-05 11:21 ` [PATCH 4/4] rtc: rtc-hid-sensor-time: add support for milliseconds Alexander Holler 3 siblings, 3 replies; 78+ messages in thread From: Alexander Holler @ 2013-05-05 11:21 UTC (permalink / raw) To: linux-kernel Cc: rtc-linux, Andrew Morton, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina, John Stultz, Alexander Holler drivers/rtc/hctosys (CONFIG_RTC_HCTOSYS) doesn't work for rtc-hid-sensor-time because it will be called in late_init, and thus before rtc-hid-sensor-time gets loaded. To set the time through rtc-hid-sensor-time at startup, the module now checks by default if the system time is before 1970-01-02 and sets the system time (once) if this is the case. To disable this behaviour, set the module option hctosys to zero, e.g. by using rtc-hid-sensor-time.hctosys=0 at the kernel command line if the driver is statically linked into the kernel. Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- drivers/rtc/rtc-hid-sensor-time.c | 94 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index 7273b01..db8503a 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -27,6 +27,12 @@ /* Usage ID from spec for Time: 0x2000A0 */ #define DRIVER_NAME "HID-SENSOR-2000a0" /* must be lowercase */ +static bool hid_time_hctosys_enabled = 1; +module_param_named(hctosys, hid_time_hctosys_enabled, bool, 0644); +MODULE_PARM_DESC(hctosys, + "set the system time (once) if it is before 1970-01-02"); +static bool hid_time_time_set_once; + enum hid_time_channel { CHANNEL_SCAN_INDEX_YEAR, CHANNEL_SCAN_INDEX_MONTH, @@ -37,6 +43,11 @@ enum hid_time_channel { TIME_RTC_CHANNEL_MAX, }; +struct hid_time_workts { + struct work_struct work; + struct hid_time_state *time_state; +}; + struct hid_time_state { struct hid_sensor_hub_callbacks callbacks; struct hid_sensor_common common_attributes; @@ -46,6 +57,7 @@ struct hid_time_state { struct completion comp_last_time; struct rtc_time time_buf; struct rtc_device *rtc; + struct hid_time_workts *workts; }; static const u32 hid_time_addresses[TIME_RTC_CHANNEL_MAX] = { @@ -62,6 +74,49 @@ static const char * const hid_time_channel_names[TIME_RTC_CHANNEL_MAX] = { "year", "month", "day", "hour", "minute", "second", }; +static void hid_time_hctosys(struct hid_time_state *time_state) +{ + struct timespec ts; + int rc = rtc_valid_tm(&time_state->last_time); + + if (rc) { + dev_err(time_state->rtc->dev.parent, + "hctosys: invalid date/time\n"); + return; + } + + getnstimeofday(&ts); + if (ts.tv_sec >= 86400) /* 1970-01-02 00:00:00 UTC */ + /* + * Security: don't let a hot-pluggable device change + * a valid system time. + * In absence of a kernel-wide flag like 'systime_was_set', + * we check if the system time is earlier than 1970-01-02. + * Just using a flag inside the RTC subsystem (e.g. from + * hctosys) doesn't work, because the time could be set + * by userspace (NTP, date, user, ...) or something else + * in the kernel too. + * Using a whole day to decide if something else has set the + * time should be enough for even the longest boot to complete + * (including possible forced fscks) and load this module. + */ + return; + + ts.tv_nsec = NSEC_PER_SEC >> 1; + rtc_tm_to_time(&time_state->last_time, &ts.tv_sec); + rc = do_settimeofday(&ts); + dev_info(time_state->rtc->dev.parent, + "hctosys: setting system clock to " + "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", + time_state->last_time.tm_year + 1900, + time_state->last_time.tm_mon + 1, + time_state->last_time.tm_mday, + time_state->last_time.tm_hour, + time_state->last_time.tm_min, + time_state->last_time.tm_sec, + (unsigned int) ts.tv_sec); +} + /* Callback handler to send event after all samples are received and captured */ static int hid_time_proc_event(struct hid_sensor_hub_device *hsdev, unsigned usage_id, void *priv) @@ -73,6 +128,10 @@ static int hid_time_proc_event(struct hid_sensor_hub_device *hsdev, time_state->last_time = time_state->time_buf; spin_unlock_irqrestore(&time_state->lock_last_time, flags); complete(&time_state->comp_last_time); + if (unlikely(!hid_time_time_set_once && hid_time_hctosys_enabled)) { + hid_time_time_set_once = 1; + hid_time_hctosys(time_state); + } return 0; } @@ -237,6 +296,19 @@ static const struct rtc_class_ops hid_time_rtc_ops = { .read_time = hid_rtc_read_time, }; +static void hid_time_request_report_work(struct work_struct *work) +{ + struct hid_time_state *time_state = + container_of(work, struct hid_time_workts, work) + ->time_state; + /* get a report with all values through requesting one value */ + sensor_hub_input_attr_get_raw_value( + time_state->common_attributes.hsdev, HID_USAGE_SENSOR_TIME, + hid_time_addresses[0], time_state->info[0].report_id); + time_state->workts = NULL; + kfree(work); +} + static int hid_time_probe(struct platform_device *pdev) { int ret = 0; @@ -288,13 +360,35 @@ static int hid_time_probe(struct platform_device *pdev) return PTR_ERR(time_state->rtc); } + if (!hid_time_time_set_once && hid_time_hctosys_enabled) { + /* + * Request a HID report to set the time. + * Calling sensor_hub_..._get_raw_value() here directly + * doesn't work, therefor we have to use a work. + */ + time_state->workts = kmalloc(sizeof(struct hid_time_workts), + GFP_KERNEL); + if (time_state->workts == NULL) + return -ENOMEM; + time_state->workts->time_state = time_state; + INIT_WORK(&time_state->workts->work, + hid_time_request_report_work); + schedule_work(&time_state->workts->work); + } + return ret; } static int hid_time_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct hid_time_state *time_state = platform_get_drvdata(pdev); + if (time_state->workts) { + cancel_work_sync(&time_state->workts->work); + kfree(time_state->workts); + time_state->workts = NULL; + } sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); return 0; -- 1.8.1.5 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* Re: [PATCH 3/4] rtc: rtc-hid-sensor-time: add option hctosys to set time at boot 2013-05-05 11:21 ` [PATCH 3/4] rtc: rtc-hid-sensor-time: add option hctosys to set time at boot Alexander Holler @ 2013-05-21 21:42 ` Andrew Morton 2013-05-21 22:02 ` John Stultz 2013-06-04 9:38 ` [PATCH] rtc: rtc-hid-sensor-time: fix possible bug on driver_remove Alexander Holler 2 siblings, 0 replies; 78+ messages in thread From: Andrew Morton @ 2013-05-21 21:42 UTC (permalink / raw) To: Alexander Holler Cc: linux-kernel, rtc-linux, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina, John Stultz On Sun, 5 May 2013 13:21:26 +0200 Alexander Holler <holler@ahsoftware.de> wrote: > drivers/rtc/hctosys (CONFIG_RTC_HCTOSYS) doesn't work for > rtc-hid-sensor-time because it will be called in late_init, and thus before > rtc-hid-sensor-time gets loaded. To set the time through > rtc-hid-sensor-time at startup, the module now checks by default if the > system time is before 1970-01-02 and sets the system time (once) if this is > the case. > > To disable this behaviour, set the module option hctosys to zero, e.g. by > using rtc-hid-sensor-time.hctosys=0 at the kernel command line if the > driver is statically linked into the kernel. I still find this rather unpleasant. Partly because it's hacky, mainly because it only solves the problem for one driver. Can we please try harder to find a more general fix? For example: if hctosys finds there are no drivers available, it sets a flag. Later when drivers are registered(?), that flag is queried and, if set, we set the system time at this time. Or something. ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 3/4] rtc: rtc-hid-sensor-time: add option hctosys to set time at boot 2013-05-05 11:21 ` [PATCH 3/4] rtc: rtc-hid-sensor-time: add option hctosys to set time at boot Alexander Holler 2013-05-21 21:42 ` Andrew Morton @ 2013-05-21 22:02 ` John Stultz 2013-05-21 23:15 ` Alexander Holler 2013-06-04 9:38 ` [PATCH] rtc: rtc-hid-sensor-time: fix possible bug on driver_remove Alexander Holler 2 siblings, 1 reply; 78+ messages in thread From: John Stultz @ 2013-05-21 22:02 UTC (permalink / raw) To: Alexander Holler Cc: linux-kernel, rtc-linux, Andrew Morton, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina On 05/05/2013 04:21 AM, Alexander Holler wrote: > drivers/rtc/hctosys (CONFIG_RTC_HCTOSYS) doesn't work for > rtc-hid-sensor-time because it will be called in late_init, and thus before > rtc-hid-sensor-time gets loaded. To set the time through > rtc-hid-sensor-time at startup, the module now checks by default if the > system time is before 1970-01-02 and sets the system time (once) if this is > the case. > > To disable this behaviour, set the module option hctosys to zero, e.g. by > using rtc-hid-sensor-time.hctosys=0 at the kernel command line if the > driver is statically linked into the kernel. Sorry I missed this earlier, it fell into my spam box for some reason. Like Andrew, I think this feels particularly hacky. Why exactly is late_init too early? (I'm unfamiliar with the rtc-hid-sensor-time driver) If this is a hotplug rtc device (why I'm guessing its not available at late_init), would it not be better to leave the setting of time using hwclock --hctosys via a udev rule or something? thanks -john ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 3/4] rtc: rtc-hid-sensor-time: add option hctosys to set time at boot 2013-05-21 22:02 ` John Stultz @ 2013-05-21 23:15 ` Alexander Holler 2013-05-28 19:37 ` John Stultz 0 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-05-21 23:15 UTC (permalink / raw) To: John Stultz Cc: linux-kernel, rtc-linux, Andrew Morton, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina Am 22.05.2013 00:02, schrieb John Stultz: > On 05/05/2013 04:21 AM, Alexander Holler wrote: >> drivers/rtc/hctosys (CONFIG_RTC_HCTOSYS) doesn't work for >> rtc-hid-sensor-time because it will be called in late_init, and thus >> before >> rtc-hid-sensor-time gets loaded. To set the time through >> rtc-hid-sensor-time at startup, the module now checks by default if the >> system time is before 1970-01-02 and sets the system time (once) if >> this is >> the case. >> >> To disable this behaviour, set the module option hctosys to zero, e.g. by >> using rtc-hid-sensor-time.hctosys=0 at the kernel command line if the >> driver is statically linked into the kernel. > > Sorry I missed this earlier, it fell into my spam box for some reason. > I've recently heard that gmail seems to move my mails to a SPAM folder (too). As I don't know why, I can't help with that and I have to live with the fact that I seem to get censored by Google (if it isn't a problem of my mail setup, but I'm not aware of such). Anyway, I'm sure some people like that I'm silenced this way. ;) > > Like Andrew, I think this feels particularly hacky. > > Why exactly is late_init too early? (I'm unfamiliar with the > rtc-hid-sensor-time driver) Currently it can be an USB device (and maybe Bluetooth or even i2c in the future, depends on hid-sensor-hub). That has some implications: (1) Initialization might need longer (or happens later) than late_init, even if everything is linked into the kernel (same problem as with a boot from USB-storage) (2) It might not even be available at boot, but it should work if a user plugs it in afterwards. (3) To accomplish (2) it should set the system time (by default) IFF nothing else did set the time. That "nothing else" in (3) is for security reasons, because no plugable HID device should be able to change the system time by default. The check if something else did set the system time can't be accomplished only by the RTC subsystem because userspace, network or whatever else is able to set the system time most likely doesn't use the RTC subsystem (or hctosys). E.g. one of those setups could be: boot hctosys (fails because of no RTC) ntpdate/rdate/date < whatever load modules (rtc-hid-sensor-time) If we would use a flag in the hctosys module then rtc-hid-sensor-time would be able to change the time (in the setup above). Using a module option which is by default off doesn't help too. Users (or even distros) which would turn it on, might forget it and systems would be at risk if no HID clock will be found at boot (but later plugged in by some blackhat). A flag in the time subsystem itself would do the trick. Such a flag might help with the problem if the RTC subsystem or the persistent clock code did set the time too. You've mentioned in another thread that you had to solve such a problem, but I'm not aware how you did that. Implementation could be as easy as a bool "time_set_at_least_once" in the timer subsystem itself (e.g. in do_settimeofday() and whatever similiar is available). > > If this is a hotplug rtc device (why I'm guessing its not available at > late_init), would it not be better to leave the setting of time using > hwclock --hctosys via a udev rule or something? I want to set the time with millisecond precision (if the HID clock offers that), which currently isn't available through the RTC subsystem. But even if milliseconds would be available through /dev/rtcN, the problem if something else did set the time still would be the same, just that an udev-rule now would have that problem. Regards, Alexander Holler ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 3/4] rtc: rtc-hid-sensor-time: add option hctosys to set time at boot 2013-05-21 23:15 ` Alexander Holler @ 2013-05-28 19:37 ` John Stultz 2013-05-29 4:42 ` Alexander Holler 0 siblings, 1 reply; 78+ messages in thread From: John Stultz @ 2013-05-28 19:37 UTC (permalink / raw) To: Alexander Holler Cc: linux-kernel, rtc-linux, Andrew Morton, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina On 05/21/2013 04:15 PM, Alexander Holler wrote: > Am 22.05.2013 00:02, schrieb John Stultz: > >> >> Like Andrew, I think this feels particularly hacky. >> >> Why exactly is late_init too early? (I'm unfamiliar with the >> rtc-hid-sensor-time driver) > > Currently it can be an USB device (and maybe Bluetooth or even i2c in > the future, depends on hid-sensor-hub). That has some implications: > > (1) Initialization might need longer (or happens later) than > late_init, even if everything is linked into the kernel (same problem > as with a boot from USB-storage) > (2) It might not even be available at boot, but it should work if a > user plugs it in afterwards. > (3) To accomplish (2) it should set the system time (by default) IFF > nothing else did set the time. > > That "nothing else" in (3) is for security reasons, because no > plugable HID device should be able to change the system time by default. > > The check if something else did set the system time can't be > accomplished only by the RTC subsystem because userspace, network or > whatever else is able to set the system time most likely doesn't use > the RTC subsystem (or hctosys). > > E.g. one of those setups could be: > > boot > hctosys (fails because of no RTC) > ntpdate/rdate/date < whatever > load modules (rtc-hid-sensor-time) > > If we would use a flag in the hctosys module then rtc-hid-sensor-time > would be able to change the time (in the setup above). > > Using a module option which is by default off doesn't help too. Users > (or even distros) which would turn it on, might forget it and systems > would be at risk if no HID clock will be found at boot (but later > plugged in by some blackhat). > > A flag in the time subsystem itself would do the trick. Such a flag > might help with the problem if the RTC subsystem or the persistent > clock code did set the time too. You've mentioned in another thread > that you had to solve such a problem, but I'm not aware how you did that. > > Implementation could be as easy as a bool "time_set_at_least_once" in > the timer subsystem itself (e.g. in do_settimeofday() and whatever > similiar is available). If it were to be done this way, it would be good to have the RTC layer check when RTC devices are registered and call the internal hctosys functionality then (rather then just at late_init). Do you want to try to rework the patch in this way? I'm not totally sure I'd agree that it would be better over leaving it to userspace, but if we're going to go with an in-kernel policy for this, then it seems like a better approach then the current patch. > > > > > If this is a hotplug rtc device (why I'm guessing its not available at > > late_init), would it not be better to leave the setting of time using > > hwclock --hctosys via a udev rule or something? > > I want to set the time with millisecond precision (if the HID clock > offers that), which currently isn't available through the RTC subsystem. True. This is one area I'd like to see addressed at some point. A few RTC devices have sub-second granularity and we're not exposing it via the RTC subsystem to either kernel or userland consumers. > But even if milliseconds would be available through /dev/rtcN, the > problem if something else did set the time still would be the same, > just that an udev-rule now would have that problem. Though a udev hack to check if its 1970 would be fairly simple. And pushes the policy of setting or not setting clearly off to userland (which allows for less compile-time or boot option tweaks to manipulate). thanks -john ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 3/4] rtc: rtc-hid-sensor-time: add option hctosys to set time at boot 2013-05-28 19:37 ` John Stultz @ 2013-05-29 4:42 ` Alexander Holler 2013-06-04 13:41 ` Alexander Holler 0 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-05-29 4:42 UTC (permalink / raw) To: John Stultz Cc: linux-kernel, rtc-linux, Andrew Morton, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina Am 28.05.2013 21:37, schrieb John Stultz: > On 05/21/2013 04:15 PM, Alexander Holler wrote: >> Am 22.05.2013 00:02, schrieb John Stultz: >> >>> >>> Like Andrew, I think this feels particularly hacky. >>> >>> Why exactly is late_init too early? (I'm unfamiliar with the >>> rtc-hid-sensor-time driver) >> >> Currently it can be an USB device (and maybe Bluetooth or even i2c in >> the future, depends on hid-sensor-hub). That has some implications: >> >> (1) Initialization might need longer (or happens later) than >> late_init, even if everything is linked into the kernel (same problem >> as with a boot from USB-storage) >> (2) It might not even be available at boot, but it should work if a >> user plugs it in afterwards. >> (3) To accomplish (2) it should set the system time (by default) IFF >> nothing else did set the time. >> >> That "nothing else" in (3) is for security reasons, because no >> plugable HID device should be able to change the system time by default. >> >> The check if something else did set the system time can't be >> accomplished only by the RTC subsystem because userspace, network or >> whatever else is able to set the system time most likely doesn't use >> the RTC subsystem (or hctosys). >> >> E.g. one of those setups could be: >> >> boot >> hctosys (fails because of no RTC) >> ntpdate/rdate/date < whatever >> load modules (rtc-hid-sensor-time) >> >> If we would use a flag in the hctosys module then rtc-hid-sensor-time >> would be able to change the time (in the setup above). >> >> Using a module option which is by default off doesn't help too. Users >> (or even distros) which would turn it on, might forget it and systems >> would be at risk if no HID clock will be found at boot (but later >> plugged in by some blackhat). >> >> A flag in the time subsystem itself would do the trick. Such a flag >> might help with the problem if the RTC subsystem or the persistent >> clock code did set the time too. You've mentioned in another thread >> that you had to solve such a problem, but I'm not aware how you did that. >> >> Implementation could be as easy as a bool "time_set_at_least_once" in >> the timer subsystem itself (e.g. in do_settimeofday() and whatever >> similiar is available). > > If it were to be done this way, it would be good to have the RTC layer > check when RTC devices are registered and call the internal hctosys > functionality then (rather then just at late_init). Do you want to try > to rework the patch in this way? That sounds like what Andrew Morton wanted to trick me to do. ;) Of course, if the time subsystem would offer such a flag, it would be easy to get rid of the hctosys module/driver. The RTC subsystem just could check that flag and could set the system time whenever a (usually the first) RTC driver would register (and offers a valid time). In addition that would offer the possibility to add a kernel parameter which describes the driver/module (by name) which should be used to set the time. I never really liked that rtcN from hctosys, because it doesn't really specify the RTC but depends on the order drivers get loaded. And I still like the idea to have a timewait or clockwait kernel parameter which prevents booting until the system has a valid time. Booting without having a valid time, can have serious implications (see e.g. https://lkml.org/lkml/2013/5/2/260 for which I never got feedback). > I'm not totally sure I'd agree that it would be better over leaving it > to userspace, but if we're going to go with an in-kernel policy for > this, then it seems like a better approach then the current patch. The only way I see to do such in userspace would be with that hacky looking trick I'm using in this patch, because userspace can't reliable manage a flag "time_set_at_least_once". Regards, Alexander PS: I left out what happens on resume, because I just don't know how the kernel gets the time after a resume (and never looked at it). That might especially be tricky with a RTC which needs some time before it can offer the time itself (e.g. gps or radio) or is only available after some other subsystem like USB is available. ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 3/4] rtc: rtc-hid-sensor-time: add option hctosys to set time at boot 2013-05-29 4:42 ` Alexander Holler @ 2013-06-04 13:41 ` Alexander Holler 2013-06-05 17:15 ` [PATCH 0/3] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler 0 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-06-04 13:41 UTC (permalink / raw) To: John Stultz Cc: linux-kernel, rtc-linux, Andrew Morton, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina Am 29.05.2013 06:42, schrieb Alexander Holler: > Am 28.05.2013 21:37, schrieb John Stultz: >> On 05/21/2013 04:15 PM, Alexander Holler wrote: >>> Implementation could be as easy as a bool "time_set_at_least_once" in >>> the timer subsystem itself (e.g. in do_settimeofday() and whatever >>> similiar is available). >> >> If it were to be done this way, it would be good to have the RTC layer >> check when RTC devices are registered and call the internal hctosys >> functionality then (rather then just at late_init). Do you want to try >> to rework the patch in this way? > > That sounds like what Andrew Morton wanted to trick me to do. ;) Just in case that was misunderstood. Of course, I would rework the patch if we reach a consensus about how I can do that. I would also volunteer and would remove hctosys and replace it by a better approach (imho) which sets the system time when a rtc registers. That doesn't look like much work. I've just did a small test and I think the mentioned flag could be implemented by the patch below (pasted => wrong format). I don't think stuff like atomic_*, a spinlock, mutex or similiar is necessary to make sure that the system time will only be set by one rtc, because I think it is extremly unlikely that more than one rtc will register at the same time to make such necessary. That means I think it's ok to just use "if (!systime_was_set) do_settimeofday()" in the rtc subsystem afterwards. I would also implement a kernel parameter like systime_from which could not be set (== use the first clock which offers a valid time) or could be set to "persistent" or the name of a RTC module in which case either the persistent clock or the named RTC would be used to set the time, if and only if the system time wasn't be set by something else (most likely userspace). Regards, Alexander Holler diff --git a/include/linux/time.h b/include/linux/time.h index afcdc4b..9c488f3 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -129,6 +129,12 @@ extern int update_persistent_clock(struct timespec now); void timekeeping_init(void); extern int timekeeping_suspended; +/* + * Will be true if the system time was set at least once by + * a persistent clock, RTC or userspace. + */ +extern bool systime_was_set; + unsigned long get_seconds(void); struct timespec current_kernel_time(void); struct timespec __current_kernel_time(void); /* does not take xtime_lock */ diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 9a0bc98..442e03c 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -32,6 +32,9 @@ int __read_mostly timekeeping_suspended; /* Flag for if there is a persistent clock on this platform */ bool __read_mostly persistent_clock_exist = false; +/* Flag for if the system time was set at least once */ +bool __read_mostly systime_was_set = false; + static inline void tk_normalize_xtime(struct timekeeper *tk) { while (tk->xtime_nsec >= ((u64)NSEC_PER_SEC << tk->shift)) { @@ -448,6 +451,10 @@ int do_settimeofday(const struct timespec *tv) if (!timespec_valid_strict(tv)) return -EINVAL; + systime_was_set = true; + write_seqlock_irqsave(&tk->lock, flags); timekeeping_forward_now(tk); @@ -682,8 +689,11 @@ void __init timekeeping_init(void) " Check your CMOS/BIOS settings.\n"); now.tv_sec = 0; now.tv_nsec = 0; - } else if (now.tv_sec || now.tv_nsec) + } else if (now.tv_sec || now.tv_nsec) { persistent_clock_exist = true; + systime_was_set = true; + } read_boot_clock(&boot); if (!timespec_valid_strict(&boot)) { ^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 0/3] RFC: timekeeping: rtc: change hctosys mechanism 2013-06-04 13:41 ` Alexander Holler @ 2013-06-05 17:15 ` Alexander Holler 2013-06-05 17:15 ` [PATCH 1/3] RFC: timekeeping: introduce flag systime_was_set Alexander Holler ` (3 more replies) 0 siblings, 4 replies; 78+ messages in thread From: Alexander Holler @ 2013-06-05 17:15 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, John Stultz, Thomas Gleixner, Alessandro Zummo, rtc-linux Hello, because it wasn't that much work, I've already rewritten the hctosys mechanism without discussing the changes further before. So the following patches are RFC (and incomplete but imho perfectly, usable) see below under missing) and I hope they will find friends and at least one reviewer which doesn't had a bad day. To describe the changes, I first quote what I've added to Documentation/kernel-parameters.txt: hctosys= [KNL] Specifies the driver (RTC) name which sets the time at boot, if and only if userspace hasn't set the time before the driver will be loaded. If hctosys will not be specified, the first available hardware clock with a valid time will be used. Use a non-existent name (e.g. hctosys=none) if you want to avoid that a hardware clock will set the time. Currently there exist a special name "persistent" for the persistent clock found on some systems (e.g. the CMOS clock on x86 platforms which might be handled by the driver named rtc_cmos too). What the patches do change: - Default functionality: hopefully nothing changes. The only user visible change is that /proc/dev/rtc doesn't appear on systems on which a "persistent" clock still is used. But I think this is logically more correct, than what currently happens: /proc/dev/rtc outputs data from an RTC which doesn't have to be what is really used (persistent clock). Therefor /proc/dev/rtc now only appears, if a RTC-driver is used for hctosys and not if a "persistent" clock is used. Unfortunately the later is still true on most systems (at least for x86*). - CONFIG_RTC_HCTOSYS is gone. On systems with a "persistent" clock, CONFIG_RTC_HCTOSYS was meaningless, because those systems always used the "persistent" clock and so already ignored CONFIG_RTC_HCTOSYS. Now this functionality is always on, if a hardware clock ("persistent" clock or RTC-driver) is used for hctosys. - CONFIG_RTC_HCTOSYS_DEVICE is gone. This config option never really specified which RTC is used, it only specified which RTC is used in kind of the order of their appearance to the system. With the new kernel-parameter hctosys= it is now at least possible to specify the type of the used RTC. Of course, if more RTCs of the same type (same driver) are available, the first of them will be used. - The hctosys functionality works even when userspace alreads has started. Without these changes, hctosys was invoked either at initialization of the timekeeping system (for "persistent" clock) or at late_init, both happens before userspace is started. To avoid problems with that change there is now an additional rule: Userspace comes first. If the userspace sets the system clock before any hardware clock was available, the hardware clock will not change the system clock. The last point above is also the reason why I did those changes at all (to support USB RTCs). What's missing: I don't know much about those "persistent" clocks and I haven't had a deep look at them. That's especially true for the suspend/resume mechanism used by them. The mechanism I want to use is the following: The RTC subsystem now maintains the ID of the RTC device which was used for hctosys (in rtc_hctosys_dev_id) and therefor specifies the device which should be used to adjust the time after resume. Additionaly the (new) flag systime_was_set will be set to false at suspend and on resume this flag will be set to true if either the clock will be adjusted by the device used for hctosys or by userspace (through do_settimeofday()). That all should already work as expected for RTCs, what's missing for "persistent" clocks is that the flag systime_was_set is set to false on suspend and set to true on resume. Currently it just stays at true (which is set through hctosys if a "persistent" clock is found. But because "persistent" clocks don't go away (as it is possible with RTCs by removing the driver or the RTC itself), nor do "persistent" clocks might have two instances, this shouldn't be a problem at all. And last but not least, I have to add a disclaimer: This changes aren't company driven. That means until now I was the only person who has seen, reviewed and tested them and I spend only a limited amount of (my spare) time for that. I did (quick) tests with x86 and ARM systems, with and without RTCs, with and without "persistent" clocks. I also tested suspend/resume on x86. But in any case, don't expect I didn't make failures. I did those changes in my "private" mode and not in my "professional" mode, which makes a difference (at least in the amount of time I spend for review and testing). But don't be scared, even my "private" mode might spend more time for QA than many companies (are able and willing to) do. ;) Regards, Alexander Holler PS: Parts of the above documentation might be added to one of the following patches to document them better in git too. I've written the above documentation after I've done the patches and will wait for feedback before I change them again. I've already done more than I initially wanted to do. PPS: The new hctosys mechanism provides an additional feature some people might like: HA for RTCs. If a system has two hardware clocks and one of them will fail such that it provides an invalid time (in regard to rtc_valid_tm()), the second one will be used. ^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 1/3] RFC: timekeeping: introduce flag systime_was_set 2013-06-05 17:15 ` [PATCH 0/3] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler @ 2013-06-05 17:15 ` Alexander Holler 2013-06-05 17:15 ` [PATCH 2/3] RFC: timekeeping: rtc: Introduce new kernel parameter hctosys Alexander Holler ` (2 subsequent siblings) 3 siblings, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-06-05 17:15 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, John Stultz, Thomas Gleixner, Alessandro Zummo, rtc-linux, Alexander Holler In order to let an RTC set the time at boot without the problem that a second RTC overwrites it, the flag systime_was_set is introduced. systime_was_set will be true, if a persistent clock sets the time at boot, or if do_settimeofday() is called (e.g. by the RTC subsystem or userspace). Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- include/linux/time.h | 6 ++++++ kernel/time/timekeeping.c | 10 +++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/linux/time.h b/include/linux/time.h index d5d229b..888280f 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -129,6 +129,12 @@ extern int update_persistent_clock(struct timespec now); void timekeeping_init(void); extern int timekeeping_suspended; +/* + * Will be true if the system time was set at least once by + * a persistent clock, RTC or userspace. + */ +extern bool systime_was_set; + unsigned long get_seconds(void); struct timespec current_kernel_time(void); struct timespec __current_kernel_time(void); /* does not take xtime_lock */ diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 98cd470..07f151f 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -37,6 +37,9 @@ int __read_mostly timekeeping_suspended; /* Flag for if there is a persistent clock on this platform */ bool __read_mostly persistent_clock_exist = false; +/* Flag for if the system time was set at least once */ +bool __read_mostly systime_was_set; + static inline void tk_normalize_xtime(struct timekeeper *tk) { while (tk->xtime_nsec >= ((u64)NSEC_PER_SEC << tk->shift)) { @@ -498,6 +501,9 @@ int do_settimeofday(const struct timespec *tv) raw_spin_lock_irqsave(&timekeeper_lock, flags); write_seqcount_begin(&timekeeper_seq); + systime_was_set = true; + + timekeeping_forward_now(tk); xt = tk_xtime(tk); @@ -781,8 +787,10 @@ void __init timekeeping_init(void) " Check your CMOS/BIOS settings.\n"); now.tv_sec = 0; now.tv_nsec = 0; - } else if (now.tv_sec || now.tv_nsec) + } else if (now.tv_sec || now.tv_nsec) { persistent_clock_exist = true; + systime_was_set = true; + } read_boot_clock(&boot); if (!timespec_valid_strict(&boot)) { -- 1.8.1.5 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 2/3] RFC: timekeeping: rtc: Introduce new kernel parameter hctosys 2013-06-05 17:15 ` [PATCH 0/3] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler 2013-06-05 17:15 ` [PATCH 1/3] RFC: timekeeping: introduce flag systime_was_set Alexander Holler @ 2013-06-05 17:15 ` Alexander Holler 2013-06-05 17:15 ` [PATCH 3/3] RFC: timekeeping: rtc: remove CONFIG_RTC_HCTOSYS and RTC_HCTOSYS_DEVICE Alexander Holler 2013-06-06 10:51 ` [PATCH 0/3 v2] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler 3 siblings, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-06-05 17:15 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, John Stultz, Thomas Gleixner, Alessandro Zummo, rtc-linux, Alexander Holler hctosys= specifies the driver (RTC) name which sets the system clock at boot, if and only if userspace hasn't set the time before the driver will be loaded. If hctosys will not be specified, the first available hardware clock with a valid time will be used (again, if and only if ...). If you don't want that the system clock will be set by any hardware clock, just specify a non-existent RTC driver name, e.g. with hctosys=none. Currently there exist a special name "persistent" for the persistent clock found on some systems (e.g. the CMOS clock on x86 platforms which might be handled by the driver named rtc_cmos too). This will replace the existent driver/mechanism hctosys and the kernel config options CONFIG_RTC_HCTOSYS and CONFIG_RTC_HCTOSYS_DEVICE (done with one of the following patches) Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- Documentation/kernel-parameters.txt | 12 ++++++++++++ drivers/rtc/class.c | 32 ++++++++++++++++++++++++++++++++ include/linux/time.h | 6 ++++++ kernel/time/timekeeping.c | 31 ++++++++++++++++++++++++++++++- 4 files changed, 80 insertions(+), 1 deletion(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 6e3b18a..a8b7a9c 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -983,6 +983,18 @@ bytes respectively. Such letter suffixes can also be entirely omitted. hcl= [IA-64] SGI's Hardware Graph compatibility layer + hctosys= [KNL] Specifies the driver (RTC) name which sets the + time at boot, if and only if userspace hasn't set the + time before the driver will be loaded. If hctosys will + not be specified, the first available hardware clock + with a valid time will be used. + Use a non-existent name (e.g. hctosys=none) if you want + to avoid that a hardware clock will set the time. + Currently there exist a special name "persistent" for + the persistent clock found on some systems (e.g. the + CMOS clock on x86 platforms which might be handled + by the driver named rtc_cmos too). + hd= [EIDE] (E)IDE hard drive subsystem geometry Format: <cyl>,<head>,<sect> diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 6638540..841d4e9 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -141,6 +141,33 @@ static int rtc_resume(struct device *dev) #endif +static void hctosys(struct rtc_device *rtc) +{ + struct rtc_time now; + struct timespec tv = { + .tv_nsec = NSEC_PER_SEC >> 1, + }; + int err; + + err = rtc_read_time(rtc, &now); + if (err) + return; + err = rtc_valid_tm(&now); + if (err) + return; + rtc_tm_to_time(&now, &tv.tv_sec); + if (systime_was_set) + return; + err = do_settimeofday(&tv); + if (!err && systime_was_set) + dev_info(rtc->dev.parent, + "setting system clock to " + "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", + now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, + now.tm_hour, now.tm_min, now.tm_sec, + (unsigned int) tv.tv_sec); +} + /** * rtc_device_register - register w/ RTC class * @dev: the device to register @@ -157,6 +184,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, struct rtc_device *rtc; struct rtc_wkalrm alrm; int id, err; + const char *hctosys_name = get_hctosys_name(); id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL); if (id < 0) { @@ -196,6 +224,10 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, rtc->pie_timer.function = rtc_pie_update_irq; rtc->pie_enabled = 0; + if (!systime_was_set && + (!hctosys_name[0] || !strcasecmp(name, hctosys_name))) + hctosys(rtc); + /* Check to see if there is an ALARM already set in hw */ err = __rtc_read_alarm(rtc, &alrm); diff --git a/include/linux/time.h b/include/linux/time.h index 888280f..e5f644c 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -135,6 +135,12 @@ extern int timekeeping_suspended; */ extern bool systime_was_set; +/* + * Returns a pointer to the string specified with + * hctosys= at the kernel command line. + */ +const char *get_hctosys_name(void); + unsigned long get_seconds(void); struct timespec current_kernel_time(void); struct timespec __current_kernel_time(void); /* does not take xtime_lock */ diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 07f151f..1de734c 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -22,6 +22,7 @@ #include <linux/tick.h> #include <linux/stop_machine.h> #include <linux/pvclock_gtod.h> +#include <linux/rtc.h> #include "tick-internal.h" #include "ntp_internal.h" @@ -40,6 +41,22 @@ bool __read_mostly persistent_clock_exist = false; /* Flag for if the system time was set at least once */ bool __read_mostly systime_was_set; +static char hctosys_name[RTC_DEVICE_NAME_SIZE]; + +static int __init hctosys_setup(char *line) +{ + strlcpy(hctosys_name, line, sizeof(hctosys_name)); + return 1; +} + +__setup("hctosys=", hctosys_setup); + +const char *get_hctosys_name(void) +{ + return hctosys_name; +} +EXPORT_SYMBOL_GPL(get_hctosys_name); + static inline void tk_normalize_xtime(struct timekeeper *tk) { while (tk->xtime_nsec >= ((u64)NSEC_PER_SEC << tk->shift)) { @@ -780,7 +797,8 @@ void __init timekeeping_init(void) unsigned long flags; struct timespec now, boot, tmp; - read_persistent_clock(&now); + if (!hctosys_name[0] || !strcasecmp(hctosys_name, "persistent")) + read_persistent_clock(&now); if (!timespec_valid_strict(&now)) { pr_warn("WARNING: Persistent clock returned invalid value!\n" @@ -826,6 +844,17 @@ void __init timekeeping_init(void) write_seqcount_end(&timekeeper_seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); + + if (systime_was_set) { + /* print a msg like if the time was set by a RTC */ + struct tm now_tm; + time_to_tm(now.tv_sec, 0, &now_tm); + pr_info("persistent clock: setting system clock to " + "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", + (int)now_tm.tm_year + 1900, now_tm.tm_mon + 1, + now_tm.tm_mday, now_tm.tm_hour, now_tm.tm_min, + now_tm.tm_sec, (unsigned int) now.tv_sec); + } } /* time in seconds when suspend began */ -- 1.8.1.5 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 3/3] RFC: timekeeping: rtc: remove CONFIG_RTC_HCTOSYS and RTC_HCTOSYS_DEVICE 2013-06-05 17:15 ` [PATCH 0/3] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler 2013-06-05 17:15 ` [PATCH 1/3] RFC: timekeeping: introduce flag systime_was_set Alexander Holler 2013-06-05 17:15 ` [PATCH 2/3] RFC: timekeeping: rtc: Introduce new kernel parameter hctosys Alexander Holler @ 2013-06-05 17:15 ` Alexander Holler 2013-06-06 10:51 ` [PATCH 0/3 v2] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler 3 siblings, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-06-05 17:15 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, John Stultz, Thomas Gleixner, Alessandro Zummo, rtc-linux, Alexander Holler Those config options don't make sense anymore with the new hctosys mechanism introduced with the previous patch. That means two things: - If a (hardware) clock is available it will be used to set the time at boot. This was already the case for system which have a "persistent" clock, e.g. most x86 systems. The only way to specify the device used for hctosys is now by using the kernel parameter hctosys= introduced with a previous patch. - If a hardware clock was used for hctosys before suspend, this clock will be used to adjust the clock at resume. Again, this doesn't change anything on systems with a "persistent" clock. What's missing: I don't know much about those "persistent" clocks and I haven't had a deep look at them. That's especially true for the suspend/resume mechanism used by them. The mechanism I want to use is the following: The RTC subsystem now maintains the ID of the RTC device which was used for hctosys (in rtc_hctosys_dev_id) and therefor specifies the device which should be used to adjust the time after resume. Additionaly the (new) flag systime_was_set will be set to false at suspend and on resume this flag will be set to true if either the clock will be adjusted by the device used for hctosys or by userspace (through do_settimeofday()). That all should already work as expected for RTCs, what's missing for "persistent" clocks is that the flag systime_was_set is set to false on suspend and set to true on resume. Currently it just stays at true (which is set through hctosys if a "persistent" clock is found. But because "persistent" clocks don't go away (as it is possible with RTCs by removing the driver or the RTC itself), nor do "persistent" clocks might have two instances, this shouldn't be a problem at all. Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- Documentation/rtc.txt | 8 +++--- drivers/rtc/Kconfig | 35 ++--------------------- drivers/rtc/Makefile | 1 - drivers/rtc/class.c | 30 ++++++++++++------- drivers/rtc/hctosys.c | 76 ------------------------------------------------- drivers/rtc/rtc-proc.c | 25 ++-------------- drivers/rtc/rtc-sysfs.c | 6 +--- drivers/rtc/systohc.c | 5 +++- include/linux/rtc.h | 7 ++--- 9 files changed, 34 insertions(+), 159 deletions(-) delete mode 100644 drivers/rtc/hctosys.c diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt index 32aa400..a1abfd8 100644 --- a/Documentation/rtc.txt +++ b/Documentation/rtc.txt @@ -121,8 +121,9 @@ three different userspace interfaces: * /proc/driver/rtc ... the system clock RTC may expose itself using a procfs interface. If there is no RTC for the system clock, - rtc0 is used by default. More information is (currently) shown - here than through sysfs. + or a "persistent" clock is used to set the system clock, + /proc/driver/rtc will not exist. + More information is (currently) shown here than through sysfs. The RTC Class framework supports a wide variety of RTCs, ranging from those integrated into embeddable system-on-chip (SOC) processors to discrete chips @@ -144,8 +145,7 @@ rtc attributes without requiring the use of ioctls. All dates and times are in the RTC's timezone, rather than in system time. date: RTC-provided date -hctosys: 1 if the RTC provided the system time at boot via the - CONFIG_RTC_HCTOSYS kernel option, 0 otherwise +hctosys: 1 if the RTC provided the system time at boot, 0 otherwise max_user_freq: The maximum interrupt rate an unprivileged user may request from this RTC. name: The name of the RTC corresponding to this sysfs directory diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index b983813..b1d6691 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -17,44 +17,13 @@ menuconfig RTC_CLASS if RTC_CLASS -config RTC_HCTOSYS - bool "Set system time from RTC on startup and resume" - default y - help - If you say yes here, the system time (wall clock) will be set using - the value read from a specified RTC device. This is useful to avoid - unnecessary fsck runs at boot time, and to network better. - config RTC_SYSTOHC bool "Set the RTC time based on NTP synchronization" default y help If you say yes here, the system time (wall clock) will be stored - in the RTC specified by RTC_HCTOSYS_DEVICE approximately every 11 - minutes if userspace reports synchronized NTP status. - -config RTC_HCTOSYS_DEVICE - string "RTC used to set the system time" - depends on RTC_HCTOSYS = y || RTC_SYSTOHC = y - default "rtc0" - help - The RTC device that will be used to (re)initialize the system - clock, usually rtc0. Initialization is done when the system - starts up, and when it resumes from a low power state. This - device should record time in UTC, since the kernel won't do - timezone correction. - - The driver for this RTC device must be loaded before late_initcall - functions run, so it must usually be statically linked. - - This clock should be battery-backed, so that it reads the correct - time when the system boots from a power-off state. Otherwise, your - system will need an external clock source (like an NTP server). - - If the clock you specify here is not battery backed, it may still - be useful to reinitialize system time when resuming from system - sleep states. Do not specify an RTC here unless it stays powered - during all this system's supported sleep states. + in the RTC used to set the time at boot or resume approximately + every 11 minutes if userspace reports synchronized NTP status. config RTC_DEBUG bool "RTC debug support" diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index c33f86f..b699504 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -5,7 +5,6 @@ ccflags-$(CONFIG_RTC_DEBUG) := -DDEBUG obj-$(CONFIG_RTC_LIB) += rtc-lib.o -obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o obj-$(CONFIG_RTC_SYSTOHC) += systohc.o obj-$(CONFIG_RTC_CLASS) += rtc-core.o rtc-core-y := class.o interface.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 841d4e9..8ec4a0b 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -26,6 +26,9 @@ static DEFINE_IDA(rtc_ida); struct class *rtc_class; +/* The ID of the RTC device used to set the system clock */ +int __read_mostly rtc_hctosys_dev_id = -1; + static void rtc_device_release(struct device *dev) { struct rtc_device *rtc = to_rtc_device(dev); @@ -33,12 +36,7 @@ static void rtc_device_release(struct device *dev) kfree(rtc); } -#ifdef CONFIG_RTC_HCTOSYS_DEVICE -/* Result of the last RTC to system clock attempt. */ -int rtc_hctosys_ret = -ENODEV; -#endif - -#if defined(CONFIG_PM) && defined(CONFIG_RTC_HCTOSYS_DEVICE) +#if defined(CONFIG_PM) /* * On suspend(), measure the delta between one RTC and the * system's wall clock; restore it on resume(). @@ -53,12 +51,18 @@ static int rtc_suspend(struct device *dev, pm_message_t mesg) struct rtc_time tm; struct timespec delta, delta_delta; + + if (!systime_was_set) + return 0; + if (has_persistent_clock()) return 0; - if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) + if (rtc->id != rtc_hctosys_dev_id) return 0; + systime_was_set = false; + /* snapshot the current RTC and system time at suspend*/ rtc_read_time(rtc, &tm); getnstimeofday(&old_system); @@ -94,11 +98,13 @@ static int rtc_resume(struct device *dev) struct timespec new_system, new_rtc; struct timespec sleep_time; + if (systime_was_set) + return 0; + if (has_persistent_clock()) return 0; - rtc_hctosys_ret = -ENODEV; - if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) + if (rtc->id != rtc_hctosys_dev_id) return 0; /* snapshot the current rtc and system time at resume */ @@ -131,7 +137,7 @@ static int rtc_resume(struct device *dev) if (sleep_time.tv_sec >= 0) timekeeping_inject_sleeptime(&sleep_time); - rtc_hctosys_ret = 0; + systime_was_set = true; return 0; } @@ -159,13 +165,15 @@ static void hctosys(struct rtc_device *rtc) if (systime_was_set) return; err = do_settimeofday(&tv); - if (!err && systime_was_set) + if (!err && systime_was_set) { + rtc_hctosys_dev_id = rtc->id; dev_info(rtc->dev.parent, "setting system clock to " "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec, (unsigned int) tv.tv_sec); + } } /** diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c deleted file mode 100644 index 4aa60d7..0000000 --- a/drivers/rtc/hctosys.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * RTC subsystem, initialize system time on startup - * - * Copyright (C) 2005 Tower Technologies - * Author: Alessandro Zummo <a.zummo@towertech.it> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include <linux/rtc.h> - -/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary - * whether it stores the most close value or the value with partial - * seconds truncated. However, it is important that we use it to store - * the truncated value. This is because otherwise it is necessary, - * in an rtc sync function, to read both xtime.tv_sec and - * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read - * of >32bits is not possible. So storing the most close value would - * slow down the sync API. So here we have the truncated value and - * the best guess is to add 0.5s. - */ - -static int __init rtc_hctosys(void) -{ - int err = -ENODEV; - struct rtc_time tm; - struct timespec tv = { - .tv_nsec = NSEC_PER_SEC >> 1, - }; - struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); - - if (rtc == NULL) { - pr_err("%s: unable to open rtc device (%s)\n", - __FILE__, CONFIG_RTC_HCTOSYS_DEVICE); - goto err_open; - } - - err = rtc_read_time(rtc, &tm); - if (err) { - dev_err(rtc->dev.parent, - "hctosys: unable to read the hardware clock\n"); - goto err_read; - - } - - err = rtc_valid_tm(&tm); - if (err) { - dev_err(rtc->dev.parent, - "hctosys: invalid date/time\n"); - goto err_invalid; - } - - rtc_tm_to_time(&tm, &tv.tv_sec); - - err = do_settimeofday(&tv); - - dev_info(rtc->dev.parent, - "setting system clock to " - "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, - (unsigned int) tv.tv_sec); - -err_invalid: -err_read: - rtc_class_close(rtc); - -err_open: - rtc_hctosys_ret = err; - - return err; -} - -late_initcall(rtc_hctosys); diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c index ffa69e1..fd59c1b 100644 --- a/drivers/rtc/rtc-proc.c +++ b/drivers/rtc/rtc-proc.c @@ -18,27 +18,6 @@ #include "rtc-core.h" -#define NAME_SIZE 10 - -#if defined(CONFIG_RTC_HCTOSYS_DEVICE) -static bool is_rtc_hctosys(struct rtc_device *rtc) -{ - int size; - char name[NAME_SIZE]; - - size = scnprintf(name, NAME_SIZE, "rtc%d", rtc->id); - if (size > NAME_SIZE) - return false; - - return !strncmp(name, CONFIG_RTC_HCTOSYS_DEVICE, NAME_SIZE); -} -#else -static bool is_rtc_hctosys(struct rtc_device *rtc) -{ - return (rtc->id == 0); -} -#endif - static int rtc_proc_show(struct seq_file *seq, void *offset) { int err; @@ -137,12 +116,12 @@ static const struct file_operations rtc_proc_fops = { void rtc_proc_add_device(struct rtc_device *rtc) { - if (is_rtc_hctosys(rtc)) + if (rtc->id == rtc_hctosys_dev_id) proc_create_data("driver/rtc", 0, NULL, &rtc_proc_fops, rtc); } void rtc_proc_del_device(struct rtc_device *rtc) { - if (is_rtc_hctosys(rtc)) + if (rtc->id == rtc_hctosys_dev_id) remove_proc_entry("driver/rtc", NULL); } diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index b70e2bb..6b8a41b 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -112,13 +112,9 @@ static ssize_t rtc_sysfs_show_hctosys(struct device *dev, struct device_attribute *attr, char *buf) { -#ifdef CONFIG_RTC_HCTOSYS_DEVICE - if (rtc_hctosys_ret == 0 && - strcmp(dev_name(&to_rtc_device(dev)->dev), - CONFIG_RTC_HCTOSYS_DEVICE) == 0) + if (to_rtc_device(dev)->id == rtc_hctosys_dev_id) return sprintf(buf, "1\n"); else -#endif return sprintf(buf, "0\n"); } diff --git a/drivers/rtc/systohc.c b/drivers/rtc/systohc.c index bf3e242..1962f4c 100644 --- a/drivers/rtc/systohc.c +++ b/drivers/rtc/systohc.c @@ -25,13 +25,16 @@ int rtc_set_ntp_time(struct timespec now) struct rtc_device *rtc; struct rtc_time tm; int err = -ENODEV; + char rtc_hctosys_name[10]; if (now.tv_nsec < (NSEC_PER_SEC >> 1)) rtc_time_to_tm(now.tv_sec, &tm); else rtc_time_to_tm(now.tv_sec + 1, &tm); - rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); + scnprintf(rtc_hctosys_name, sizeof(rtc_hctosys_name), "rtc%d", + rtc_hctosys_dev_id); + rtc = rtc_class_open(rtc_hctosys_name); if (rtc) { /* rtc_hctosys exclusively uses UTC, so we call set_time here, * not set_mmss. */ diff --git a/include/linux/rtc.h b/include/linux/rtc.h index c2c2897..50caf0d 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -191,10 +191,7 @@ static inline bool is_leap_year(unsigned int year) return (!(year % 4) && (year % 100)) || !(year % 400); } -#ifdef CONFIG_RTC_HCTOSYS_DEVICE -extern int rtc_hctosys_ret; -#else -#define rtc_hctosys_ret -ENODEV -#endif +/* The ID of the RTC device used to set the system clock */ +extern int rtc_hctosys_dev_id; #endif /* _LINUX_RTC_H_ */ -- 1.8.1.5 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 0/3 v2] RFC: timekeeping: rtc: change hctosys mechanism 2013-06-05 17:15 ` [PATCH 0/3] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler ` (2 preceding siblings ...) 2013-06-05 17:15 ` [PATCH 3/3] RFC: timekeeping: rtc: remove CONFIG_RTC_HCTOSYS and RTC_HCTOSYS_DEVICE Alexander Holler @ 2013-06-06 10:51 ` Alexander Holler 2013-06-06 10:51 ` [PATCH 1/3 RESEND] RFC: timekeeping: introduce flag systime_was_set Alexander Holler ` (2 more replies) 3 siblings, 3 replies; 78+ messages in thread From: Alexander Holler @ 2013-06-06 10:51 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, John Stultz, Thomas Gleixner, Alessandro Zummo, rtc-linux As already assumed, there are was at least one silly failure I made, a wrong warning if the persistent was disabled by purpose which I seem to have missed while looking at the output during my tests: WARNING: Persistent clock returned invalid value! I've fixed that in patch 2/3 and also have added some error messages to indicate why reading the time from a misfunctional RTC fails to the same patch. Because patch 3/3 didn't apply afterwards, I've solved the conflict and resend it too. And to keep the small series together, I resend patch 1/3 too. So no changes in functionality, just some "cosmetic" changes in patch 2/3. Regards, Alexander Holler ^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 1/3 RESEND] RFC: timekeeping: introduce flag systime_was_set 2013-06-06 10:51 ` [PATCH 0/3 v2] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler @ 2013-06-06 10:51 ` Alexander Holler 2013-06-06 10:51 ` [PATCH 2/3 v2] RFC: timekeeping: rtc: Introduce new kernel parameter hctosys Alexander Holler 2013-06-06 10:51 ` [PATCH 3/3 v2] RFC: timekeeping: rtc: remove CONFIG_RTC_HCTOSYS and RTC_HCTOSYS_DEVICE Alexander Holler 2 siblings, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-06-06 10:51 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, John Stultz, Thomas Gleixner, Alessandro Zummo, rtc-linux, Alexander Holler In order to let an RTC set the time at boot without the problem that a second RTC overwrites it, the flag systime_was_set is introduced. systime_was_set will be true, if a persistent clock sets the time at boot, or if do_settimeofday() is called (e.g. by the RTC subsystem or userspace). Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- include/linux/time.h | 6 ++++++ kernel/time/timekeeping.c | 10 +++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/linux/time.h b/include/linux/time.h index d5d229b..888280f 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -129,6 +129,12 @@ extern int update_persistent_clock(struct timespec now); void timekeeping_init(void); extern int timekeeping_suspended; +/* + * Will be true if the system time was set at least once by + * a persistent clock, RTC or userspace. + */ +extern bool systime_was_set; + unsigned long get_seconds(void); struct timespec current_kernel_time(void); struct timespec __current_kernel_time(void); /* does not take xtime_lock */ diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 98cd470..07f151f 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -37,6 +37,9 @@ int __read_mostly timekeeping_suspended; /* Flag for if there is a persistent clock on this platform */ bool __read_mostly persistent_clock_exist = false; +/* Flag for if the system time was set at least once */ +bool __read_mostly systime_was_set; + static inline void tk_normalize_xtime(struct timekeeper *tk) { while (tk->xtime_nsec >= ((u64)NSEC_PER_SEC << tk->shift)) { @@ -498,6 +501,9 @@ int do_settimeofday(const struct timespec *tv) raw_spin_lock_irqsave(&timekeeper_lock, flags); write_seqcount_begin(&timekeeper_seq); + systime_was_set = true; + + timekeeping_forward_now(tk); xt = tk_xtime(tk); @@ -781,8 +787,10 @@ void __init timekeeping_init(void) " Check your CMOS/BIOS settings.\n"); now.tv_sec = 0; now.tv_nsec = 0; - } else if (now.tv_sec || now.tv_nsec) + } else if (now.tv_sec || now.tv_nsec) { persistent_clock_exist = true; + systime_was_set = true; + } read_boot_clock(&boot); if (!timespec_valid_strict(&boot)) { -- 1.8.1.5 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 2/3 v2] RFC: timekeeping: rtc: Introduce new kernel parameter hctosys 2013-06-06 10:51 ` [PATCH 0/3 v2] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler 2013-06-06 10:51 ` [PATCH 1/3 RESEND] RFC: timekeeping: introduce flag systime_was_set Alexander Holler @ 2013-06-06 10:51 ` Alexander Holler 2013-06-13 19:39 ` Alexander Holler 2013-06-06 10:51 ` [PATCH 3/3 v2] RFC: timekeeping: rtc: remove CONFIG_RTC_HCTOSYS and RTC_HCTOSYS_DEVICE Alexander Holler 2 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-06-06 10:51 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, John Stultz, Thomas Gleixner, Alessandro Zummo, rtc-linux, Alexander Holler hctosys= specifies the driver (RTC) name which sets the system clock at boot, if and only if userspace hasn't set the time before the driver will be loaded. If hctosys will not be specified, the first available hardware clock with a valid time will be used (again, if and only if ...). If you don't want that the system clock will be set by any hardware clock, just specify a non-existent RTC driver name, e.g. with hctosys=none. Currently there exist a special name "persistent" for the persistent clock found on some systems (e.g. the CMOS clock on x86 platforms which might be handled by the driver named rtc_cmos too). This will replace the existent driver/mechanism hctosys and the kernel config options CONFIG_RTC_HCTOSYS and CONFIG_RTC_HCTOSYS_DEVICE (done with one of the following patches) Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- Documentation/kernel-parameters.txt | 12 +++++++++ drivers/rtc/class.c | 39 +++++++++++++++++++++++++++++ include/linux/time.h | 6 +++++ kernel/time/timekeeping.c | 49 +++++++++++++++++++++++++++++-------- 4 files changed, 96 insertions(+), 10 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 6e3b18a..a8b7a9c 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -983,6 +983,18 @@ bytes respectively. Such letter suffixes can also be entirely omitted. hcl= [IA-64] SGI's Hardware Graph compatibility layer + hctosys= [KNL] Specifies the driver (RTC) name which sets the + time at boot, if and only if userspace hasn't set the + time before the driver will be loaded. If hctosys will + not be specified, the first available hardware clock + with a valid time will be used. + Use a non-existent name (e.g. hctosys=none) if you want + to avoid that a hardware clock will set the time. + Currently there exist a special name "persistent" for + the persistent clock found on some systems (e.g. the + CMOS clock on x86 platforms which might be handled + by the driver named rtc_cmos too). + hd= [EIDE] (E)IDE hard drive subsystem geometry Format: <cyl>,<head>,<sect> diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 6638540..a159d1f 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -141,6 +141,40 @@ static int rtc_resume(struct device *dev) #endif +static void hctosys(struct rtc_device *rtc) +{ + struct rtc_time now; + struct timespec tv = { + .tv_nsec = NSEC_PER_SEC >> 1, + }; + int rc; + + rc = rtc_read_time(rtc, &now); + if (rc) { + dev_err(rtc->dev.parent, "rtc core: error reading time from RTC: %d\n", rc); + return; + } + rc = rtc_valid_tm(&now); + if (rc) { + dev_err(rtc->dev.parent, "rtc core: date/time from RTC is invalid\n"); + return; + } + rtc_tm_to_time(&now, &tv.tv_sec); + if (systime_was_set) + return; + rc = do_settimeofday(&tv); + if (rc) { + dev_err(rtc->dev.parent, "rtc core: error setting system clock: %d\n", rc); + return; + } else if (systime_was_set) + dev_info(rtc->dev.parent, + "setting system clock to " + "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", + now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, + now.tm_hour, now.tm_min, now.tm_sec, + (unsigned int) tv.tv_sec); +} + /** * rtc_device_register - register w/ RTC class * @dev: the device to register @@ -157,6 +191,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, struct rtc_device *rtc; struct rtc_wkalrm alrm; int id, err; + const char *hctosys_name = get_hctosys_name(); id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL); if (id < 0) { @@ -196,6 +231,10 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, rtc->pie_timer.function = rtc_pie_update_irq; rtc->pie_enabled = 0; + if (!systime_was_set && + (!hctosys_name[0] || !strcasecmp(name, hctosys_name))) + hctosys(rtc); + /* Check to see if there is an ALARM already set in hw */ err = __rtc_read_alarm(rtc, &alrm); diff --git a/include/linux/time.h b/include/linux/time.h index 888280f..e5f644c 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -135,6 +135,12 @@ extern int timekeeping_suspended; */ extern bool systime_was_set; +/* + * Returns a pointer to the string specified with + * hctosys= at the kernel command line. + */ +const char *get_hctosys_name(void); + unsigned long get_seconds(void); struct timespec current_kernel_time(void); struct timespec __current_kernel_time(void); /* does not take xtime_lock */ diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 07f151f..fdbe3ab 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -22,6 +22,7 @@ #include <linux/tick.h> #include <linux/stop_machine.h> #include <linux/pvclock_gtod.h> +#include <linux/rtc.h> #include "tick-internal.h" #include "ntp_internal.h" @@ -40,6 +41,22 @@ bool __read_mostly persistent_clock_exist = false; /* Flag for if the system time was set at least once */ bool __read_mostly systime_was_set; +static char hctosys_name[RTC_DEVICE_NAME_SIZE]; + +static int __init hctosys_setup(char *line) +{ + strlcpy(hctosys_name, line, sizeof(hctosys_name)); + return 1; +} + +__setup("hctosys=", hctosys_setup); + +const char *get_hctosys_name(void) +{ + return hctosys_name; +} +EXPORT_SYMBOL_GPL(get_hctosys_name); + static inline void tk_normalize_xtime(struct timekeeper *tk) { while (tk->xtime_nsec >= ((u64)NSEC_PER_SEC << tk->shift)) { @@ -780,16 +797,17 @@ void __init timekeeping_init(void) unsigned long flags; struct timespec now, boot, tmp; - read_persistent_clock(&now); - - if (!timespec_valid_strict(&now)) { - pr_warn("WARNING: Persistent clock returned invalid value!\n" - " Check your CMOS/BIOS settings.\n"); - now.tv_sec = 0; - now.tv_nsec = 0; - } else if (now.tv_sec || now.tv_nsec) { - persistent_clock_exist = true; - systime_was_set = true; + if (!hctosys_name[0] || !strcasecmp(hctosys_name, "persistent")) { + read_persistent_clock(&now); + if (!timespec_valid_strict(&now)) { + pr_warn("WARNING: Persistent clock returned invalid value!\n" + " Check your CMOS/BIOS settings.\n"); + now.tv_sec = 0; + now.tv_nsec = 0; + } else if (now.tv_sec || now.tv_nsec) { + persistent_clock_exist = true; + systime_was_set = true; + } } read_boot_clock(&boot); @@ -826,6 +844,17 @@ void __init timekeeping_init(void) write_seqcount_end(&timekeeper_seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); + + if (systime_was_set) { + /* print a msg like if the time was set by a RTC */ + struct tm now_tm; + time_to_tm(now.tv_sec, 0, &now_tm); + pr_info("persistent clock: setting system clock to " + "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", + (int)now_tm.tm_year + 1900, now_tm.tm_mon + 1, + now_tm.tm_mday, now_tm.tm_hour, now_tm.tm_min, + now_tm.tm_sec, (unsigned int) now.tv_sec); + } } /* time in seconds when suspend began */ -- 1.8.1.5 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* Re: [PATCH 2/3 v2] RFC: timekeeping: rtc: Introduce new kernel parameter hctosys 2013-06-06 10:51 ` [PATCH 2/3 v2] RFC: timekeeping: rtc: Introduce new kernel parameter hctosys Alexander Holler @ 2013-06-13 19:39 ` Alexander Holler 2013-06-14 16:52 ` [PATCH 0/9 v3] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler 0 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-06-13 19:39 UTC (permalink / raw) To: Alexander Holler Cc: linux-kernel, Andrew Morton, John Stultz, Thomas Gleixner, Alessandro Zummo, rtc-linux Am 06.06.2013 12:51, schrieb Alexander Holler: > hctosys= specifies the driver (RTC) name which sets the system clock at > boot, if and only if userspace hasn't set the time before the driver will > be loaded. > > If hctosys will not be specified, the first available hardware clock > with a valid time will be used (again, if and only if ...). > > If you don't want that the system clock will be set by any hardware clock, > just specify a non-existent RTC driver name, e.g. with hctosys=none. > > Currently there exist a special name "persistent" for the persistent clock > found on some systems (e.g. the CMOS clock on x86 platforms which might be > handled by the driver named rtc_cmos too). > > This will replace the existent driver/mechanism hctosys and the kernel > config options CONFIG_RTC_HCTOSYS and CONFIG_RTC_HCTOSYS_DEVICE (done > with one of the following patches) > > Signed-off-by: Alexander Holler <holler@ahsoftware.de> While implementing support for high resolution (read-only) clocks (e.g. radio or GPS) for the new hctosys, I've found another bug in my (quickly done) RFC hctosys implementation. Instead of posting the whole patch or the whole series again, here is the small diff which should be added to patch2/3: ---------- diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 49dd97c..e101468 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -795,7 +795,7 @@ void __init timekeeping_init(void) struct timekeeper *tk = &timekeeper; struct clocksource *clock; unsigned long flags; - struct timespec now, boot, tmp; + struct timespec now = {0, 0}, boot, tmp; if (!hctosys_name[0] || !strcasecmp(hctosys_name, "persistent")) { read_persistent_clock(&now); ---------- I now have 4 additional patches here: rtc: rtc-hid-sensor-time: delay registering as rtc into a work rtc: implement rtc_read_timeval() rtc: hctosys: support rtc_read_timeval() for high precision clocks rtc: rtc-hid-sensor-time: add support for rtc_read_timeval() The first oatch is necessary because registering a rtc wants to read the clock (for hctosys) and in case of the HID RTC this only works after the HID device is actually registered. Therefor registering should not happen in probe(). The other 3 new patches do add a read_timeval to rtc_ops and use it, if available, instead of read_time to retrieve and set the system clock with hctosys using a higher precision timestamp (us). I requested, I will post the whole series or the just the additional/fixed patches. Regards, Alexander Holler ^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 0/9 v3] RFC: timekeeping: rtc: change hctosys mechanism 2013-06-13 19:39 ` Alexander Holler @ 2013-06-14 16:52 ` Alexander Holler 2013-06-14 16:52 ` [PATCH 1/9 RESEND] rtc: rtc-hid-sensor-time: allow full years (16bit) in HID reports Alexander Holler ` (9 more replies) 0 siblings, 10 replies; 78+ messages in thread From: Alexander Holler @ 2013-06-14 16:52 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, John Stultz, rtc-linux, Thomas Gleixner, Alessandro Zummo Hello, Because I've become a request which made me slightly more optimistic about the RFC patches, I've spend some more time on the patches doing cosmetic. I know think the "quickly done" is gone and they might be ready for submission. The whole series consists more or less of 3 mini-series. The first two patches are already in -mm, the 3. should end there too. Then there are 3 patches to change the hctosys mechanism and another 3 patches to implement read_timeval for rtc_ops, together with an example implementation for read_timeval in rtc-hid-sensor-time. The introductory message of my first post of this series still describes all changes to hctosys, what the additional 3 patches with read_timeval are doing should be obvious. Regards, Alexander Holler BTW: rtc_device_unregister is broken in 3.10-rc5, most likely because of the switch to devm*. But I will start another thread for that as this is unrelated to this series of patches. ^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 1/9 RESEND] rtc: rtc-hid-sensor-time: allow full years (16bit) in HID reports 2013-06-14 16:52 ` [PATCH 0/9 v3] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler @ 2013-06-14 16:52 ` Alexander Holler 2013-06-14 16:52 ` [PATCH 2/9 RESEND] rtc: rtc-hid-sensor-time: allow 16 and 32 bit values for all attributes Alexander Holler ` (8 subsequent siblings) 9 siblings, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-06-14 16:52 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, John Stultz, rtc-linux, Thomas Gleixner, Alessandro Zummo, Alexander Holler The draft for HID-sensors (HUTRR39) currently doesn't define the range for the attribute year. Asking one of the authors revealed that full years (e.g. 2013 instead of just 13) were meant. So we now allow both, 8 bit and 16 bit values for the attribute year and assuming full years when the value is 16 bits wide. We will still support 8 bit values until the specification gets final (and maybe defines a way to set the time too). Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- drivers/rtc/rtc-hid-sensor-time.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index 6302450..b8c1b10 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -85,10 +85,13 @@ static int hid_time_capture_sample(struct hid_sensor_hub_device *hsdev, switch (usage_id) { case HID_USAGE_SENSOR_TIME_YEAR: - time_buf->tm_year = *(u8 *)raw_data; - if (time_buf->tm_year < 70) - /* assume we are in 1970...2069 */ - time_buf->tm_year += 100; + if (raw_len == 1) { + time_buf->tm_year = *(u8 *)raw_data; + if (time_buf->tm_year < 70) + /* assume we are in 1970...2069 */ + time_buf->tm_year += 100; + } else + time_buf->tm_year = *(u16 *)raw_data-1900; break; case HID_USAGE_SENSOR_TIME_MONTH: /* sensor sending the month as 1-12, we need 0-11 */ @@ -151,11 +154,27 @@ static int hid_time_parse_report(struct platform_device *pdev, return -EINVAL; } if (time_state->info[i].size != 1) { - dev_err(&pdev->dev, - "attribute '%s' not 8 bits wide!\n", + /* + * The draft for HID-sensors (HUTRR39) currently + * doesn't define the range for the year attribute. + * Therefor we support both 8 bit (0-99) and 16 bit + * (full) as size for the year. + */ + if (time_state->info[i].attrib_id != + HID_USAGE_SENSOR_TIME_YEAR) { + dev_err(&pdev->dev, + "attribute '%s' not 8 bits wide!\n", hid_time_attrib_name( time_state->info[i].attrib_id)); - return -EINVAL; + return -EINVAL; + } + if (time_state->info[i].size != 2) { + dev_err(&pdev->dev, + "attribute '%s' not 8 or 16 bits wide!\n", + hid_time_attrib_name( + time_state->info[i].attrib_id)); + return -EINVAL; + } } if (time_state->info[i].units != HID_USAGE_SENSOR_UNITS_NOT_SPECIFIED && -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 2/9 RESEND] rtc: rtc-hid-sensor-time: allow 16 and 32 bit values for all attributes. 2013-06-14 16:52 ` [PATCH 0/9 v3] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler 2013-06-14 16:52 ` [PATCH 1/9 RESEND] rtc: rtc-hid-sensor-time: allow full years (16bit) in HID reports Alexander Holler @ 2013-06-14 16:52 ` Alexander Holler 2013-06-14 16:52 ` [PATCH 3/9] rtc: rtc-hid-sensor-time: delay registering as rtc into a work Alexander Holler ` (7 subsequent siblings) 9 siblings, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-06-14 16:52 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, John Stultz, rtc-linux, Thomas Gleixner, Alessandro Zummo, Alexander Holler There is no real reason to not support 16 or 32 bit values too. Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- drivers/rtc/rtc-hid-sensor-time.c | 59 +++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index b8c1b10..7273b01 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -76,6 +76,20 @@ static int hid_time_proc_event(struct hid_sensor_hub_device *hsdev, return 0; } +static u32 hid_time_value(size_t raw_len, char *raw_data) +{ + switch (raw_len) { + case 1: + return *(u8 *)raw_data; + case 2: + return *(u16 *)raw_data; + case 4: + return *(u32 *)raw_data; + default: + return (u32)(~0U); /* 0xff... or -1 to denote an error */ + } +} + static int hid_time_capture_sample(struct hid_sensor_hub_device *hsdev, unsigned usage_id, size_t raw_len, char *raw_data, void *priv) @@ -85,29 +99,35 @@ static int hid_time_capture_sample(struct hid_sensor_hub_device *hsdev, switch (usage_id) { case HID_USAGE_SENSOR_TIME_YEAR: + /* + * The draft for HID-sensors (HUTRR39) currently doesn't define + * the range for the year attribute. Therefor we support + * 8 bit (0-99) and 16 or 32 bits (full) as size for the year. + */ if (raw_len == 1) { time_buf->tm_year = *(u8 *)raw_data; if (time_buf->tm_year < 70) /* assume we are in 1970...2069 */ time_buf->tm_year += 100; } else - time_buf->tm_year = *(u16 *)raw_data-1900; + time_buf->tm_year = + (int)hid_time_value(raw_len, raw_data)-1900; break; case HID_USAGE_SENSOR_TIME_MONTH: - /* sensor sending the month as 1-12, we need 0-11 */ - time_buf->tm_mon = *(u8 *)raw_data-1; + /* sensors are sending the month as 1-12, we need 0-11 */ + time_buf->tm_mon = (int)hid_time_value(raw_len, raw_data)-1; break; case HID_USAGE_SENSOR_TIME_DAY: - time_buf->tm_mday = *(u8 *)raw_data; + time_buf->tm_mday = (int)hid_time_value(raw_len, raw_data); break; case HID_USAGE_SENSOR_TIME_HOUR: - time_buf->tm_hour = *(u8 *)raw_data; + time_buf->tm_hour = (int)hid_time_value(raw_len, raw_data); break; case HID_USAGE_SENSOR_TIME_MINUTE: - time_buf->tm_min = *(u8 *)raw_data; + time_buf->tm_min = (int)hid_time_value(raw_len, raw_data); break; case HID_USAGE_SENSOR_TIME_SECOND: - time_buf->tm_sec = *(u8 *)raw_data; + time_buf->tm_sec = (int)hid_time_value(raw_len, raw_data); break; default: return -EINVAL; @@ -153,28 +173,13 @@ static int hid_time_parse_report(struct platform_device *pdev, "not all needed attributes inside the same report!\n"); return -EINVAL; } - if (time_state->info[i].size != 1) { - /* - * The draft for HID-sensors (HUTRR39) currently - * doesn't define the range for the year attribute. - * Therefor we support both 8 bit (0-99) and 16 bit - * (full) as size for the year. - */ - if (time_state->info[i].attrib_id != - HID_USAGE_SENSOR_TIME_YEAR) { - dev_err(&pdev->dev, - "attribute '%s' not 8 bits wide!\n", - hid_time_attrib_name( - time_state->info[i].attrib_id)); - return -EINVAL; - } - if (time_state->info[i].size != 2) { - dev_err(&pdev->dev, - "attribute '%s' not 8 or 16 bits wide!\n", + if (time_state->info[i].size == 3 || + time_state->info[i].size > 4) { + dev_err(&pdev->dev, + "attribute '%s' not 8, 16 or 32 bits wide!\n", hid_time_attrib_name( time_state->info[i].attrib_id)); - return -EINVAL; - } + return -EINVAL; } if (time_state->info[i].units != HID_USAGE_SENSOR_UNITS_NOT_SPECIFIED && -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 3/9] rtc: rtc-hid-sensor-time: delay registering as rtc into a work 2013-06-14 16:52 ` [PATCH 0/9 v3] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler 2013-06-14 16:52 ` [PATCH 1/9 RESEND] rtc: rtc-hid-sensor-time: allow full years (16bit) in HID reports Alexander Holler 2013-06-14 16:52 ` [PATCH 2/9 RESEND] rtc: rtc-hid-sensor-time: allow 16 and 32 bit values for all attributes Alexander Holler @ 2013-06-14 16:52 ` Alexander Holler 2013-06-20 10:39 ` [PATCH 3/9 v2] " Alexander Holler 2013-06-14 16:52 ` [PATCH 4/9 RESEND] RFC: timekeeping: introduce flag systime_was_set Alexander Holler ` (6 subsequent siblings) 9 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-06-14 16:52 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, John Stultz, rtc-linux, Thomas Gleixner, Alessandro Zummo, Alexander Holler rtc_device_register() might want to read the clock which doesn't work before the hid device is registered. Therefor we delay the registration of the rtc driver by moving it to a work. Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- drivers/rtc/rtc-hid-sensor-time.c | 66 ++++++++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index 7273b01..b842730 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -37,6 +37,11 @@ enum hid_time_channel { TIME_RTC_CHANNEL_MAX, }; +struct hid_time_workts { + struct work_struct work; + struct hid_time_state *time_state; +}; + struct hid_time_state { struct hid_sensor_hub_callbacks callbacks; struct hid_sensor_common common_attributes; @@ -46,6 +51,7 @@ struct hid_time_state { struct completion comp_last_time; struct rtc_time time_buf; struct rtc_device *rtc; + struct hid_time_workts *workts; }; static const u32 hid_time_addresses[TIME_RTC_CHANNEL_MAX] = { @@ -237,6 +243,36 @@ static const struct rtc_class_ops hid_time_rtc_ops = { .read_time = hid_rtc_read_time, }; +static void hid_time_register_rtc_work(struct work_struct *work) +{ + struct hid_time_state *time_state = + container_of(work, struct hid_time_workts, work) + ->time_state; + struct platform_device *pdev = time_state->callbacks.pdev; + + time_state->rtc = devm_rtc_device_register(&pdev->dev, + "hid-sensor-time", &hid_time_rtc_ops, + THIS_MODULE); + if (IS_ERR_OR_NULL(time_state->rtc)) { + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); + time_state->rtc = NULL; + dev_err(&pdev->dev, "rtc device register failed!\n"); + /* + * I haven't a found a way to remove only this device from + * hid-sensor-hub. Removing the device a level above (the + * complete HID device) doesn't work, because a sensor-hub + * might provide more than just a time-sensor and thus we + * would remove all sensors not just this one. + * So we just leave this driver idling around until I or + * someone else has figured out how to remove this device + * from hid-sensor-hub. + */ + } + time_state->workts = NULL; + kfree(work); +} + static int hid_time_probe(struct platform_device *pdev) { int ret = 0; @@ -279,22 +315,36 @@ static int hid_time_probe(struct platform_device *pdev) return ret; } - time_state->rtc = devm_rtc_device_register(&pdev->dev, - "hid-sensor-time", &hid_time_rtc_ops, - THIS_MODULE); - - if (IS_ERR(time_state->rtc)) { - dev_err(&pdev->dev, "rtc device register failed!\n"); - return PTR_ERR(time_state->rtc); + /* + * The HID device has to be registered to read the clock. + * Because rtc_device_register() might read the time, we have to delay + * rtc_device_register() to a work in order to finish the probe before. + */ + time_state->workts = kmalloc(sizeof(struct hid_time_workts), + GFP_KERNEL); + if (time_state->workts == NULL) { + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); + return -ENOMEM; } + time_state->workts->time_state = time_state; + INIT_WORK(&time_state->workts->work, + hid_time_register_rtc_work); + schedule_work(&time_state->workts->work); - return ret; + return 0; } static int hid_time_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct hid_time_state *time_state = platform_get_drvdata(pdev); + if (time_state->workts) { + flush_work(&time_state->workts->work); + WARN_ON(time_state->workts != NULL); + } + if (time_state->rtc) + rtc_device_unregister(time_state->rtc); sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); return 0; -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 3/9 v2] rtc: rtc-hid-sensor-time: delay registering as rtc into a work 2013-06-14 16:52 ` [PATCH 3/9] rtc: rtc-hid-sensor-time: delay registering as rtc into a work Alexander Holler @ 2013-06-20 10:39 ` Alexander Holler 2013-06-26 19:55 ` Andrew Morton 0 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-06-20 10:39 UTC (permalink / raw) To: linux-kernel; +Cc: Andrew Morton, rtc-linux, Alessandro Zummo, Alexander Holler rtc_device_register() might want to read the clock which doesn't work before the hid device is registered. Therefor we delay the registration of the rtc driver by moving it to a work. Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- Changes to v1: I've fixed a bug calling rtc_device_unregister() in remove() which was necessary in 3.9 but leads to a crash in 3.10 (through the use of devm_*). Sorry for that, I assume I've resolved a conflict wrong while moving this patch from 3.9.x to 3.10. This patch can already be added to -mm. It is only necessary if rtc_device_register() reads the time (which would fail without this patch). I've left the "3/9" in the subject only there, because the patch was named as such before. But the patch is independ if hctosys will be changed or not. 1/9 and 2/9 are already in -mm, 4-9 are in discussion which will need some time. Thanks, Alexander Holler drivers/rtc/rtc-hid-sensor-time.c | 64 ++++++++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index 7273b01..0767395 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -37,6 +37,11 @@ enum hid_time_channel { TIME_RTC_CHANNEL_MAX, }; +struct hid_time_workts { + struct work_struct work; + struct hid_time_state *time_state; +}; + struct hid_time_state { struct hid_sensor_hub_callbacks callbacks; struct hid_sensor_common common_attributes; @@ -46,6 +51,7 @@ struct hid_time_state { struct completion comp_last_time; struct rtc_time time_buf; struct rtc_device *rtc; + struct hid_time_workts *workts; }; static const u32 hid_time_addresses[TIME_RTC_CHANNEL_MAX] = { @@ -237,6 +243,36 @@ static const struct rtc_class_ops hid_time_rtc_ops = { .read_time = hid_rtc_read_time, }; +static void hid_time_register_rtc_work(struct work_struct *work) +{ + struct hid_time_state *time_state = + container_of(work, struct hid_time_workts, work) + ->time_state; + struct platform_device *pdev = time_state->callbacks.pdev; + + time_state->rtc = devm_rtc_device_register(&pdev->dev, + "hid-sensor-time", &hid_time_rtc_ops, + THIS_MODULE); + if (IS_ERR_OR_NULL(time_state->rtc)) { + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); + time_state->rtc = NULL; + dev_err(&pdev->dev, "rtc device register failed!\n"); + /* + * I haven't a found a way to remove only this device from + * hid-sensor-hub. Removing the device a level above (the + * complete HID device) doesn't work, because a sensor-hub + * might provide more than just a time-sensor and thus we + * would remove all sensors not just this one. + * So we just leave this driver idling around until I or + * someone else has figured out how to remove this device + * from hid-sensor-hub. + */ + } + time_state->workts = NULL; + kfree(work); +} + static int hid_time_probe(struct platform_device *pdev) { int ret = 0; @@ -279,22 +315,34 @@ static int hid_time_probe(struct platform_device *pdev) return ret; } - time_state->rtc = devm_rtc_device_register(&pdev->dev, - "hid-sensor-time", &hid_time_rtc_ops, - THIS_MODULE); - - if (IS_ERR(time_state->rtc)) { - dev_err(&pdev->dev, "rtc device register failed!\n"); - return PTR_ERR(time_state->rtc); + /* + * The HID device has to be registered to read the clock. + * Because rtc_device_register() might read the time, we have to delay + * rtc_device_register() to a work in order to finish the probe before. + */ + time_state->workts = kmalloc(sizeof(struct hid_time_workts), + GFP_KERNEL); + if (time_state->workts == NULL) { + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); + return -ENOMEM; } + time_state->workts->time_state = time_state; + INIT_WORK(&time_state->workts->work, + hid_time_register_rtc_work); + schedule_work(&time_state->workts->work); - return ret; + return 0; } static int hid_time_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct hid_time_state *time_state = platform_get_drvdata(pdev); + if (time_state->workts) { + flush_work(&time_state->workts->work); + WARN_ON(time_state->workts != NULL); + } sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); return 0; -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* Re: [PATCH 3/9 v2] rtc: rtc-hid-sensor-time: delay registering as rtc into a work 2013-06-20 10:39 ` [PATCH 3/9 v2] " Alexander Holler @ 2013-06-26 19:55 ` Andrew Morton 2013-06-26 21:34 ` [rtc-linux] " Alexander Holler 0 siblings, 1 reply; 78+ messages in thread From: Andrew Morton @ 2013-06-26 19:55 UTC (permalink / raw) To: Alexander Holler; +Cc: linux-kernel, rtc-linux, Alessandro Zummo On Thu, 20 Jun 2013 12:39:36 +0200 Alexander Holler <holler@ahsoftware.de> wrote: > rtc_device_register() might want to read the clock which doesn't work > before the hid device is registered. Therefor we delay the registration of > the rtc driver by moving it to a work. > > --- a/drivers/rtc/rtc-hid-sensor-time.c > +++ b/drivers/rtc/rtc-hid-sensor-time.c > @@ -37,6 +37,11 @@ enum hid_time_channel { > TIME_RTC_CHANNEL_MAX, > }; > > +struct hid_time_workts { Strange name. I can't work out what the "ts" means. > + struct work_struct work; > + struct hid_time_state *time_state; > +}; > + > struct hid_time_state { > struct hid_sensor_hub_callbacks callbacks; > struct hid_sensor_common common_attributes; > > ... > > @@ -237,6 +243,36 @@ static const struct rtc_class_ops hid_time_rtc_ops = { > .read_time = hid_rtc_read_time, > }; > > +static void hid_time_register_rtc_work(struct work_struct *work) > +{ > + struct hid_time_state *time_state = > + container_of(work, struct hid_time_workts, work) > + ->time_state; > + struct platform_device *pdev = time_state->callbacks.pdev; Ick. When the initialisers overflow 80 cols, the fix is easy: don't use initalisers: struct hid_time_state *time_state; struct platform_device *pdev; time_state = container_of(work, struct hid_time_workts, work)->time_state; pdev = time_state->callbacks.pdev; > + time_state->rtc = devm_rtc_device_register(&pdev->dev, > + "hid-sensor-time", &hid_time_rtc_ops, > + THIS_MODULE); > + if (IS_ERR_OR_NULL(time_state->rtc)) { > + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; Newline after end-of-definitions and before start-of-code, please. > + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); > + time_state->rtc = NULL; > + dev_err(&pdev->dev, "rtc device register failed!\n"); > + /* > + * I haven't a found a way to remove only this device from > + * hid-sensor-hub. Removing the device a level above (the > + * complete HID device) doesn't work, because a sensor-hub > + * might provide more than just a time-sensor and thus we > + * would remove all sensors not just this one. > + * So we just leave this driver idling around until I or > + * someone else has figured out how to remove this device > + * from hid-sensor-hub. > + */ > + } > + time_state->workts = NULL; > + kfree(work); > +} > + > static int hid_time_probe(struct platform_device *pdev) > { > int ret = 0; > @@ -279,22 +315,34 @@ static int hid_time_probe(struct platform_device *pdev) > return ret; > } > > - time_state->rtc = devm_rtc_device_register(&pdev->dev, > - "hid-sensor-time", &hid_time_rtc_ops, > - THIS_MODULE); > - > - if (IS_ERR(time_state->rtc)) { > - dev_err(&pdev->dev, "rtc device register failed!\n"); > - return PTR_ERR(time_state->rtc); > + /* > + * The HID device has to be registered to read the clock. > + * Because rtc_device_register() might read the time, we have to delay > + * rtc_device_register() to a work in order to finish the probe before. > + */ > + time_state->workts = kmalloc(sizeof(struct hid_time_workts), > + GFP_KERNEL); > + if (time_state->workts == NULL) { > + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); > + return -ENOMEM; > } > + time_state->workts->time_state = time_state; > + INIT_WORK(&time_state->workts->work, > + hid_time_register_rtc_work); > + schedule_work(&time_state->workts->work); This seems unreliable. The scheduled work can run one nanosecond later, on this or a different CPU. What guarantees that the HID device will then be fully registered? ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [rtc-linux] Re: [PATCH 3/9 v2] rtc: rtc-hid-sensor-time: delay registering as rtc into a work 2013-06-26 19:55 ` Andrew Morton @ 2013-06-26 21:34 ` Alexander Holler 2013-06-26 22:07 ` Greg KH 2013-06-28 1:29 ` [rtc-linux] Re: [PATCH 3/9 v2] rtc: rtc-hid-sensor-time: delay registering as rtc into a work Alexander Holler 0 siblings, 2 replies; 78+ messages in thread From: Alexander Holler @ 2013-06-26 21:34 UTC (permalink / raw) To: rtc-linux; +Cc: Andrew Morton, linux-kernel, Alessandro Zummo Am 26.06.2013 21:55, schrieb Andrew Morton: > On Thu, 20 Jun 2013 12:39:36 +0200 Alexander Holler <holler@ahsoftware.de> wrote: > >> rtc_device_register() might want to read the clock which doesn't work >> before the hid device is registered. Therefor we delay the registration of >> the rtc driver by moving it to a work. >> > > >> --- a/drivers/rtc/rtc-hid-sensor-time.c >> +++ b/drivers/rtc/rtc-hid-sensor-time.c >> @@ -37,6 +37,11 @@ enum hid_time_channel { >> TIME_RTC_CHANNEL_MAX, >> }; >> >> +struct hid_time_workts { > > Strange name. I can't work out what the "ts" means. It's just a name > >> + struct work_struct work; >> + struct hid_time_state *time_state; >> +}; and stands for work + time_state. Peronally I would use hid_time_work_time_state, but then I would get even more problems to go conform with CGA restrictions on line widths. >> + >> struct hid_time_state { >> struct hid_sensor_hub_callbacks callbacks; >> struct hid_sensor_common common_attributes; >> >> ... >> >> @@ -237,6 +243,36 @@ static const struct rtc_class_ops hid_time_rtc_ops = { >> .read_time = hid_rtc_read_time, >> }; >> >> +static void hid_time_register_rtc_work(struct work_struct *work) >> +{ >> + struct hid_time_state *time_state = >> + container_of(work, struct hid_time_workts, work) >> + ->time_state; >> + struct platform_device *pdev = time_state->callbacks.pdev; > > Ick. When the initialisers overflow 80 cols, the fix is easy: don't > use initalisers: > > struct hid_time_state *time_state; > struct platform_device *pdev; > > time_state = container_of(work, struct hid_time_workts, work)->time_state; > pdev = time_state->callbacks.pdev; > Sorry, but it's long ago since I had to use a DOS machine and I still don't use a phone to write source, therefor I'm not very skilled in writing readable source with meaningfull names in max. 72 (80-8) chars per line. But I will work hard to relearn those long forgotten skills, they might become handy again, when PCs with monitors got finally replaced by phones and tablets with small screens. ;) >> + time_state->rtc = devm_rtc_device_register(&pdev->dev, >> + "hid-sensor-time", &hid_time_rtc_ops, >> + THIS_MODULE); >> + if (IS_ERR_OR_NULL(time_state->rtc)) { >> + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; > > Newline after end-of-definitions and before start-of-code, please. > >> + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); >> + time_state->rtc = NULL; >> + dev_err(&pdev->dev, "rtc device register failed!\n"); >> + /* >> + * I haven't a found a way to remove only this device from >> + * hid-sensor-hub. Removing the device a level above (the >> + * complete HID device) doesn't work, because a sensor-hub >> + * might provide more than just a time-sensor and thus we >> + * would remove all sensors not just this one. >> + * So we just leave this driver idling around until I or >> + * someone else has figured out how to remove this device >> + * from hid-sensor-hub. >> + */ >> + } >> + time_state->workts = NULL; >> + kfree(work); >> +} >> + >> static int hid_time_probe(struct platform_device *pdev) >> { >> int ret = 0; >> @@ -279,22 +315,34 @@ static int hid_time_probe(struct platform_device *pdev) >> return ret; >> } >> >> - time_state->rtc = devm_rtc_device_register(&pdev->dev, >> - "hid-sensor-time", &hid_time_rtc_ops, >> - THIS_MODULE); >> - >> - if (IS_ERR(time_state->rtc)) { >> - dev_err(&pdev->dev, "rtc device register failed!\n"); >> - return PTR_ERR(time_state->rtc); >> + /* >> + * The HID device has to be registered to read the clock. >> + * Because rtc_device_register() might read the time, we have to delay >> + * rtc_device_register() to a work in order to finish the probe before. >> + */ >> + time_state->workts = kmalloc(sizeof(struct hid_time_workts), >> + GFP_KERNEL); >> + if (time_state->workts == NULL) { >> + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); >> + return -ENOMEM; >> } >> + time_state->workts->time_state = time_state; >> + INIT_WORK(&time_state->workts->work, >> + hid_time_register_rtc_work); >> + schedule_work(&time_state->workts->work); > > This seems unreliable. The scheduled work can run one nanosecond > later, on this or a different CPU. What guarantees that the HID device > will then be fully registered? Nothing, but schedule_delayed_work() is as unreliable as without delay and I don't know of any callback after registration has happened. I have to dig through the hid-(sensor-)code, maybe I will find a callback I can (mis)use to register the rtc driver after the hid driver was registered. I will write a v3 if I've found something. Regards, Alexander Holler ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [rtc-linux] Re: [PATCH 3/9 v2] rtc: rtc-hid-sensor-time: delay registering as rtc into a work 2013-06-26 21:34 ` [rtc-linux] " Alexander Holler @ 2013-06-26 22:07 ` Greg KH 2013-06-26 23:51 ` Alexander Holler 2013-06-28 1:29 ` [rtc-linux] Re: [PATCH 3/9 v2] rtc: rtc-hid-sensor-time: delay registering as rtc into a work Alexander Holler 1 sibling, 1 reply; 78+ messages in thread From: Greg KH @ 2013-06-26 22:07 UTC (permalink / raw) To: Alexander Holler; +Cc: rtc-linux, Andrew Morton, linux-kernel, Alessandro Zummo On Wed, Jun 26, 2013 at 11:34:35PM +0200, Alexander Holler wrote: > >> + /* > >> + * The HID device has to be registered to read the clock. > >> + * Because rtc_device_register() might read the time, we have to delay > >> + * rtc_device_register() to a work in order to finish the probe before. > >> + */ > >> + time_state->workts = kmalloc(sizeof(struct hid_time_workts), > >> + GFP_KERNEL); > >> + if (time_state->workts == NULL) { > >> + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); > >> + return -ENOMEM; > >> } > >> + time_state->workts->time_state = time_state; > >> + INIT_WORK(&time_state->workts->work, > >> + hid_time_register_rtc_work); > >> + schedule_work(&time_state->workts->work); > > > > This seems unreliable. The scheduled work can run one nanosecond > > later, on this or a different CPU. What guarantees that the HID device > > will then be fully registered? > > Nothing, but schedule_delayed_work() is as unreliable as without delay > and I don't know of any callback after registration has happened. I have > to dig through the hid-(sensor-)code, maybe I will find a callback I can > (mis)use to register the rtc driver after the hid driver was registered. Why not use the deferred_probe code, which is there just for this type of thing (i.e. your other drivers/devices aren't present/initialized yet.)? Just return -EPROBE_DEFER from your probe function if you don't find everything already set up properly, the driver core will call you again later after it has initialized everything it has found. Hope this helps, greg k-h ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [rtc-linux] Re: [PATCH 3/9 v2] rtc: rtc-hid-sensor-time: delay registering as rtc into a work 2013-06-26 22:07 ` Greg KH @ 2013-06-26 23:51 ` Alexander Holler 2013-07-06 8:55 ` Alexander Holler 0 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-06-26 23:51 UTC (permalink / raw) To: rtc-linux; +Cc: Greg KH, Andrew Morton, linux-kernel, Alessandro Zummo Am 27.06.2013 00:07, schrieb Greg KH: > On Wed, Jun 26, 2013 at 11:34:35PM +0200, Alexander Holler wrote: >>>> + /* >>>> + * The HID device has to be registered to read the clock. >>>> + * Because rtc_device_register() might read the time, we have to delay >>>> + * rtc_device_register() to a work in order to finish the probe before. >>>> + */ >>>> + time_state->workts = kmalloc(sizeof(struct hid_time_workts), >>>> + GFP_KERNEL); >>>> + if (time_state->workts == NULL) { >>>> + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); >>>> + return -ENOMEM; >>>> } >>>> + time_state->workts->time_state = time_state; >>>> + INIT_WORK(&time_state->workts->work, >>>> + hid_time_register_rtc_work); >>>> + schedule_work(&time_state->workts->work); >>> >>> This seems unreliable. The scheduled work can run one nanosecond >>> later, on this or a different CPU. What guarantees that the HID device >>> will then be fully registered? >> >> Nothing, but schedule_delayed_work() is as unreliable as without delay >> and I don't know of any callback after registration has happened. I have >> to dig through the hid-(sensor-)code, maybe I will find a callback I can >> (mis)use to register the rtc driver after the hid driver was registered. > > Why not use the deferred_probe code, which is there just for this type > of thing (i.e. your other drivers/devices aren't present/initialized > yet.)? Just return -EPROBE_DEFER from your probe function if you don't > find everything already set up properly, the driver core will call you > again later after it has initialized everything it has found. Hmm, didn't know about the deferred_probe stuff. Thanks. Unfortunately I currently don't see how this might help here. The rtc-device will not be probed, so it can't be deferred. And even if I will find or implement a way to add a probe for the rtc device, I still have to search how to find out if the HID device is registered. Anyway, back to reading to sources. Maybe there already is some callback from hid-sensor-hub or the hid-subsystem I can use. I haven't searched in deep for such because using a work worked just fine here on several machines (besides that it was a quick hack which got only necessary with the changed hctosys which reads the time in rtc_device_register()). I already wondered why using a work (even without delay) did work, but I explained it with some (maybe imaginary) locality of works, such that they get called after the scheduling thread gives up his timeslice which happily happened after the hid-device was registered. So I hoped (hope dies last ;) ) to only have to fix it, if it actually doesn't work somewhere or sometimes after the foreseen discussion about hctosys has come to an end. Regards, Alexander Holler ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [rtc-linux] Re: [PATCH 3/9 v2] rtc: rtc-hid-sensor-time: delay registering as rtc into a work 2013-06-26 23:51 ` Alexander Holler @ 2013-07-06 8:55 ` Alexander Holler 2013-07-06 18:21 ` Jiri Kosina 0 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-07-06 8:55 UTC (permalink / raw) To: rtc-linux Cc: Greg KH, Andrew Morton, linux-kernel, Alessandro Zummo, Jiri Kosina Am 27.06.2013 01:51, schrieb Alexander Holler: > Am 27.06.2013 00:07, schrieb Greg KH: >> On Wed, Jun 26, 2013 at 11:34:35PM +0200, Alexander Holler wrote: >>>>> + /* >>>>> + * The HID device has to be registered to read the clock. >>>>> + * Because rtc_device_register() might read the time, we have to delay >>>>> + * rtc_device_register() to a work in order to finish the probe before. >>>>> + */ >>>>> + time_state->workts = kmalloc(sizeof(struct hid_time_workts), >>>>> + GFP_KERNEL); >>>>> + if (time_state->workts == NULL) { >>>>> + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); >>>>> + return -ENOMEM; >>>>> } >>>>> + time_state->workts->time_state = time_state; >>>>> + INIT_WORK(&time_state->workts->work, >>>>> + hid_time_register_rtc_work); >>>>> + schedule_work(&time_state->workts->work); >>>> >>>> This seems unreliable. The scheduled work can run one nanosecond >>>> later, on this or a different CPU. What guarantees that the HID device >>>> will then be fully registered? >>> >>> Nothing, but schedule_delayed_work() is as unreliable as without delay >>> and I don't know of any callback after registration has happened. I have >>> to dig through the hid-(sensor-)code, maybe I will find a callback I can >>> (mis)use to register the rtc driver after the hid driver was registered. >> >> Why not use the deferred_probe code, which is there just for this type >> of thing (i.e. your other drivers/devices aren't present/initialized >> yet.)? Just return -EPROBE_DEFER from your probe function if you don't >> find everything already set up properly, the driver core will call you >> again later after it has initialized everything it has found. > > Hmm, didn't know about the deferred_probe stuff. Thanks. > > Unfortunately I currently don't see how this might help here. The > rtc-device will not be probed, so it can't be deferred. And even if I > will find or implement a way to add a probe for the rtc device, I still > have to search how to find out if the HID device is registered. > > Anyway, back to reading to sources. Maybe there already is some callback > from hid-sensor-hub or the hid-subsystem I can use. I haven't searched > in deep for such because using a work worked just fine here on several > machines (besides that it was a quick hack which got only necessary with > the changed hctosys which reads the time in rtc_device_register()). > > I already wondered why using a work (even without delay) did work, but I > explained it with some (maybe imaginary) locality of works, such that > they get called after the scheduling thread gives up his timeslice which > happily happened after the hid-device was registered. So I hoped (hope > dies last ;) ) to only have to fix it, if it actually doesn't work > somewhere or sometimes after the foreseen discussion about hctosys has > come to an end. > I've now traced down why the above patch _really_ is needed: it's because of how the locking is done in the hid-subsystem. So my intuition to use a work was ok, but my assumption that it's because the HID device driver wasn't registered before probe() finished was wrong. What happens without using a work is the following (shortened a lot): hid_device_probe() // hid subsystem locks hdev->driver_input_lock hid_time_probe() devm_rtc_device_register() // wants to read the clock hid_rtc_read_time() // submits GET_REPORT and waits for the answer // (the timestamp from the clock) hid_input_report() And there we have something like a deadlock situation because hid_input_report() needs hdev->driver_input_lock to submit the report to the HID driver. So in short, it's currently impossible for a HID driver to read input from a HID device from inside it's probe function. That means the patch is fine, but the comment is wrong. Because I think it would be better to change the locking inside the HID subsystem (drivers/hid/hid-core.c) in order to allow the probe function of HID drivers to read input, I will first have a look if I see a way to change the locking in hid-core.c, before I will post an update to the above patch with a corrected comment. But this might need some time as I'm not familiar with the locking in the HID subsystem and my motivation currently isn't very high. Regards, Alexander Holler ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [rtc-linux] Re: [PATCH 3/9 v2] rtc: rtc-hid-sensor-time: delay registering as rtc into a work 2013-07-06 8:55 ` Alexander Holler @ 2013-07-06 18:21 ` Jiri Kosina 2013-07-07 7:35 ` Alexander Holler 0 siblings, 1 reply; 78+ messages in thread From: Jiri Kosina @ 2013-07-06 18:21 UTC (permalink / raw) To: Alexander Holler Cc: rtc-linux, Greg KH, Andrew Morton, linux-kernel, Alessandro Zummo On Sat, 6 Jul 2013, Alexander Holler wrote: > I've now traced down why the above patch _really_ is needed: it's because of > how the locking is done in the hid-subsystem. So my intuition to use a work > was ok, but my assumption that it's because the HID device driver wasn't > registered before probe() finished was wrong. > > What happens without using a work is the following (shortened a lot): > > hid_device_probe() // hid subsystem locks hdev->driver_input_lock > hid_time_probe() > devm_rtc_device_register() // wants to read the clock > hid_rtc_read_time() // submits GET_REPORT and waits for the answer > // (the timestamp from the clock) > hid_input_report() > > And there we have something like a deadlock situation because > hid_input_report() needs hdev->driver_input_lock to submit the report to the > HID driver. > > So in short, it's currently impossible for a HID driver to read input from a > HID device from inside it's probe function. Please see commit c849a6143b ("HID: Separate struct hid_device's driver_lock into two locks"). It's done exactly in order to allow for receiving input inside of the probe() function of the driver. -- Jiri Kosina SUSE Labs ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [rtc-linux] Re: [PATCH 3/9 v2] rtc: rtc-hid-sensor-time: delay registering as rtc into a work 2013-07-06 18:21 ` Jiri Kosina @ 2013-07-07 7:35 ` Alexander Holler 2013-07-08 9:12 ` [PATCH 0/2] rtc: rtc-hid-sensor-time: enable HID input processing early Alexander Holler 0 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-07-07 7:35 UTC (permalink / raw) To: rtc-linux Cc: Jiri Kosina, Greg KH, Andrew Morton, linux-kernel, Alessandro Zummo Am 06.07.2013 20:21, schrieb Jiri Kosina: > On Sat, 6 Jul 2013, Alexander Holler wrote: > >> I've now traced down why the above patch _really_ is needed: it's because of >> how the locking is done in the hid-subsystem. So my intuition to use a work >> was ok, but my assumption that it's because the HID device driver wasn't >> registered before probe() finished was wrong. >> >> What happens without using a work is the following (shortened a lot): >> >> hid_device_probe() // hid subsystem locks hdev->driver_input_lock >> hid_time_probe() >> devm_rtc_device_register() // wants to read the clock >> hid_rtc_read_time() // submits GET_REPORT and waits for the answer >> // (the timestamp from the clock) >> hid_input_report() >> >> And there we have something like a deadlock situation because >> hid_input_report() needs hdev->driver_input_lock to submit the report to the >> HID driver. >> >> So in short, it's currently impossible for a HID driver to read input from a >> HID device from inside it's probe function. > > Please see commit c849a6143b ("HID: Separate struct hid_device's > driver_lock into two locks"). It's done exactly in order to allow for > receiving input inside of the probe() function of the driver. So that would have been likely my next discovery. ;) Very nice, this will reduce the whole patch to one line. I will test it and send an updated patch. Thanks a lot, Alexander Holler ^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 0/2] rtc: rtc-hid-sensor-time: enable HID input processing early 2013-07-07 7:35 ` Alexander Holler @ 2013-07-08 9:12 ` Alexander Holler 2013-07-08 9:12 ` [PATCH 1/2] rtc: rtc-hid-sensor-time: improve error handling when rtc register fails Alexander Holler 2013-07-08 9:12 ` [PATCH 2/2] rtc: rtc-hid-sensor-time: enable HID input processing early Alexander Holler 0 siblings, 2 replies; 78+ messages in thread From: Alexander Holler @ 2013-07-08 9:12 UTC (permalink / raw) To: linux-kernel; +Cc: Andrew Morton, rtc-linux, Alessandro Zummo, Jiri Kosina The following 2 patches together replace the previous send patch "rtc: rtc-hid-sensor-time: delay registering as rtc into a work". They are based on the current master, so they might become included in 3.11. I've splitted the changes into two patches because the patch changed such, that combining them into just one patch doesn't make sense anymore. Regards, Alexander Holler ^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 1/2] rtc: rtc-hid-sensor-time: improve error handling when rtc register fails 2013-07-08 9:12 ` [PATCH 0/2] rtc: rtc-hid-sensor-time: enable HID input processing early Alexander Holler @ 2013-07-08 9:12 ` Alexander Holler 2013-07-08 9:12 ` [PATCH 2/2] rtc: rtc-hid-sensor-time: enable HID input processing early Alexander Holler 1 sibling, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-07-08 9:12 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, rtc-linux, Alessandro Zummo, Jiri Kosina, Alexander Holler Stop processing hid input when registering the RTC fails and handle a NULL returned from devm_rtc_device_register() as a failure too. Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- drivers/rtc/rtc-hid-sensor-time.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index 7273b01..1ab3d13 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -283,9 +283,11 @@ static int hid_time_probe(struct platform_device *pdev) "hid-sensor-time", &hid_time_rtc_ops, THIS_MODULE); - if (IS_ERR(time_state->rtc)) { + if (IS_ERR_OR_NULL(time_state->rtc)) { + ret = time_state->rtc ? PTR_ERR(time_state->rtc) : -ENODEV; + time_state->rtc = NULL; + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); dev_err(&pdev->dev, "rtc device register failed!\n"); - return PTR_ERR(time_state->rtc); } return ret; -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 2/2] rtc: rtc-hid-sensor-time: enable HID input processing early 2013-07-08 9:12 ` [PATCH 0/2] rtc: rtc-hid-sensor-time: enable HID input processing early Alexander Holler 2013-07-08 9:12 ` [PATCH 1/2] rtc: rtc-hid-sensor-time: improve error handling when rtc register fails Alexander Holler @ 2013-07-08 9:12 ` Alexander Holler 1 sibling, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-07-08 9:12 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, rtc-linux, Alessandro Zummo, Jiri Kosina, Alexander Holler Enable the processing of HID input records before the RTC will be registered, in order to allow the RTC register function to read clock. Without doing that the clock can only be read after the probe function has finished. Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- drivers/rtc/rtc-hid-sensor-time.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index 1ab3d13..1006a62 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -279,11 +279,18 @@ static int hid_time_probe(struct platform_device *pdev) return ret; } + /* + * Enable HID input processing early in order to be able to read the + * clock already in devm_rtc_device_register(). + */ + hid_device_io_start(hsdev->hdev); + time_state->rtc = devm_rtc_device_register(&pdev->dev, "hid-sensor-time", &hid_time_rtc_ops, THIS_MODULE); if (IS_ERR_OR_NULL(time_state->rtc)) { + hid_device_io_stop(hsdev->hdev); ret = time_state->rtc ? PTR_ERR(time_state->rtc) : -ENODEV; time_state->rtc = NULL; sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* Re: [rtc-linux] Re: [PATCH 3/9 v2] rtc: rtc-hid-sensor-time: delay registering as rtc into a work 2013-06-26 21:34 ` [rtc-linux] " Alexander Holler 2013-06-26 22:07 ` Greg KH @ 2013-06-28 1:29 ` Alexander Holler 1 sibling, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-06-28 1:29 UTC (permalink / raw) To: rtc-linux; +Cc: Andrew Morton, linux-kernel, Alessandro Zummo Am 26.06.2013 23:34, schrieb Alexander Holler: > Am 26.06.2013 21:55, schrieb Andrew Morton: >> On Thu, 20 Jun 2013 12:39:36 +0200 Alexander Holler <holler@ahsoftware.de> wrote: >>> +static void hid_time_register_rtc_work(struct work_struct *work) >>> +{ >>> + struct hid_time_state *time_state = >>> + container_of(work, struct hid_time_workts, work) >>> + ->time_state; >>> + struct platform_device *pdev = time_state->callbacks.pdev; >> >> Ick. When the initialisers overflow 80 cols, the fix is easy: don't >> use initalisers: >> >> struct hid_time_state *time_state; >> struct platform_device *pdev; >> >> time_state = container_of(work, struct hid_time_workts, work)->time_state; >> pdev = time_state->callbacks.pdev; >> > > Sorry, but it's long ago since I had to use a DOS machine and I still > don't use a phone to write source, therefor I'm not very skilled in > writing readable source with meaningfull names in max. 72 (80-8) chars > per line. But I will work hard to relearn those long forgotten skills, > they might become handy again, when PCs with monitors got finally > replaced by phones and tablets with small screens. ;) To do other poor patch submitters which don't use a video terminal too a favor, I've decided it might make sense to describe the workflow which is responsible for the above stuff which makes you cry so often. It isn't that I don't know that I don't have to use initializers, I know C since 3 decades. The following happens here: - I'm writing source/patches without limiting myself to 80x25 chars. - Then I'm executing the insulting and must be one of the most hated piece of software callled checkpatch.pl. - It tells me to place or delete spaces here and cut lines there. - I do exactly that, while having my brain turned off (self-protection) Therefor stuff the like the above happens. It isn't badwill, incompetence or inability. Regards, Alexander Holler ^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9 RESEND] RFC: timekeeping: introduce flag systime_was_set 2013-06-14 16:52 ` [PATCH 0/9 v3] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler ` (2 preceding siblings ...) 2013-06-14 16:52 ` [PATCH 3/9] rtc: rtc-hid-sensor-time: delay registering as rtc into a work Alexander Holler @ 2013-06-14 16:52 ` Alexander Holler 2013-06-14 17:41 ` John Stultz 2013-06-14 16:52 ` [PATCH 5/9 v3] RFC: timekeeping: rtc: Introduce new kernel parameter hctosys Alexander Holler ` (5 subsequent siblings) 9 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-06-14 16:52 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, John Stultz, rtc-linux, Thomas Gleixner, Alessandro Zummo, Alexander Holler In order to let an RTC set the time at boot without the problem that a second RTC overwrites it, the flag systime_was_set is introduced. systime_was_set will be true, if a persistent clock sets the time at boot, or if do_settimeofday() is called (e.g. by the RTC subsystem or userspace). Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- include/linux/time.h | 6 ++++++ kernel/time/timekeeping.c | 10 +++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/linux/time.h b/include/linux/time.h index d5d229b..888280f 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -129,6 +129,12 @@ extern int update_persistent_clock(struct timespec now); void timekeeping_init(void); extern int timekeeping_suspended; +/* + * Will be true if the system time was set at least once by + * a persistent clock, RTC or userspace. + */ +extern bool systime_was_set; + unsigned long get_seconds(void); struct timespec current_kernel_time(void); struct timespec __current_kernel_time(void); /* does not take xtime_lock */ diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index baeeb5c..07d8531 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -37,6 +37,9 @@ int __read_mostly timekeeping_suspended; /* Flag for if there is a persistent clock on this platform */ bool __read_mostly persistent_clock_exist = false; +/* Flag for if the system time was set at least once */ +bool __read_mostly systime_was_set; + static inline void tk_normalize_xtime(struct timekeeper *tk) { while (tk->xtime_nsec >= ((u64)NSEC_PER_SEC << tk->shift)) { @@ -498,6 +501,9 @@ int do_settimeofday(const struct timespec *tv) raw_spin_lock_irqsave(&timekeeper_lock, flags); write_seqcount_begin(&timekeeper_seq); + systime_was_set = true; + + timekeeping_forward_now(tk); xt = tk_xtime(tk); @@ -781,8 +787,10 @@ void __init timekeeping_init(void) " Check your CMOS/BIOS settings.\n"); now.tv_sec = 0; now.tv_nsec = 0; - } else if (now.tv_sec || now.tv_nsec) + } else if (now.tv_sec || now.tv_nsec) { persistent_clock_exist = true; + systime_was_set = true; + } read_boot_clock(&boot); if (!timespec_valid_strict(&boot)) { -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* Re: [PATCH 4/9 RESEND] RFC: timekeeping: introduce flag systime_was_set 2013-06-14 16:52 ` [PATCH 4/9 RESEND] RFC: timekeeping: introduce flag systime_was_set Alexander Holler @ 2013-06-14 17:41 ` John Stultz 2013-06-14 18:05 ` [rtc-linux] " Alexander Holler 0 siblings, 1 reply; 78+ messages in thread From: John Stultz @ 2013-06-14 17:41 UTC (permalink / raw) To: Alexander Holler Cc: linux-kernel, Andrew Morton, rtc-linux, Thomas Gleixner, Alessandro Zummo On 06/14/2013 09:52 AM, Alexander Holler wrote: > In order to let an RTC set the time at boot without the problem that a > second RTC overwrites it, the flag systime_was_set is introduced. > > systime_was_set will be true, if a persistent clock sets the time at boot, > or if do_settimeofday() is called (e.g. by the RTC subsystem or userspace). > > Signed-off-by: Alexander Holler <holler@ahsoftware.de> > --- > include/linux/time.h | 6 ++++++ > kernel/time/timekeeping.c | 10 +++++++++- > 2 files changed, 15 insertions(+), 1 deletion(-) > > diff --git a/include/linux/time.h b/include/linux/time.h > index d5d229b..888280f 100644 > --- a/include/linux/time.h > +++ b/include/linux/time.h > @@ -129,6 +129,12 @@ extern int update_persistent_clock(struct timespec now); > void timekeeping_init(void); > extern int timekeeping_suspended; > > +/* > + * Will be true if the system time was set at least once by > + * a persistent clock, RTC or userspace. > + */ > +extern bool systime_was_set; > + Probably should make this static to timekeeping.c and create an accessor function so you don't have to export locking rules on this. > unsigned long get_seconds(void); > struct timespec current_kernel_time(void); > struct timespec __current_kernel_time(void); /* does not take xtime_lock */ > diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c > index baeeb5c..07d8531 100644 > --- a/kernel/time/timekeeping.c > +++ b/kernel/time/timekeeping.c > @@ -37,6 +37,9 @@ int __read_mostly timekeeping_suspended; > /* Flag for if there is a persistent clock on this platform */ > bool __read_mostly persistent_clock_exist = false; > > +/* Flag for if the system time was set at least once */ > +bool __read_mostly systime_was_set; > + Probably should also move this to be part of the timekeeper structure (since it will be protected by the timekeeper lock. > static inline void tk_normalize_xtime(struct timekeeper *tk) > { > while (tk->xtime_nsec >= ((u64)NSEC_PER_SEC << tk->shift)) { > @@ -498,6 +501,9 @@ int do_settimeofday(const struct timespec *tv) > raw_spin_lock_irqsave(&timekeeper_lock, flags); > write_seqcount_begin(&timekeeper_seq); > > + systime_was_set = true; > + > + > timekeeping_forward_now(tk); > > xt = tk_xtime(tk); Might also want to add the flag to inject_offset as well, since that could be used to set the time. thanks -john ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [rtc-linux] Re: [PATCH 4/9 RESEND] RFC: timekeeping: introduce flag systime_was_set 2013-06-14 17:41 ` John Stultz @ 2013-06-14 18:05 ` Alexander Holler 2013-06-14 18:28 ` John Stultz 0 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-06-14 18:05 UTC (permalink / raw) To: rtc-linux Cc: John Stultz, linux-kernel, Andrew Morton, Thomas Gleixner, Alessandro Zummo Am 14.06.2013 19:41, schrieb John Stultz: > On 06/14/2013 09:52 AM, Alexander Holler wrote: >> In order to let an RTC set the time at boot without the problem that a >> second RTC overwrites it, the flag systime_was_set is introduced. >> >> systime_was_set will be true, if a persistent clock sets the time at >> boot, >> or if do_settimeofday() is called (e.g. by the RTC subsystem or >> userspace). >> >> Signed-off-by: Alexander Holler <holler@ahsoftware.de> >> --- >> include/linux/time.h | 6 ++++++ >> kernel/time/timekeeping.c | 10 +++++++++- >> 2 files changed, 15 insertions(+), 1 deletion(-) >> >> diff --git a/include/linux/time.h b/include/linux/time.h >> index d5d229b..888280f 100644 >> --- a/include/linux/time.h >> +++ b/include/linux/time.h >> @@ -129,6 +129,12 @@ extern int update_persistent_clock(struct >> timespec now); >> void timekeeping_init(void); >> extern int timekeeping_suspended; >> +/* >> + * Will be true if the system time was set at least once by >> + * a persistent clock, RTC or userspace. >> + */ >> +extern bool systime_was_set; >> + > > Probably should make this static to timekeeping.c and create an accessor > function so you don't have to export locking rules on this. > > >> unsigned long get_seconds(void); >> struct timespec current_kernel_time(void); >> struct timespec __current_kernel_time(void); /* does not take >> xtime_lock */ >> diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c >> index baeeb5c..07d8531 100644 >> --- a/kernel/time/timekeeping.c >> +++ b/kernel/time/timekeeping.c >> @@ -37,6 +37,9 @@ int __read_mostly timekeeping_suspended; >> /* Flag for if there is a persistent clock on this platform */ >> bool __read_mostly persistent_clock_exist = false; >> +/* Flag for if the system time was set at least once */ >> +bool __read_mostly systime_was_set; >> + > Probably should also move this to be part of the timekeeper structure > (since it will be protected by the timekeeper lock. > I wanted to avoid locks for this silly flag at all. It is only set once at boot (and resume) and set to 0 at suspend. And I don't see any possible race condition which could make a lock necessary. Therefor I've decided to not use a lock or atomic_* in order to skip any delay in setting the time. Of course, I might be wrong and there might be a use case where multiple things do set the system time concurrently and nothing else did set system time before, but I found that extremly unlikely. >> static inline void tk_normalize_xtime(struct timekeeper *tk) >> { >> while (tk->xtime_nsec >= ((u64)NSEC_PER_SEC << tk->shift)) { >> @@ -498,6 +501,9 @@ int do_settimeofday(const struct timespec *tv) >> raw_spin_lock_irqsave(&timekeeper_lock, flags); >> write_seqcount_begin(&timekeeper_seq); >> + systime_was_set = true; >> + >> + >> timekeeping_forward_now(tk); >> xt = tk_xtime(tk); > > Might also want to add the flag to inject_offset as well, since that > could be used to set the time. I wasn't sure about that because I had only a quick look at inject_offset() and had the impression it's only able to inject a relative small offset (so not usable at boot). And, as written sometimes before, I haven't had a deep look at suspend/resume, which might be the only place where it is really used to set the clock when systime_was_set is false. Regards, Alexander ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [rtc-linux] Re: [PATCH 4/9 RESEND] RFC: timekeeping: introduce flag systime_was_set 2013-06-14 18:05 ` [rtc-linux] " Alexander Holler @ 2013-06-14 18:28 ` John Stultz 2013-06-15 6:01 ` Alexander Holler 0 siblings, 1 reply; 78+ messages in thread From: John Stultz @ 2013-06-14 18:28 UTC (permalink / raw) To: Alexander Holler Cc: rtc-linux, linux-kernel, Andrew Morton, Thomas Gleixner, Alessandro Zummo On 06/14/2013 11:05 AM, Alexander Holler wrote: > Am 14.06.2013 19:41, schrieb John Stultz: >> On 06/14/2013 09:52 AM, Alexander Holler wrote: >>> In order to let an RTC set the time at boot without the problem that a >>> second RTC overwrites it, the flag systime_was_set is introduced. >>> >>> systime_was_set will be true, if a persistent clock sets the time at >>> boot, >>> or if do_settimeofday() is called (e.g. by the RTC subsystem or >>> userspace). >>> >>> Signed-off-by: Alexander Holler <holler@ahsoftware.de> >>> --- >>> include/linux/time.h | 6 ++++++ >>> kernel/time/timekeeping.c | 10 +++++++++- >>> 2 files changed, 15 insertions(+), 1 deletion(-) >>> >>> diff --git a/include/linux/time.h b/include/linux/time.h >>> index d5d229b..888280f 100644 >>> --- a/include/linux/time.h >>> +++ b/include/linux/time.h >>> @@ -129,6 +129,12 @@ extern int update_persistent_clock(struct >>> timespec now); >>> void timekeeping_init(void); >>> extern int timekeeping_suspended; >>> +/* >>> + * Will be true if the system time was set at least once by >>> + * a persistent clock, RTC or userspace. >>> + */ >>> +extern bool systime_was_set; >>> + >> >> Probably should make this static to timekeeping.c and create an accessor >> function so you don't have to export locking rules on this. >> >> >>> unsigned long get_seconds(void); >>> struct timespec current_kernel_time(void); >>> struct timespec __current_kernel_time(void); /* does not take >>> xtime_lock */ >>> diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c >>> index baeeb5c..07d8531 100644 >>> --- a/kernel/time/timekeeping.c >>> +++ b/kernel/time/timekeeping.c >>> @@ -37,6 +37,9 @@ int __read_mostly timekeeping_suspended; >>> /* Flag for if there is a persistent clock on this platform */ >>> bool __read_mostly persistent_clock_exist = false; >>> +/* Flag for if the system time was set at least once */ >>> +bool __read_mostly systime_was_set; >>> + >> Probably should also move this to be part of the timekeeper structure >> (since it will be protected by the timekeeper lock. >> > > I wanted to avoid locks for this silly flag at all. It is only set > once at boot (and resume) and set to 0 at suspend. And I don't see any > possible race condition which could make a lock necessary. Therefor > I've decided to not use a lock or atomic_* in order to skip any delay > in setting the time. Even so, having random flag variables with special rules being exported out is likely to cause eventual trouble (someone will mis-use or overload some meaning on it). So at least providing a accessor function for non-timekeeping.c uses would be good. > Of course, I might be wrong and there might be a use case where > multiple things do set the system time concurrently and nothing else > did set system time before, but I found that extremly unlikely. Yea, the condition check and the action won't be both be done under a lock, so its likely going to be racy anyway. >>> static inline void tk_normalize_xtime(struct timekeeper *tk) >>> { >>> while (tk->xtime_nsec >= ((u64)NSEC_PER_SEC << tk->shift)) { >>> @@ -498,6 +501,9 @@ int do_settimeofday(const struct timespec *tv) >>> raw_spin_lock_irqsave(&timekeeper_lock, flags); >>> write_seqcount_begin(&timekeeper_seq); >>> + systime_was_set = true; >>> + >>> + >>> timekeeping_forward_now(tk); >>> xt = tk_xtime(tk); >> >> Might also want to add the flag to inject_offset as well, since that >> could be used to set the time. > > I wasn't sure about that because I had only a quick look at > inject_offset() and had the impression it's only able to inject a > relative small offset (so not usable at boot). And, as written > sometimes before, I haven't had a deep look at suspend/resume, which > might be the only place where it is really used to set the clock when > systime_was_set is false. Not via suspend/resume, since those modify the boottime to account for the sleep time that has past. I'm thinking via adjtimex ADJ_SETOFFSET (which is relatively new, and not widely used). See the do_adjtimex() path in timekeeping.c thanks -john ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [rtc-linux] Re: [PATCH 4/9 RESEND] RFC: timekeeping: introduce flag systime_was_set 2013-06-14 18:28 ` John Stultz @ 2013-06-15 6:01 ` Alexander Holler 2013-06-17 18:10 ` John Stultz 0 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-06-15 6:01 UTC (permalink / raw) To: John Stultz Cc: rtc-linux, linux-kernel, Andrew Morton, Thomas Gleixner, Alessandro Zummo Am 14.06.2013 20:28, schrieb John Stultz: > On 06/14/2013 11:05 AM, Alexander Holler wrote: >> Am 14.06.2013 19:41, schrieb John Stultz: >>> On 06/14/2013 09:52 AM, Alexander Holler wrote: >>>> In order to let an RTC set the time at boot without the problem that a >>>> second RTC overwrites it, the flag systime_was_set is introduced. >>>> >>>> systime_was_set will be true, if a persistent clock sets the time at >>>> boot, >>>> or if do_settimeofday() is called (e.g. by the RTC subsystem or >>>> userspace). >>>> >>>> Signed-off-by: Alexander Holler <holler@ahsoftware.de> >>>> --- >>>> include/linux/time.h | 6 ++++++ >>>> kernel/time/timekeeping.c | 10 +++++++++- >>>> 2 files changed, 15 insertions(+), 1 deletion(-) >>>> >>>> diff --git a/include/linux/time.h b/include/linux/time.h >>>> index d5d229b..888280f 100644 >>>> --- a/include/linux/time.h >>>> +++ b/include/linux/time.h >>>> @@ -129,6 +129,12 @@ extern int update_persistent_clock(struct >>>> timespec now); >>>> void timekeeping_init(void); >>>> extern int timekeeping_suspended; >>>> +/* >>>> + * Will be true if the system time was set at least once by >>>> + * a persistent clock, RTC or userspace. >>>> + */ >>>> +extern bool systime_was_set; >>>> + >>> >>> Probably should make this static to timekeeping.c and create an accessor >>> function so you don't have to export locking rules on this. >>> >>> >>>> unsigned long get_seconds(void); >>>> struct timespec current_kernel_time(void); >>>> struct timespec __current_kernel_time(void); /* does not take >>>> xtime_lock */ >>>> diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c >>>> index baeeb5c..07d8531 100644 >>>> --- a/kernel/time/timekeeping.c >>>> +++ b/kernel/time/timekeeping.c >>>> @@ -37,6 +37,9 @@ int __read_mostly timekeeping_suspended; >>>> /* Flag for if there is a persistent clock on this platform */ >>>> bool __read_mostly persistent_clock_exist = false; >>>> +/* Flag for if the system time was set at least once */ >>>> +bool __read_mostly systime_was_set; >>>> + >>> Probably should also move this to be part of the timekeeper structure >>> (since it will be protected by the timekeeper lock. >>> >> >> I wanted to avoid locks for this silly flag at all. It is only set >> once at boot (and resume) and set to 0 at suspend. And I don't see any >> possible race condition which could make a lock necessary. Therefor >> I've decided to not use a lock or atomic_* in order to skip any delay >> in setting the time. > > Even so, having random flag variables with special rules being exported > out is likely to cause eventual trouble (someone will mis-use or > overload some meaning on it). > > So at least providing a accessor function for non-timekeeping.c uses > would be good. It's rather hard to misuse a bool (even if a bool in C is just a define). What do you think I should write? void set_systime_was_set(void) and void clear_systime_was_set(void)? And both functions would have to be exported in order to be usable from modules? Or do you think I should write something like that: extern bool foo; inline void set_foo(void) { foo = true}; inline void clear_foo(void) { foo = false }; That's just silly, sorry to call it such. So now I'm unsure if I'm able to continue work on this series. I seem to be unable to think and code like maintainers do want I should think and code, whatever that might be. >> Of course, I might be wrong and there might be a use case where >> multiple things do set the system time concurrently and nothing else >> did set system time before, but I found that extremly unlikely. > > Yea, the condition check and the action won't be both be done under a > lock, so its likely going to be racy anyway. And if there ever will be a race for the first timesource to set this flag (the first time), and something does care about the outtake, the system would be completly broken. In order to keep it simple, I just tread userspace like a RTC of type X and will call them all timesources of type x where a the type is defined by the driver. Let us go through the possible cases: - 2 or more timesources of different type: If the order is undefined and they have to race for which clock might be used for hctosys (and thus for adjusting the time after resume too), the only reason one would want such is for HA purposes. And in case of HA, both clocks must have the same time, so nobody does care about which one will win the race (=> no race, no lock or atomic_* needed). If the purpose isn't for HA and someone does care about which timesource should be used, the way to do this is to use hctosys=type (or hctosys=none in case of userspace) to define which timesource should be used for hctosys (=> no race, no lock or atomic_* needed). - 2 or more timesources of the same type: There is no possibility to define which one should win the race. Such a system configuration is only usable for HA purposes, so if such exists, nobody cares about the outtake of the race (=> no race, no lock or atomic_* needed). Regards, Alexander Holler ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [rtc-linux] Re: [PATCH 4/9 RESEND] RFC: timekeeping: introduce flag systime_was_set 2013-06-15 6:01 ` Alexander Holler @ 2013-06-17 18:10 ` John Stultz 2013-06-20 10:15 ` Alexander Holler 0 siblings, 1 reply; 78+ messages in thread From: John Stultz @ 2013-06-17 18:10 UTC (permalink / raw) To: Alexander Holler Cc: rtc-linux, linux-kernel, Andrew Morton, Thomas Gleixner, Alessandro Zummo On 06/14/2013 11:01 PM, Alexander Holler wrote: > Am 14.06.2013 20:28, schrieb John Stultz: >> On 06/14/2013 11:05 AM, Alexander Holler wrote: >>> Am 14.06.2013 19:41, schrieb John Stultz: >>>> On 06/14/2013 09:52 AM, Alexander Holler wrote: >>>>> In order to let an RTC set the time at boot without the problem >>>>> that a >>>>> second RTC overwrites it, the flag systime_was_set is introduced. >>>>> >>>>> systime_was_set will be true, if a persistent clock sets the time at >>>>> boot, >>>>> or if do_settimeofday() is called (e.g. by the RTC subsystem or >>>>> userspace). >>>>> >>>>> Signed-off-by: Alexander Holler <holler@ahsoftware.de> >>>>> --- >>>>> include/linux/time.h | 6 ++++++ >>>>> kernel/time/timekeeping.c | 10 +++++++++- >>>>> 2 files changed, 15 insertions(+), 1 deletion(-) >>>>> >>>>> diff --git a/include/linux/time.h b/include/linux/time.h >>>>> index d5d229b..888280f 100644 >>>>> --- a/include/linux/time.h >>>>> +++ b/include/linux/time.h >>>>> @@ -129,6 +129,12 @@ extern int update_persistent_clock(struct >>>>> timespec now); >>>>> void timekeeping_init(void); >>>>> extern int timekeeping_suspended; >>>>> +/* >>>>> + * Will be true if the system time was set at least once by >>>>> + * a persistent clock, RTC or userspace. >>>>> + */ >>>>> +extern bool systime_was_set; >>>>> + >>>> >>>> Probably should make this static to timekeeping.c and create an >>>> accessor >>>> function so you don't have to export locking rules on this. >>>> >>>> >>>>> unsigned long get_seconds(void); >>>>> struct timespec current_kernel_time(void); >>>>> struct timespec __current_kernel_time(void); /* does not take >>>>> xtime_lock */ >>>>> diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c >>>>> index baeeb5c..07d8531 100644 >>>>> --- a/kernel/time/timekeeping.c >>>>> +++ b/kernel/time/timekeeping.c >>>>> @@ -37,6 +37,9 @@ int __read_mostly timekeeping_suspended; >>>>> /* Flag for if there is a persistent clock on this platform */ >>>>> bool __read_mostly persistent_clock_exist = false; >>>>> +/* Flag for if the system time was set at least once */ >>>>> +bool __read_mostly systime_was_set; >>>>> + >>>> Probably should also move this to be part of the timekeeper structure >>>> (since it will be protected by the timekeeper lock. >>>> >>> >>> I wanted to avoid locks for this silly flag at all. It is only set >>> once at boot (and resume) and set to 0 at suspend. And I don't see any >>> possible race condition which could make a lock necessary. Therefor >>> I've decided to not use a lock or atomic_* in order to skip any delay >>> in setting the time. >> >> Even so, having random flag variables with special rules being exported >> out is likely to cause eventual trouble (someone will mis-use or >> overload some meaning on it). >> >> So at least providing a accessor function for non-timekeeping.c uses >> would be good. > > > It's rather hard to misuse a bool (even if a bool in C is just a define). I'm trying to avoid allowing non-timekeeping users of the value to be able to set it. By putting the value behind a timekeeping_systime_was_set() accessor, and making the boolean value static, we can make sure its properly managed by the timekeeping code alone. > What do you think I should write? > > void set_systime_was_set(void) and void clear_systime_was_set(void)? > > And both functions would have to be exported in order to be usable > from modules? > > Or do you think I should write something like that: > > extern bool foo; > inline void set_foo(void) { foo = true}; > inline void clear_foo(void) { foo = false }; > > That's just silly, sorry to call it such. No no. I'm only asking that the boolean be static to timekeeping.c and an accessor function be used to read it. Since the timekeeping core should be managing this value, there should be no reason for any other users to be setting or clearing the value. >>> Of course, I might be wrong and there might be a use case where >>> multiple things do set the system time concurrently and nothing else >>> did set system time before, but I found that extremly unlikely. >> >> Yea, the condition check and the action won't be both be done under a >> lock, so its likely going to be racy anyway. > > And if there ever will be a race for the first timesource to set this > flag (the first time), and something does care about the outtake, the > system would be completly broken. > > In order to keep it simple, I just tread userspace like a RTC of type > X and will call them all timesources of type x where a the type is > defined by the driver. > > Let us go through the possible cases: > > - 2 or more timesources of different type: > > If the order is undefined and they have to race for which clock might > be used for hctosys (and thus for adjusting the time after resume > too), the only reason one would want such is for HA purposes. And in > case of HA, both clocks must have the same time, so nobody does care > about which one will win the race (=> no race, no lock or atomic_* > needed). > > If the purpose isn't for HA and someone does care about which > timesource should be used, the way to do this is to use hctosys=type > (or hctosys=none in case of userspace) to define which timesource > should be used for hctosys (=> no race, no lock or atomic_* needed). > > - 2 or more timesources of the same type: > There is no possibility to define which one should win the race. Such > a system configuration is only usable for HA purposes, so if such > exists, nobody cares about the outtake of the race (=> no race, no > lock or atomic_* needed). > The race I'm thinking of is you have a system that normally sets the time via ntpdate at bootup. Thus they expect the system to always be started w/ NTP time (even if the system time was initially set via hctosys). Then because of of some delay in the driver (or because the RTC device was plugged in during boot), the hctosys functionality runs just as ntpdate is being called. hctosys sees time has not yet been set and reads the RTC hardware time. At this point, ntpdate sets the time to NTP time. Then hctosys completes, setting the time to the RTC time. This results in the system clock being wrong from the user's perspective (as they expect it to be set to NTP time). This is basically what this code is trying to avoid in the first place. And I'll grant that its a small race window, but it may lead to irregular behavior. So either we need to document that this race is theoretically possible, and explain *why* its safe to ignore it. Or if we really want to do something like this properly, we need to drop the accessor function to the boolean, and instead provide a special timekeeping_set_time_if_unset() (with hopefully a better name then what I just came up with ;) function which checks the boolean and sets the clock all while holding the same lock. That way we really can be sure that if userland sets the time, we don't accidentally over-write that time. thanks -john ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [rtc-linux] Re: [PATCH 4/9 RESEND] RFC: timekeeping: introduce flag systime_was_set 2013-06-17 18:10 ` John Stultz @ 2013-06-20 10:15 ` Alexander Holler 2013-06-20 17:27 ` John Stultz 0 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-06-20 10:15 UTC (permalink / raw) To: John Stultz Cc: rtc-linux, linux-kernel, Andrew Morton, Thomas Gleixner, Alessandro Zummo Am 17.06.2013 20:10, schrieb John Stultz: > On 06/14/2013 11:01 PM, Alexander Holler wrote: >> Am 14.06.2013 20:28, schrieb John Stultz: >>> On 06/14/2013 11:05 AM, Alexander Holler wrote: >>>> Am 14.06.2013 19:41, schrieb John Stultz: >>>>> On 06/14/2013 09:52 AM, Alexander Holler wrote: >>>>>> In order to let an RTC set the time at boot without the problem >>>>>> that a >>>>>> second RTC overwrites it, the flag systime_was_set is introduced. >>>>>> >>>>>> systime_was_set will be true, if a persistent clock sets the time at >>>>>> boot, >>>>>> or if do_settimeofday() is called (e.g. by the RTC subsystem or >>>>>> userspace). >>>>>> >>>>>> Signed-off-by: Alexander Holler <holler@ahsoftware.de> >>>>>> --- >>>>>> include/linux/time.h | 6 ++++++ >>>>>> kernel/time/timekeeping.c | 10 +++++++++- >>>>>> 2 files changed, 15 insertions(+), 1 deletion(-) >>>>>> >>>>>> diff --git a/include/linux/time.h b/include/linux/time.h >>>>>> index d5d229b..888280f 100644 >>>>>> --- a/include/linux/time.h >>>>>> +++ b/include/linux/time.h >>>>>> @@ -129,6 +129,12 @@ extern int update_persistent_clock(struct >>>>>> timespec now); >>>>>> void timekeeping_init(void); >>>>>> extern int timekeeping_suspended; >>>>>> +/* >>>>>> + * Will be true if the system time was set at least once by >>>>>> + * a persistent clock, RTC or userspace. >>>>>> + */ >>>>>> +extern bool systime_was_set; >>>>>> + >>>>> >>>>> Probably should make this static to timekeeping.c and create an >>>>> accessor >>>>> function so you don't have to export locking rules on this. >>>>> >>>>> >>>>>> unsigned long get_seconds(void); >>>>>> struct timespec current_kernel_time(void); >>>>>> struct timespec __current_kernel_time(void); /* does not take >>>>>> xtime_lock */ >>>>>> diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c >>>>>> index baeeb5c..07d8531 100644 >>>>>> --- a/kernel/time/timekeeping.c >>>>>> +++ b/kernel/time/timekeeping.c >>>>>> @@ -37,6 +37,9 @@ int __read_mostly timekeeping_suspended; >>>>>> /* Flag for if there is a persistent clock on this platform */ >>>>>> bool __read_mostly persistent_clock_exist = false; >>>>>> +/* Flag for if the system time was set at least once */ >>>>>> +bool __read_mostly systime_was_set; >>>>>> + >>>>> Probably should also move this to be part of the timekeeper structure >>>>> (since it will be protected by the timekeeper lock. >>>>> >>>> >>>> I wanted to avoid locks for this silly flag at all. It is only set >>>> once at boot (and resume) and set to 0 at suspend. And I don't see any >>>> possible race condition which could make a lock necessary. Therefor >>>> I've decided to not use a lock or atomic_* in order to skip any delay >>>> in setting the time. >>> >>> Even so, having random flag variables with special rules being exported >>> out is likely to cause eventual trouble (someone will mis-use or >>> overload some meaning on it). >>> >>> So at least providing a accessor function for non-timekeeping.c uses >>> would be good. >> >> >> It's rather hard to misuse a bool (even if a bool in C is just a define). > > I'm trying to avoid allowing non-timekeeping users of the value to be > able to set it. > By putting the value behind a timekeeping_systime_was_set() accessor, > and making the boolean value static, we can make sure its properly > managed by the timekeeping code alone. > >> What do you think I should write? >> >> void set_systime_was_set(void) and void clear_systime_was_set(void)? >> >> And both functions would have to be exported in order to be usable >> from modules? >> >> Or do you think I should write something like that: >> >> extern bool foo; >> inline void set_foo(void) { foo = true}; >> inline void clear_foo(void) { foo = false }; >> >> That's just silly, sorry to call it such. > > No no. I'm only asking that the boolean be static to timekeeping.c and > an accessor function be used to read it. Since the timekeeping core > should be managing this value, there should be no reason for any other > users to be setting or clearing the value. First you can't make the value static (semantically) because it has to be set and cleared from different parts of the kernel. And adding accessor functions doesn't help in any way, everyone will still be able to set or clear the value (this still is C and no C++ with classes or other encapsulation features). The only thing what will happen with such an accessor function is that a small overhead through the then necessary function call is introduced. > > >>>> Of course, I might be wrong and there might be a use case where >>>> multiple things do set the system time concurrently and nothing else >>>> did set system time before, but I found that extremly unlikely. >>> >>> Yea, the condition check and the action won't be both be done under a >>> lock, so its likely going to be racy anyway. >> >> And if there ever will be a race for the first timesource to set this >> flag (the first time), and something does care about the outtake, the >> system would be completly broken. >> >> In order to keep it simple, I just tread userspace like a RTC of type >> X and will call them all timesources of type x where a the type is >> defined by the driver. >> >> Let us go through the possible cases: >> >> - 2 or more timesources of different type: >> >> If the order is undefined and they have to race for which clock might >> be used for hctosys (and thus for adjusting the time after resume >> too), the only reason one would want such is for HA purposes. And in >> case of HA, both clocks must have the same time, so nobody does care >> about which one will win the race (=> no race, no lock or atomic_* >> needed). >> >> If the purpose isn't for HA and someone does care about which >> timesource should be used, the way to do this is to use hctosys=type >> (or hctosys=none in case of userspace) to define which timesource >> should be used for hctosys (=> no race, no lock or atomic_* needed). >> >> - 2 or more timesources of the same type: >> There is no possibility to define which one should win the race. Such >> a system configuration is only usable for HA purposes, so if such >> exists, nobody cares about the outtake of the race (=> no race, no >> lock or atomic_* needed). >> > > The race I'm thinking of is you have a system that normally sets the > time via ntpdate at bootup. Thus they expect the system to always be > started w/ NTP time (even if the system time was initially set via > hctosys). > > Then because of of some delay in the driver (or because the RTC device > was plugged in during boot), the hctosys functionality runs just as > ntpdate is being called. hctosys sees time has not yet been set and > reads the RTC hardware time. At this point, ntpdate sets the time to NTP > time. Then hctosys completes, setting the time to the RTC time. This > results in the system clock being wrong from the user's perspective (as > they expect it to be set to NTP time). Therefor there now will be hctosys as a kernel command line parameter. Instead of a kernel config option which can't be changed by 99% of all Linux users, that option allows ordinary (non kernel compiling) users to disable hctosys at all. Something which wasn't possible before without recompiling the kernel. And, like before, most RTC drivers will be loaded before userspace calls ntp/ntpdate. If not, the system is already broken. And just in case, I've made that possible window for the above race very small by checking the flag systime_was_set twice, once before starting to read the time and a second time right before the time is set. Ok, the race is still there, but as said before, if that problem does exist at all, the system would be setup wrong at all. > > This is basically what this code is trying to avoid in the first place. > And I'll grant that its a small race window, but it may lead to > irregular behavior. > > So either we need to document that this race is theoretically possible, > and explain *why* its safe to ignore it. Or if we really want to do I would think that documenting hctosys=none should be enough. All systems I've seen do load modules very early (before they would start anything ntp related). And the new hctosys is done inside the registration of the RTC. So if a system is configured in such a way that the race really might happen, the system would be broken because the RTC would not be there when starting ntp. To conclude, I think the problem is highly academic/artificial and, if possible at all, only possible on already misconfigured systems during a very, very small window. Therfor I still believe that no locking mechanism is needed. Anyway, I don't care, if you want, I will make an accessor-function with locks and an return code for "set" to indicate if it was already set. We could also request and wait for a third opinion on that topic. As it most likely will not end up in any kernel before the end of this year (if at all), there is enough time to do so. Regards, Alexander Holler ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [rtc-linux] Re: [PATCH 4/9 RESEND] RFC: timekeeping: introduce flag systime_was_set 2013-06-20 10:15 ` Alexander Holler @ 2013-06-20 17:27 ` John Stultz 2013-06-20 18:45 ` Alexander Holler 0 siblings, 1 reply; 78+ messages in thread From: John Stultz @ 2013-06-20 17:27 UTC (permalink / raw) To: Alexander Holler Cc: rtc-linux, linux-kernel, Andrew Morton, Thomas Gleixner, Alessandro Zummo On 06/20/2013 03:15 AM, Alexander Holler wrote: > Am 17.06.2013 20:10, schrieb John Stultz: >> On 06/14/2013 11:01 PM, Alexander Holler wrote: >> >>> What do you think I should write? >>> >>> void set_systime_was_set(void) and void clear_systime_was_set(void)? >>> >>> And both functions would have to be exported in order to be usable >>> from modules? >>> >>> Or do you think I should write something like that: >>> >>> extern bool foo; >>> inline void set_foo(void) { foo = true}; >>> inline void clear_foo(void) { foo = false }; >>> >>> That's just silly, sorry to call it such. >> >> No no. I'm only asking that the boolean be static to timekeeping.c and >> an accessor function be used to read it. Since the timekeeping core >> should be managing this value, there should be no reason for any other >> users to be setting or clearing the value. > > First you can't make the value static (semantically) because it has to > be set and cleared from different parts of the kernel. And adding > accessor functions doesn't help in any way, everyone will still be > able to set or clear the value (this still is C and no C++ with > classes or other encapsulation features). The only thing what will > happen with such an accessor function is that a small overhead through > the then necessary function call is introduced. Why would it be set and cleared from different parts of the kernel? We're checking if the system time was set. The system time can be set only from a limited number functions in timekeeping.c. It seems reasonable it should be static to timekeeping.c Even so, this is all a tangent. I really think the flag value is racy and should be dropped for a timekeeping_setime_if_not_set() - or better named - function that can act atomically. >> >>>>> Of course, I might be wrong and there might be a use case where >>>>> multiple things do set the system time concurrently and nothing else >>>>> did set system time before, but I found that extremly unlikely. >>>> >>>> Yea, the condition check and the action won't be both be done under a >>>> lock, so its likely going to be racy anyway. >>> >>> And if there ever will be a race for the first timesource to set this >>> flag (the first time), and something does care about the outtake, the >>> system would be completly broken. >>> >>> In order to keep it simple, I just tread userspace like a RTC of type >>> X and will call them all timesources of type x where a the type is >>> defined by the driver. >>> >>> Let us go through the possible cases: >>> >>> - 2 or more timesources of different type: >>> >>> If the order is undefined and they have to race for which clock might >>> be used for hctosys (and thus for adjusting the time after resume >>> too), the only reason one would want such is for HA purposes. And in >>> case of HA, both clocks must have the same time, so nobody does care >>> about which one will win the race (=> no race, no lock or atomic_* >>> needed). >>> >>> If the purpose isn't for HA and someone does care about which >>> timesource should be used, the way to do this is to use hctosys=type >>> (or hctosys=none in case of userspace) to define which timesource >>> should be used for hctosys (=> no race, no lock or atomic_* needed). >>> >>> - 2 or more timesources of the same type: >>> There is no possibility to define which one should win the race. Such >>> a system configuration is only usable for HA purposes, so if such >>> exists, nobody cares about the outtake of the race (=> no race, no >>> lock or atomic_* needed). >>> >> >> The race I'm thinking of is you have a system that normally sets the >> time via ntpdate at bootup. Thus they expect the system to always be >> started w/ NTP time (even if the system time was initially set via >> hctosys). >> >> Then because of of some delay in the driver (or because the RTC device >> was plugged in during boot), the hctosys functionality runs just as >> ntpdate is being called. hctosys sees time has not yet been set and >> reads the RTC hardware time. At this point, ntpdate sets the time to NTP >> time. Then hctosys completes, setting the time to the RTC time. This >> results in the system clock being wrong from the user's perspective (as >> they expect it to be set to NTP time). > > Therefor there now will be hctosys as a kernel command line parameter. > Instead of a kernel config option which can't be changed by 99% of all > Linux users, that option allows ordinary (non kernel compiling) users > to disable hctosys at all. I agree your suggestion of having a hctosys= boot option (to override the CONFIG_HCTOSYS_DEVICE value) could be a useful extension. But we shouldn't expect users to set magic boot flags in order to have a reliably functioning system. If userland sets the time during init, and the hctosys functionality isn't supposed to overwrite that value, then there should be no case where userland sets the time at boot, but we end up with the RTC time after boot. But currently that race is possible (though small). A more concrete case: On many distros ntpd isn't installed by default. Instead they leave the kernel to initialize the time from the RTC. But ntpd can be installed afterwards, and it would be silly to require users edit their boot arguments when installing the ntp package. > Something which wasn't possible before without recompiling the kernel. > And, like before, most RTC drivers will be loaded before userspace > calls ntp/ntpdate. If not, the system is already broken. I'm not sure I'm following how the system is already broken? > And just in case, I've made that possible window for the above race > very small by checking the flag systime_was_set twice, once before > starting to read the time and a second time right before the time is > set. Ok, the race is still there, but as said before, if that problem > does exist at all, the system would be setup wrong at all. It just seems that if we really want a to do this, we might as well do it right, using the timekeeping_settime_first() or whatever function that can properly check the value and complete the action atomically while holding the lock. >> >> This is basically what this code is trying to avoid in the first place. >> And I'll grant that its a small race window, but it may lead to >> irregular behavior. >> >> So either we need to document that this race is theoretically possible, >> and explain *why* its safe to ignore it. Or if we really want to do > > I would think that documenting hctosys=none should be enough. Again, I don't think users who install ntpd should have to also change their boot parameters. > All systems I've seen do load modules very early (before they would > start anything ntp related). And the new hctosys is done inside the > registration of the RTC. So if a system is configured in such a way > that the race really might happen, the system would be broken because > the RTC would not be there when starting ntp. To conclude, I think the > problem is highly academic/artificial and, if possible at all, only > possible on already misconfigured systems during a very, very small > window. Therfor I still believe that no locking mechanism is needed. > > Anyway, I don't care, if you want, I will make an accessor-function > with locks and an return code for "set" to indicate if it was already > set. Sorry if I'm frustrating you here, that's not my intent. > > We could also request and wait for a third opinion on that topic. As > it most likely will not end up in any kernel before the end of this > year (if at all), there is enough time to do so. > I'm in no rush. I think the changes you're proposing are interesting and novel cases that we should handle. But I also do think we should do it properly, especially since its relatively easy to do in this case. thanks -john ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [rtc-linux] Re: [PATCH 4/9 RESEND] RFC: timekeeping: introduce flag systime_was_set 2013-06-20 17:27 ` John Stultz @ 2013-06-20 18:45 ` Alexander Holler 2013-06-20 19:28 ` John Stultz 0 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-06-20 18:45 UTC (permalink / raw) To: John Stultz Cc: rtc-linux, linux-kernel, Andrew Morton, Thomas Gleixner, Alessandro Zummo Am 20.06.2013 19:27, schrieb John Stultz: > On 06/20/2013 03:15 AM, Alexander Holler wrote: >> Am 17.06.2013 20:10, schrieb John Stultz: >>> On 06/14/2013 11:01 PM, Alexander Holler wrote: >>> >>>> What do you think I should write? >>>> >>>> void set_systime_was_set(void) and void clear_systime_was_set(void)? >>>> >>>> And both functions would have to be exported in order to be usable >>>> from modules? >>>> >>>> Or do you think I should write something like that: >>>> >>>> extern bool foo; >>>> inline void set_foo(void) { foo = true}; >>>> inline void clear_foo(void) { foo = false }; >>>> >>>> That's just silly, sorry to call it such. >>> >>> No no. I'm only asking that the boolean be static to timekeeping.c and >>> an accessor function be used to read it. Since the timekeeping core >>> should be managing this value, there should be no reason for any other >>> users to be setting or clearing the value. >> >> First you can't make the value static (semantically) because it has to >> be set and cleared from different parts of the kernel. And adding >> accessor functions doesn't help in any way, everyone will still be >> able to set or clear the value (this still is C and no C++ with >> classes or other encapsulation features). The only thing what will >> happen with such an accessor function is that a small overhead through >> the then necessary function call is introduced. > > > > > Why would it be set and cleared from different parts of the kernel? > > We're checking if the system time was set. The system time can be set > only from a limited number functions in timekeeping.c. It seems > reasonable it should be static to timekeeping.c > > Even so, this is all a tangent. I really think the flag value is racy > and should be dropped for a timekeeping_setime_if_not_set() - or better > named - function that can act atomically. > > > > >>> >>>>>> Of course, I might be wrong and there might be a use case where >>>>>> multiple things do set the system time concurrently and nothing else >>>>>> did set system time before, but I found that extremly unlikely. >>>>> >>>>> Yea, the condition check and the action won't be both be done under a >>>>> lock, so its likely going to be racy anyway. >>>> >>>> And if there ever will be a race for the first timesource to set this >>>> flag (the first time), and something does care about the outtake, the >>>> system would be completly broken. >>>> >>>> In order to keep it simple, I just tread userspace like a RTC of type >>>> X and will call them all timesources of type x where a the type is >>>> defined by the driver. >>>> >>>> Let us go through the possible cases: >>>> >>>> - 2 or more timesources of different type: >>>> >>>> If the order is undefined and they have to race for which clock might >>>> be used for hctosys (and thus for adjusting the time after resume >>>> too), the only reason one would want such is for HA purposes. And in >>>> case of HA, both clocks must have the same time, so nobody does care >>>> about which one will win the race (=> no race, no lock or atomic_* >>>> needed). >>>> >>>> If the purpose isn't for HA and someone does care about which >>>> timesource should be used, the way to do this is to use hctosys=type >>>> (or hctosys=none in case of userspace) to define which timesource >>>> should be used for hctosys (=> no race, no lock or atomic_* needed). >>>> >>>> - 2 or more timesources of the same type: >>>> There is no possibility to define which one should win the race. Such >>>> a system configuration is only usable for HA purposes, so if such >>>> exists, nobody cares about the outtake of the race (=> no race, no >>>> lock or atomic_* needed). >>>> >>> >>> The race I'm thinking of is you have a system that normally sets the >>> time via ntpdate at bootup. Thus they expect the system to always be >>> started w/ NTP time (even if the system time was initially set via >>> hctosys). >>> >>> Then because of of some delay in the driver (or because the RTC device >>> was plugged in during boot), the hctosys functionality runs just as >>> ntpdate is being called. hctosys sees time has not yet been set and >>> reads the RTC hardware time. At this point, ntpdate sets the time to NTP >>> time. Then hctosys completes, setting the time to the RTC time. This >>> results in the system clock being wrong from the user's perspective (as >>> they expect it to be set to NTP time). >> >> Therefor there now will be hctosys as a kernel command line parameter. >> Instead of a kernel config option which can't be changed by 99% of all >> Linux users, that option allows ordinary (non kernel compiling) users >> to disable hctosys at all. > > > I agree your suggestion of having a hctosys= boot option (to override > the CONFIG_HCTOSYS_DEVICE value) could be a useful extension. > > But we shouldn't expect users to set magic boot flags in order to have a > reliably functioning system. If userland sets the time during init, and > the hctosys functionality isn't supposed to overwrite that value, then > there should be no case where userland sets the time at boot, but we end > up with the RTC time after boot. But currently that race is possible > (though small). > > A more concrete case: > On many distros ntpd isn't installed by default. Instead they leave the > kernel to initialize the time from the RTC. Which still is done, even earlier with the new hctosys (if a RTC is used instead of a persistent clock). Nothing changed there. And if the persistent clock is used, which is true on almost all x86 systems, the race doesn't exist at all, at least as long as the persistent clock still exists and will be used (instead of rtc-cmos). > > But ntpd can be installed afterwards, and it would be silly to require > users edit their boot arguments when installing the ntp package. > > >> Something which wasn't possible before without recompiling the kernel. >> And, like before, most RTC drivers will be loaded before userspace >> calls ntp/ntpdate. If not, the system is already broken. > > I'm not sure I'm following how the system is already broken? Because it isn't determined what does set the time. The race you've described happens because someone wants to use ntp for the hctosys functionality but he doesn't want it, if the date might come first from a RTC (in case the race window would be even hit). So the configuration is broken because it is non-deterministic while someone wants deterministic. > > >> And just in case, I've made that possible window for the above race >> very small by checking the flag systime_was_set twice, once before >> starting to read the time and a second time right before the time is >> set. Ok, the race is still there, but as said before, if that problem >> does exist at all, the system would be setup wrong at all. > > It just seems that if we really want a to do this, we might as well do > it right, using the timekeeping_settime_first() or whatever function > that can properly check the value and complete the action atomically > while holding the lock. > > >>> >>> This is basically what this code is trying to avoid in the first place. >>> And I'll grant that its a small race window, but it may lead to >>> irregular behavior. >>> >>> So either we need to document that this race is theoretically possible, >>> and explain *why* its safe to ignore it. Or if we really want to do >> >> I would think that documenting hctosys=none should be enough. > > Again, I don't think users who install ntpd should have to also change > their boot parameters. > > >> All systems I've seen do load modules very early (before they would >> start anything ntp related). And the new hctosys is done inside the >> registration of the RTC. So if a system is configured in such a way >> that the race really might happen, the system would be broken because >> the RTC would not be there when starting ntp. To conclude, I think the >> problem is highly academic/artificial and, if possible at all, only >> possible on already misconfigured systems during a very, very small >> window. Therfor I still believe that no locking mechanism is needed. >> >> Anyway, I don't care, if you want, I will make an accessor-function >> with locks and an return code for "set" to indicate if it was already >> set. > > Sorry if I'm frustrating you here, that's not my intent. I'm not frustrated, I'm just annoyed. I don't know why everyone seems to assume that I'm getting frustrated while I just find it totally annoying to invest time to make checkpatch-clean max. 80 chars per line wide patches while having to use 8 chars intendation and meaningfull variable and function names. Besides having to explain and discuss every single line and often get called a fool or similiar. I might become frustrated if I would need to get patches into the mainline kernel, but happily I'm able to manage my own tree of patches and don't have to care if patches from me will end up in the mainline kernel. After all I still find it much less time consuming to fix bugs and add additional functionalities myself instead of just writing bug reports or requesting features. And it becomes easier with every patch I write for subsystem xy. ;) > >> >> We could also request and wait for a third opinion on that topic. As >> it most likely will not end up in any kernel before the end of this >> year (if at all), there is enough time to do so. >> > > I'm in no rush. I think the changes you're proposing are interesting and > novel cases that we should handle. But I also do think we should do it > properly, especially since its relatively easy to do in this case. Anyway, my intention was to avoid locking stuff in the time-setting functions but it looks like that isn't wanted. So I will implement the locking foo, after we finished the discussion about the other parts and I will have come to the impression that I don't write stuff just for nothing. A quick look at your other comments revealed that I have to explain a lot more in order to not get accused that I want to kill the timekeeping system. ;) I will answer the next comment shortly. Regards, Alexander Holler ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [rtc-linux] Re: [PATCH 4/9 RESEND] RFC: timekeeping: introduce flag systime_was_set 2013-06-20 18:45 ` Alexander Holler @ 2013-06-20 19:28 ` John Stultz 2013-06-20 23:10 ` Alexander Holler 0 siblings, 1 reply; 78+ messages in thread From: John Stultz @ 2013-06-20 19:28 UTC (permalink / raw) To: Alexander Holler Cc: rtc-linux, linux-kernel, Andrew Morton, Thomas Gleixner, Alessandro Zummo On 06/20/2013 11:45 AM, Alexander Holler wrote: > Am 20.06.2013 19:27, schrieb John Stultz: >> On 06/20/2013 03:15 AM, Alexander Holler wrote: >>> Therefor there now will be hctosys as a kernel command line parameter. >>> Instead of a kernel config option which can't be changed by 99% of all >>> Linux users, that option allows ordinary (non kernel compiling) users >>> to disable hctosys at all. >> >> >> I agree your suggestion of having a hctosys= boot option (to override >> the CONFIG_HCTOSYS_DEVICE value) could be a useful extension. >> >> But we shouldn't expect users to set magic boot flags in order to have a >> reliably functioning system. If userland sets the time during init, and >> the hctosys functionality isn't supposed to overwrite that value, then >> there should be no case where userland sets the time at boot, but we end >> up with the RTC time after boot. But currently that race is possible >> (though small). >> >> A more concrete case: >> On many distros ntpd isn't installed by default. Instead they leave the >> kernel to initialize the time from the RTC. > > Which still is done, even earlier with the new hctosys (if a RTC is > used instead of a persistent clock). Nothing changed there. And if the > persistent clock is used, which is true on almost all x86 systems, the > race doesn't exist at all, at least as long as the persistent clock > still exists and will be used (instead of rtc-cmos). Yea, eventually I'd like to push the persistent clock functionality into the RTC core, or remove its use for time initialization and only use the persistent clock for suspend/resume timing. But just because the race doesn't exist on x86, doesn't mean we can ignore it for all the various other arches. > >> >> But ntpd can be installed afterwards, and it would be silly to require >> users edit their boot arguments when installing the ntp package. >> This point you left un-addressed, and is the key problem I see with requiring boot arguments. >> >>> Something which wasn't possible before without recompiling the kernel. >>> And, like before, most RTC drivers will be loaded before userspace >>> calls ntp/ntpdate. If not, the system is already broken. >> >> I'm not sure I'm following how the system is already broken? > > Because it isn't determined what does set the time. The race you've > described happens because someone wants to use ntp for the hctosys > functionality but he doesn't want it, if the date might come first > from a RTC (in case the race window would be even hit). So the > configuration is broken because it is non-deterministic while someone > wants deterministic. I still don't see this. As it stands with the current kernel, the HCTOSYS functionality runs prior to init starting, so it may initialize time, but any userland setting of time will have the final say. You're patches allow for the HCTOSYS functionality to happen after init starts. And the systime_was_set flag you proposed seems to address this change in behavior the following way: Assuming userland has not set the clock, allow the HCTOSYS functionality to set the clock after userland has run. This seems like a reasonable balance. However, with your implementation there is a small race possible, such that the hctosys might set the time to RTC time after userland has set the time. You seem to be saying the race is only possible if the system doesn't use the hctosys= boot argument you're also proposing. But machines don't need a boot argument now, and aren't broken, so why do we want to add an option that requires everyone to use it? Personally I think requiring a boot argument is unnecessary (though having a boot option can be helpful in some cases - don't mistake me for thinking the option is a bad idea, I just don't think it should be required) and is actually problematic for distros to handle properly. > >> >> >>> And just in case, I've made that possible window for the above race >>> very small by checking the flag systime_was_set twice, once before >>> starting to read the time and a second time right before the time is >>> set. Ok, the race is still there, but as said before, if that problem >>> does exist at all, the system would be setup wrong at all. >> >> It just seems that if we really want a to do this, we might as well do >> it right, using the timekeeping_settime_first() or whatever function >> that can properly check the value and complete the action atomically >> while holding the lock. >> >> >>>> >>>> This is basically what this code is trying to avoid in the first >>>> place. >>>> And I'll grant that its a small race window, but it may lead to >>>> irregular behavior. >>>> >>>> So either we need to document that this race is theoretically >>>> possible, >>>> and explain *why* its safe to ignore it. Or if we really want to do >>> >>> I would think that documenting hctosys=none should be enough. >> >> Again, I don't think users who install ntpd should have to also change >> their boot parameters. >> >> >>> All systems I've seen do load modules very early (before they would >>> start anything ntp related). And the new hctosys is done inside the >>> registration of the RTC. So if a system is configured in such a way >>> that the race really might happen, the system would be broken because >>> the RTC would not be there when starting ntp. To conclude, I think the >>> problem is highly academic/artificial and, if possible at all, only >>> possible on already misconfigured systems during a very, very small >>> window. Therfor I still believe that no locking mechanism is needed. >>> >>> Anyway, I don't care, if you want, I will make an accessor-function >>> with locks and an return code for "set" to indicate if it was already >>> set. >> >> Sorry if I'm frustrating you here, that's not my intent. > > I'm not frustrated, I'm just annoyed. Well, I'm sorry if I'm annoying you. Again, not my intent. > I don't know why everyone seems to assume that I'm getting frustrated > while I just find it totally annoying to invest time to make > checkpatch-clean max. 80 chars per line wide patches while having to > use 8 chars intendation and meaningfull variable and function names. > Besides having to explain and discuss every single line and often get > called a fool or similiar. Just to be clear, I'm in no way calling you a fool. Part of the review process is that we have to understand not only what is done but *why* its being done. So I have to ask (sometimes dumb) questions so that *why* is clearly established. Please don't take these inquiries as questioning your ability. >>> >>> We could also request and wait for a third opinion on that topic. As >>> it most likely will not end up in any kernel before the end of this >>> year (if at all), there is enough time to do so. >>> >> >> I'm in no rush. I think the changes you're proposing are interesting and >> novel cases that we should handle. But I also do think we should do it >> properly, especially since its relatively easy to do in this case. > > Anyway, my intention was to avoid locking stuff in the time-setting > functions but it looks like that isn't wanted. So I will implement the > locking foo, after we finished the discussion about the other parts > and I will have come to the impression that I don't write stuff just > for nothing. A quick look at your other comments revealed that I have > to explain a lot more in order to not get accused that I want to kill > the timekeeping system. ;) To be clear, we already do locking in the time-setting functions. I'm just proposing we introduce a new time setting function that uses the same locking to allow for the flag to be tested and the time to be set atomically (returning an error code if the time had been previously set). thanks -john ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [rtc-linux] Re: [PATCH 4/9 RESEND] RFC: timekeeping: introduce flag systime_was_set 2013-06-20 19:28 ` John Stultz @ 2013-06-20 23:10 ` Alexander Holler 0 siblings, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-06-20 23:10 UTC (permalink / raw) To: John Stultz Cc: rtc-linux, linux-kernel, Andrew Morton, Thomas Gleixner, Alessandro Zummo Am 20.06.2013 21:28, schrieb John Stultz: >>> >>> But ntpd can be installed afterwards, and it would be silly to require >>> users edit their boot arguments when installing the ntp package. >>> > > This point you left un-addressed, and is the key problem I see with > requiring boot arguments. There is no requirement for an additional boot argument. That would only be necessary if you start ntpdate without using a persistent clock and before loading of (working) rtc-modules would have finished. And even then it would only be necessary if you use ntpdate (once) while a driver for the rtc is in it's registration phase and wants to set the clock or if you use ntp and the rtc which registers while ntp sets the time, has a time which would force ntp to refuse further adjustments. And in both cases only, if you don't have disabled the proposed hctosys with using a boot argument. Just because a boot argument makes it possible to disable hctosys by RTC doesn't mean it's necessary. Sorry for beeing pedantic, but I have to defend my decision to avoid locking just because of that possibility. I was fully aware of that unlikely race condition. Anyway, I've already accomplished to add locking to prevent that case. Regards, Alexander Holler ^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 5/9 v3] RFC: timekeeping: rtc: Introduce new kernel parameter hctosys 2013-06-14 16:52 ` [PATCH 0/9 v3] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler ` (3 preceding siblings ...) 2013-06-14 16:52 ` [PATCH 4/9 RESEND] RFC: timekeeping: introduce flag systime_was_set Alexander Holler @ 2013-06-14 16:52 ` Alexander Holler 2013-06-14 19:24 ` John Stultz 2013-06-14 16:52 ` [PATCH 6/9 v3] RFC: timekeeping: rtc: remove CONFIG_RTC_HCTOSYS and RTC_HCTOSYS_DEVICE Alexander Holler ` (4 subsequent siblings) 9 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-06-14 16:52 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, John Stultz, rtc-linux, Thomas Gleixner, Alessandro Zummo, Alexander Holler hctosys= specifies the driver (RTC) name which sets the system clock at boot, if and only if userspace hasn't set the time before the driver will be loaded. If hctosys will not be specified, the first available hardware clock with a valid time will be used (again, if and only if ...). If you don't want that the system clock will be set by any hardware clock, just specify a non-existent RTC driver name, e.g. with hctosys=none. Currently there exist a special name "persistent" for the persistent clock found on some systems (e.g. the CMOS clock on x86 platforms which might be handled by the driver named rtc_cmos too). This will replace the existent driver/mechanism hctosys and the kernel config options CONFIG_RTC_HCTOSYS and CONFIG_RTC_HCTOSYS_DEVICE (done with one of the following patches) Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- Documentation/kernel-parameters.txt | 12 +++++++++ drivers/rtc/class.c | 42 +++++++++++++++++++++++++++++ include/linux/time.h | 6 +++++ kernel/time/timekeeping.c | 53 ++++++++++++++++++++++++++++--------- 4 files changed, 101 insertions(+), 12 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 2fe6e76..0b8f101 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -983,6 +983,18 @@ bytes respectively. Such letter suffixes can also be entirely omitted. hcl= [IA-64] SGI's Hardware Graph compatibility layer + hctosys= [KNL] Specifies the driver (RTC) name which sets the + time at boot, if and only if userspace hasn't set the + time before the driver will be loaded. If hctosys will + not be specified, the first available hardware clock + with a valid time will be used. + Use a non-existent name (e.g. hctosys=none) if you want + to avoid that a hardware clock will set the time. + Currently there exist a special name "persistent" for + the persistent clock found on some systems (e.g. the + CMOS clock on x86 platforms which might be handled + by the driver named rtc_cmos too). + hd= [EIDE] (E)IDE hard drive subsystem geometry Format: <cyl>,<head>,<sect> diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 6638540..37a1647 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -141,6 +141,43 @@ static int rtc_resume(struct device *dev) #endif +static void hctosys(struct rtc_device *rtc) +{ + struct rtc_time now; + struct timespec ts = { + .tv_nsec = NSEC_PER_SEC >> 1, + }; + int rc; + + rc = rtc_read_time(rtc, &now); + if (unlikely(rc)) { + dev_err(rtc->dev.parent, + "rtc core: error reading time from RTC: %d\n", rc); + return; + } + rc = rtc_valid_tm(&now); + if (unlikely(rc)) { + dev_err(rtc->dev.parent, + "rtc core: timestamp from RTC is invalid\n"); + return; + } + rtc_tm_to_time(&now, &ts.tv_sec); + if (systime_was_set) + return; + rc = do_settimeofday(&ts); + if (unlikely(rc)) { + dev_err(rtc->dev.parent, + "rtc core: error setting system clock: %d\n", rc); + return; + } else if (systime_was_set) + dev_info(rtc->dev.parent, + "rtc core: setting system clock to " + "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", + now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, + now.tm_hour, now.tm_min, now.tm_sec, + (unsigned int) ts.tv_sec); +} + /** * rtc_device_register - register w/ RTC class * @dev: the device to register @@ -157,6 +194,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, struct rtc_device *rtc; struct rtc_wkalrm alrm; int id, err; + const char *hctosys_name = get_hctosys_name(); id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL); if (id < 0) { @@ -196,6 +234,10 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, rtc->pie_timer.function = rtc_pie_update_irq; rtc->pie_enabled = 0; + if (!systime_was_set && + (!hctosys_name[0] || !strcasecmp(name, hctosys_name))) + hctosys(rtc); + /* Check to see if there is an ALARM already set in hw */ err = __rtc_read_alarm(rtc, &alrm); diff --git a/include/linux/time.h b/include/linux/time.h index 888280f..e5f644c 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -135,6 +135,12 @@ extern int timekeeping_suspended; */ extern bool systime_was_set; +/* + * Returns a pointer to the string specified with + * hctosys= at the kernel command line. + */ +const char *get_hctosys_name(void); + unsigned long get_seconds(void); struct timespec current_kernel_time(void); struct timespec __current_kernel_time(void); /* does not take xtime_lock */ diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 07d8531..e101468 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -22,6 +22,7 @@ #include <linux/tick.h> #include <linux/stop_machine.h> #include <linux/pvclock_gtod.h> +#include <linux/rtc.h> #include "tick-internal.h" #include "ntp_internal.h" @@ -40,6 +41,22 @@ bool __read_mostly persistent_clock_exist = false; /* Flag for if the system time was set at least once */ bool __read_mostly systime_was_set; +static char hctosys_name[RTC_DEVICE_NAME_SIZE]; + +static int __init hctosys_setup(char *line) +{ + strlcpy(hctosys_name, line, sizeof(hctosys_name)); + return 1; +} + +__setup("hctosys=", hctosys_setup); + +const char *get_hctosys_name(void) +{ + return hctosys_name; +} +EXPORT_SYMBOL_GPL(get_hctosys_name); + static inline void tk_normalize_xtime(struct timekeeper *tk) { while (tk->xtime_nsec >= ((u64)NSEC_PER_SEC << tk->shift)) { @@ -778,18 +795,19 @@ void __init timekeeping_init(void) struct timekeeper *tk = &timekeeper; struct clocksource *clock; unsigned long flags; - struct timespec now, boot, tmp; - - read_persistent_clock(&now); - - if (!timespec_valid_strict(&now)) { - pr_warn("WARNING: Persistent clock returned invalid value!\n" - " Check your CMOS/BIOS settings.\n"); - now.tv_sec = 0; - now.tv_nsec = 0; - } else if (now.tv_sec || now.tv_nsec) { - persistent_clock_exist = true; - systime_was_set = true; + struct timespec now = {0, 0}, boot, tmp; + + if (!hctosys_name[0] || !strcasecmp(hctosys_name, "persistent")) { + read_persistent_clock(&now); + if (!timespec_valid_strict(&now)) { + pr_warn("WARNING: Persistent clock returned invalid value!\n" + " Check your CMOS/BIOS settings.\n"); + now.tv_sec = 0; + now.tv_nsec = 0; + } else if (now.tv_sec || now.tv_nsec) { + persistent_clock_exist = true; + systime_was_set = true; + } } read_boot_clock(&boot); @@ -826,6 +844,17 @@ void __init timekeeping_init(void) write_seqcount_end(&timekeeper_seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); + + if (systime_was_set) { + /* print a msg like if the time was set by a RTC */ + struct tm now_tm; + time_to_tm(now.tv_sec, 0, &now_tm); + pr_info("persistent clock: setting system clock to " + "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", + (int)now_tm.tm_year + 1900, now_tm.tm_mon + 1, + now_tm.tm_mday, now_tm.tm_hour, now_tm.tm_min, + now_tm.tm_sec, (unsigned int) now.tv_sec); + } } /* time in seconds when suspend began */ -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* Re: [PATCH 5/9 v3] RFC: timekeeping: rtc: Introduce new kernel parameter hctosys 2013-06-14 16:52 ` [PATCH 5/9 v3] RFC: timekeeping: rtc: Introduce new kernel parameter hctosys Alexander Holler @ 2013-06-14 19:24 ` John Stultz 0 siblings, 0 replies; 78+ messages in thread From: John Stultz @ 2013-06-14 19:24 UTC (permalink / raw) To: Alexander Holler Cc: linux-kernel, Andrew Morton, rtc-linux, Thomas Gleixner, Alessandro Zummo On 06/14/2013 09:52 AM, Alexander Holler wrote: > hctosys= specifies the driver (RTC) name which sets the system clock at > boot, if and only if userspace hasn't set the time before the driver will > be loaded. > > If hctosys will not be specified, the first available hardware clock > with a valid time will be used (again, if and only if ...). > > If you don't want that the system clock will be set by any hardware clock, > just specify a non-existent RTC driver name, e.g. with hctosys=none. So what was the rational for this to be a boot time argument instead of using the existing compile time CONFIG_RTC_HCTOSYS_DEVICE? If we need a boot argument, that's still doable, but it probably should fall back to CONFIG_RTC_HCTOSYS_DEVICE if not specified. thanks -john ^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 6/9 v3] RFC: timekeeping: rtc: remove CONFIG_RTC_HCTOSYS and RTC_HCTOSYS_DEVICE 2013-06-14 16:52 ` [PATCH 0/9 v3] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler ` (4 preceding siblings ...) 2013-06-14 16:52 ` [PATCH 5/9 v3] RFC: timekeeping: rtc: Introduce new kernel parameter hctosys Alexander Holler @ 2013-06-14 16:52 ` Alexander Holler 2013-06-14 19:11 ` John Stultz 2013-06-14 16:52 ` [PATCH 7/9] RFC: rtc: implement rtc_read_timeval() Alexander Holler ` (3 subsequent siblings) 9 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-06-14 16:52 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, John Stultz, rtc-linux, Thomas Gleixner, Alessandro Zummo, Alexander Holler Those config options don't make sense anymore with the new hctosys mechanism introduced with the previous patch. That means two things: - If a (hardware) clock is available it will be used to set the time at boot. This was already the case for system which have a "persistent" clock, e.g. most x86 systems. The only way to specify the device used for hctosys is now by using the kernel parameter hctosys= introduced with a previous patch. - If a hardware clock was used for hctosys before suspend, this clock will be used to adjust the clock at resume. Again, this doesn't change anything on systems with a "persistent" clock. What's missing: I don't know much about those "persistent" clocks and I haven't had a deep look at them. That's especially true for the suspend/resume mechanism used by them. The mechanism I want to use is the following: The RTC subsystem now maintains the ID of the RTC device which was used for hctosys (in rtc_hctosys_dev_id) and therefor specifies the device which should be used to adjust the time after resume. Additionaly the (new) flag systime_was_set will be set to false at suspend and on resume this flag will be set to true if either the clock will be adjusted by the device used for hctosys or by userspace (through do_settimeofday()). That all should already work as expected for RTCs, what's missing for "persistent" clocks is that the flag systime_was_set is set to false on suspend and set to true on resume. Currently it just stays at true (which is set through hctosys if a "persistent" clock is found. But because "persistent" clocks don't go away (as it is possible with RTCs by removing the driver or the RTC itself), nor do "persistent" clocks might have two instances, this shouldn't be a problem at all. Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- Documentation/rtc.txt | 8 +++--- drivers/rtc/Kconfig | 35 ++--------------------- drivers/rtc/Makefile | 1 - drivers/rtc/class.c | 30 ++++++++++++------- drivers/rtc/hctosys.c | 76 ------------------------------------------------- drivers/rtc/rtc-proc.c | 25 ++-------------- drivers/rtc/rtc-sysfs.c | 6 +--- drivers/rtc/systohc.c | 5 +++- include/linux/rtc.h | 7 ++--- 9 files changed, 34 insertions(+), 159 deletions(-) delete mode 100644 drivers/rtc/hctosys.c diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt index 32aa400..a1abfd8 100644 --- a/Documentation/rtc.txt +++ b/Documentation/rtc.txt @@ -121,8 +121,9 @@ three different userspace interfaces: * /proc/driver/rtc ... the system clock RTC may expose itself using a procfs interface. If there is no RTC for the system clock, - rtc0 is used by default. More information is (currently) shown - here than through sysfs. + or a "persistent" clock is used to set the system clock, + /proc/driver/rtc will not exist. + More information is (currently) shown here than through sysfs. The RTC Class framework supports a wide variety of RTCs, ranging from those integrated into embeddable system-on-chip (SOC) processors to discrete chips @@ -144,8 +145,7 @@ rtc attributes without requiring the use of ioctls. All dates and times are in the RTC's timezone, rather than in system time. date: RTC-provided date -hctosys: 1 if the RTC provided the system time at boot via the - CONFIG_RTC_HCTOSYS kernel option, 0 otherwise +hctosys: 1 if the RTC provided the system time at boot, 0 otherwise max_user_freq: The maximum interrupt rate an unprivileged user may request from this RTC. name: The name of the RTC corresponding to this sysfs directory diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index b983813..b1d6691 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -17,44 +17,13 @@ menuconfig RTC_CLASS if RTC_CLASS -config RTC_HCTOSYS - bool "Set system time from RTC on startup and resume" - default y - help - If you say yes here, the system time (wall clock) will be set using - the value read from a specified RTC device. This is useful to avoid - unnecessary fsck runs at boot time, and to network better. - config RTC_SYSTOHC bool "Set the RTC time based on NTP synchronization" default y help If you say yes here, the system time (wall clock) will be stored - in the RTC specified by RTC_HCTOSYS_DEVICE approximately every 11 - minutes if userspace reports synchronized NTP status. - -config RTC_HCTOSYS_DEVICE - string "RTC used to set the system time" - depends on RTC_HCTOSYS = y || RTC_SYSTOHC = y - default "rtc0" - help - The RTC device that will be used to (re)initialize the system - clock, usually rtc0. Initialization is done when the system - starts up, and when it resumes from a low power state. This - device should record time in UTC, since the kernel won't do - timezone correction. - - The driver for this RTC device must be loaded before late_initcall - functions run, so it must usually be statically linked. - - This clock should be battery-backed, so that it reads the correct - time when the system boots from a power-off state. Otherwise, your - system will need an external clock source (like an NTP server). - - If the clock you specify here is not battery backed, it may still - be useful to reinitialize system time when resuming from system - sleep states. Do not specify an RTC here unless it stays powered - during all this system's supported sleep states. + in the RTC used to set the time at boot or resume approximately + every 11 minutes if userspace reports synchronized NTP status. config RTC_DEBUG bool "RTC debug support" diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index c33f86f..b699504 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -5,7 +5,6 @@ ccflags-$(CONFIG_RTC_DEBUG) := -DDEBUG obj-$(CONFIG_RTC_LIB) += rtc-lib.o -obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o obj-$(CONFIG_RTC_SYSTOHC) += systohc.o obj-$(CONFIG_RTC_CLASS) += rtc-core.o rtc-core-y := class.o interface.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 37a1647..625076b 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -26,6 +26,9 @@ static DEFINE_IDA(rtc_ida); struct class *rtc_class; +/* The ID of the RTC device used to set the system clock */ +int __read_mostly rtc_hctosys_dev_id = -1; + static void rtc_device_release(struct device *dev) { struct rtc_device *rtc = to_rtc_device(dev); @@ -33,12 +36,7 @@ static void rtc_device_release(struct device *dev) kfree(rtc); } -#ifdef CONFIG_RTC_HCTOSYS_DEVICE -/* Result of the last RTC to system clock attempt. */ -int rtc_hctosys_ret = -ENODEV; -#endif - -#if defined(CONFIG_PM) && defined(CONFIG_RTC_HCTOSYS_DEVICE) +#if defined(CONFIG_PM) /* * On suspend(), measure the delta between one RTC and the * system's wall clock; restore it on resume(). @@ -53,12 +51,18 @@ static int rtc_suspend(struct device *dev, pm_message_t mesg) struct rtc_time tm; struct timespec delta, delta_delta; + + if (!systime_was_set) + return 0; + if (has_persistent_clock()) return 0; - if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) + if (rtc->id != rtc_hctosys_dev_id) return 0; + systime_was_set = false; + /* snapshot the current RTC and system time at suspend*/ rtc_read_time(rtc, &tm); getnstimeofday(&old_system); @@ -94,11 +98,13 @@ static int rtc_resume(struct device *dev) struct timespec new_system, new_rtc; struct timespec sleep_time; + if (systime_was_set) + return 0; + if (has_persistent_clock()) return 0; - rtc_hctosys_ret = -ENODEV; - if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) + if (rtc->id != rtc_hctosys_dev_id) return 0; /* snapshot the current rtc and system time at resume */ @@ -131,7 +137,7 @@ static int rtc_resume(struct device *dev) if (sleep_time.tv_sec >= 0) timekeeping_inject_sleeptime(&sleep_time); - rtc_hctosys_ret = 0; + systime_was_set = true; return 0; } @@ -169,13 +175,15 @@ static void hctosys(struct rtc_device *rtc) dev_err(rtc->dev.parent, "rtc core: error setting system clock: %d\n", rc); return; - } else if (systime_was_set) + } else if (systime_was_set) { + rtc_hctosys_dev_id = rtc->id; dev_info(rtc->dev.parent, "rtc core: setting system clock to " "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec, (unsigned int) ts.tv_sec); + } } /** diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c deleted file mode 100644 index 4aa60d7..0000000 --- a/drivers/rtc/hctosys.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * RTC subsystem, initialize system time on startup - * - * Copyright (C) 2005 Tower Technologies - * Author: Alessandro Zummo <a.zummo@towertech.it> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include <linux/rtc.h> - -/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary - * whether it stores the most close value or the value with partial - * seconds truncated. However, it is important that we use it to store - * the truncated value. This is because otherwise it is necessary, - * in an rtc sync function, to read both xtime.tv_sec and - * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read - * of >32bits is not possible. So storing the most close value would - * slow down the sync API. So here we have the truncated value and - * the best guess is to add 0.5s. - */ - -static int __init rtc_hctosys(void) -{ - int err = -ENODEV; - struct rtc_time tm; - struct timespec tv = { - .tv_nsec = NSEC_PER_SEC >> 1, - }; - struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); - - if (rtc == NULL) { - pr_err("%s: unable to open rtc device (%s)\n", - __FILE__, CONFIG_RTC_HCTOSYS_DEVICE); - goto err_open; - } - - err = rtc_read_time(rtc, &tm); - if (err) { - dev_err(rtc->dev.parent, - "hctosys: unable to read the hardware clock\n"); - goto err_read; - - } - - err = rtc_valid_tm(&tm); - if (err) { - dev_err(rtc->dev.parent, - "hctosys: invalid date/time\n"); - goto err_invalid; - } - - rtc_tm_to_time(&tm, &tv.tv_sec); - - err = do_settimeofday(&tv); - - dev_info(rtc->dev.parent, - "setting system clock to " - "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, - (unsigned int) tv.tv_sec); - -err_invalid: -err_read: - rtc_class_close(rtc); - -err_open: - rtc_hctosys_ret = err; - - return err; -} - -late_initcall(rtc_hctosys); diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c index ffa69e1..fd59c1b 100644 --- a/drivers/rtc/rtc-proc.c +++ b/drivers/rtc/rtc-proc.c @@ -18,27 +18,6 @@ #include "rtc-core.h" -#define NAME_SIZE 10 - -#if defined(CONFIG_RTC_HCTOSYS_DEVICE) -static bool is_rtc_hctosys(struct rtc_device *rtc) -{ - int size; - char name[NAME_SIZE]; - - size = scnprintf(name, NAME_SIZE, "rtc%d", rtc->id); - if (size > NAME_SIZE) - return false; - - return !strncmp(name, CONFIG_RTC_HCTOSYS_DEVICE, NAME_SIZE); -} -#else -static bool is_rtc_hctosys(struct rtc_device *rtc) -{ - return (rtc->id == 0); -} -#endif - static int rtc_proc_show(struct seq_file *seq, void *offset) { int err; @@ -137,12 +116,12 @@ static const struct file_operations rtc_proc_fops = { void rtc_proc_add_device(struct rtc_device *rtc) { - if (is_rtc_hctosys(rtc)) + if (rtc->id == rtc_hctosys_dev_id) proc_create_data("driver/rtc", 0, NULL, &rtc_proc_fops, rtc); } void rtc_proc_del_device(struct rtc_device *rtc) { - if (is_rtc_hctosys(rtc)) + if (rtc->id == rtc_hctosys_dev_id) remove_proc_entry("driver/rtc", NULL); } diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index b70e2bb..6b8a41b 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -112,13 +112,9 @@ static ssize_t rtc_sysfs_show_hctosys(struct device *dev, struct device_attribute *attr, char *buf) { -#ifdef CONFIG_RTC_HCTOSYS_DEVICE - if (rtc_hctosys_ret == 0 && - strcmp(dev_name(&to_rtc_device(dev)->dev), - CONFIG_RTC_HCTOSYS_DEVICE) == 0) + if (to_rtc_device(dev)->id == rtc_hctosys_dev_id) return sprintf(buf, "1\n"); else -#endif return sprintf(buf, "0\n"); } diff --git a/drivers/rtc/systohc.c b/drivers/rtc/systohc.c index bf3e242..1962f4c 100644 --- a/drivers/rtc/systohc.c +++ b/drivers/rtc/systohc.c @@ -25,13 +25,16 @@ int rtc_set_ntp_time(struct timespec now) struct rtc_device *rtc; struct rtc_time tm; int err = -ENODEV; + char rtc_hctosys_name[10]; if (now.tv_nsec < (NSEC_PER_SEC >> 1)) rtc_time_to_tm(now.tv_sec, &tm); else rtc_time_to_tm(now.tv_sec + 1, &tm); - rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); + scnprintf(rtc_hctosys_name, sizeof(rtc_hctosys_name), "rtc%d", + rtc_hctosys_dev_id); + rtc = rtc_class_open(rtc_hctosys_name); if (rtc) { /* rtc_hctosys exclusively uses UTC, so we call set_time here, * not set_mmss. */ diff --git a/include/linux/rtc.h b/include/linux/rtc.h index c2c2897..50caf0d 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -191,10 +191,7 @@ static inline bool is_leap_year(unsigned int year) return (!(year % 4) && (year % 100)) || !(year % 400); } -#ifdef CONFIG_RTC_HCTOSYS_DEVICE -extern int rtc_hctosys_ret; -#else -#define rtc_hctosys_ret -ENODEV -#endif +/* The ID of the RTC device used to set the system clock */ +extern int rtc_hctosys_dev_id; #endif /* _LINUX_RTC_H_ */ -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* Re: [PATCH 6/9 v3] RFC: timekeeping: rtc: remove CONFIG_RTC_HCTOSYS and RTC_HCTOSYS_DEVICE 2013-06-14 16:52 ` [PATCH 6/9 v3] RFC: timekeeping: rtc: remove CONFIG_RTC_HCTOSYS and RTC_HCTOSYS_DEVICE Alexander Holler @ 2013-06-14 19:11 ` John Stultz 2013-06-22 8:00 ` Alexander Holler 0 siblings, 1 reply; 78+ messages in thread From: John Stultz @ 2013-06-14 19:11 UTC (permalink / raw) To: Alexander Holler Cc: linux-kernel, Andrew Morton, rtc-linux, Thomas Gleixner, Alessandro Zummo On 06/14/2013 09:52 AM, Alexander Holler wrote: > Those config options don't make sense anymore with the new hctosys > mechanism introduced with the previous patch. > > That means two things: > > - If a (hardware) clock is available it will be used to set the time at > boot. This was already the case for system which have a "persistent" > clock, e.g. most x86 systems. The only way to specify the device used > for hctosys is now by using the kernel parameter hctosys= introduced > with a previous patch. > > - If a hardware clock was used for hctosys before suspend, this clock > will be used to adjust the clock at resume. Again, this doesn't change > anything on systems with a "persistent" clock. > > What's missing: > > I don't know much about those "persistent" clocks and I haven't had a > deep look at them. That's especially true for the suspend/resume > mechanism used by them. The mechanism I want to use is the following: > The RTC subsystem now maintains the ID of the RTC device which was used > for hctosys (in rtc_hctosys_dev_id) and therefor specifies the device > which should be used to adjust the time after resume. Additionaly the > (new) flag systime_was_set will be set to false at suspend and on resume > this flag will be set to true if either the clock will be adjusted by > the device used for hctosys or by userspace (through do_settimeofday()). > > That all should already work as expected for RTCs, what's missing for > "persistent" clocks is that the flag systime_was_set is set to false on > suspend and set to true on resume. Currently it just stays at true > (which is set through hctosys if a "persistent" clock is found. > But because "persistent" clocks don't go away (as it is possible with > RTCs by removing the driver or the RTC itself), nor do "persistent" > clocks might have two instances, this shouldn't be a problem at all. This one concerns me a bit. Since you're removing quite a bit and it looks like it may break userland expectations. I ran into this myself recently, when I found some distros look for /sys/class/rtc/rtcN/hctosys in order to determine which rtc device should be synced with from userland. So I'd probably suggest instead to re-factor this so you leave all the hctosys bits alone, but just change it from being called by a late_initcall() and instead have it called when we register the RTC that matches CONFIG_RTC_HCTOSYS_DEVICE. I suspect it will end up being a much smaller change that way. Then the last bit is just a matter of adding the timekeeping_systimeset() check to the hctosys bits. thanks -john ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 6/9 v3] RFC: timekeeping: rtc: remove CONFIG_RTC_HCTOSYS and RTC_HCTOSYS_DEVICE 2013-06-14 19:11 ` John Stultz @ 2013-06-22 8:00 ` Alexander Holler 0 siblings, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-06-22 8:00 UTC (permalink / raw) To: John Stultz Cc: linux-kernel, Andrew Morton, rtc-linux, Thomas Gleixner, Alessandro Zummo Am 14.06.2013 21:11, schrieb John Stultz: > On 06/14/2013 09:52 AM, Alexander Holler wrote: >> Those config options don't make sense anymore with the new hctosys >> mechanism introduced with the previous patch. >> >> That means two things: >> >> - If a (hardware) clock is available it will be used to set the time at >> boot. This was already the case for system which have a "persistent" >> clock, e.g. most x86 systems. The only way to specify the device used >> for hctosys is now by using the kernel parameter hctosys= introduced >> with a previous patch. >> >> - If a hardware clock was used for hctosys before suspend, this clock >> will be used to adjust the clock at resume. Again, this doesn't change >> anything on systems with a "persistent" clock. >> >> What's missing: >> >> I don't know much about those "persistent" clocks and I haven't had a >> deep look at them. That's especially true for the suspend/resume >> mechanism used by them. The mechanism I want to use is the following: >> The RTC subsystem now maintains the ID of the RTC device which was used >> for hctosys (in rtc_hctosys_dev_id) and therefor specifies the device >> which should be used to adjust the time after resume. Additionaly the >> (new) flag systime_was_set will be set to false at suspend and on resume >> this flag will be set to true if either the clock will be adjusted by >> the device used for hctosys or by userspace (through do_settimeofday()). >> >> That all should already work as expected for RTCs, what's missing for >> "persistent" clocks is that the flag systime_was_set is set to false on >> suspend and set to true on resume. Currently it just stays at true >> (which is set through hctosys if a "persistent" clock is found. >> But because "persistent" clocks don't go away (as it is possible with >> RTCs by removing the driver or the RTC itself), nor do "persistent" >> clocks might have two instances, this shouldn't be a problem at all. > > This one concerns me a bit. Since you're removing quite a bit and it > looks like it may break userland expectations. The only thing I remove from a user point of view is a broken (because undetermined) informational entry (/proc/driver/rtc) if persistent clocks are used. > > I ran into this myself recently, when I found some distros look for > /sys/class/rtc/rtcN/hctosys in order to determine which rtc device > should be synced with from userland. The patches don't change anything in /sys. > > So I'd probably suggest instead to re-factor this so you leave all the > hctosys bits alone, but just change it from being called by a > late_initcall() and instead have it called when we register the RTC that > matches CONFIG_RTC_HCTOSYS_DEVICE. > > I suspect it will end up being a much smaller change that way. > > Then the last bit is just a matter of adding the > timekeeping_systimeset() check to the hctosys bits. This doesn't work because the current hctosys approach is (imho) broken by design, at least how it currently works. Of course, this might be the result of changes, refused patches or whatever, I don't know the history of the current hctosys. First it's only a kernel configuration, that means most users can't even change it. Second, it just defines the N in rtcN, which is based on the order RTC drivers are loaded (undefined). Third, it ignores persistent clocks, and if persistent clocks are used, the informational entry in /proc is misleading and just might fit because of some lucky circumstance. As it seems hard to understand the changes, here they are again, maybe my second description is more understandable. 1. Replacment of the Kernel config option CONFIG_RTC_HCTOSYS by a kernel command line parameter hctosys=. - Kernel config options are unavailable for most users. A kernel command line parameter gives them the possibility to change it. - The current config option ignores persistent clocks at all. It doesn't allow to disable persistent clocks and therefor it is misleading. I assume most users don't even know persistent clocks do exist. Fixed with the new kernel command line parameter. 2. Replacement of RTC_HCTOSYS_DEVICE by a kernel command line parameter hctosys=. - Again, it's a kernel config option only, not changeable by most users. The new hctosys= allows ordinary (non-kernel-compiling) users to change that. - The current config option is based on the order RTC drivers are loaded, which is non-deterministic thus undefined. The new hctosys= allows to choose the used RTC driver by name. - The config option ignores persistent clocks, the new hctosys= kernel commandline parameter doesn't. 3. Removal of /proc/driver/rtc if and only if a persistent clock is used. - If a persistent clock is used, the informational entry in /proc might be totally wrong because it is based on the first loaded RTC driver. The first loaded RTC driver doesn't have to be the corresponding rtc-driver which uses the same hardware clock as the persistent clock and might describe a totally different hardware clock. - If a persistent clock is used, it describes the abilities of the RTC driver, but not those of the persistent clock driver. This might be misleading because only the persistent clock driver is used and not the corresponding (described) RTC driver. - No changes for users of any RTC driver. The entry in /proc will still be there. Regards, Alexander Holler ^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 7/9] RFC: rtc: implement rtc_read_timeval() 2013-06-14 16:52 ` [PATCH 0/9 v3] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler ` (5 preceding siblings ...) 2013-06-14 16:52 ` [PATCH 6/9 v3] RFC: timekeeping: rtc: remove CONFIG_RTC_HCTOSYS and RTC_HCTOSYS_DEVICE Alexander Holler @ 2013-06-14 16:52 ` Alexander Holler 2013-06-14 17:23 ` John Stultz 2013-06-14 17:28 ` John Stultz 2013-06-14 16:52 ` [PATCH 8/9] RFC: rtc: hctosys: support rtc_read_timeval() for high precision clocks Alexander Holler ` (2 subsequent siblings) 9 siblings, 2 replies; 78+ messages in thread From: Alexander Holler @ 2013-06-14 16:52 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, John Stultz, rtc-linux, Thomas Gleixner, Alessandro Zummo, Alexander Holler Some RTCs offer a higher resolution than seconds. To support reading such high resolution timestamps from inside the kernel implement rtc_read_timeval() and add a read_timeval to the rtc-ops. This is done to support high precision read-only clocks (like radio- or GPS-clocks) from inside the kernel (mainly hctosys). Therfor there is currently no need to set the clock or to extend the (rtc-)userspace api to support high precision timestamps. Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- drivers/rtc/interface.c | 28 ++++++++++++++++++++++++++++ include/linux/rtc.h | 3 +++ 2 files changed, 31 insertions(+) diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 42bd57d..f09f384 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -48,6 +48,34 @@ int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) } EXPORT_SYMBOL_GPL(rtc_read_time); +static int __rtc_read_timeval(struct rtc_device *rtc, struct timeval *tv) +{ + int err; + if (!rtc->ops) + err = -ENODEV; + else if (!rtc->ops->read_timeval) + err = -EINVAL; + else { + memset(tv, 0, sizeof(struct timeval)); + err = rtc->ops->read_timeval(rtc->dev.parent, tv); + } + return err; +} + +int rtc_read_timeval(struct rtc_device *rtc, struct timeval *tv) +{ + int err; + + err = mutex_lock_interruptible(&rtc->ops_lock); + if (err) + return err; + + err = __rtc_read_timeval(rtc, tv); + mutex_unlock(&rtc->ops_lock); + return err; +} +EXPORT_SYMBOL_GPL(rtc_read_timeval); + int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) { int err; diff --git a/include/linux/rtc.h b/include/linux/rtc.h index 50caf0d..863f916 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -15,6 +15,7 @@ #include <linux/types.h> #include <linux/interrupt.h> #include <uapi/linux/rtc.h> +#include <uapi/linux/time.h> extern int rtc_month_days(unsigned int month, unsigned int year); extern int rtc_year_days(unsigned int day, unsigned int month, unsigned int year); @@ -63,6 +64,7 @@ struct rtc_class_ops { int (*set_mmss)(struct device *, unsigned long secs); int (*read_callback)(struct device *, int data); int (*alarm_irq_enable)(struct device *, unsigned int enabled); + int (*read_timeval)(struct device *, struct timeval *); }; #define RTC_DEVICE_NAME_SIZE 20 @@ -143,6 +145,7 @@ extern void devm_rtc_device_unregister(struct device *dev, extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm); extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm); +extern int rtc_read_timeval(struct rtc_device *rtc, struct timeval *tv); extern int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs); extern int rtc_set_ntp_time(struct timespec now); int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm); -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* Re: [PATCH 7/9] RFC: rtc: implement rtc_read_timeval() 2013-06-14 16:52 ` [PATCH 7/9] RFC: rtc: implement rtc_read_timeval() Alexander Holler @ 2013-06-14 17:23 ` John Stultz 2013-06-14 17:43 ` Alexander Holler 2013-06-14 17:28 ` John Stultz 1 sibling, 1 reply; 78+ messages in thread From: John Stultz @ 2013-06-14 17:23 UTC (permalink / raw) To: Alexander Holler Cc: linux-kernel, Andrew Morton, rtc-linux, Thomas Gleixner, Alessandro Zummo On 06/14/2013 09:52 AM, Alexander Holler wrote: > Some RTCs offer a higher resolution than seconds. To support reading such > high resolution timestamps from inside the kernel implement > rtc_read_timeval() and add a read_timeval to the rtc-ops. So I like the direction this patch is going. But if we're going to add a new interface, lets not use an already out-dated structure (timeval). Instead could you rework this to be timepsec based? Or ktime_t if its really internal only? thanks -john ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 7/9] RFC: rtc: implement rtc_read_timeval() 2013-06-14 17:23 ` John Stultz @ 2013-06-14 17:43 ` Alexander Holler 2013-06-14 19:18 ` John Stultz 0 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-06-14 17:43 UTC (permalink / raw) To: John Stultz Cc: linux-kernel, Andrew Morton, rtc-linux, Thomas Gleixner, Alessandro Zummo Am 14.06.2013 19:23, schrieb John Stultz: > On 06/14/2013 09:52 AM, Alexander Holler wrote: >> Some RTCs offer a higher resolution than seconds. To support reading such >> high resolution timestamps from inside the kernel implement >> rtc_read_timeval() and add a read_timeval to the rtc-ops. > > So I like the direction this patch is going. But if we're going to add a > new interface, lets not use an already out-dated structure (timeval). > > Instead could you rework this to be timepsec based? Or ktime_t if its > really internal only? Sure, no problem. I wasn't aware timeval is out-dated and I've read somewhere in the sources a comment that ktime_t has to disappear. I had no clue if I should use timeval or timespec, and just have roled a dice to decide between timeval and timespec. That "internal only" is only because I don't want to write changes for the userspace api to handle RTCs with greater precision than seconds. I don't have a writable RTC supporting such a precision and I want to leave this for people which are developing such devices and earning money with them. Besides that, I have almost no knowledge about the userspace api for RTCs. If just looked a bit around in the in-kernel-ntp-sources for adjtimex, but that's all. Please don't forget, my only motivation is to use an USB-RTC I've build myself to use with developer-boards without RTCs. All the other work like the support for higher precisions, the new hctosys or similiar is just because I let me trick to do that ;) Regards, Alexander Holler ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 7/9] RFC: rtc: implement rtc_read_timeval() 2013-06-14 17:43 ` Alexander Holler @ 2013-06-14 19:18 ` John Stultz 0 siblings, 0 replies; 78+ messages in thread From: John Stultz @ 2013-06-14 19:18 UTC (permalink / raw) To: Alexander Holler Cc: linux-kernel, Andrew Morton, rtc-linux, Thomas Gleixner, Alessandro Zummo On 06/14/2013 10:43 AM, Alexander Holler wrote: > Am 14.06.2013 19:23, schrieb John Stultz: >> On 06/14/2013 09:52 AM, Alexander Holler wrote: >>> Some RTCs offer a higher resolution than seconds. To support reading >>> such >>> high resolution timestamps from inside the kernel implement >>> rtc_read_timeval() and add a read_timeval to the rtc-ops. >> >> So I like the direction this patch is going. But if we're going to add a >> new interface, lets not use an already out-dated structure (timeval). >> >> Instead could you rework this to be timepsec based? Or ktime_t if its >> really internal only? > > Sure, no problem. I wasn't aware timeval is out-dated and I've read > somewhere in the sources a comment that ktime_t has to disappear. I > had no clue if I should use timeval or timespec, and just have roled a > dice to decide between timeval and timespec. > > That "internal only" is only because I don't want to write changes for > the userspace api to handle RTCs with greater precision than seconds. > I don't have a writable RTC supporting such a precision and I want to > leave this for people which are developing such devices and earning > money with them. > Ok. Pushing it out to userland and the settime interfaces are probably logically separate enough. That said, the the pain with this change is it leaves us with duplicate internal interfaces to read the time. So at some point we'll have to go through all the clocksource drivers and convert them to provide the timespec granular method, even if they just return the second portion. Otherwise, you end up with a mishmash of some users using the second granular and some users using the highres and not all RTCs working for all users (or the users have to do their own fallback logic). That said, I think such a transition is needed eventually, and this gets us at least started in that direction. Alessandro: You have any thoughts here on how to best approach this sort of eventually far-reaching change? thanks -john ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 7/9] RFC: rtc: implement rtc_read_timeval() 2013-06-14 16:52 ` [PATCH 7/9] RFC: rtc: implement rtc_read_timeval() Alexander Holler 2013-06-14 17:23 ` John Stultz @ 2013-06-14 17:28 ` John Stultz 1 sibling, 0 replies; 78+ messages in thread From: John Stultz @ 2013-06-14 17:28 UTC (permalink / raw) To: Alexander Holler Cc: linux-kernel, Andrew Morton, rtc-linux, Thomas Gleixner, Alessandro Zummo On 06/14/2013 09:52 AM, Alexander Holler wrote: > Some RTCs offer a higher resolution than seconds. To support reading such > high resolution timestamps from inside the kernel implement > rtc_read_timeval() and add a read_timeval to the rtc-ops. > > This is done to support high precision read-only clocks (like radio- or > GPS-clocks) from inside the kernel (mainly hctosys). Therfor there is > currently no need to set the clock or to extend the (rtc-)userspace api to > support high precision timestamps. And is there really no reason to eventually pass this out to userland? Also won't we need an equivalent resolution settime method? thanks -john ^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 8/9] RFC: rtc: hctosys: support rtc_read_timeval() for high precision clocks 2013-06-14 16:52 ` [PATCH 0/9 v3] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler ` (6 preceding siblings ...) 2013-06-14 16:52 ` [PATCH 7/9] RFC: rtc: implement rtc_read_timeval() Alexander Holler @ 2013-06-14 16:52 ` Alexander Holler 2013-06-14 19:20 ` John Stultz 2013-06-14 16:52 ` [PATCH 9/9] RFC: rtc: rtc-hid-sensor-time: add support for rtc_read_timeval() Alexander Holler 2013-06-14 17:27 ` [PATCH 0/9 v3] RFC: timekeeping: rtc: change hctosys mechanism John Stultz 9 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-06-14 16:52 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, John Stultz, rtc-linux, Thomas Gleixner, Alessandro Zummo, Alexander Holler Some RTCs do provide a higher precision than seconds. Add support for them by trying rtc_read_timeval() before using rtc_read_time() to get the time in the hctosys mechanism. Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- drivers/rtc/class.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 625076b..1cdd506 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -150,16 +150,25 @@ static int rtc_resume(struct device *dev) static void hctosys(struct rtc_device *rtc) { struct rtc_time now; - struct timespec ts = { - .tv_nsec = NSEC_PER_SEC >> 1, - }; + struct timespec ts; + struct timeval tv = { 0, 0 }; int rc; - rc = rtc_read_time(rtc, &now); - if (unlikely(rc)) { - dev_err(rtc->dev.parent, - "rtc core: error reading time from RTC: %d\n", rc); - return; + rc = rtc_read_timeval(rtc, &tv); + if (rc || (!tv.tv_sec && !tv.tv_usec)) { + rc = rtc_read_time(rtc, &now); + if (unlikely(rc)) { + dev_err(rtc->dev.parent, + "rtc core: error reading time from RTC: %d\n", + rc); + return; + } + rtc_tm_to_time(&now, &ts.tv_sec); + ts.tv_nsec = NSEC_PER_SEC >> 1; + } else { + rtc_time_to_tm(tv.tv_sec, &now); + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_usec*NSEC_PER_USEC; } rc = rtc_valid_tm(&now); if (unlikely(rc)) { @@ -167,7 +176,6 @@ static void hctosys(struct rtc_device *rtc) "rtc core: timestamp from RTC is invalid\n"); return; } - rtc_tm_to_time(&now, &ts.tv_sec); if (systime_was_set) return; rc = do_settimeofday(&ts); @@ -176,12 +184,17 @@ static void hctosys(struct rtc_device *rtc) "rtc core: error setting system clock: %d\n", rc); return; } else if (systime_was_set) { + char usbuf[8]; rtc_hctosys_dev_id = rtc->id; + if (tv.tv_sec) + snprintf(usbuf, sizeof(usbuf), ":%06ld", tv.tv_usec); + else + *usbuf = 0; dev_info(rtc->dev.parent, "rtc core: setting system clock to " - "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", + "%d-%02d-%02d %02d:%02d:%02d%s UTC (%u)\n", now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, - now.tm_hour, now.tm_min, now.tm_sec, + now.tm_hour, now.tm_min, now.tm_sec, usbuf, (unsigned int) ts.tv_sec); } } -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* Re: [PATCH 8/9] RFC: rtc: hctosys: support rtc_read_timeval() for high precision clocks 2013-06-14 16:52 ` [PATCH 8/9] RFC: rtc: hctosys: support rtc_read_timeval() for high precision clocks Alexander Holler @ 2013-06-14 19:20 ` John Stultz 0 siblings, 0 replies; 78+ messages in thread From: John Stultz @ 2013-06-14 19:20 UTC (permalink / raw) To: Alexander Holler Cc: linux-kernel, Andrew Morton, rtc-linux, Thomas Gleixner, Alessandro Zummo On 06/14/2013 09:52 AM, Alexander Holler wrote: > Some RTCs do provide a higher precision than seconds. Add support for them > by trying rtc_read_timeval() before using rtc_read_time() to get the time > in the hctosys mechanism. > > [snip] > + rc = rtc_read_timeval(rtc, &tv); > + if (rc || (!tv.tv_sec && !tv.tv_usec)) { > + rc = rtc_read_time(rtc, &now); > + if (unlikely(rc)) { > + dev_err(rtc->dev.parent, > + "rtc core: error reading time from RTC: %d\n", > + rc); > + return; > + } > + rtc_tm_to_time(&now, &ts.tv_sec); > + ts.tv_nsec = NSEC_PER_SEC >> 1; > + } else { > + rtc_time_to_tm(tv.tv_sec, &now); > + ts.tv_sec = tv.tv_sec; > + ts.tv_nsec = tv.tv_usec*NSEC_PER_USEC; Yea, this sort of fallback logic should be centralized in the RTC layer rather then in the individual users. Might be easiest to modify the rtc_read_timeval() interface to try the ops->read_timeval() operation and do the fallback to rtc_read_time() internally. thanks -john ^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 9/9] RFC: rtc: rtc-hid-sensor-time: add support for rtc_read_timeval() 2013-06-14 16:52 ` [PATCH 0/9 v3] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler ` (7 preceding siblings ...) 2013-06-14 16:52 ` [PATCH 8/9] RFC: rtc: hctosys: support rtc_read_timeval() for high precision clocks Alexander Holler @ 2013-06-14 16:52 ` Alexander Holler 2013-06-14 17:27 ` [PATCH 0/9 v3] RFC: timekeeping: rtc: change hctosys mechanism John Stultz 9 siblings, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-06-14 16:52 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, John Stultz, rtc-linux, Thomas Gleixner, Alessandro Zummo, Alexander Holler Some HID clocks do provide milliseconds. Make it possible to read a high precision timestamp by supporting rtc_read_timeval(). Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- drivers/rtc/rtc-hid-sensor-time.c | 74 +++++++++++++++++++++++++++++++-------- include/linux/hid-sensor-ids.h | 1 + 2 files changed, 61 insertions(+), 14 deletions(-) diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index b842730..3e6d874 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -34,6 +34,7 @@ enum hid_time_channel { CHANNEL_SCAN_INDEX_HOUR, CHANNEL_SCAN_INDEX_MINUTE, CHANNEL_SCAN_INDEX_SECOND, + CHANNEL_SCAN_INDEX_MILLISECOND, /* optional */ TIME_RTC_CHANNEL_MAX, }; @@ -47,11 +48,14 @@ struct hid_time_state { struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info info[TIME_RTC_CHANNEL_MAX]; struct rtc_time last_time; + unsigned last_ms; /* == UINT_MAX to indicate ms aren't supported */ spinlock_t lock_last_time; struct completion comp_last_time; struct rtc_time time_buf; + unsigned ms_buf; struct rtc_device *rtc; struct hid_time_workts *workts; + struct rtc_class_ops rtc_ops; }; static const u32 hid_time_addresses[TIME_RTC_CHANNEL_MAX] = { @@ -61,11 +65,12 @@ static const u32 hid_time_addresses[TIME_RTC_CHANNEL_MAX] = { HID_USAGE_SENSOR_TIME_HOUR, HID_USAGE_SENSOR_TIME_MINUTE, HID_USAGE_SENSOR_TIME_SECOND, + HID_USAGE_SENSOR_TIME_MILLISECOND, /* optional */ }; /* Channel names for verbose error messages */ static const char * const hid_time_channel_names[TIME_RTC_CHANNEL_MAX] = { - "year", "month", "day", "hour", "minute", "second", + "year", "month", "day", "hour", "minute", "second", "millisecond", }; /* Callback handler to send event after all samples are received and captured */ @@ -77,6 +82,8 @@ static int hid_time_proc_event(struct hid_sensor_hub_device *hsdev, spin_lock_irqsave(&time_state->lock_last_time, flags); time_state->last_time = time_state->time_buf; + if (time_state->last_ms != UINT_MAX) + time_state->last_ms = time_state->ms_buf; spin_unlock_irqrestore(&time_state->lock_last_time, flags); complete(&time_state->comp_last_time); return 0; @@ -135,6 +142,9 @@ static int hid_time_capture_sample(struct hid_sensor_hub_device *hsdev, case HID_USAGE_SENSOR_TIME_SECOND: time_buf->tm_sec = (int)hid_time_value(raw_len, raw_data); break; + case HID_USAGE_SENSOR_TIME_MILLISECOND: + time_state->ms_buf = hid_time_value(raw_len, raw_data); + break; default: return -EINVAL; } @@ -161,12 +171,18 @@ static int hid_time_parse_report(struct platform_device *pdev, { int report_id, i; - for (i = 0; i < TIME_RTC_CHANNEL_MAX; ++i) + /* Check if all required attributes are available */ + for (i = 0; i < CHANNEL_SCAN_INDEX_MILLISECOND; ++i) if (sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT, usage_id, hid_time_addresses[i], &time_state->info[i]) < 0) return -EINVAL; + if (!sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT, + usage_id, hid_time_addresses[i], &time_state->info[i])) { + dev_info(&pdev->dev, "milliseconds supported\n"); + time_state->last_ms = 0; + } /* Check the (needed) attributes for sanity */ report_id = time_state->info[0].report_id; if (report_id < 0) { @@ -174,6 +190,10 @@ static int hid_time_parse_report(struct platform_device *pdev, return -EINVAL; } for (i = 0; i < TIME_RTC_CHANNEL_MAX; ++i) { + if (time_state->info[i].attrib_id == + HID_USAGE_SENSOR_TIME_MILLISECOND && + time_state->last_ms == UINT_MAX) + continue; if (time_state->info[i].report_id != report_id) { dev_err(&pdev->dev, "not all needed attributes inside the same report!\n"); @@ -212,21 +232,25 @@ static int hid_time_parse_report(struct platform_device *pdev, return 0; } -static int hid_rtc_read_time(struct device *dev, struct rtc_time *tm) +static int hid_time_get_report(struct hid_time_state *time_state) { - unsigned long flags; - struct hid_time_state *time_state = - platform_get_drvdata(to_platform_device(dev)); - int ret; - INIT_COMPLETION(time_state->comp_last_time); /* get a report with all values through requesting one value */ sensor_hub_input_attr_get_raw_value(time_state->common_attributes.hsdev, HID_USAGE_SENSOR_TIME, hid_time_addresses[0], time_state->info[0].report_id); /* wait for all values (event) */ - ret = wait_for_completion_killable_timeout( - &time_state->comp_last_time, HZ*6); + return wait_for_completion_killable_timeout(&time_state->comp_last_time, + HZ*6); +} + +static int hid_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + unsigned long flags; + struct hid_time_state *time_state = + platform_get_drvdata(to_platform_device(dev)); + int ret = hid_time_get_report(time_state); + if (ret > 0) { /* no error */ spin_lock_irqsave(&time_state->lock_last_time, flags); @@ -239,9 +263,25 @@ static int hid_rtc_read_time(struct device *dev, struct rtc_time *tm) return ret; /* killed (-ERESTARTSYS) */ } -static const struct rtc_class_ops hid_time_rtc_ops = { - .read_time = hid_rtc_read_time, -}; +static int hid_rtc_read_timeval(struct device *dev, struct timeval *tv) +{ + unsigned long flags; + struct hid_time_state *time_state = + platform_get_drvdata(to_platform_device(dev)); + int ret = hid_time_get_report(time_state); + + if (ret > 0) { + /* no error */ + spin_lock_irqsave(&time_state->lock_last_time, flags); + rtc_tm_to_time(&time_state->last_time, &tv->tv_sec); + tv->tv_usec = time_state->last_ms * USEC_PER_MSEC; + spin_unlock_irqrestore(&time_state->lock_last_time, flags); + return 0; + } + if (!ret) + return -EIO; /* timeouted */ + return ret; /* killed (-ERESTARTSYS) */ +} static void hid_time_register_rtc_work(struct work_struct *work) { @@ -251,7 +291,7 @@ static void hid_time_register_rtc_work(struct work_struct *work) struct platform_device *pdev = time_state->callbacks.pdev; time_state->rtc = devm_rtc_device_register(&pdev->dev, - "hid-sensor-time", &hid_time_rtc_ops, + "hid-sensor-time", &time_state->rtc_ops, THIS_MODULE); if (IS_ERR_OR_NULL(time_state->rtc)) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; @@ -283,6 +323,8 @@ static int hid_time_probe(struct platform_device *pdev) if (time_state == NULL) return -ENOMEM; + time_state->last_ms = UINT_MAX; + platform_set_drvdata(pdev, time_state); spin_lock_init(&time_state->lock_last_time); @@ -315,6 +357,10 @@ static int hid_time_probe(struct platform_device *pdev) return ret; } + time_state->rtc_ops.read_time = hid_rtc_read_time; + if (time_state->last_ms != UINT_MAX) + time_state->rtc_ops.read_timeval = hid_rtc_read_timeval; + /* * The HID device has to be registered to read the clock. * Because rtc_device_register() might read the time, we have to delay diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index 6f24446..b519c47 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -74,6 +74,7 @@ #define HID_USAGE_SENSOR_TIME_HOUR 0x200525 #define HID_USAGE_SENSOR_TIME_MINUTE 0x200526 #define HID_USAGE_SENSOR_TIME_SECOND 0x200527 +#define HID_USAGE_SENSOR_TIME_MILLISECOND 0x200528 /* Units */ #define HID_USAGE_SENSOR_UNITS_NOT_SPECIFIED 0x00 -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* Re: [PATCH 0/9 v3] RFC: timekeeping: rtc: change hctosys mechanism 2013-06-14 16:52 ` [PATCH 0/9 v3] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler ` (8 preceding siblings ...) 2013-06-14 16:52 ` [PATCH 9/9] RFC: rtc: rtc-hid-sensor-time: add support for rtc_read_timeval() Alexander Holler @ 2013-06-14 17:27 ` John Stultz 9 siblings, 0 replies; 78+ messages in thread From: John Stultz @ 2013-06-14 17:27 UTC (permalink / raw) To: Alexander Holler Cc: linux-kernel, Andrew Morton, rtc-linux, Thomas Gleixner, Alessandro Zummo On 06/14/2013 09:52 AM, Alexander Holler wrote: > Hello, > > Because I've become a request which made me slightly more optimistic about > the RFC patches, I've spend some more time on the patches doing cosmetic. > I know think the "quickly done" is gone and they might be ready for > submission. > > The whole series consists more or less of 3 mini-series. In the future, it might be easier if you split the series up into separate patchsets. That way it makes the dependencies clear. For instance, 1-3 I've got no objection to, and 7-9 are getting there, but the middle three patches are probably going to need a good bit more work. thanks -john ^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 3/3 v2] RFC: timekeeping: rtc: remove CONFIG_RTC_HCTOSYS and RTC_HCTOSYS_DEVICE 2013-06-06 10:51 ` [PATCH 0/3 v2] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler 2013-06-06 10:51 ` [PATCH 1/3 RESEND] RFC: timekeeping: introduce flag systime_was_set Alexander Holler 2013-06-06 10:51 ` [PATCH 2/3 v2] RFC: timekeeping: rtc: Introduce new kernel parameter hctosys Alexander Holler @ 2013-06-06 10:51 ` Alexander Holler 2 siblings, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-06-06 10:51 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, John Stultz, Thomas Gleixner, Alessandro Zummo, rtc-linux, Alexander Holler Those config options don't make sense anymore with the new hctosys mechanism introduced with the previous patch. That means two things: - If a (hardware) clock is available it will be used to set the time at boot. This was already the case for system which have a "persistent" clock, e.g. most x86 systems. The only way to specify the device used for hctosys is now by using the kernel parameter hctosys= introduced with a previous patch. - If a hardware clock was used for hctosys before suspend, this clock will be used to adjust the clock at resume. Again, this doesn't change anything on systems with a "persistent" clock. What's missing: I don't know much about those "persistent" clocks and I haven't had a deep look at them. That's especially true for the suspend/resume mechanism used by them. The mechanism I want to use is the following: The RTC subsystem now maintains the ID of the RTC device which was used for hctosys (in rtc_hctosys_dev_id) and therefor specifies the device which should be used to adjust the time after resume. Additionaly the (new) flag systime_was_set will be set to false at suspend and on resume this flag will be set to true if either the clock will be adjusted by the device used for hctosys or by userspace (through do_settimeofday()). That all should already work as expected for RTCs, what's missing for "persistent" clocks is that the flag systime_was_set is set to false on suspend and set to true on resume. Currently it just stays at true (which is set through hctosys if a "persistent" clock is found. But because "persistent" clocks don't go away (as it is possible with RTCs by removing the driver or the RTC itself), nor do "persistent" clocks might have two instances, this shouldn't be a problem at all. Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- Documentation/rtc.txt | 8 +++--- drivers/rtc/Kconfig | 35 ++--------------------- drivers/rtc/Makefile | 1 - drivers/rtc/class.c | 30 ++++++++++++------- drivers/rtc/hctosys.c | 76 ------------------------------------------------- drivers/rtc/rtc-proc.c | 25 ++-------------- drivers/rtc/rtc-sysfs.c | 6 +--- drivers/rtc/systohc.c | 5 +++- include/linux/rtc.h | 7 ++--- 9 files changed, 34 insertions(+), 159 deletions(-) delete mode 100644 drivers/rtc/hctosys.c diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt index 32aa400..a1abfd8 100644 --- a/Documentation/rtc.txt +++ b/Documentation/rtc.txt @@ -121,8 +121,9 @@ three different userspace interfaces: * /proc/driver/rtc ... the system clock RTC may expose itself using a procfs interface. If there is no RTC for the system clock, - rtc0 is used by default. More information is (currently) shown - here than through sysfs. + or a "persistent" clock is used to set the system clock, + /proc/driver/rtc will not exist. + More information is (currently) shown here than through sysfs. The RTC Class framework supports a wide variety of RTCs, ranging from those integrated into embeddable system-on-chip (SOC) processors to discrete chips @@ -144,8 +145,7 @@ rtc attributes without requiring the use of ioctls. All dates and times are in the RTC's timezone, rather than in system time. date: RTC-provided date -hctosys: 1 if the RTC provided the system time at boot via the - CONFIG_RTC_HCTOSYS kernel option, 0 otherwise +hctosys: 1 if the RTC provided the system time at boot, 0 otherwise max_user_freq: The maximum interrupt rate an unprivileged user may request from this RTC. name: The name of the RTC corresponding to this sysfs directory diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index b983813..b1d6691 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -17,44 +17,13 @@ menuconfig RTC_CLASS if RTC_CLASS -config RTC_HCTOSYS - bool "Set system time from RTC on startup and resume" - default y - help - If you say yes here, the system time (wall clock) will be set using - the value read from a specified RTC device. This is useful to avoid - unnecessary fsck runs at boot time, and to network better. - config RTC_SYSTOHC bool "Set the RTC time based on NTP synchronization" default y help If you say yes here, the system time (wall clock) will be stored - in the RTC specified by RTC_HCTOSYS_DEVICE approximately every 11 - minutes if userspace reports synchronized NTP status. - -config RTC_HCTOSYS_DEVICE - string "RTC used to set the system time" - depends on RTC_HCTOSYS = y || RTC_SYSTOHC = y - default "rtc0" - help - The RTC device that will be used to (re)initialize the system - clock, usually rtc0. Initialization is done when the system - starts up, and when it resumes from a low power state. This - device should record time in UTC, since the kernel won't do - timezone correction. - - The driver for this RTC device must be loaded before late_initcall - functions run, so it must usually be statically linked. - - This clock should be battery-backed, so that it reads the correct - time when the system boots from a power-off state. Otherwise, your - system will need an external clock source (like an NTP server). - - If the clock you specify here is not battery backed, it may still - be useful to reinitialize system time when resuming from system - sleep states. Do not specify an RTC here unless it stays powered - during all this system's supported sleep states. + in the RTC used to set the time at boot or resume approximately + every 11 minutes if userspace reports synchronized NTP status. config RTC_DEBUG bool "RTC debug support" diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index c33f86f..b699504 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -5,7 +5,6 @@ ccflags-$(CONFIG_RTC_DEBUG) := -DDEBUG obj-$(CONFIG_RTC_LIB) += rtc-lib.o -obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o obj-$(CONFIG_RTC_SYSTOHC) += systohc.o obj-$(CONFIG_RTC_CLASS) += rtc-core.o rtc-core-y := class.o interface.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index a159d1f..9ea5bdc 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -26,6 +26,9 @@ static DEFINE_IDA(rtc_ida); struct class *rtc_class; +/* The ID of the RTC device used to set the system clock */ +int __read_mostly rtc_hctosys_dev_id = -1; + static void rtc_device_release(struct device *dev) { struct rtc_device *rtc = to_rtc_device(dev); @@ -33,12 +36,7 @@ static void rtc_device_release(struct device *dev) kfree(rtc); } -#ifdef CONFIG_RTC_HCTOSYS_DEVICE -/* Result of the last RTC to system clock attempt. */ -int rtc_hctosys_ret = -ENODEV; -#endif - -#if defined(CONFIG_PM) && defined(CONFIG_RTC_HCTOSYS_DEVICE) +#if defined(CONFIG_PM) /* * On suspend(), measure the delta between one RTC and the * system's wall clock; restore it on resume(). @@ -53,12 +51,18 @@ static int rtc_suspend(struct device *dev, pm_message_t mesg) struct rtc_time tm; struct timespec delta, delta_delta; + + if (!systime_was_set) + return 0; + if (has_persistent_clock()) return 0; - if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) + if (rtc->id != rtc_hctosys_dev_id) return 0; + systime_was_set = false; + /* snapshot the current RTC and system time at suspend*/ rtc_read_time(rtc, &tm); getnstimeofday(&old_system); @@ -94,11 +98,13 @@ static int rtc_resume(struct device *dev) struct timespec new_system, new_rtc; struct timespec sleep_time; + if (systime_was_set) + return 0; + if (has_persistent_clock()) return 0; - rtc_hctosys_ret = -ENODEV; - if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) + if (rtc->id != rtc_hctosys_dev_id) return 0; /* snapshot the current rtc and system time at resume */ @@ -131,7 +137,7 @@ static int rtc_resume(struct device *dev) if (sleep_time.tv_sec >= 0) timekeeping_inject_sleeptime(&sleep_time); - rtc_hctosys_ret = 0; + systime_was_set = true; return 0; } @@ -166,13 +172,15 @@ static void hctosys(struct rtc_device *rtc) if (rc) { dev_err(rtc->dev.parent, "rtc core: error setting system clock: %d\n", rc); return; - } else if (systime_was_set) + } else if (systime_was_set) { + rtc_hctosys_dev_id = rtc->id; dev_info(rtc->dev.parent, "setting system clock to " "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec, (unsigned int) tv.tv_sec); + } } /** diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c deleted file mode 100644 index 4aa60d7..0000000 --- a/drivers/rtc/hctosys.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * RTC subsystem, initialize system time on startup - * - * Copyright (C) 2005 Tower Technologies - * Author: Alessandro Zummo <a.zummo@towertech.it> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include <linux/rtc.h> - -/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary - * whether it stores the most close value or the value with partial - * seconds truncated. However, it is important that we use it to store - * the truncated value. This is because otherwise it is necessary, - * in an rtc sync function, to read both xtime.tv_sec and - * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read - * of >32bits is not possible. So storing the most close value would - * slow down the sync API. So here we have the truncated value and - * the best guess is to add 0.5s. - */ - -static int __init rtc_hctosys(void) -{ - int err = -ENODEV; - struct rtc_time tm; - struct timespec tv = { - .tv_nsec = NSEC_PER_SEC >> 1, - }; - struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); - - if (rtc == NULL) { - pr_err("%s: unable to open rtc device (%s)\n", - __FILE__, CONFIG_RTC_HCTOSYS_DEVICE); - goto err_open; - } - - err = rtc_read_time(rtc, &tm); - if (err) { - dev_err(rtc->dev.parent, - "hctosys: unable to read the hardware clock\n"); - goto err_read; - - } - - err = rtc_valid_tm(&tm); - if (err) { - dev_err(rtc->dev.parent, - "hctosys: invalid date/time\n"); - goto err_invalid; - } - - rtc_tm_to_time(&tm, &tv.tv_sec); - - err = do_settimeofday(&tv); - - dev_info(rtc->dev.parent, - "setting system clock to " - "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, - (unsigned int) tv.tv_sec); - -err_invalid: -err_read: - rtc_class_close(rtc); - -err_open: - rtc_hctosys_ret = err; - - return err; -} - -late_initcall(rtc_hctosys); diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c index ffa69e1..fd59c1b 100644 --- a/drivers/rtc/rtc-proc.c +++ b/drivers/rtc/rtc-proc.c @@ -18,27 +18,6 @@ #include "rtc-core.h" -#define NAME_SIZE 10 - -#if defined(CONFIG_RTC_HCTOSYS_DEVICE) -static bool is_rtc_hctosys(struct rtc_device *rtc) -{ - int size; - char name[NAME_SIZE]; - - size = scnprintf(name, NAME_SIZE, "rtc%d", rtc->id); - if (size > NAME_SIZE) - return false; - - return !strncmp(name, CONFIG_RTC_HCTOSYS_DEVICE, NAME_SIZE); -} -#else -static bool is_rtc_hctosys(struct rtc_device *rtc) -{ - return (rtc->id == 0); -} -#endif - static int rtc_proc_show(struct seq_file *seq, void *offset) { int err; @@ -137,12 +116,12 @@ static const struct file_operations rtc_proc_fops = { void rtc_proc_add_device(struct rtc_device *rtc) { - if (is_rtc_hctosys(rtc)) + if (rtc->id == rtc_hctosys_dev_id) proc_create_data("driver/rtc", 0, NULL, &rtc_proc_fops, rtc); } void rtc_proc_del_device(struct rtc_device *rtc) { - if (is_rtc_hctosys(rtc)) + if (rtc->id == rtc_hctosys_dev_id) remove_proc_entry("driver/rtc", NULL); } diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index b70e2bb..6b8a41b 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -112,13 +112,9 @@ static ssize_t rtc_sysfs_show_hctosys(struct device *dev, struct device_attribute *attr, char *buf) { -#ifdef CONFIG_RTC_HCTOSYS_DEVICE - if (rtc_hctosys_ret == 0 && - strcmp(dev_name(&to_rtc_device(dev)->dev), - CONFIG_RTC_HCTOSYS_DEVICE) == 0) + if (to_rtc_device(dev)->id == rtc_hctosys_dev_id) return sprintf(buf, "1\n"); else -#endif return sprintf(buf, "0\n"); } diff --git a/drivers/rtc/systohc.c b/drivers/rtc/systohc.c index bf3e242..1962f4c 100644 --- a/drivers/rtc/systohc.c +++ b/drivers/rtc/systohc.c @@ -25,13 +25,16 @@ int rtc_set_ntp_time(struct timespec now) struct rtc_device *rtc; struct rtc_time tm; int err = -ENODEV; + char rtc_hctosys_name[10]; if (now.tv_nsec < (NSEC_PER_SEC >> 1)) rtc_time_to_tm(now.tv_sec, &tm); else rtc_time_to_tm(now.tv_sec + 1, &tm); - rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); + scnprintf(rtc_hctosys_name, sizeof(rtc_hctosys_name), "rtc%d", + rtc_hctosys_dev_id); + rtc = rtc_class_open(rtc_hctosys_name); if (rtc) { /* rtc_hctosys exclusively uses UTC, so we call set_time here, * not set_mmss. */ diff --git a/include/linux/rtc.h b/include/linux/rtc.h index c2c2897..50caf0d 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -191,10 +191,7 @@ static inline bool is_leap_year(unsigned int year) return (!(year % 4) && (year % 100)) || !(year % 400); } -#ifdef CONFIG_RTC_HCTOSYS_DEVICE -extern int rtc_hctosys_ret; -#else -#define rtc_hctosys_ret -ENODEV -#endif +/* The ID of the RTC device used to set the system clock */ +extern int rtc_hctosys_dev_id; #endif /* _LINUX_RTC_H_ */ -- 1.8.1.5 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH] rtc: rtc-hid-sensor-time: fix possible bug on driver_remove 2013-05-05 11:21 ` [PATCH 3/4] rtc: rtc-hid-sensor-time: add option hctosys to set time at boot Alexander Holler 2013-05-21 21:42 ` Andrew Morton 2013-05-21 22:02 ` John Stultz @ 2013-06-04 9:38 ` Alexander Holler 2013-06-08 8:56 ` Alexander Holler 2 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2013-06-04 9:38 UTC (permalink / raw) To: Andrew Morton Cc: linux-kernel, rtc-linux, Alessandro Zummo, John Stultz, Alexander Holler The work we schedule on register deletes himself. Therefor we cannot use cancel_work_sync() because that calls flush_work() but still uses the pointer to the (now deleted) work afterwards (for clear_work_data) which ends up in a bug. Replacing cancel_work_sync() with flush_work() fixes that. Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- This patch applies on top of PATCH 3/4 or 4/4 of the small series of 4 patches for rtc-hid-sensor-time, which was already merged into the -mm tree. drivers/rtc/rtc-hid-sensor-time.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index 4aca12d..acb2bc2 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -414,9 +414,8 @@ static int hid_time_remove(struct platform_device *pdev) struct hid_time_state *time_state = platform_get_drvdata(pdev); if (time_state->workts) { - cancel_work_sync(&time_state->workts->work); - kfree(time_state->workts); - time_state->workts = NULL; + flush_work(&time_state->workts->work); + BUG_ON(time_state->workts != NULL); } sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); -- 1.8.1.5 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* Re: [PATCH] rtc: rtc-hid-sensor-time: fix possible bug on driver_remove 2013-06-04 9:38 ` [PATCH] rtc: rtc-hid-sensor-time: fix possible bug on driver_remove Alexander Holler @ 2013-06-08 8:56 ` Alexander Holler 0 siblings, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-06-08 8:56 UTC (permalink / raw) To: Alexander Holler Cc: Andrew Morton, linux-kernel, rtc-linux, Alessandro Zummo, John Stultz Hello, sorry to bother again. I've now had the time to play with the new hctosys I proposed patches for and rtc-hid-sensor-time. If the new hctosys mechanism will end up in the kernel, the following patches I've recently send and which already got merged to -mm won't work anymore and should disappear: [PATCH 3/4] rtc: rtc-hid-sensor-time: add option hctosys to set time at boot [PATCH 4/4] rtc: rtc-hid-sensor-time: add support for milliseconds [PATCH] rtc: rtc-hid-sensor-time: fix possible bug on driver_remove The other two patches [PATCH 1/4] rtc: rtc-hid-sensor-time: allow full years (16bit) in HID reports [PATCH 2/4] rtc: rtc-hid-sensor-time: allow 16 and 32 bit values for all attributes. which got merged too are still fine. I don't know if I should send reverts for those 3 patches, or ... I've already have a patch which would be needed if the new hctosys would be used, but I will delay sending them until we figured out if and how that new hctosys will become real. But you might already revert or delete the above 3 patches in your tree. That silly looking driver rtc-hid-sensor-time is really an endless story. :/ Besides writing the driver and an example firmware implementation I had to make patches for iio, hid-sensor-hub and hid, and now for timekeeping and rtc. All for nothing but the fun having to convince maintainers of all sorts and bothering them. ;) And the todo-list still contains some stuff: - rtc-hid-sensor-time still does not get loaded automatically if a matching hid-sensor-hub appears to the system. That needs changes to hid and/or hid-sensor-hub. Problem is that I don't have a real hid sensor hub and I don't know why the people which do produce such products and have written hid-sensor-hub didn't have implemented a way to do such. Or I've just missed something. - Have to redo millisecond support. - ntp functionality (e.g. module parameter adjtime) to make it possible to use a hardware clock with support for milliseconds to turn the system clock to a stratum 1 clock. - and last but not least I hope the standard for those HID sensors will become a standardized way to set the time. I still wouldn't like it if I had to "invent" something myself (easy, but it would be linux-specific and "invented" by some fool like me who just wrote it's own firmware without having any knowledge about some real hid-sensor products ;) ), but ... Regards, Alexander Holler ^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/4] rtc: rtc-hid-sensor-time: add support for milliseconds 2013-05-05 11:21 ` [PATCH 0/4] rtc: rtc-hid-sensor-time: some changes Alexander Holler ` (2 preceding siblings ...) 2013-05-05 11:21 ` [PATCH 3/4] rtc: rtc-hid-sensor-time: add option hctosys to set time at boot Alexander Holler @ 2013-05-05 11:21 ` Alexander Holler 3 siblings, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-05-05 11:21 UTC (permalink / raw) To: linux-kernel Cc: rtc-linux, Andrew Morton, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, Jiri Kosina, John Stultz, Alexander Holler If a device sends milliseconds too, the driver will use them if it sets the system clock at startup (through module option hctosys). Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- drivers/rtc/rtc-hid-sensor-time.c | 37 +++++++++++++++++++++++++++++++++---- include/linux/hid-sensor-ids.h | 1 + 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index db8503a..4aca12d 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -40,6 +40,7 @@ enum hid_time_channel { CHANNEL_SCAN_INDEX_HOUR, CHANNEL_SCAN_INDEX_MINUTE, CHANNEL_SCAN_INDEX_SECOND, + CHANNEL_SCAN_INDEX_MILLISECOND, /* optional */ TIME_RTC_CHANNEL_MAX, }; @@ -53,9 +54,11 @@ struct hid_time_state { struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info info[TIME_RTC_CHANNEL_MAX]; struct rtc_time last_time; + unsigned last_ms; /* == UINT_MAX to indicate ms aren't supported */ spinlock_t lock_last_time; struct completion comp_last_time; struct rtc_time time_buf; + unsigned ms_buf; struct rtc_device *rtc; struct hid_time_workts *workts; }; @@ -67,16 +70,18 @@ static const u32 hid_time_addresses[TIME_RTC_CHANNEL_MAX] = { HID_USAGE_SENSOR_TIME_HOUR, HID_USAGE_SENSOR_TIME_MINUTE, HID_USAGE_SENSOR_TIME_SECOND, + HID_USAGE_SENSOR_TIME_MILLISECOND, /* optional */ }; /* Channel names for verbose error messages */ static const char * const hid_time_channel_names[TIME_RTC_CHANNEL_MAX] = { - "year", "month", "day", "hour", "minute", "second", + "year", "month", "day", "hour", "minute", "second", "millisecond", }; static void hid_time_hctosys(struct hid_time_state *time_state) { struct timespec ts; + char msbuf[5]; int rc = rtc_valid_tm(&time_state->last_time); if (rc) { @@ -102,18 +107,25 @@ static void hid_time_hctosys(struct hid_time_state *time_state) */ return; - ts.tv_nsec = NSEC_PER_SEC >> 1; + if (time_state->last_ms != UINT_MAX) { + ts.tv_nsec = time_state->last_ms * NSEC_PER_MSEC; + snprintf(msbuf, sizeof(msbuf), ":%03d", time_state->last_ms); + } else { + ts.tv_nsec = NSEC_PER_SEC >> 1; + *msbuf = 0; + } rtc_tm_to_time(&time_state->last_time, &ts.tv_sec); rc = do_settimeofday(&ts); dev_info(time_state->rtc->dev.parent, "hctosys: setting system clock to " - "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", + "%d-%02d-%02d %02d:%02d:%02d%s UTC (%u)\n", time_state->last_time.tm_year + 1900, time_state->last_time.tm_mon + 1, time_state->last_time.tm_mday, time_state->last_time.tm_hour, time_state->last_time.tm_min, time_state->last_time.tm_sec, + msbuf, (unsigned int) ts.tv_sec); } @@ -126,6 +138,8 @@ static int hid_time_proc_event(struct hid_sensor_hub_device *hsdev, spin_lock_irqsave(&time_state->lock_last_time, flags); time_state->last_time = time_state->time_buf; + if (time_state->last_ms != UINT_MAX) + time_state->last_ms = time_state->ms_buf; spin_unlock_irqrestore(&time_state->lock_last_time, flags); complete(&time_state->comp_last_time); if (unlikely(!hid_time_time_set_once && hid_time_hctosys_enabled)) { @@ -188,6 +202,9 @@ static int hid_time_capture_sample(struct hid_sensor_hub_device *hsdev, case HID_USAGE_SENSOR_TIME_SECOND: time_buf->tm_sec = (int)hid_time_value(raw_len, raw_data); break; + case HID_USAGE_SENSOR_TIME_MILLISECOND: + time_state->ms_buf = hid_time_value(raw_len, raw_data); + break; default: return -EINVAL; } @@ -214,12 +231,18 @@ static int hid_time_parse_report(struct platform_device *pdev, { int report_id, i; - for (i = 0; i < TIME_RTC_CHANNEL_MAX; ++i) + /* Check if all required attributes are available */ + for (i = 0; i < CHANNEL_SCAN_INDEX_MILLISECOND; ++i) if (sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT, usage_id, hid_time_addresses[i], &time_state->info[i]) < 0) return -EINVAL; + if (!sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT, + usage_id, hid_time_addresses[i], &time_state->info[i])) { + dev_info(&pdev->dev, "milliseconds supported\n"); + time_state->last_ms = 0; + } /* Check the (needed) attributes for sanity */ report_id = time_state->info[0].report_id; if (report_id < 0) { @@ -227,6 +250,10 @@ static int hid_time_parse_report(struct platform_device *pdev, return -EINVAL; } for (i = 0; i < TIME_RTC_CHANNEL_MAX; ++i) { + if (time_state->info[i].attrib_id == + HID_USAGE_SENSOR_TIME_MILLISECOND && + time_state->last_ms == UINT_MAX) + continue; if (time_state->info[i].report_id != report_id) { dev_err(&pdev->dev, "not all needed attributes inside the same report!\n"); @@ -319,6 +346,8 @@ static int hid_time_probe(struct platform_device *pdev) if (time_state == NULL) return -ENOMEM; + time_state->last_ms = UINT_MAX; + platform_set_drvdata(pdev, time_state); spin_lock_init(&time_state->lock_last_time); diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index 6f24446..b519c47 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -74,6 +74,7 @@ #define HID_USAGE_SENSOR_TIME_HOUR 0x200525 #define HID_USAGE_SENSOR_TIME_MINUTE 0x200526 #define HID_USAGE_SENSOR_TIME_SECOND 0x200527 +#define HID_USAGE_SENSOR_TIME_MILLISECOND 0x200528 /* Units */ #define HID_USAGE_SENSOR_UNITS_NOT_SPECIFIED 0x00 -- 1.8.1.5 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* Re: [PATCH 0/3] rtc: rtc-hid-sensor-time 2013-04-19 15:14 [PATCH 0/3] rtc: rtc-hid-sensor-time Alexander Holler ` (2 preceding siblings ...) 2013-04-19 15:14 ` [PATCH 3/3] rtc: rtc-hid-sensor-time; add option hctosys to set time at boot Alexander Holler @ 2013-04-20 23:46 ` Jiri Kosina 2013-04-21 6:38 ` Alexander Holler 3 siblings, 1 reply; 78+ messages in thread From: Jiri Kosina @ 2013-04-20 23:46 UTC (permalink / raw) To: Alexander Holler Cc: linux-kernel, rtc-linux, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron On Fri, 19 Apr 2013, Alexander Holler wrote: > as I'm not sure if the maintainer of the RTC subsystem is active again, > I've added the people which where involved with rtc-hid-sensor-time > before to cc too. That might be a good idea even he is active again, > as the driver depends on hid-sensor-hub and as such works a bit > outside the stuff other RTC drivers do use. Agreed. I'd say let's wait if RTC maintainer(s) step up and have anything to say to this patchset. If there's a silence, it'll probably be ok taking it through my review process and my tree, but at least for 3/3 I'd definitely like to have Ack from someone else as well. For this reason, this is likely not be 3.10 material, but 3.11. Thanks, -- Jiri Kosina SUSE Labs ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: [PATCH 0/3] rtc: rtc-hid-sensor-time 2013-04-20 23:46 ` [PATCH 0/3] rtc: rtc-hid-sensor-time Jiri Kosina @ 2013-04-21 6:38 ` Alexander Holler 0 siblings, 0 replies; 78+ messages in thread From: Alexander Holler @ 2013-04-21 6:38 UTC (permalink / raw) To: Jiri Kosina Cc: linux-kernel, rtc-linux, Alessandro Zummo, Lars-Peter Clausen, Jonathan Cameron, John Stultz, Thomas Gleixner Am 21.04.2013 01:46, schrieb Jiri Kosina: > On Fri, 19 Apr 2013, Alexander Holler wrote: > >> as I'm not sure if the maintainer of the RTC subsystem is active again, >> I've added the people which where involved with rtc-hid-sensor-time >> before to cc too. That might be a good idea even he is active again, >> as the driver depends on hid-sensor-hub and as such works a bit >> outside the stuff other RTC drivers do use. > > Agreed. I'd say let's wait if RTC maintainer(s) step up and have anything > to say to this patchset. > > If there's a silence, it'll probably be ok taking it through my review > process and my tree, but at least for 3/3 I'd definitely like to have Ack > from someone else as well. > > For this reason, this is likely not be 3.10 material, but 3.11. Thanks a lot. I already have another patch here to support milliseconds (for hctosys), and I might have another patch ready in a few days, which adjusts the system time whenever the HID device sends a timestamp which includes milliseconds (enabled by a new module option named adjtime for rtc-hid-sensor-time, which is by default off). The basics do already work, but I'm just starting to look at how to adjust the system time best, so suggestions are welcome. ;) (Therefor I've now added the maintainers for kernel/time/timekeeping.c to cc). Regards, Alexander ^ permalink raw reply [flat|nested] 78+ messages in thread
* Re: rtc/hctosys.c Problem during kernel boot
@ 2014-06-12 13:15 Alessandro Zummo
2014-06-13 4:13 ` [PATCH 1/3] RFC: timekeeping: introduce flag systime_was_set Alexander Holler
0 siblings, 1 reply; 78+ messages in thread
From: Alessandro Zummo @ 2014-06-12 13:15 UTC (permalink / raw)
To: Alexander Holler; +Cc: John Stultz, John Whitmore, Linux Kernel Mailing List
On Thu, 12 Jun 2014 14:01:46 +0200
Alexander Holler <holler@ahsoftware.de> wrote:
> Unfortunately my expieriences with Linux kernel maintainers became even
> worse and I'm not very eager to post patches. But if someone wants these
> patches based on 3.15, feel free to notice me.
>
> To get rid of hctosys, I have 3 patches, and 2 more to implement
> rtc_read_timeval() for higher resolution clocks.
Yes, I know the experience might be a painful one.
Please send the patches and let's see if they fix the issue for John too.
--
Best regards,
Alessandro Zummo,
Tower Technologies - Torino, Italy
http://www.towertech.it
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 1/3] RFC: timekeeping: introduce flag systime_was_set 2014-06-12 13:15 rtc/hctosys.c Problem during kernel boot Alessandro Zummo @ 2014-06-13 4:13 ` Alexander Holler 2014-06-13 4:13 ` [PATCH 2/3] RFC: timekeeping: rtc: Introduce new kernel parameter hctosys Alexander Holler 0 siblings, 1 reply; 78+ messages in thread From: Alexander Holler @ 2014-06-13 4:13 UTC (permalink / raw) To: John Whitmore Cc: John Stultz, Alessandro Zummo, linux-kernel, Alexander Holler In order to let an RTC set the time at boot without the problem that a second RTC overwrites it, the flag systime_was_set is introduced. systime_was_set will be true, if a persistent clock sets the time at boot, or if do_settimeofday() is called (e.g. by the RTC subsystem or userspace). Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- I've based these patches on 3.15, an older version can be found at LKML, Besides discussing possible *real* bugs, I don't care what any person (including maintainers) will request. I'm fine with these patches (I'm using them since a year) and I don't play remote keyboard or patch ping-pong. If someone want changes I suggest he gets responsible for them himself and just puts a patch on top of my patches. And in any case, feel free to completely ignore these patches. (This note will destroy itself when using git am.) include/linux/time.h | 6 ++++++ kernel/time/timekeeping.c | 10 +++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/linux/time.h b/include/linux/time.h index d5d229b..888280f 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -129,6 +129,12 @@ extern int update_persistent_clock(struct timespec now); void timekeeping_init(void); extern int timekeeping_suspended; +/* + * Will be true if the system time was set at least once by + * a persistent clock, RTC or userspace. + */ +extern bool systime_was_set; + unsigned long get_seconds(void); struct timespec current_kernel_time(void); struct timespec __current_kernel_time(void); /* does not take xtime_lock */ diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index f7df8ea..6be8b72 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -43,6 +43,9 @@ int __read_mostly timekeeping_suspended; /* Flag for if there is a persistent clock on this platform */ bool __read_mostly persistent_clock_exist = false; +/* Flag for if the system time was set at least once */ +bool __read_mostly systime_was_set; + static inline void tk_normalize_xtime(struct timekeeper *tk) { while (tk->xtime_nsec >= ((u64)NSEC_PER_SEC << tk->shift)) { @@ -505,6 +508,9 @@ int do_settimeofday(const struct timespec *tv) raw_spin_lock_irqsave(&timekeeper_lock, flags); write_seqcount_begin(&timekeeper_seq); + systime_was_set = true; + + timekeeping_forward_now(tk); xt = tk_xtime(tk); @@ -799,8 +805,10 @@ void __init timekeeping_init(void) " Check your CMOS/BIOS settings.\n"); now.tv_sec = 0; now.tv_nsec = 0; - } else if (now.tv_sec || now.tv_nsec) + } else if (now.tv_sec || now.tv_nsec) { persistent_clock_exist = true; + systime_was_set = true; + } read_boot_clock(&boot); if (!timespec_valid_strict(&boot)) { -- 1.8.3.2 ^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 2/3] RFC: timekeeping: rtc: Introduce new kernel parameter hctosys 2014-06-13 4:13 ` [PATCH 1/3] RFC: timekeeping: introduce flag systime_was_set Alexander Holler @ 2014-06-13 4:13 ` Alexander Holler 0 siblings, 0 replies; 78+ messages in thread From: Alexander Holler @ 2014-06-13 4:13 UTC (permalink / raw) To: John Whitmore Cc: John Stultz, Alessandro Zummo, linux-kernel, Alexander Holler hctosys= specifies the driver (RTC) name which sets the system clock at boot, if and only if userspace hasn't set the time before the driver will be loaded. If hctosys will not be specified, the first available hardware clock with a valid time will be used (again, if and only if ...). If you don't want that the system clock will be set by any hardware clock, just specify a non-existent RTC driver name, e.g. with hctosys=none. Currently there exist a special name "persistent" for the persistent clock found on some systems (e.g. the CMOS clock on x86 platforms which might be handled by the driver named rtc_cmos too). This will replace the existent driver/mechanism hctosys and the kernel config options CONFIG_RTC_HCTOSYS and CONFIG_RTC_HCTOSYS_DEVICE (done with one of the following patches) Signed-off-by: Alexander Holler <holler@ahsoftware.de> --- I've based these patches on 3.15, an older version can be found at LKML, Besides discussing possible *real* bugs, I don't care what any person (including maintainers) will request. I'm fine with these patches (I'm using them since a year) and I don't play remote keyboard or patch ping-pong. If someone want changes I suggest he gets responsible for them himself and just puts a patch on top of my patches. And in any case, feel free to completely ignore these patches. (This note will destroy itself when using git am.) Documentation/kernel-parameters.txt | 12 +++++++++ drivers/rtc/class.c | 42 +++++++++++++++++++++++++++++ include/linux/time.h | 6 +++++ kernel/time/timekeeping.c | 53 ++++++++++++++++++++++++++++--------- 4 files changed, 101 insertions(+), 12 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 30a8ad0d..77a36ba 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1110,6 +1110,18 @@ bytes respectively. Such letter suffixes can also be entirely omitted. hcl= [IA-64] SGI's Hardware Graph compatibility layer + hctosys= [KNL] Specifies the driver (RTC) name which sets the + time at boot, if and only if userspace hasn't set the + time before the driver will be loaded. If hctosys will + not be specified, the first available hardware clock + with a valid time will be used. + Use a non-existent name (e.g. hctosys=none) if you want + to avoid that a hardware clock will set the time. + Currently there exist a special name "persistent" for + the persistent clock found on some systems (e.g. the + CMOS clock on x86 platforms which might be handled + by the driver named rtc_cmos too). + hd= [EIDE] (E)IDE hard drive subsystem geometry Format: <cyl>,<head>,<sect> diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 589351e..18c47b0 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -143,6 +143,43 @@ static SIMPLE_DEV_PM_OPS(rtc_class_dev_pm_ops, rtc_suspend, rtc_resume); #endif +static void hctosys(struct rtc_device *rtc) +{ + struct rtc_time now; + struct timespec ts = { + .tv_nsec = NSEC_PER_SEC >> 1, + }; + int rc; + + rc = rtc_read_time(rtc, &now); + if (unlikely(rc)) { + dev_err(rtc->dev.parent, + "rtc core: error reading time from RTC: %d\n", rc); + return; + } + rc = rtc_valid_tm(&now); + if (unlikely(rc)) { + dev_err(rtc->dev.parent, + "rtc core: timestamp from RTC is invalid\n"); + return; + } + rtc_tm_to_time(&now, &ts.tv_sec); + if (systime_was_set) + return; + rc = do_settimeofday(&ts); + if (unlikely(rc)) { + dev_err(rtc->dev.parent, + "rtc core: error setting system clock: %d\n", rc); + return; + } else if (systime_was_set) + dev_info(rtc->dev.parent, + "rtc core: setting system clock to " + "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", + now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, + now.tm_hour, now.tm_min, now.tm_sec, + (unsigned int) ts.tv_sec); +} + /** * rtc_device_register - register w/ RTC class * @dev: the device to register @@ -159,6 +196,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, struct rtc_device *rtc; struct rtc_wkalrm alrm; int of_id = -1, id = -1, err; + const char *hctosys_name = get_hctosys_name(); if (dev->of_node) of_id = of_alias_get_id(dev->of_node, "rtc"); @@ -213,6 +251,10 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, rtc->pie_timer.function = rtc_pie_update_irq; rtc->pie_enabled = 0; + if (!systime_was_set && + (!hctosys_name[0] || !strcasecmp(name, hctosys_name))) + hctosys(rtc); + /* Check to see if there is an ALARM already set in hw */ err = __rtc_read_alarm(rtc, &alrm); diff --git a/include/linux/time.h b/include/linux/time.h index 888280f..e5f644c 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -135,6 +135,12 @@ extern int timekeeping_suspended; */ extern bool systime_was_set; +/* + * Returns a pointer to the string specified with + * hctosys= at the kernel command line. + */ +const char *get_hctosys_name(void); + unsigned long get_seconds(void); struct timespec current_kernel_time(void); struct timespec __current_kernel_time(void); /* does not take xtime_lock */ diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 6be8b72..c8992e4 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -18,6 +18,7 @@ #include <linux/syscore_ops.h> #include <linux/clocksource.h> #include <linux/jiffies.h> +#include <linux/rtc.h> #include <linux/time.h> #include <linux/tick.h> #include <linux/stop_machine.h> @@ -46,6 +47,22 @@ bool __read_mostly persistent_clock_exist = false; /* Flag for if the system time was set at least once */ bool __read_mostly systime_was_set; +static char hctosys_name[RTC_DEVICE_NAME_SIZE]; + +static int __init hctosys_setup(char *line) +{ + strlcpy(hctosys_name, line, sizeof(hctosys_name)); + return 1; +} + +__setup("hctosys=", hctosys_setup); + +const char *get_hctosys_name(void) +{ + return hctosys_name; +} +EXPORT_SYMBOL_GPL(get_hctosys_name); + static inline void tk_normalize_xtime(struct timekeeper *tk) { while (tk->xtime_nsec >= ((u64)NSEC_PER_SEC << tk->shift)) { @@ -796,18 +813,19 @@ void __init timekeeping_init(void) struct timekeeper *tk = &timekeeper; struct clocksource *clock; unsigned long flags; - struct timespec now, boot, tmp; - - read_persistent_clock(&now); - - if (!timespec_valid_strict(&now)) { - pr_warn("WARNING: Persistent clock returned invalid value!\n" - " Check your CMOS/BIOS settings.\n"); - now.tv_sec = 0; - now.tv_nsec = 0; - } else if (now.tv_sec || now.tv_nsec) { - persistent_clock_exist = true; - systime_was_set = true; + struct timespec now = {0, 0}, boot, tmp; + + if (!hctosys_name[0] || !strcasecmp(hctosys_name, "persistent")) { + read_persistent_clock(&now); + if (!timespec_valid_strict(&now)) { + pr_warn("WARNING: Persistent clock returned invalid value!\n" + " Check your CMOS/BIOS settings.\n"); + now.tv_sec = 0; + now.tv_nsec = 0; + } else if (now.tv_sec || now.tv_nsec) { + persistent_clock_exist = true; + systime_was_set = true; + } } read_boot_clock(&boot); @@ -844,6 +862,17 @@ void __init timekeeping_init(void) write_seqcount_end(&timekeeper_seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); + + if (systime_was_set) { + /* print a msg like if the time was set by a RTC */ + struct tm now_tm; + time_to_tm(now.tv_sec, 0, &now_tm); + pr_info("persistent clock: setting system clock to " + "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n", + (int)now_tm.tm_year + 1900, now_tm.tm_mon + 1, + now_tm.tm_mday, now_tm.tm_hour, now_tm.tm_min, + now_tm.tm_sec, (unsigned int) now.tv_sec); + } } /* time in seconds when suspend began */ -- 1.8.3.2 ^ permalink raw reply related [flat|nested] 78+ messages in thread
end of thread, other threads:[~2014-06-13 4:14 UTC | newest] Thread overview: 78+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2013-04-19 15:14 [PATCH 0/3] rtc: rtc-hid-sensor-time Alexander Holler 2013-04-19 15:14 ` [PATCH 1/3 RESEND] rtc: rtc-hid-sensor-time: allow full years (16bit) in HID reports Alexander Holler 2013-04-19 15:14 ` [PATCH 2/3] rtc: rtc-hid-sensor-time: allow 16 and 32 bit values for all attributes Alexander Holler 2013-04-19 15:14 ` [PATCH 3/3] rtc: rtc-hid-sensor-time; add option hctosys to set time at boot Alexander Holler 2013-04-22 23:38 ` Andrew Morton 2013-04-23 8:51 ` Alexander Holler 2013-04-23 10:08 ` Alexander Holler 2013-04-23 10:13 ` Alexander Holler 2013-04-23 10:17 ` Alexander Holler 2013-04-23 15:47 ` Alexander Holler 2013-04-24 21:14 ` Andrew Morton 2013-04-25 6:55 ` Alexander Holler 2013-05-05 11:21 ` [PATCH 0/4] rtc: rtc-hid-sensor-time: some changes Alexander Holler 2013-05-05 11:21 ` [PATCH 1/4] rtc: rtc-hid-sensor-time: allow full years (16bit) in HID reports Alexander Holler 2013-05-05 11:21 ` [PATCH 2/4] rtc: rtc-hid-sensor-time: allow 16 and 32 bit values for all attributes Alexander Holler 2013-05-05 11:21 ` [PATCH 3/4] rtc: rtc-hid-sensor-time: add option hctosys to set time at boot Alexander Holler 2013-05-21 21:42 ` Andrew Morton 2013-05-21 22:02 ` John Stultz 2013-05-21 23:15 ` Alexander Holler 2013-05-28 19:37 ` John Stultz 2013-05-29 4:42 ` Alexander Holler 2013-06-04 13:41 ` Alexander Holler 2013-06-05 17:15 ` [PATCH 0/3] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler 2013-06-05 17:15 ` [PATCH 1/3] RFC: timekeeping: introduce flag systime_was_set Alexander Holler 2013-06-05 17:15 ` [PATCH 2/3] RFC: timekeeping: rtc: Introduce new kernel parameter hctosys Alexander Holler 2013-06-05 17:15 ` [PATCH 3/3] RFC: timekeeping: rtc: remove CONFIG_RTC_HCTOSYS and RTC_HCTOSYS_DEVICE Alexander Holler 2013-06-06 10:51 ` [PATCH 0/3 v2] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler 2013-06-06 10:51 ` [PATCH 1/3 RESEND] RFC: timekeeping: introduce flag systime_was_set Alexander Holler 2013-06-06 10:51 ` [PATCH 2/3 v2] RFC: timekeeping: rtc: Introduce new kernel parameter hctosys Alexander Holler 2013-06-13 19:39 ` Alexander Holler 2013-06-14 16:52 ` [PATCH 0/9 v3] RFC: timekeeping: rtc: change hctosys mechanism Alexander Holler 2013-06-14 16:52 ` [PATCH 1/9 RESEND] rtc: rtc-hid-sensor-time: allow full years (16bit) in HID reports Alexander Holler 2013-06-14 16:52 ` [PATCH 2/9 RESEND] rtc: rtc-hid-sensor-time: allow 16 and 32 bit values for all attributes Alexander Holler 2013-06-14 16:52 ` [PATCH 3/9] rtc: rtc-hid-sensor-time: delay registering as rtc into a work Alexander Holler 2013-06-20 10:39 ` [PATCH 3/9 v2] " Alexander Holler 2013-06-26 19:55 ` Andrew Morton 2013-06-26 21:34 ` [rtc-linux] " Alexander Holler 2013-06-26 22:07 ` Greg KH 2013-06-26 23:51 ` Alexander Holler 2013-07-06 8:55 ` Alexander Holler 2013-07-06 18:21 ` Jiri Kosina 2013-07-07 7:35 ` Alexander Holler 2013-07-08 9:12 ` [PATCH 0/2] rtc: rtc-hid-sensor-time: enable HID input processing early Alexander Holler 2013-07-08 9:12 ` [PATCH 1/2] rtc: rtc-hid-sensor-time: improve error handling when rtc register fails Alexander Holler 2013-07-08 9:12 ` [PATCH 2/2] rtc: rtc-hid-sensor-time: enable HID input processing early Alexander Holler 2013-06-28 1:29 ` [rtc-linux] Re: [PATCH 3/9 v2] rtc: rtc-hid-sensor-time: delay registering as rtc into a work Alexander Holler 2013-06-14 16:52 ` [PATCH 4/9 RESEND] RFC: timekeeping: introduce flag systime_was_set Alexander Holler 2013-06-14 17:41 ` John Stultz 2013-06-14 18:05 ` [rtc-linux] " Alexander Holler 2013-06-14 18:28 ` John Stultz 2013-06-15 6:01 ` Alexander Holler 2013-06-17 18:10 ` John Stultz 2013-06-20 10:15 ` Alexander Holler 2013-06-20 17:27 ` John Stultz 2013-06-20 18:45 ` Alexander Holler 2013-06-20 19:28 ` John Stultz 2013-06-20 23:10 ` Alexander Holler 2013-06-14 16:52 ` [PATCH 5/9 v3] RFC: timekeeping: rtc: Introduce new kernel parameter hctosys Alexander Holler 2013-06-14 19:24 ` John Stultz 2013-06-14 16:52 ` [PATCH 6/9 v3] RFC: timekeeping: rtc: remove CONFIG_RTC_HCTOSYS and RTC_HCTOSYS_DEVICE Alexander Holler 2013-06-14 19:11 ` John Stultz 2013-06-22 8:00 ` Alexander Holler 2013-06-14 16:52 ` [PATCH 7/9] RFC: rtc: implement rtc_read_timeval() Alexander Holler 2013-06-14 17:23 ` John Stultz 2013-06-14 17:43 ` Alexander Holler 2013-06-14 19:18 ` John Stultz 2013-06-14 17:28 ` John Stultz 2013-06-14 16:52 ` [PATCH 8/9] RFC: rtc: hctosys: support rtc_read_timeval() for high precision clocks Alexander Holler 2013-06-14 19:20 ` John Stultz 2013-06-14 16:52 ` [PATCH 9/9] RFC: rtc: rtc-hid-sensor-time: add support for rtc_read_timeval() Alexander Holler 2013-06-14 17:27 ` [PATCH 0/9 v3] RFC: timekeeping: rtc: change hctosys mechanism John Stultz 2013-06-06 10:51 ` [PATCH 3/3 v2] RFC: timekeeping: rtc: remove CONFIG_RTC_HCTOSYS and RTC_HCTOSYS_DEVICE Alexander Holler 2013-06-04 9:38 ` [PATCH] rtc: rtc-hid-sensor-time: fix possible bug on driver_remove Alexander Holler 2013-06-08 8:56 ` Alexander Holler 2013-05-05 11:21 ` [PATCH 4/4] rtc: rtc-hid-sensor-time: add support for milliseconds Alexander Holler 2013-04-20 23:46 ` [PATCH 0/3] rtc: rtc-hid-sensor-time Jiri Kosina 2013-04-21 6:38 ` Alexander Holler 2014-06-12 13:15 rtc/hctosys.c Problem during kernel boot Alessandro Zummo 2014-06-13 4:13 ` [PATCH 1/3] RFC: timekeeping: introduce flag systime_was_set Alexander Holler 2014-06-13 4:13 ` [PATCH 2/3] RFC: timekeeping: rtc: Introduce new kernel parameter hctosys Alexander Holler
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).