From: gregory.clement@free-electrons.com (Gregory CLEMENT)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v2 2/5] drivers/rtc/rtc-armada38x: Add a new RTC driver for recent mvebu SoCs
Date: Thu, 15 Jan 2015 10:51:44 +0100 [thread overview]
Message-ID: <54B78DB0.5050808@free-electrons.com> (raw)
In-Reply-To: <871tmxrsj8.fsf@natisbad.org>
Hi Arnaud,
[...]
>> +/*
>> + * According to the datasheet, we need to wait for 5us only between
>> + * two consecutive writes
>> + */
>> +static void rtc_delayed_write(u32 val, struct armada38x_rtc *rtc, int offset)
>> +{
>> + writel(val, rtc->regs + offset);
>> + udelay(5);
>> +}
>
> The thing I do not get is how you can guarantee that an undelayed
> writel() in a function will not be followed less than 5?s later by
> another writel() in another function. For instance:
>
> 1) a call to set_alarm() followed by a call to alarm_irq_enable().
> 2) some writel() or even rtc_udelayed_write() w/ sth asynchronous
> occuring like your interrupt handler just after that.
>
> I guess it may be possible to make assumptions on the fact that the
> amount of code before a writel() or rtc_udelayed_write() may prevent
> such scenario but it's difficult to tell, all the more w/ a spinlock
> before the writel() in irq_enable().
>
> Considering the description of the bug, why not doing the following:
>
> 1) implement rtc_delayed_write() a bit differently:
>
> static inline void rtc_delayed_write(u32 val, struct armada38x_rtc *rtc, int offset)
> {
> udelay(5);
> writel(val, rtc->regs + offset);
> }
>
> 2) remove all writel() in the driver and use rtc_delayed_write()
> everywhere.
>
> All writes being under the protection of your spinlock, this will
> guarantee the 5?s delay in all cases.
You're right. I tried avoiding loosing microseconds here and there, but there
is too many case where it can fail. So let's us it everywhere.
[...]
>> +static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
>> +{
>> + struct armada38x_rtc *rtc = dev_get_drvdata(dev);
>> + int ret = 0;
>> + unsigned long time, flags;
>> +
>> + ret = rtc_tm_to_time(tm, &time);
>> +
>> + if (ret)
>> + goto out;
>> + /*
>> + * Setting the RTC time not always succeeds. According to the
>> + * errata we need to first write on the status register and
>> + * then wait for 100ms before writing to the time register to be
>> + * sure that the data will be taken into account.
>> + */
>> + spin_lock_irqsave(&rtc->lock, flags);
>> +
>> + writel(0, rtc->regs + RTC_STATUS);
>> +
>> + spin_unlock_irqrestore(&rtc->lock, flags);
>> +
>> + msleep(100);
>> +
>> + spin_lock_irqsave(&rtc->lock, flags);
>> +
>> + writel(time, rtc->regs + RTC_TIME);
>
> probably not critical (it's rtc clock and not system clock) but you still
> introduce a 100ms shift when setting time here.
I am aware of this shift but the granularity is the second, so we can't do
better, we have to deal with the limitation of the hardware. :(
>
> As for the two writel() not being done w/o releasing the spinlock, it
> looks a bit weird but it seems it's ok for other functions manipulating
> RTC_STATUS reg.
>
> Nonetheless, in the reverse direction, if a writel() occurs somewhere
> (e.g. in the alarm irq handler) during your msleep(), you may do your
> final writel() w/o having enforced the expected 100ms delay.
Actually I don't know if it is problematic if a writel occur in an other register
during the 100ms. I still wait for an answer for it.
Thanks,
Gregory
--
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
WARNING: multiple messages have this Message-ID (diff)
From: Gregory CLEMENT <gregory.clement-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
To: Arnaud Ebalard <arno-LkuqDEemtHBg9hUCZPvPmw@public.gmane.org>
Cc: Alessandro Zummo
<a.zummo-BfzFCNDTiLLj+vYz1yj4TQ@public.gmane.org>,
rtc-linux-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org,
Jason Cooper <jason-NLaQJdtUoK4Be96aLqz0jA@public.gmane.org>,
Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>,
Sebastian Hesselbarth
<sebastian.hesselbarth-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
Thomas Petazzoni
<thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>,
Ezequiel Garcia
<ezequiel.garcia-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
Maxime Ripard
<maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>,
Boris BREZILLON
<boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>,
Lior Amsalem <alior-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>,
Tawfik Bayouk <tawfik-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>,
Nadav Haklai <nadavh-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>,
Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: Re: [PATCH v2 2/5] drivers/rtc/rtc-armada38x: Add a new RTC driver for recent mvebu SoCs
Date: Thu, 15 Jan 2015 10:51:44 +0100 [thread overview]
Message-ID: <54B78DB0.5050808@free-electrons.com> (raw)
In-Reply-To: <871tmxrsj8.fsf-LkuqDEemtHBg9hUCZPvPmw@public.gmane.org>
Hi Arnaud,
[...]
>> +/*
>> + * According to the datasheet, we need to wait for 5us only between
>> + * two consecutive writes
>> + */
>> +static void rtc_delayed_write(u32 val, struct armada38x_rtc *rtc, int offset)
>> +{
>> + writel(val, rtc->regs + offset);
>> + udelay(5);
>> +}
>
> The thing I do not get is how you can guarantee that an undelayed
> writel() in a function will not be followed less than 5µs later by
> another writel() in another function. For instance:
>
> 1) a call to set_alarm() followed by a call to alarm_irq_enable().
> 2) some writel() or even rtc_udelayed_write() w/ sth asynchronous
> occuring like your interrupt handler just after that.
>
> I guess it may be possible to make assumptions on the fact that the
> amount of code before a writel() or rtc_udelayed_write() may prevent
> such scenario but it's difficult to tell, all the more w/ a spinlock
> before the writel() in irq_enable().
>
> Considering the description of the bug, why not doing the following:
>
> 1) implement rtc_delayed_write() a bit differently:
>
> static inline void rtc_delayed_write(u32 val, struct armada38x_rtc *rtc, int offset)
> {
> udelay(5);
> writel(val, rtc->regs + offset);
> }
>
> 2) remove all writel() in the driver and use rtc_delayed_write()
> everywhere.
>
> All writes being under the protection of your spinlock, this will
> guarantee the 5µs delay in all cases.
You're right. I tried avoiding loosing microseconds here and there, but there
is too many case where it can fail. So let's us it everywhere.
[...]
>> +static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
>> +{
>> + struct armada38x_rtc *rtc = dev_get_drvdata(dev);
>> + int ret = 0;
>> + unsigned long time, flags;
>> +
>> + ret = rtc_tm_to_time(tm, &time);
>> +
>> + if (ret)
>> + goto out;
>> + /*
>> + * Setting the RTC time not always succeeds. According to the
>> + * errata we need to first write on the status register and
>> + * then wait for 100ms before writing to the time register to be
>> + * sure that the data will be taken into account.
>> + */
>> + spin_lock_irqsave(&rtc->lock, flags);
>> +
>> + writel(0, rtc->regs + RTC_STATUS);
>> +
>> + spin_unlock_irqrestore(&rtc->lock, flags);
>> +
>> + msleep(100);
>> +
>> + spin_lock_irqsave(&rtc->lock, flags);
>> +
>> + writel(time, rtc->regs + RTC_TIME);
>
> probably not critical (it's rtc clock and not system clock) but you still
> introduce a 100ms shift when setting time here.
I am aware of this shift but the granularity is the second, so we can't do
better, we have to deal with the limitation of the hardware. :(
>
> As for the two writel() not being done w/o releasing the spinlock, it
> looks a bit weird but it seems it's ok for other functions manipulating
> RTC_STATUS reg.
>
> Nonetheless, in the reverse direction, if a writel() occurs somewhere
> (e.g. in the alarm irq handler) during your msleep(), you may do your
> final writel() w/o having enforced the expected 100ms delay.
Actually I don't know if it is problematic if a writel occur in an other register
during the 100ms. I still wait for an answer for it.
Thanks,
Gregory
--
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2015-01-15 9:51 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-01-14 17:39 [PATCH v2 0/5] Add a new RTC driver for recent mvebu SoCs Gregory CLEMENT
2015-01-14 17:39 ` Gregory CLEMENT
2015-01-14 17:39 ` [PATCH v2 1/5] rtc: armada38x: Add the device tree binding documentation Gregory CLEMENT
2015-01-14 17:39 ` Gregory CLEMENT
2015-01-14 19:22 ` Thomas Petazzoni
2015-01-14 19:22 ` Thomas Petazzoni
2015-01-15 7:50 ` Gregory CLEMENT
2015-01-15 7:50 ` Gregory CLEMENT
2015-01-15 8:24 ` Thomas Petazzoni
2015-01-15 8:24 ` Thomas Petazzoni
2015-01-15 8:25 ` Gregory CLEMENT
2015-01-15 8:25 ` Gregory CLEMENT
2015-01-14 17:39 ` [PATCH v2 2/5] drivers/rtc/rtc-armada38x: Add a new RTC driver for recent mvebu SoCs Gregory CLEMENT
2015-01-14 17:39 ` Gregory CLEMENT
2015-01-14 20:55 ` Arnaud Ebalard
2015-01-14 20:55 ` Arnaud Ebalard
2015-01-15 9:51 ` Gregory CLEMENT [this message]
2015-01-15 9:51 ` Gregory CLEMENT
2015-01-14 17:39 ` [PATCH v2 3/5] MAINTAINERS: Add the RTC driver for the Armada38x Gregory CLEMENT
2015-01-14 17:39 ` Gregory CLEMENT
2015-01-14 17:39 ` [PATCH v2 4/5] ARM: mvebu: add Device Tree description of RTC on Armada 38x Gregory CLEMENT
2015-01-14 17:39 ` Gregory CLEMENT
2015-01-14 17:39 ` [PATCH v2 5/5] ARM: mvebu: enable Armada 38x RTC driver in mvebu_v7_defconfig Gregory CLEMENT
2015-01-14 17:39 ` Gregory CLEMENT
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=54B78DB0.5050808@free-electrons.com \
--to=gregory.clement@free-electrons.com \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.