* [PATCH 03/18] arm64: introduce sysreg_clear_set()
From: Mark Rutland @ 2018-05-14 9:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180514094640.27569-1-mark.rutland@arm.com>
Currently we have a couple of helpers to manipulate bits in particular
sysregs:
* config_sctlr_el1(u32 clear, u32 set)
* change_cpacr(u64 val, u64 mask)
The parameters of these differ in naming convention, order, and size,
which is unfortunate. They also differ slightly in behaviour, as
change_cpacr() skips the sysreg write if the bits are unchanged, which
is a useful optimization when sysreg writes are expensive.
Before we gain more yet another sysreg manipulation function, let's
unify these with a common helper, providing a consistent order for
clear/set operands, and the write skipping behaviour from
change_cpacr(). Code will be migrated to the new helper in subsequent
patches.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Dave Martin <dave.martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm64/include/asm/sysreg.h | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index bd1d1194a5e7..b52762769329 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -729,6 +729,17 @@ asm(
asm volatile("msr_s " __stringify(r) ", %x0" : : "rZ" (__val)); \
} while (0)
+/*
+ * Modify bits in a sysreg. Bits in the clear mask are zeroed, then bits in the
+ * set mask are set. Other bits are left as-is.
+ */
+#define sysreg_clear_set(sysreg, clear, set) do { \
+ u64 __scs_val = read_sysreg(sysreg); \
+ u64 __scs_new = (__scs_val & ~(u64)(clear)) | (set); \
+ if (__scs_new != __scs_val) \
+ write_sysreg(__scs_new, sysreg); \
+} while (0)
+
static inline void config_sctlr_el1(u32 clear, u32 set)
{
u32 val;
--
2.11.0
^ permalink raw reply related
* [PATCH 02/18] arm64: move SCTLR_EL{1,2} assertions to <asm/sysreg.h>
From: Mark Rutland @ 2018-05-14 9:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180514094640.27569-1-mark.rutland@arm.com>
Currently we assert that the SCTLR_EL{1,2}_{SET,CLEAR} bits are
self-consistent with an assertion in config_sctlr_el1(). This is a bit
unusual, since config_sctlr_el1() doesn't make use of these definitions,
and is far away from the definitions themselves.
We can use the CPP #error directive to have equivalent assertions in
<asm/sysreg.h>, next to the definitions of the set/clear bits, which is
a bit clearer and simpler.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: James Morse <james.morse@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
arch/arm64/include/asm/sysreg.h | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 6171178075dc..bd1d1194a5e7 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -452,9 +452,9 @@
SCTLR_ELx_SA | SCTLR_ELx_I | SCTLR_ELx_WXN | \
ENDIAN_CLEAR_EL2 | SCTLR_EL2_RES0)
-/* Check all the bits are accounted for */
-#define SCTLR_EL2_BUILD_BUG_ON_MISSING_BITS BUILD_BUG_ON((SCTLR_EL2_SET ^ SCTLR_EL2_CLEAR) != ~0)
-
+#if (SCTLR_EL2_SET ^ SCTLR_EL2_CLEAR) != 0xffffffff
+#error "Inconsistent SCTLR_EL2 set/clear bits"
+#endif
/* SCTLR_EL1 specific flags. */
#define SCTLR_EL1_UCI (1 << 26)
@@ -492,8 +492,9 @@
SCTLR_EL1_UMA | SCTLR_ELx_WXN | ENDIAN_CLEAR_EL1 |\
SCTLR_EL1_RES0)
-/* Check all the bits are accounted for */
-#define SCTLR_EL1_BUILD_BUG_ON_MISSING_BITS BUILD_BUG_ON((SCTLR_EL1_SET ^ SCTLR_EL1_CLEAR) != ~0)
+#if (SCTLR_EL1_SET ^ SCTLR_EL1_CLEAR) != 0xffffffff
+#error "Inconsistent SCTLR_EL1 set/clear bits"
+#endif
/* id_aa64isar0 */
#define ID_AA64ISAR0_TS_SHIFT 52
@@ -732,9 +733,6 @@ static inline void config_sctlr_el1(u32 clear, u32 set)
{
u32 val;
- SCTLR_EL2_BUILD_BUG_ON_MISSING_BITS;
- SCTLR_EL1_BUILD_BUG_ON_MISSING_BITS;
-
val = read_sysreg(sctlr_el1);
val &= ~clear;
val |= set;
--
2.11.0
^ permalink raw reply related
* [PATCH 01/18] arm64: consistently use unsigned long for thread flags
From: Mark Rutland @ 2018-05-14 9:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180514094640.27569-1-mark.rutland@arm.com>
In do_notify_resume, we manipulate thread_flags as a 32-bit unsigned
int, whereas thread_info::flags is a 64-bit unsigned long, and elsewhere
(e.g. in the entry assembly) we manipulate the flags as a 64-bit
quantity.
For consistency, and to avoid problems if we end up with more than 32
flags, let's make do_notify_resume take the flags as a 64-bit unsigned
long.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
arch/arm64/kernel/signal.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 154b7d30145d..8e624fec4707 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -896,7 +896,7 @@ static void do_signal(struct pt_regs *regs)
}
asmlinkage void do_notify_resume(struct pt_regs *regs,
- unsigned int thread_flags)
+ unsigned long thread_flags)
{
/*
* The assembly code enters us with IRQs off, but it hasn't
--
2.11.0
^ permalink raw reply related
* [PATCH 00/18] arm64: invoke syscalls with pt_regs
From: Mark Rutland @ 2018-05-14 9:46 UTC (permalink / raw)
To: linux-arm-kernel
This series reworks arm64's syscall handling to minimize the propagation
of user-controlled register values into speculated code paths. As with
x86 [1], a wrapper is generated for each syscall, which extracts the
argument from a struct pt_regs. During kernel entry from userspace,
registers are zeroed.
The arm64 kernel code directly invokes some syscalls which the x86 code
doesn't, so I've added ksys_* wrappers for these, following the x86
example. The rest of the series is arm64-specific.
I've pushed the series out to my arm64/syscall-regs branch [2] on
kernel.org.
Thanks,
Mark.
[1] https://lkml.kernel.org/r/20180330093720.6780-1-linux at dominikbrodowski.net
[2] git://git.kernel.org/pub/scm/linux/kernel/git/mark/linux.git
Mark Rutland (18):
arm64: consistently use unsigned long for thread flags
arm64: move SCTLR_EL{1,2} assertions to <asm/sysreg.h>
arm64: introduce sysreg_clear_set()
arm64: kill config_sctlr_el1()
arm64: kill change_cpacr()
arm64: move sve_user_{enable,disable} to <asm/fpsimd.h>
arm64: remove sigreturn wrappers
arm64: convert raw syscall invocation to C
arm64: convert syscall trace logic to C
arm64: convert native/compat syscall entry to C
arm64: zero GPRs upon entry from EL0
kernel: add ksys_personality()
kernel: add kcompat_sys_{f,}statfs64()
arm64: remove in-kernel call to sys_personality()
arm64: use {COMPAT,}SYSCALL_DEFINE0 for sigreturn
arm64: use SYSCALL_DEFINE6() for mmap
arm64: convert compat wrappers to C
arm64: implement syscall wrappers
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/fpsimd.h | 17 ++++-
arch/arm64/include/asm/syscall_wrapper.h | 80 ++++++++++++++++++++
arch/arm64/include/asm/sysreg.h | 33 ++++----
arch/arm64/include/asm/unistd32.h | 26 +++----
arch/arm64/kernel/Makefile | 5 +-
arch/arm64/kernel/armv8_deprecated.c | 8 +-
arch/arm64/kernel/cpu_errata.c | 3 +-
arch/arm64/kernel/entry.S | 126 +++----------------------------
arch/arm64/kernel/entry32.S | 121 -----------------------------
arch/arm64/kernel/fpsimd.c | 20 -----
arch/arm64/kernel/signal.c | 5 +-
arch/arm64/kernel/signal32.c | 6 +-
arch/arm64/kernel/sys.c | 19 +++--
arch/arm64/kernel/sys32.c | 116 ++++++++++++++++++++++++----
arch/arm64/kernel/syscall.c | 113 +++++++++++++++++++++++++++
arch/arm64/kernel/traps.c | 4 +-
arch/arm64/mm/fault.c | 2 +-
fs/statfs.c | 14 +++-
include/linux/syscalls.h | 9 +++
kernel/exec_domain.c | 7 +-
21 files changed, 411 insertions(+), 324 deletions(-)
create mode 100644 arch/arm64/include/asm/syscall_wrapper.h
delete mode 100644 arch/arm64/kernel/entry32.S
create mode 100644 arch/arm64/kernel/syscall.c
--
2.11.0
^ permalink raw reply
* [PATCH v2 04/13] soc: rockchip: power-domain: Fix wrong value when power up pd
From: Heiko Stuebner @ 2018-05-14 9:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1526268578-9361-1-git-send-email-zhangqing@rock-chips.com>
Hi Elaine,
Am Montag, 14. Mai 2018, 05:29:38 CEST schrieb Elaine Zhang:
> From: Finley Xiao <finley.xiao@rock-chips.com>
>
> Solve the pd could only ever turn off but never turn them on again,
> If the pd registers have the writemask bits.
>
> Fix up the code error for commit:
> commit 79bb17ce8edb3141339b5882e372d0ec7346217c
> Author: Elaine Zhang <zhangqing@rock-chips.com>
> Date: Fri Dec 23 11:47:52 2016 +0800
>
> soc: rockchip: power-domain: Support domain control in hiword-registers
>
> New Rockchips SoCs may have their power-domain control in registers
> using a writemask-based access scheme (upper 16bit being the write
> mask). So add a DOMAIN_M type and handle this case accordingly.
> Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
> Signed-off-by: Heiko Stuebner <heiko@sntech.de>
>
> Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
> Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
As Gregs automated mail noted, the stable-notice needed some changes.
I've done these changes and applied the result for 4.18.
When you look at [0] you'll see the two lines "Fixes:..." and "Cc:..."
in the commit message. Greg then has automated scripts running that
extract so marked patches from Linus' tree and queue them for possible
stable-inclusion.
[The other patches need to wait a bit to give Rob a chance to Ack them]
Heiko
[0] https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git/commit/?id=ed726894761c056b3513ce15915af74ce5d7d57b
^ permalink raw reply
* Allwinner A64: Issue on external rtc clock to wifi chip
From: Jagan Teki @ 2018-05-14 9:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180514090618.r5xc3elzpvfp47f4@flea>
On Mon, May 14, 2018 at 2:36 PM, Maxime Ripard
<maxime.ripard@bootlin.com> wrote:
> On Mon, May 14, 2018 at 02:34:22PM +0530, Jagan Teki wrote:
>> On Mon, May 14, 2018 at 1:57 PM, Maxime Ripard
>> <maxime.ripard@bootlin.com> wrote:
>> > On Mon, May 14, 2018 at 01:34:56PM +0530, Jagan Teki wrote:
>> >> On Mon, May 14, 2018 at 1:27 PM, Maxime Ripard
>> >> <maxime.ripard@bootlin.com> wrote:
>> >> > Hi,
>> >> >
>> >> > On Mon, May 14, 2018 at 12:37:49PM +0530, Jagan Teki wrote:
>> >> >> Hi Maxime and All,
>> >> >>
>> >> >> We are trying to bring-up AP6330 Wifi chip for A64 board. We noticed
>> >> >> to have an external rtc clock has driven from wifi chip.
>> >> >>
>> >> >> So the devicetree is configured according to this as below.
>> >> >>
>> >> >> / {
>> >> >> wifi_pwrseq: wifi-pwrseq {
>> >> >> compatible = "mmc-pwrseq-simple";
>> >> >> clocks = <&rtc 1>;
>> >> >> clock-names = "ext_clock";
>> >> >> reset-gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>; /* PL2 */
>> >> >> post-power-on-delay-ms = <400>;
>> >> >> };
>> >> >> };
>> >> >>
>> >> >> &rtc {
>> >> >> clock-output-names = "rtc-osc32k", "rtc-osc32k-out";
>> >> >> clocks = <&osc32k>;
>> >> >> #clock-cells = <1>;
>> >> >> };
>> >> >>
>> >> >> &mmc1 {
>> >> >> pinctrl-names = "default";
>> >> >> pinctrl-0 = <&mmc1_pins>;
>> >> >> vmmc-supply = <®_dcdc1>;
>> >> >> vqmmc-supply = <®_eldo1>;
>> >> >> mmc-pwrseq = <&wifi_pwrseq>;
>> >> >> bus-width = <4>;
>> >> >> non-removable;
>> >> >> status = "okay";
>> >> >>
>> >> >> brcmf: wifi at 1 {
>> >> >> reg = <1>;
>> >> >> compatible = "brcm,bcm4329-fmac";
>> >> >> interrupt-parent = <&r_pio>;
>> >> >> interrupts = <0 3 IRQ_TYPE_LEVEL_LOW>; /* WL-WAKE-AP: PL3 */
>> >> >> interrupt-names = "host-wake";
>> >> >> };
>> >> >> };
>> >> >>
>> >> >> And observed rtc-osc32k-out clock is never enabled[1] and the value of
>> >> >> LOSC_OUT_GATING is 0x0 which eventually not enabling
>> >> >> LOSC_OUT_GATING_EN
>> >> >>
>> >> >> Pls. let us know if we miss anything here?
>> >> >>
>> >> >> [1] https://paste.ubuntu.com/p/X2By4q8kD2/
>> >> >
>> >> > Could you paste your config and the logs from a boot to?
>> >>
>> >> .config
>> >> https://paste.ubuntu.com/p/w9w2KB7RFc/
>> >>
>> >> dmesg
>> >> https://paste.ubuntu.com/p/mrZGk5bWRR/
>> >
>> > This is kind of weird. Have you tested with a 4.17 kernel? We have
>> > runtime_pm changes lined up in next, so that might be a regression
>> > there, even though we tested it with Quentin at some point.
>>
>> This is 4.17-rc4 do you want to try it on 4.16 ?
>
> No, this is next-20180503. Please try with 4.17-rc4
Couldn't find any different in behaviour [2]
[2] https://paste.ubuntu.com/p/m3PGBwrv6W/
^ permalink raw reply
* [GIT PULL 3/3] omap sdhci dts changes for v4.18 merge window
From: Ulf Hansson @ 2018-05-14 9:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180514082224.dx63ao3vz3ay5ng5@localhost>
On 14 May 2018 at 10:22, Olof Johansson <olof@lixom.net> wrote:
> On Fri, May 04, 2018 at 09:17:33AM -0700, Tony Lindgren wrote:
>> From: "Tony Lindgren" <tony@atomide.com>
>>
>> The following changes since commit 3f4028780287ff5a7308f40e10bbba9a42b993aa:
>>
>> mmc: sdhci-omap: Get IODelay values for 3.3v DDR mode (2018-05-03 09:37:13 +0200)
>>
>> are available in the Git repository at:
>>
>> git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap tags/omap-for-v4.18/dt-sdhci-signed
>>
>> for you to fetch changes up to 24a6f1f65ea567d017c598faf1374ee443f73851:
>>
>> Documentation: ARM: Add new MMC requirements for DRA7/K2G (2018-05-03 10:32:20 -0700)
>>
>> ----------------------------------------------------------------
>> Device tree changes for omap variants for SDHCI
>>
>> This series adds the devicetree configuration needed for pinctrl on
>> dra7 variants to use the SDHCI SDIO driver instead of mmc-omap-hs
>> driver. To use SDHCI, both the pins and the iodelay needs to be
>> configured.
>>
>> This series is based on the related SDHCI drivers changes on a branch
>> set up by Ulf.
>
> Hi Tony,
>
> Just to make sure Ulf isn't taken by surprise (since I didn't see the initial
> agreement of a stable branch), it's a good idea to include him on the pull
> request.
No surprise.
>
> Also, the diffstat doesn't take that branch into consideration so it doesn't
> match with what I've merged with. Having the URL of Ulf's branch helps, in that
> case I'd just merge that branch first and get the dependency documented.
>
>
> Ulf, does the above sound OK with you, and said branch is 100% guaranteed to
> not be rebased?
Right, the branch is immutable. Feel free to pull it.
git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git sdhci_omap
Or if you prefer a signed tag: sdhci-omap-v4.17-rc3
Kind regards
Uffe
^ permalink raw reply
* [PATCH 2/2] arm64: Clear the stack
From: Alexander Popov @ 2018-05-14 9:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180514051555.bpbydgr56hyffjch@salmiak>
On 14.05.2018 08:15, Mark Rutland wrote:
> On Sun, May 13, 2018 at 11:40:07AM +0300, Alexander Popov wrote:
>> It seems that previously I was very "lucky" to accidentally have those MIN_STACK_LEFT,
>> call trace depth and oops=panic together to experience a hang on stack overflow
>> during BUG().
>>
>>
>> When I run my test in a loop _without_ VMAP_STACK, I manage to corrupt the neighbour
>> processes with BUG() handling overstepping the stack boundary. It's a pity, but
>> I have an idea.
>
> I think that in the absence of VMAP_STACK, there will always be cases where we
> *could* corrupt a neighbouring stack, but I agree that trying to minimize that
> possibility would be good.
Ok!
>> In kernel/sched/core.c we already have:
>>
>> #ifdef CONFIG_SCHED_STACK_END_CHECK
>> if (task_stack_end_corrupted(prev))
>> panic("corrupted stack end detected inside scheduler\n");
>> #endif
>>
>> So what would you think if I do the following in check_alloca():
>>
>> if (size >= stack_left) {
>> #if !defined(CONFIG_VMAP_STACK) && defined(CONFIG_SCHED_STACK_END_CHECK)
>> panic("alloca over the kernel stack boundary\n");
>> #else
>> BUG();
>> #endif
>
> Given this is already out-of-line, how about we always use panic(), regardless
> of VMAP_STACK and SCHED_STACK_END_CHECK? i.e. just
>
> if (unlikely(size >= stack_left))
> panic("alloca over the kernel stack boundary");
>
> If we have VMAP_STACK selected, and overflow during the panic, it's the same as
> if we overflowed during the BUG(). It's likely that panic() will use less stack
> space than BUG(), and the compiler can put the call in a slow path that
> shouldn't affect most calls, so in all cases it's likely preferable.
I'm sure that maintainers and Linus will strongly dislike my patch if I always
use panic() here. panic() kills the whole kernel and we shouldn't use it when we
can safely continue to work.
Let me describe my logic. So let's have size >= stack_left on a thread stack.
1. If CONFIG_VMAP_STACK is enabled, we can safely use BUG(). Even if BUG()
handling overflows the thread stack into the guard page, handle_stack_overflow()
is called and the neighbour memory is not corrupted. The kernel can proceed to live.
2. If CONFIG_VMAP_STACK is disabled, BUG() handling can corrupt the neighbour
kernel memory and cause the undefined behaviour of the whole kernel. I see it on
my lkdtm test. That is a cogent reason for panic().
2.a. If CONFIG_SCHED_STACK_END_CHECK is enabled, the kernel already does panic()
when STACK_END_MAGIC is corrupted. So we will _not_ break the safety policy if
we do panic() in a similar situation in check_alloca().
2.b. If CONFIG_SCHED_STACK_END_CHECK is disabled, the user has some real reasons
not to do panic() when the kernel stack is corrupted. So we should not do it in
check_alloca() as well, just use BUG() and hope for the best.
That logic can be expressed this way:
if (size >= stack_left) {
#if !defined(CONFIG_VMAP_STACK) && defined(CONFIG_SCHED_STACK_END_CHECK)
panic("alloca over the kernel stack boundary\n");
#else
BUG();
#endif
I think I should add a proper comment to describe it.
Thank you.
Best regards,
Alexander
^ permalink raw reply
* [PATCH net-next v2 02/13] net: phy: sfp: handle non-wired SFP connectors
From: Antoine Tenart @ 2018-05-14 9:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180508115247.GF16141@n2100.armlinux.org.uk>
Hi Russell,
On Tue, May 08, 2018 at 12:52:47PM +0100, Russell King - ARM Linux wrote:
> On Fri, May 04, 2018 at 03:56:32PM +0200, Antoine Tenart wrote:
> > SFP connectors can be solder on a board without having any of their pins
> > (LOS, i2c...) wired. In such cases the SFP link state cannot be guessed,
> > and the overall link status reporting is left to other layers.
> >
> > In order to achieve this, a new SFP_DEV status is added, named UNKNOWN.
> > This mode is set when it is not possible for the SFP code to get the
> > link status and as a result the link status is reported to be always UP
> > from the SFP point of view.
>
> This looks weird to me. SFP_DEV_* states track the netdevice up/down
> state and have little to do with whether LOS or MODDEF0 are implemented.
That's right.
> I think it would be better to have a new SFP_MOD_* and to force
> sm_mod_state to that in this circumstance.
The idea was to avoid depending on the state machine, as this could be
difficult to maintain in the future (it's hard to tell exactly what are
all the possible paths). But I get your point about SFP_DEV_.
I can have a look at adding a new SFP_MOD_, or I could add a broken flag
into 'struct sfp', although having a SFP_MOD_ would be proper.
Before doing so, we should decide whether or not this approach is valid,
as there were comments from Florian and Andrew asking for a fixed-link
solution. I think fixed-link wouldn't be perfect from the user point of
view, but I understand the point. If we go with fixed-link, then this
patch can be dropped (the two others net: sfp: patches could be kept).
What do you think?
Thanks,
Antoine
--
Antoine T?nart, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* [PATCH v2] tty: pl011: Avoid spuriously stuck-off interrupts
From: Wei Xu @ 2018-05-14 9:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1525972103-26691-1-git-send-email-Dave.Martin@arm.com>
Hi Dave,
On 2018/5/10 18:08, Dave Martin wrote:
> Commit 9b96fbacda34 ("serial: PL011: clear pending interrupts")
> clears the RX and receive timeout interrupts on pl011 startup, to
> avoid a screaming-interrupt scenario that can occur when the
> firmware or bootloader leaves these interrupts asserted.
>
> This has been noted as an issue when running Linux on qemu [1].
>
> Unfortunately, the above fix seems to lead to potential
> misbehaviour if the RX FIFO interrupt is asserted _non_ spuriously
> on driver startup, if the RX FIFO is also already full to the
> trigger level.
>
> Clearing the RX FIFO interrupt does not change the FIFO fill level.
> In this scenario, because the interrupt is now clear and because
> the FIFO is already full to the trigger level, no new assertion of
> the RX FIFO interrupt can occur unless the FIFO is drained back
> below the trigger level. This never occurs because the pl011
> driver is waiting for an RX FIFO interrupt to tell it that there is
> something to read, and does not read the FIFO at all until that
> interrupt occurs.
>
> Thus, simply clearing "spurious" interrupts on startup may be
> misguided, since there is no way to be sure that the interrupts are
> truly spurious, and things can go wrong if they are not.
>
> This patch instead clears the interrupt condition by draining the
> RX FIFO during UART startup, after clearing any potentially
> spurious interrupt. This should ensure that an interrupt will
> definitely be asserted if the RX FIFO subsequently becomes
> sufficiently full.
>
> The drain is done at the point of enabling interrupts only. This
> means that it will occur any time the UART is newly opened through
> the tty layer. It will not apply to polled-mode use of the UART by
> kgdboc: since that scenario cannot use interrupts by design, this
> should not matter. kgdboc will interact badly with "normal" use of
> the UART in any case: this patch makes no attempt to paper over
> such issues.
>
> This patch does not attempt to address the case where the RX FIFO
> fills faster than it can be drained: that is a pathological
> hardware design problem that is beyond the scope of the driver to
> work around. As a failsafe, the number of poll iterations for
> draining the FIFO is limited to twice the FIFO size. This will
> ensure that the kernel at least boots even if it is impossible to
> drain the FIFO for some reason.
>
> [1] [Qemu-devel] [Qemu-arm] [PATCH] pl011: do not put into fifo
> before enabled the interruption
> https://lists.gnu.org/archive/html/qemu-devel/2018-01/msg06446.html
>
> Reported-by: Wei Xu <xuwei5@hisilicon.com>
> Cc: Russell King <linux@armlinux.org.uk>
> Cc: Linus Walleij <linus.walleij@linaro.org>
> Cc: Peter Maydell <peter.maydell@linaro.org>
> Fixes: 9b96fbacda34 ("serial: PL011: clear pending interrupts")
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Thanks!
Tested on hisilicon D05 board.
Tested-by: Wei Xu <xuwei5@hisilicon.com>
Best Regards,
Wei
>
> ---
>
> Changes since v1 [1]
>
> * Deleted Andrew Jones' Reviewed/Tested-bys due to the following
> change.
>
> If you can please retest that the updated patch fixes your
> issue that would be appreciated.
>
> Suggested by Russell King:
>
> * Only drain 2 * FIFO size, to avoid going into an infinite spin
> if something does wrong. If the FIFO still couldn't be drained
> sufficiently then pl011 RX won't work properly, but the kernel
> will at least boot.
>
>
> [1] [PATCH] tty: pl011: Avoid spuriously stuck-off interrupts
> http://lists.infradead.org/pipermail/linux-arm-kernel/2018-April/574362.html
>
> ---
> drivers/tty/serial/amba-pl011.c | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
>
> diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
> index 4b40a5b..ebd33c0 100644
> --- a/drivers/tty/serial/amba-pl011.c
> +++ b/drivers/tty/serial/amba-pl011.c
> @@ -1727,10 +1727,26 @@ static int pl011_allocate_irq(struct uart_amba_port *uap)
> */
> static void pl011_enable_interrupts(struct uart_amba_port *uap)
> {
> + unsigned int i;
> +
> spin_lock_irq(&uap->port.lock);
>
> /* Clear out any spuriously appearing RX interrupts */
> pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR);
> +
> + /*
> + * RXIS is asserted only when the RX FIFO transitions from below
> + * to above the trigger threshold. If the RX FIFO is already
> + * full to the threshold this can't happen and RXIS will now be
> + * stuck off. Drain the RX FIFO explicitly to fix this:
> + */
> + for (i = 0; i < uap->fifosize * 2; ++i) {
> + if (pl011_read(uap, REG_FR) & UART01x_FR_RXFE)
> + break;
> +
> + pl011_read(uap, REG_DR);
> + }
> +
> uap->im = UART011_RTIM;
> if (!pl011_dma_rx_running(uap))
> uap->im |= UART011_RXIM;
>
^ permalink raw reply
* [PATCH 1/3] thermal: imx: remove cpufreq cooling registration
From: Bastian Stender @ 2018-05-14 9:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <AM3PR04MB1315B6320421800346313075F59C0@AM3PR04MB1315.eurprd04.prod.outlook.com>
On 05/14/2018 11:10 AM, Anson Huang wrote:
>> -----Original Message-----
>> From: Bastian Stender [mailto:bst at pengutronix.de]
>> Sent: Monday, May 14, 2018 4:37 PM
>> To: Anson Huang <anson.huang@nxp.com>; shawnguo at kernel.org;
>> s.hauer at pengutronix.de; kernel at pengutronix.de; Fabio Estevam
>> <fabio.estevam@nxp.com>; robh+dt at kernel.org; mark.rutland at arm.com;
>> rjw at rjwysocki.net; viresh.kumar at linaro.org; rui.zhang at intel.com;
>> edubezval at gmail.com
>> Cc: devicetree at vger.kernel.org; linux-pm at vger.kernel.org; dl-linux-imx
>> <linux-imx@nxp.com>; linux-arm-kernel at lists.infradead.org;
>> linux-kernel at vger.kernel.org
>> Subject: Re: [PATCH 1/3] thermal: imx: remove cpufreq cooling registration
>>
>> Hi,
>>
>> On 05/14/2018 10:09 AM, Anson Huang wrote:
>>> This patch removes cpufreq cooling registration in thermal .probe
>>> function, cpufreq cooling should be done in cpufreq driver when it is
>>> ready.
>>>
>>> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
>>
>> It seems you are trying to achieve something similar to a patch I sent a couple
>> of month ago. Unfortunately I did not have the time to rework it yet:
>>
>>
>> https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatch
>> work.kernel.org%2Fpatch%2F10059085%2F&data=02%7C01%7Canson.huang
>> %40nxp.com%7C179da3635cab4a14deef08d5b975ecb6%7C686ea1d3bc2b4c6f
>> a92cd99c5c301635%7C0%7C0%7C636618838508978629&sdata=BcQ9tc%2BE
>> CZ%2Fk4AsZFxshgmvSsPg7eRN0ASzP8LO8yBI%3D&reserved=0
>>
>> Some of the comments might apply here too.
>
> Ah, I did NOT notice this thread, so how to proceed, will you
> continue to finish your patch? If yes, then you can just ignore/skip
> my patch, thanks.
Yes, I will revisit the patch in a couple of weeks. It would be nice to
get your feedback then.
Regards,
Bastian
--
Pengutronix e.K.
Industrial Linux Solutions
http://www.pengutronix.de/
Peiner Str. 6-8, 31137 Hildesheim, Germany
Amtsgericht Hildesheim, HRA 2686
^ permalink raw reply
* [PATCH 1/3] thermal: imx: remove cpufreq cooling registration
From: Anson Huang @ 2018-05-14 9:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5a449fc0-4d3e-c7c7-0e9a-43efb4b909cf@pengutronix.de>
Anson Huang
Best Regards!
> -----Original Message-----
> From: Bastian Stender [mailto:bst at pengutronix.de]
> Sent: Monday, May 14, 2018 4:37 PM
> To: Anson Huang <anson.huang@nxp.com>; shawnguo at kernel.org;
> s.hauer at pengutronix.de; kernel at pengutronix.de; Fabio Estevam
> <fabio.estevam@nxp.com>; robh+dt at kernel.org; mark.rutland at arm.com;
> rjw at rjwysocki.net; viresh.kumar at linaro.org; rui.zhang at intel.com;
> edubezval at gmail.com
> Cc: devicetree at vger.kernel.org; linux-pm at vger.kernel.org; dl-linux-imx
> <linux-imx@nxp.com>; linux-arm-kernel at lists.infradead.org;
> linux-kernel at vger.kernel.org
> Subject: Re: [PATCH 1/3] thermal: imx: remove cpufreq cooling registration
>
> Hi,
>
> On 05/14/2018 10:09 AM, Anson Huang wrote:
> > This patch removes cpufreq cooling registration in thermal .probe
> > function, cpufreq cooling should be done in cpufreq driver when it is
> > ready.
> >
> > Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
>
> It seems you are trying to achieve something similar to a patch I sent a couple
> of month ago. Unfortunately I did not have the time to rework it yet:
>
>
> https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpatch
> work.kernel.org%2Fpatch%2F10059085%2F&data=02%7C01%7Canson.huang
> %40nxp.com%7C179da3635cab4a14deef08d5b975ecb6%7C686ea1d3bc2b4c6f
> a92cd99c5c301635%7C0%7C0%7C636618838508978629&sdata=BcQ9tc%2BE
> CZ%2Fk4AsZFxshgmvSsPg7eRN0ASzP8LO8yBI%3D&reserved=0
>
> Some of the comments might apply here too.
Ah, I did NOT notice this thread, so how to proceed, will you continue to finish your patch?
If yes, then you can just ignore/skip my patch, thanks.
Anson.
>
> Regards,
> Bastian
>
> > ---
> > drivers/thermal/imx_thermal.c | 16 ----------------
> > 1 file changed, 16 deletions(-)
> >
> > diff --git a/drivers/thermal/imx_thermal.c
> > b/drivers/thermal/imx_thermal.c index c30dc21..8eedb97 100644
> > --- a/drivers/thermal/imx_thermal.c
> > +++ b/drivers/thermal/imx_thermal.c
> > @@ -9,7 +9,6 @@
> >
> > #include <linux/clk.h>
> > #include <linux/cpufreq.h>
> > -#include <linux/cpu_cooling.h>
> > #include <linux/delay.h>
> > #include <linux/device.h>
> > #include <linux/init.h>
> > @@ -207,7 +206,6 @@ static struct thermal_soc_data thermal_imx7d_data
> = {
> > struct imx_thermal_data {
> > struct cpufreq_policy *policy;
> > struct thermal_zone_device *tz;
> > - struct thermal_cooling_device *cdev;
> > enum thermal_device_mode mode;
> > struct regmap *tempmon;
> > u32 c1, c2; /* See formula in imx_init_calib() */ @@ -729,22
> > +727,12 @@ static int imx_thermal_probe(struct platform_device *pdev)
> > return -EPROBE_DEFER;
> > }
> >
> > - data->cdev = cpufreq_cooling_register(data->policy);
> > - if (IS_ERR(data->cdev)) {
> > - ret = PTR_ERR(data->cdev);
> > - dev_err(&pdev->dev,
> > - "failed to register cpufreq cooling device: %d\n", ret);
> > - cpufreq_cpu_put(data->policy);
> > - return ret;
> > - }
> > -
> > data->thermal_clk = devm_clk_get(&pdev->dev, NULL);
> > if (IS_ERR(data->thermal_clk)) {
> > ret = PTR_ERR(data->thermal_clk);
> > if (ret != -EPROBE_DEFER)
> > dev_err(&pdev->dev,
> > "failed to get thermal clk: %d\n", ret);
> > - cpufreq_cooling_unregister(data->cdev);
> > cpufreq_cpu_put(data->policy);
> > return ret;
> > }
> > @@ -759,7 +747,6 @@ static int imx_thermal_probe(struct platform_device
> *pdev)
> > ret = clk_prepare_enable(data->thermal_clk);
> > if (ret) {
> > dev_err(&pdev->dev, "failed to enable thermal clk: %d\n", ret);
> > - cpufreq_cooling_unregister(data->cdev);
> > cpufreq_cpu_put(data->policy);
> > return ret;
> > }
> > @@ -775,7 +762,6 @@ static int imx_thermal_probe(struct platform_device
> *pdev)
> > dev_err(&pdev->dev,
> > "failed to register thermal zone device %d\n", ret);
> > clk_disable_unprepare(data->thermal_clk);
> > - cpufreq_cooling_unregister(data->cdev);
> > cpufreq_cpu_put(data->policy);
> > return ret;
> > }
> > @@ -811,7 +797,6 @@ static int imx_thermal_probe(struct platform_device
> *pdev)
> > dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);
> > clk_disable_unprepare(data->thermal_clk);
> > thermal_zone_device_unregister(data->tz);
> > - cpufreq_cooling_unregister(data->cdev);
> > cpufreq_cpu_put(data->policy);
> > return ret;
> > }
> > @@ -831,7 +816,6 @@ static int imx_thermal_remove(struct
> platform_device *pdev)
> > clk_disable_unprepare(data->thermal_clk);
> >
> > thermal_zone_device_unregister(data->tz);
> > - cpufreq_cooling_unregister(data->cdev);
> > cpufreq_cpu_put(data->policy);
> >
> > return 0;
> >
>
> --
> Pengutronix e.K.
> Industrial Linux Solutions
> https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.
> pengutronix.de%2F&data=02%7C01%7Canson.huang%40nxp.com%7C179da36
> 35cab4a14deef08d5b975ecb6%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0
> %7C0%7C636618838508978629&sdata=kHHjnbmj2kV0aPlAvULXUh%2Fm%2Fp
> gbu21luMQ6jfIUgLo%3D&reserved=0
> Peiner Str. 6-8, 31137 Hildesheim, Germany Amtsgericht Hildesheim, HRA 2686
^ permalink raw reply
* Allwinner A64: Issue on external rtc clock to wifi chip
From: Maxime Ripard @ 2018-05-14 9:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAMty3ZC3ggxkZwirpQ-aRP8Udg=aYypBArb0KcR0_Z0AG8wATA@mail.gmail.com>
On Mon, May 14, 2018 at 02:34:22PM +0530, Jagan Teki wrote:
> On Mon, May 14, 2018 at 1:57 PM, Maxime Ripard
> <maxime.ripard@bootlin.com> wrote:
> > On Mon, May 14, 2018 at 01:34:56PM +0530, Jagan Teki wrote:
> >> On Mon, May 14, 2018 at 1:27 PM, Maxime Ripard
> >> <maxime.ripard@bootlin.com> wrote:
> >> > Hi,
> >> >
> >> > On Mon, May 14, 2018 at 12:37:49PM +0530, Jagan Teki wrote:
> >> >> Hi Maxime and All,
> >> >>
> >> >> We are trying to bring-up AP6330 Wifi chip for A64 board. We noticed
> >> >> to have an external rtc clock has driven from wifi chip.
> >> >>
> >> >> So the devicetree is configured according to this as below.
> >> >>
> >> >> / {
> >> >> wifi_pwrseq: wifi-pwrseq {
> >> >> compatible = "mmc-pwrseq-simple";
> >> >> clocks = <&rtc 1>;
> >> >> clock-names = "ext_clock";
> >> >> reset-gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>; /* PL2 */
> >> >> post-power-on-delay-ms = <400>;
> >> >> };
> >> >> };
> >> >>
> >> >> &rtc {
> >> >> clock-output-names = "rtc-osc32k", "rtc-osc32k-out";
> >> >> clocks = <&osc32k>;
> >> >> #clock-cells = <1>;
> >> >> };
> >> >>
> >> >> &mmc1 {
> >> >> pinctrl-names = "default";
> >> >> pinctrl-0 = <&mmc1_pins>;
> >> >> vmmc-supply = <®_dcdc1>;
> >> >> vqmmc-supply = <®_eldo1>;
> >> >> mmc-pwrseq = <&wifi_pwrseq>;
> >> >> bus-width = <4>;
> >> >> non-removable;
> >> >> status = "okay";
> >> >>
> >> >> brcmf: wifi at 1 {
> >> >> reg = <1>;
> >> >> compatible = "brcm,bcm4329-fmac";
> >> >> interrupt-parent = <&r_pio>;
> >> >> interrupts = <0 3 IRQ_TYPE_LEVEL_LOW>; /* WL-WAKE-AP: PL3 */
> >> >> interrupt-names = "host-wake";
> >> >> };
> >> >> };
> >> >>
> >> >> And observed rtc-osc32k-out clock is never enabled[1] and the value of
> >> >> LOSC_OUT_GATING is 0x0 which eventually not enabling
> >> >> LOSC_OUT_GATING_EN
> >> >>
> >> >> Pls. let us know if we miss anything here?
> >> >>
> >> >> [1] https://paste.ubuntu.com/p/X2By4q8kD2/
> >> >
> >> > Could you paste your config and the logs from a boot to?
> >>
> >> .config
> >> https://paste.ubuntu.com/p/w9w2KB7RFc/
> >>
> >> dmesg
> >> https://paste.ubuntu.com/p/mrZGk5bWRR/
> >
> > This is kind of weird. Have you tested with a 4.17 kernel? We have
> > runtime_pm changes lined up in next, so that might be a regression
> > there, even though we tested it with Quentin at some point.
>
> This is 4.17-rc4 do you want to try it on 4.16 ?
No, this is next-20180503. Please try with 4.17-rc4
Maxime
--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180514/4a2bdde5/attachment-0001.sig>
^ permalink raw reply
* Allwinner A64: Issue on external rtc clock to wifi chip
From: Jagan Teki @ 2018-05-14 9:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180514082744.ydmfg5mzsbol5onu@flea>
On Mon, May 14, 2018 at 1:57 PM, Maxime Ripard
<maxime.ripard@bootlin.com> wrote:
> On Mon, May 14, 2018 at 01:34:56PM +0530, Jagan Teki wrote:
>> On Mon, May 14, 2018 at 1:27 PM, Maxime Ripard
>> <maxime.ripard@bootlin.com> wrote:
>> > Hi,
>> >
>> > On Mon, May 14, 2018 at 12:37:49PM +0530, Jagan Teki wrote:
>> >> Hi Maxime and All,
>> >>
>> >> We are trying to bring-up AP6330 Wifi chip for A64 board. We noticed
>> >> to have an external rtc clock has driven from wifi chip.
>> >>
>> >> So the devicetree is configured according to this as below.
>> >>
>> >> / {
>> >> wifi_pwrseq: wifi-pwrseq {
>> >> compatible = "mmc-pwrseq-simple";
>> >> clocks = <&rtc 1>;
>> >> clock-names = "ext_clock";
>> >> reset-gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>; /* PL2 */
>> >> post-power-on-delay-ms = <400>;
>> >> };
>> >> };
>> >>
>> >> &rtc {
>> >> clock-output-names = "rtc-osc32k", "rtc-osc32k-out";
>> >> clocks = <&osc32k>;
>> >> #clock-cells = <1>;
>> >> };
>> >>
>> >> &mmc1 {
>> >> pinctrl-names = "default";
>> >> pinctrl-0 = <&mmc1_pins>;
>> >> vmmc-supply = <®_dcdc1>;
>> >> vqmmc-supply = <®_eldo1>;
>> >> mmc-pwrseq = <&wifi_pwrseq>;
>> >> bus-width = <4>;
>> >> non-removable;
>> >> status = "okay";
>> >>
>> >> brcmf: wifi at 1 {
>> >> reg = <1>;
>> >> compatible = "brcm,bcm4329-fmac";
>> >> interrupt-parent = <&r_pio>;
>> >> interrupts = <0 3 IRQ_TYPE_LEVEL_LOW>; /* WL-WAKE-AP: PL3 */
>> >> interrupt-names = "host-wake";
>> >> };
>> >> };
>> >>
>> >> And observed rtc-osc32k-out clock is never enabled[1] and the value of
>> >> LOSC_OUT_GATING is 0x0 which eventually not enabling
>> >> LOSC_OUT_GATING_EN
>> >>
>> >> Pls. let us know if we miss anything here?
>> >>
>> >> [1] https://paste.ubuntu.com/p/X2By4q8kD2/
>> >
>> > Could you paste your config and the logs from a boot to?
>>
>> .config
>> https://paste.ubuntu.com/p/w9w2KB7RFc/
>>
>> dmesg
>> https://paste.ubuntu.com/p/mrZGk5bWRR/
>
> This is kind of weird. Have you tested with a 4.17 kernel? We have
> runtime_pm changes lined up in next, so that might be a regression
> there, even though we tested it with Quentin at some point.
This is 4.17-rc4 do you want to try it on 4.16 ?
^ permalink raw reply
* [RFC PATCH 10/10] time: timekeeping: Remove time compensating from nonstop clocksources
From: Baolin Wang @ 2018-05-14 8:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1526285602.git.baolin.wang@linaro.org>
Since we have converted all nonstop clocksources to use persistent clock,
thus we can simplify the time compensating by removing the nonstop
clocksources. Now we can compensate the suspend time for the OS time from
the persistent clock or rtc device.
Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
---
kernel/time/timekeeping.c | 19 ++++---------------
1 file changed, 4 insertions(+), 15 deletions(-)
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 49cbcee..48d2a80 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -1666,7 +1666,6 @@ void timekeeping_inject_sleeptime64(struct timespec64 *delta)
void timekeeping_resume(void)
{
struct timekeeper *tk = &tk_core.timekeeper;
- struct clocksource *clock = tk->tkr_mono.clock;
unsigned long flags;
struct timespec64 ts_new, ts_delta;
u64 cycle_now;
@@ -1682,27 +1681,17 @@ void timekeeping_resume(void)
/*
* After system resumes, we need to calculate the suspended time and
- * compensate it for the OS time. There are 3 sources that could be
- * used: Nonstop clocksource during suspend, persistent clock and rtc
- * device.
+ * compensate it for the OS time. There are 2 sources that could be
+ * used: persistent clock and rtc device.
*
* One specific platform may have 1 or 2 or all of them, and the
* preference will be:
- * suspend-nonstop clocksource -> persistent clock -> rtc
+ * persistent clock -> rtc
* The less preferred source will only be tried if there is no better
* usable source. The rtc part is handled separately in rtc core code.
*/
cycle_now = tk_clock_read(&tk->tkr_mono);
- if ((clock->flags & CLOCK_SOURCE_SUSPEND_NONSTOP) &&
- cycle_now > tk->tkr_mono.cycle_last) {
- u64 nsec, cyc_delta;
-
- cyc_delta = clocksource_delta(cycle_now, tk->tkr_mono.cycle_last,
- tk->tkr_mono.mask);
- nsec = mul_u64_u32_shr(cyc_delta, clock->mult, clock->shift);
- ts_delta = ns_to_timespec64(nsec);
- sleeptime_injected = true;
- } else if (timespec64_compare(&ts_new, &timekeeping_suspend_time) > 0) {
+ if (timespec64_compare(&ts_new, &timekeeping_suspend_time) > 0) {
ts_delta = timespec64_sub(ts_new, timekeeping_suspend_time);
sleeptime_injected = true;
}
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH 09/10] x86: tsc: Register the persistent clock
From: Baolin Wang @ 2018-05-14 8:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1526285602.git.baolin.wang@linaro.org>
Register the tsc as one persistent clock to compensate the suspend time
if the tsc clocksource is always available.
Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
---
arch/x86/Kconfig | 1 +
arch/x86/kernel/tsc.c | 16 ++++++++++++++++
2 files changed, 17 insertions(+)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index c07f492..667e3a7 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -195,6 +195,7 @@ config X86
select USER_STACKTRACE_SUPPORT
select VIRT_TO_BUS
select X86_FEATURE_NAMES if PROC_FS
+ select PERSISTENT_CLOCK
config INSTRUCTION_DECODER
def_bool y
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 74392d9..dd8d7c3 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -11,6 +11,7 @@
#include <linux/delay.h>
#include <linux/clocksource.h>
#include <linux/percpu.h>
+#include <linux/persistent_clock.h>
#include <linux/timex.h>
#include <linux/static_key.h>
@@ -1032,6 +1033,11 @@ static u64 read_tsc(struct clocksource *cs)
return (u64)rdtsc_ordered();
}
+static u64 notrace tsc_read_persistent_clock(void)
+{
+ return (u64)rdtsc_ordered();
+}
+
static void tsc_cs_mark_unstable(struct clocksource *cs)
{
if (tsc_unstable)
@@ -1300,6 +1306,11 @@ static void tsc_refine_calibration_work(struct work_struct *work)
if (boot_cpu_has(X86_FEATURE_ART))
art_related_clocksource = &clocksource_tsc;
clocksource_register_khz(&clocksource_tsc, tsc_khz);
+
+ if (clocksource_tsc.flags & CLOCK_SOURCE_SUSPEND_NONSTOP)
+ persistent_clock_init_and_register(tsc_read_persistent_clock,
+ CLOCKSOURCE_MASK(64),
+ tsc_khz, 0);
unreg:
clocksource_unregister(&clocksource_tsc_early);
}
@@ -1327,6 +1338,11 @@ static int __init init_tsc_clocksource(void)
if (boot_cpu_has(X86_FEATURE_ART))
art_related_clocksource = &clocksource_tsc;
clocksource_register_khz(&clocksource_tsc, tsc_khz);
+
+ if (clocksource_tsc.flags & CLOCK_SOURCE_SUSPEND_NONSTOP)
+ persistent_clock_init_and_register(tsc_read_persistent_clock,
+ CLOCKSOURCE_MASK(64),
+ tsc_khz, 0);
unreg:
clocksource_unregister(&clocksource_tsc_early);
return 0;
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH 08/10] clocksource: time-pistachio: Register the persistent clock
From: Baolin Wang @ 2018-05-14 8:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1526285602.git.baolin.wang@linaro.org>
Since the timer on pistachio platform is always available, we can
register it as one persistent clock to compensate the suspend time
for the OS time.
Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
---
drivers/clocksource/Kconfig | 1 +
drivers/clocksource/time-pistachio.c | 3 +++
2 files changed, 4 insertions(+)
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index ed19757..b45be75 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -255,6 +255,7 @@ config CLKSRC_PISTACHIO
bool "Clocksource for Pistachio SoC" if COMPILE_TEST
depends on HAS_IOMEM
select TIMER_OF
+ select PERSISTENT_CLOCK
help
Enables the clocksource for the Pistachio SoC.
diff --git a/drivers/clocksource/time-pistachio.c b/drivers/clocksource/time-pistachio.c
index a2dd85d..5c3eb71 100644
--- a/drivers/clocksource/time-pistachio.c
+++ b/drivers/clocksource/time-pistachio.c
@@ -20,6 +20,7 @@
#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/persistent_clock.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/sched_clock.h>
@@ -212,6 +213,8 @@ static int __init pistachio_clksrc_of_init(struct device_node *node)
raw_spin_lock_init(&pcs_gpt.lock);
sched_clock_register(pistachio_read_sched_clock, 32, rate);
+ persistent_clock_init_and_register(pistachio_read_sched_clock,
+ CLOCKSOURCE_MASK(32), rate, 0);
return clocksource_register_hz(&pcs_gpt.cs, rate);
}
TIMER_OF_DECLARE(pistachio_gptimer, "img,pistachio-gptimer",
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH 07/10] clocksource: timer-ti-32k: Register the persistent clock
From: Baolin Wang @ 2018-05-14 8:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1526285602.git.baolin.wang@linaro.org>
Since the 32K counter is always available, then we can register the
persistent clock to compensate the suspend time for the OS time.
Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
---
drivers/clocksource/Kconfig | 1 +
drivers/clocksource/timer-ti-32k.c | 4 ++++
2 files changed, 5 insertions(+)
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 884719c..ed19757 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -262,6 +262,7 @@ config CLKSRC_TI_32K
bool "Texas Instruments 32.768 Hz Clocksource" if COMPILE_TEST
depends on GENERIC_SCHED_CLOCK
select TIMER_OF if OF
+ select PERSISTENT_CLOCK
help
This option enables support for Texas Instruments 32.768 Hz clocksource
available on many OMAP-like platforms.
diff --git a/drivers/clocksource/timer-ti-32k.c b/drivers/clocksource/timer-ti-32k.c
index 880a861..353ff9d 100644
--- a/drivers/clocksource/timer-ti-32k.c
+++ b/drivers/clocksource/timer-ti-32k.c
@@ -41,6 +41,7 @@
#include <linux/clocksource.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/persistent_clock.h>
/*
* 32KHz clocksource ... always available, on pretty most chips except
@@ -120,6 +121,9 @@ static int __init ti_32k_timer_init(struct device_node *np)
}
sched_clock_register(omap_32k_read_sched_clock, 32, 32768);
+ persistent_clock_init_and_register(omap_32k_read_sched_clock,
+ CLOCKSOURCE_MASK(32), 32768, 0);
+
pr_info("OMAP clocksource: 32k_counter at 32768 Hz\n");
return 0;
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH 06/10] clocksource: arm_arch_timer: Register the persistent clock
From: Baolin Wang @ 2018-05-14 8:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1526285602.git.baolin.wang@linaro.org>
Register the persistent clock to compensate the suspend time for OS time,
if the ARM counter clocksource will not be stopped in suspend state.
Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
---
drivers/clocksource/Kconfig | 1 +
drivers/clocksource/arm_arch_timer.c | 10 ++++++++++
2 files changed, 11 insertions(+)
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index d7dddcc..884719c 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -308,6 +308,7 @@ config ARC_TIMERS_64BIT
config ARM_ARCH_TIMER
bool
+ select PERSISTENT_CLOCK
select TIMER_OF if OF
select TIMER_ACPI if ACPI
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 57cb2f0..671be63 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -32,6 +32,7 @@
#include <asm/virt.h>
#include <clocksource/arm_arch_timer.h>
+#include <linux/persistent_clock.h>
#undef pr_fmt
#define pr_fmt(fmt) "arch_timer: " fmt
@@ -950,6 +951,15 @@ static void __init arch_counter_register(unsigned type)
/* 56 bits minimum, so we assume worst case rollover */
sched_clock_register(arch_timer_read_counter, 56, arch_timer_rate);
+
+ /*
+ * Register the persistent clock if the clocksource will not be stopped
+ * in suspend state.
+ */
+ if (!arch_counter_suspend_stop)
+ persistent_clock_init_and_register(arch_timer_read_counter,
+ CLOCKSOURCE_MASK(56),
+ arch_timer_rate, 0);
}
static void arch_timer_stop(struct clock_event_device *clk)
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH 05/10] arm: time: Remove the persistent clock support for ARM
From: Baolin Wang @ 2018-05-14 8:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1526285602.git.baolin.wang@linaro.org>
We have converted all drivers to use common persistent clock framework
to compensate the suspend time, so we can remove the persistent clock,
which only supports the ARM architecture.
Moreover there are no drivers will register read_boot_clock64(), so
remove it too.
Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
---
arch/arm/include/asm/mach/time.h | 4 ----
arch/arm/kernel/time.c | 36 ------------------------------------
2 files changed, 40 deletions(-)
diff --git a/arch/arm/include/asm/mach/time.h b/arch/arm/include/asm/mach/time.h
index 0f79e4d..3cbcafc 100644
--- a/arch/arm/include/asm/mach/time.h
+++ b/arch/arm/include/asm/mach/time.h
@@ -12,8 +12,4 @@
extern void timer_tick(void);
-typedef void (*clock_access_fn)(struct timespec64 *);
-extern int register_persistent_clock(clock_access_fn read_boot,
- clock_access_fn read_persistent);
-
#endif
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index cf2701c..713905c 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -76,42 +76,6 @@ void timer_tick(void)
}
#endif
-static void dummy_clock_access(struct timespec64 *ts)
-{
- ts->tv_sec = 0;
- ts->tv_nsec = 0;
-}
-
-static clock_access_fn __read_persistent_clock = dummy_clock_access;
-static clock_access_fn __read_boot_clock = dummy_clock_access;
-
-void read_persistent_clock64(struct timespec64 *ts)
-{
- __read_persistent_clock(ts);
-}
-
-void read_boot_clock64(struct timespec64 *ts)
-{
- __read_boot_clock(ts);
-}
-
-int __init register_persistent_clock(clock_access_fn read_boot,
- clock_access_fn read_persistent)
-{
- /* Only allow the clockaccess functions to be registered once */
- if (__read_persistent_clock == dummy_clock_access &&
- __read_boot_clock == dummy_clock_access) {
- if (read_boot)
- __read_boot_clock = read_boot;
- if (read_persistent)
- __read_persistent_clock = read_persistent;
-
- return 0;
- }
-
- return -EINVAL;
-}
-
void __init time_init(void)
{
if (machine_desc->init_time) {
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH 04/10] clocksource: tegra20_timer: Remove register_persistent_clock() API
From: Baolin Wang @ 2018-05-14 8:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1526285602.git.baolin.wang@linaro.org>
We will convert all drivers to use persistent clock framework to compensate
the suspend time for OS time, instead of using the register_persistent_clock()
API in ARM architecture.
So this patch removes the register_persistent_clock() and implement its
function to read persistent clock.
Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
---
drivers/clocksource/tegra20_timer.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c
index c337a81..97a34cb 100644
--- a/drivers/clocksource/tegra20_timer.c
+++ b/drivers/clocksource/tegra20_timer.c
@@ -124,7 +124,7 @@ static u64 tegra_rtc_read_ms(void)
}
/*
- * tegra_read_persistent_clock64 - Return time from a persistent clock.
+ * read_persistent_clock64 - Return time from a persistent clock.
*
* Reads the time from a source which isn't disabled during PM, the
* 32k sync timer. Convert the cycles elapsed since last read into
@@ -133,10 +133,16 @@ static u64 tegra_rtc_read_ms(void)
* tegra_rtc driver could be executing to avoid race conditions
* on the RTC shadow register
*/
-static void tegra_read_persistent_clock64(struct timespec64 *ts)
+void read_persistent_clock64(struct timespec64 *ts)
{
u64 delta;
+ if (!rtc_base) {
+ ts->tv_sec = 0;
+ ts->tv_nsec = 0;
+ return;
+ }
+
last_persistent_ms = persistent_ms;
persistent_ms = tegra_rtc_read_ms();
delta = persistent_ms - last_persistent_ms;
@@ -259,6 +265,6 @@ static int __init tegra20_init_rtc(struct device_node *np)
else
clk_prepare_enable(clk);
- return register_persistent_clock(NULL, tegra_read_persistent_clock64);
+ return 0;
}
TIMER_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc);
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH 03/10] arm: omap: Convert 32K counter to use persistent clock
From: Baolin Wang @ 2018-05-14 8:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1526285602.git.baolin.wang@linaro.org>
We have introduced the persistent clock framework to support the OS time
compensating from persistent clock, so this patch converts the 32k counter
to use persistent clock framework to save lots of duplicate code.
Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
---
arch/arm/plat-omap/Kconfig | 1 +
arch/arm/plat-omap/counter_32k.c | 44 ++++++--------------------------------
2 files changed, 8 insertions(+), 37 deletions(-)
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index afc1a1d..0e4e385 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
config ARCH_OMAP
+ select PERSISTENT_CLOCK
bool
if ARCH_OMAP
diff --git a/arch/arm/plat-omap/counter_32k.c b/arch/arm/plat-omap/counter_32k.c
index 2438b96..5d52f7c 100644
--- a/arch/arm/plat-omap/counter_32k.c
+++ b/arch/arm/plat-omap/counter_32k.c
@@ -19,8 +19,7 @@
#include <linux/io.h>
#include <linux/clocksource.h>
#include <linux/sched_clock.h>
-
-#include <asm/mach/time.h>
+#include <linux/persistent_clock.h>
#include <plat/counter-32k.h>
@@ -44,33 +43,6 @@ static u64 notrace omap_32k_read_sched_clock(void)
}
/**
- * omap_read_persistent_clock64 - Return time from a persistent clock.
- *
- * Reads the time from a source which isn't disabled during PM, the
- * 32k sync timer. Convert the cycles elapsed since last read into
- * nsecs and adds to a monotonically increasing timespec64.
- */
-static struct timespec64 persistent_ts;
-static cycles_t cycles;
-static unsigned int persistent_mult, persistent_shift;
-
-static void omap_read_persistent_clock64(struct timespec64 *ts)
-{
- unsigned long long nsecs;
- cycles_t last_cycles;
-
- last_cycles = cycles;
- cycles = sync32k_cnt_reg ? readl_relaxed(sync32k_cnt_reg) : 0;
-
- nsecs = clocksource_cyc2ns(cycles - last_cycles,
- persistent_mult, persistent_shift);
-
- timespec64_add_ns(&persistent_ts, nsecs);
-
- *ts = persistent_ts;
-}
-
-/**
* omap_init_clocksource_32k - setup and register counter 32k as a
* kernel clocksource
* @pbase: base addr of counter_32k module
@@ -95,13 +67,6 @@ int __init omap_init_clocksource_32k(void __iomem *vbase)
else
sync32k_cnt_reg = vbase + OMAP2_32KSYNCNT_CR_OFF_LOW;
- /*
- * 120000 rough estimate from the calculations in
- * __clocksource_update_freq_scale.
- */
- clocks_calc_mult_shift(&persistent_mult, &persistent_shift,
- 32768, NSEC_PER_SEC, 120000);
-
ret = clocksource_mmio_init(sync32k_cnt_reg, "32k_counter", 32768,
250, 32, clocksource_mmio_readl_up);
if (ret) {
@@ -110,7 +75,12 @@ int __init omap_init_clocksource_32k(void __iomem *vbase)
}
sched_clock_register(omap_32k_read_sched_clock, 32, 32768);
- register_persistent_clock(NULL, omap_read_persistent_clock64);
+ /*
+ * 120000 rough estimate from the calculations in
+ * __clocksource_update_freq_scale.
+ */
+ persistent_clock_init_and_register(omap_32k_read_sched_clock,
+ CLOCKSOURCE_MASK(32), 32768, 120000);
pr_info("OMAP clocksource: 32k_counter at 32768 Hz\n");
return 0;
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH 02/10] clocksource: sprd: Add one persistent timer for Spreadtrum platform
From: Baolin Wang @ 2018-05-14 8:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1526285602.git.baolin.wang@linaro.org>
On Spreadtrum SC9860 platform, we need one persistent timer to calculate
the suspend time to compensate the OS time.
This patch registers one Spreadtrum AON timer as persistent timer, which
runs at 32bit and periodic mode.
Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
---
drivers/clocksource/Kconfig | 1 +
drivers/clocksource/timer-sprd.c | 80 ++++++++++++++++++++++++++++++++++++++
2 files changed, 81 insertions(+)
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 8e8a097..d7dddcc 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -453,6 +453,7 @@ config SPRD_TIMER
bool "Spreadtrum timer driver" if COMPILE_TEST
depends on HAS_IOMEM
select TIMER_OF
+ select PERSISTENT_CLOCK
help
Enables support for the Spreadtrum timer driver.
diff --git a/drivers/clocksource/timer-sprd.c b/drivers/clocksource/timer-sprd.c
index ef9ebea..c6f657a 100644
--- a/drivers/clocksource/timer-sprd.c
+++ b/drivers/clocksource/timer-sprd.c
@@ -3,8 +3,11 @@
* Copyright (C) 2017 Spreadtrum Communications Inc.
*/
+#include <linux/clk.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/of_address.h>
+#include <linux/persistent_clock.h>
#include "timer-of.h"
@@ -157,3 +160,80 @@ static int __init sprd_timer_init(struct device_node *np)
}
TIMER_OF_DECLARE(sc9860_timer, "sprd,sc9860-timer", sprd_timer_init);
+
+void __iomem *pbase;
+
+static u64 sprd_persistent_timer_read(void)
+{
+ return ~(u64)readl_relaxed(pbase + TIMER_VALUE_SHDW_LO) &
+ CLOCKSOURCE_MASK(32);
+}
+
+static void sprd_persistent_timer_disable(void)
+{
+ sprd_timer_disable(pbase);
+}
+
+static void sprd_persistent_timer_enable(void)
+{
+ sprd_timer_disable(pbase);
+ sprd_timer_update_counter(pbase, TIMER_VALUE_LO_MASK);
+ sprd_timer_enable(pbase, TIMER_CTL_PERIOD_MODE);
+}
+
+static int __init sprd_persistent_timer_init(struct device_node *np)
+{
+ struct clk *clk;
+ u32 freq;
+ int ret;
+
+ clk = of_clk_get(np, 0);
+ if (IS_ERR(clk)) {
+ pr_err("Can't get timer clock for %pOF\n", np);
+ return PTR_ERR(clk);
+ }
+
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ pr_err("Failed to enable clock for %pOF\n", np);
+ clk_put(clk);
+ return ret;
+ }
+
+ freq = clk_get_rate(clk);
+ if (!freq) {
+ pr_err("Failed to get clock rate for %pOF\n", np);
+ ret = -EINVAL;
+ goto clk_rate_err;
+ }
+
+ pbase = of_io_request_and_map(np, 0, of_node_full_name(np));
+ if (IS_ERR(pbase)) {
+ pr_err("Can't map timer registers for %pOF\n", np);
+ ret = PTR_ERR(pbase);
+ goto clk_rate_err;
+ }
+
+ sprd_persistent_timer_enable();
+
+ ret = persistent_clock_init_and_register(sprd_persistent_timer_read,
+ CLOCKSOURCE_MASK(32), freq, 0);
+ if (ret) {
+ pr_err("Failed to register persistent clock for %pOF\n", np);
+ goto persist_err;
+ }
+
+ return 0;
+
+persist_err:
+ sprd_persistent_timer_disable();
+ iounmap(pbase);
+clk_rate_err:
+ clk_disable_unprepare(clk);
+ clk_put(clk);
+
+ return ret;
+}
+
+TIMER_OF_DECLARE(sc9860_persistent_timer, "sprd,sc9860-persistent-timer",
+ sprd_persistent_timer_init);
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH 01/10] time: Add persistent clock support
From: Baolin Wang @ 2018-05-14 8:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1526285602.git.baolin.wang@linaro.org>
On our Spreadtrum SC9860 platform, we registered the high resolution
ARM generic timer as one clocksource to update the OS time, but the
ARM generic timer will be stopped in suspend state. So we use one 64bit
always-on timer (but low resolution) of Spreadtrum to calculate the
suspend time to compensate the OS time. Though we can register the
always-on timer as one clocksource, we need re-calculate the
mult/shift with one larger conversion range to calculate the suspend
time.
But now we have too many different ways of dealing with persistent
timekeeping across architectures, and there will be many duplicate
code if we register one timer to be one persistent clock. Thus it
will be more helpful if we add one common framework for timer drivers
to be registered as one persistent clock and implement the common
read_persistent_clock64() to compensate the OS time.
Moreover we can register the clocksource with CLOCK_SOURCE_SUSPEND_NONSTOP
to be one persistent clock, then we can simplify the suspend/resume
accounting by removing CLOCK_SOURCE_SUSPEND_NONSTOP timing. After that
we can only compensate the OS time by persistent clock or RTC.
Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
---
include/linux/persistent_clock.h | 21 +++++
kernel/time/Kconfig | 4 +
kernel/time/Makefile | 1 +
kernel/time/persistent_clock.c | 180 ++++++++++++++++++++++++++++++++++++++
4 files changed, 206 insertions(+)
create mode 100644 include/linux/persistent_clock.h
create mode 100644 kernel/time/persistent_clock.c
diff --git a/include/linux/persistent_clock.h b/include/linux/persistent_clock.h
new file mode 100644
index 0000000..4917980
--- /dev/null
+++ b/include/linux/persistent_clock.h
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifndef __PERSISTENT_CLOCK_H__
+#define __PERSISTENT_CLOCK_H__
+
+#ifdef CONFIG_PERSISTENT_CLOCK
+extern int __init persistent_clock_init_and_register(u64 (*read)(void),
+ u64 mask, u32 freq,
+ u64 maxsec);
+extern void __init persistent_clock_cleanup(void);
+#else
+static inline int persistent_clock_init_and_register(u64 (*read)(void),
+ u64 mask, u32 freq,
+ u64 maxsec)
+{
+ return 0;
+}
+
+static inline void persistent_clock_cleanup(void) { }
+#endif
+
+#endif
diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig
index 78eabc4..7188600 100644
--- a/kernel/time/Kconfig
+++ b/kernel/time/Kconfig
@@ -47,6 +47,10 @@ config GENERIC_CLOCKEVENTS_MIN_ADJUST
config GENERIC_CMOS_UPDATE
bool
+# Persistent clock support
+config PERSISTENT_CLOCK
+ bool
+
if GENERIC_CLOCKEVENTS
menu "Timers subsystem"
diff --git a/kernel/time/Makefile b/kernel/time/Makefile
index f1e46f3..f6d368f 100644
--- a/kernel/time/Makefile
+++ b/kernel/time/Makefile
@@ -18,3 +18,4 @@ obj-$(CONFIG_GENERIC_SCHED_CLOCK) += sched_clock.o
obj-$(CONFIG_TICK_ONESHOT) += tick-oneshot.o tick-sched.o
obj-$(CONFIG_DEBUG_FS) += timekeeping_debug.o
obj-$(CONFIG_TEST_UDELAY) += test_udelay.o
+obj-$(CONFIG_PERSISTENT_CLOCK) += persistent_clock.o
diff --git a/kernel/time/persistent_clock.c b/kernel/time/persistent_clock.c
new file mode 100644
index 0000000..1410cb3
--- /dev/null
+++ b/kernel/time/persistent_clock.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Linaro, Inc.
+ *
+ * Author: Baolin Wang <baolin.wang@linaro.org>
+ */
+
+#include <linux/alarmtimer.h>
+#include <linux/clocksource.h>
+#include <linux/persistent_clock.h>
+
+/**
+ * persistent_clock_read_data - data required to read persistent clock
+ * @read: Returns a cycle value from persistent clock.
+ * @last_cycles: Clock cycle value at last update.
+ * @last_ns: Time value (nanoseconds) at last update.
+ * @mask: Bitmask for two's complement subtraction of non 64bit clocks.
+ * @mult: Cycle to nanosecond multiplier.
+ * @shift: Cycle to nanosecond divisor.
+ */
+struct persistent_clock_read_data {
+ u64 (*read)(void);
+ u64 last_cycles;
+ u64 last_ns;
+ u64 mask;
+ u32 mult;
+ u32 shift;
+};
+
+/**
+ * persistent_clock - represent the persistent clock
+ * @read_data: Data required to read from persistent clock.
+ * @seq: Sequence counter for protecting updates.
+ * @freq: The frequency of the persistent clock.
+ * @wrap: Duration for persistent clock can run before wrapping.
+ * @alarm: Update timeout for persistent clock wrap.
+ */
+struct persistent_clock {
+ struct persistent_clock_read_data read_data;
+ seqcount_t seq;
+ u32 freq;
+ ktime_t wrap;
+ struct alarm alarm;
+};
+
+static struct persistent_clock p;
+
+void read_persistent_clock64(struct timespec64 *ts)
+{
+ struct persistent_clock_read_data *read_data = &p.read_data;
+ unsigned long seq;
+ u64 delta, nsecs;
+
+ if (!read_data->read) {
+ ts->tv_sec = 0;
+ ts->tv_nsec = 0;
+ return;
+ }
+
+ do {
+ seq = read_seqcount_begin(&p.seq);
+ delta = (read_data->read() - read_data->last_cycles) &
+ read_data->mask;
+
+ nsecs = read_data->last_ns +
+ clocksource_cyc2ns(delta, read_data->mult,
+ read_data->shift);
+ *ts = ns_to_timespec64(nsecs);
+ } while (read_seqcount_retry(&p.seq, seq));
+}
+
+static void persistent_clock_update(void)
+{
+ struct persistent_clock_read_data *read_data = &p.read_data;
+ u64 cycles, delta;
+
+ write_seqcount_begin(&p.seq);
+
+ cycles = read_data->read();
+ delta = (cycles - read_data->last_cycles) & read_data->mask;
+ read_data->last_ns += clocksource_cyc2ns(delta, read_data->mult,
+ read_data->shift);
+ read_data->last_cycles = cycles;
+
+ write_seqcount_end(&p.seq);
+}
+
+static enum alarmtimer_restart persistent_clock_alarm_fired(struct alarm *alarm,
+ ktime_t now)
+{
+ persistent_clock_update();
+
+ alarm_forward(&p.alarm, now, p.wrap);
+ return ALARMTIMER_RESTART;
+}
+
+int __init persistent_clock_init_and_register(u64 (*read)(void), u64 mask,
+ u32 freq, u64 maxsec)
+{
+ struct persistent_clock_read_data *read_data = &p.read_data;
+ u64 wrap, res, secs = maxsec;
+
+ if (!read || !mask || !freq)
+ return -EINVAL;
+
+ if (!secs) {
+ /*
+ * If the timer driver did not specify the maximum conversion
+ * seconds of the persistent clock, then we calculate the
+ * conversion range with the persistent clock's bits and
+ * frequency.
+ */
+ secs = mask;
+ do_div(secs, freq);
+
+ /*
+ * Some persistent counter can be larger than 32bit, so we
+ * need limit the max suspend time to have a good conversion
+ * precision. So 24 hours may be enough usually.
+ */
+ if (secs > 86400)
+ secs = 86400;
+ }
+
+ /* Calculate the mult/shift to convert cycles to ns. */
+ clocks_calc_mult_shift(&read_data->mult, &read_data->shift, freq,
+ NSEC_PER_SEC, (u32)secs);
+
+ /* Calculate how many nanoseconds until we risk wrapping. */
+ wrap = clocks_calc_max_nsecs(read_data->mult, read_data->shift, 0,
+ mask, NULL);
+ p.wrap = ns_to_ktime(wrap);
+
+ p.freq = freq;
+ read_data->mask = mask;
+ read_data->read = read;
+
+ persistent_clock_update();
+
+ /* Calculate the ns resolution of this persistent clock. */
+ res = clocksource_cyc2ns(1ULL, read_data->mult, read_data->shift);
+
+ pr_info("persistent clock: mask %llu at %uHz, resolution %lluns, wraps every %lluns\n",
+ mask, freq, res, wrap);
+ return 0;
+}
+
+void __init persistent_clock_cleanup(void)
+{
+ p.read_data.read = NULL;
+ alarm_cancel(&p.alarm);
+}
+
+static int __init persistent_clock_start_alarmtimer(void)
+{
+ struct persistent_clock_read_data *read_data = &p.read_data;
+ ktime_t now;
+
+ /*
+ * If no persistent clock function has been provided at that point,
+ * just return.
+ */
+ if (!read_data->read)
+ return 0;
+
+ persistent_clock_update();
+
+ /*
+ * Since the persistent clock will not be stopped when system enters the
+ * suspend state, thus we need start one alarmtimer to wakeup the system
+ * to update the persistent clock before wrapping. We should start the
+ * update alarmtimer after the alarmtimer subsystem was initialized.
+ */
+ alarm_init(&p.alarm, ALARM_BOOTTIME, persistent_clock_alarm_fired);
+ now = ktime_get_boottime();
+ alarm_start(&p.alarm, ktime_add(now, p.wrap));
+
+ return 0;
+}
+late_initcall(persistent_clock_start_alarmtimer);
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH 00/10] Add persistent clock support
From: Baolin Wang @ 2018-05-14 8:55 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
We will meet below issues when compensating the suspend time for the timekeeping.
1. We have too many different ways of dealing with persistent timekeeping
across architectures, so it is hard for one driver to compatable with different
architectures.
2. On some platforms (such as Spreadtrum platform), we registered the high
resolution timer as one clocksource to update the OS time, but the high
resolution timer will be stopped in suspend state. So we use another one
always-on timer (but low resolution) to calculate the suspend time to
compensate the OS time. Though we can register the always-on timer as one
clocksource, we need re-calculate the mult/shift with one larger conversion
range to calculate the suspend time and need update the clock in case of
running over the always-on timer.
More duplicate code will be added if other platforms meet this case.
3. Now we have 3 sources that could be used to compensate the OS time:
Nonstop clocksource during suspend, persistent clock and rtc device,
which is complicated. Another hand is that the nonstop clocksource can
risk wrapping if the suspend time is too long, so we need one mechanism
to wake up the system before the nonstop clocksource wrapping.
According to above issues, we can introduce one common persistent clock
framework to compatable with different architectures, in future we will
remove the persistent clock implementation for each architecture. Also
this framework will implement common code to help drivers to register easily.
Moreover if we converted all SUSPEND_NONSTOP clocksource to register to
be one persistent clock, we can remove the SUSPEND_NONSTOP clocksource
accounting in timekeeping, which means we can only compensate the OS time
from persistent clock and RTC.
Will be appreciated for any comments. Thank you all.
Arnd posted some comments as below last time, but we did not get a general
consensus, so I post them again.
Arnd said:
"I was planning to discuss this with Daniel and John during Linaro Connect,
but that didn't happen, so I'd like to bring up the bigger picture here again.
Today, we have a number of subsystem-type interfaces that deal with
time keeping in the wider sense (I might be missing some):
- clock source
- clock event
- sched clock
- real time clock
- ptp clock
- persistent clock
The first five have separate registration interfaces and may all refer
to different hardware blocks, or (more commonly) have some overlap
in the hardware. The fifth one is generalized by your series, without it
it's really architecture specific (as the other ones were one one point).
Are we happy with that structure in the long run? One of my earlier
comments on this series was that I thought it should be combined with
the clocksource registration, but upon talking to Baolin about it more,
I realized that this just follows the same structure that we have for the
others.
In theory, we could have a more abstract way of registering a clock
hardware that interfaces with any combination of the six subsystems
I mentioned above, with a superset of the subsystem specific structures
and a set of flags that indicate what a particular device is usable for.
Combining all six might be a bit too much (in particular rtc, though
it clearly overlaps the persistent-clk case), but what your general
ideas on where we should be heading? Is it worth reworking the
core kernel portion of the subsystems to simplify the individual
drivers?"
Baolin Wang (10):
time: Add persistent clock support
clocksource: sprd: Add one persistent timer for Spreadtrum platform
arm: omap: Convert 32K counter to use persistent clock
clocksource: tegra20_timer: Remove register_persistent_clock() API
arm: time: Remove the persistent clock support for ARM
clocksource: arm_arch_timer: Register the persistent clock
clocksource: timer-ti-32k: Register the persistent clock
clocksource: time-pistachio: Register the persistent clock
x86: tsc: Register the persistent clock
time: timekeeping: Remove time compensating from nonstop clocksources
arch/arm/include/asm/mach/time.h | 4 -
arch/arm/kernel/time.c | 36 -------
arch/arm/plat-omap/Kconfig | 1 +
arch/arm/plat-omap/counter_32k.c | 44 ++-------
arch/x86/Kconfig | 1 +
arch/x86/kernel/tsc.c | 16 +++
drivers/clocksource/Kconfig | 4 +
drivers/clocksource/arm_arch_timer.c | 10 ++
drivers/clocksource/tegra20_timer.c | 12 ++-
drivers/clocksource/time-pistachio.c | 3 +
drivers/clocksource/timer-sprd.c | 80 +++++++++++++++
drivers/clocksource/timer-ti-32k.c | 4 +
include/linux/persistent_clock.h | 21 ++++
kernel/time/Kconfig | 4 +
kernel/time/Makefile | 1 +
kernel/time/persistent_clock.c | 180 ++++++++++++++++++++++++++++++++++
kernel/time/timekeeping.c | 19 +---
17 files changed, 345 insertions(+), 95 deletions(-)
create mode 100644 include/linux/persistent_clock.h
create mode 100644 kernel/time/persistent_clock.c
--
1.7.9.5
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox