Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull timer and time updates from Thomas Gleixner:
 "A rather large update of timers, timekeeping & co

   - Core timekeeping code is year-2038 safe now for 32bit machines.
     Now we just need to fix all in kernel users and the gazillion of
     user space interfaces which rely on timespec/timeval :)

   - Better cache layout for the timekeeping internal data structures.

   - Proper nanosecond based interfaces for in kernel users.

   - Tree wide cleanup of code which wants nanoseconds but does hoops
     and loops to convert back and forth from timespecs.  Some of it
     definitely belongs into the ugly code museum.

   - Consolidation of the timekeeping interface zoo.

   - A fast NMI safe accessor to clock monotonic for tracing.  This is a
     long standing request to support correlated user/kernel space
     traces.  With proper NTP frequency correction it's also suitable
     for correlation of traces accross separate machines.

   - Checkpoint/restart support for timerfd.

   - A few NOHZ[_FULL] improvements in the [hr]timer code.

   - Code move from kernel to kernel/time of all time* related code.

   - New clocksource/event drivers from the ARM universe.  I'm really
     impressed that despite an architected timer in the newer chips SoC
     manufacturers insist on inventing new and differently broken SoC
     specific timers.

[ Ed. "Impressed"? I don't think that word means what you think it means ]

   - Another round of code move from arch to drivers.  Looks like most
     of the legacy mess in ARM regarding timers is sorted out except for
     a few obnoxious strongholds.

   - The usual updates and fixlets all over the place"

* 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (114 commits)
  timekeeping: Fixup typo in update_vsyscall_old definition
  clocksource: document some basic timekeeping concepts
  timekeeping: Use cached ntp_tick_length when accumulating error
  timekeeping: Rework frequency adjustments to work better w/ nohz
  timekeeping: Minor fixup for timespec64->timespec assignment
  ftrace: Provide trace clocks monotonic
  timekeeping: Provide fast and NMI safe access to CLOCK_MONOTONIC
  seqcount: Add raw_write_seqcount_latch()
  seqcount: Provide raw_read_seqcount()
  timekeeping: Use tk_read_base as argument for timekeeping_get_ns()
  timekeeping: Create struct tk_read_base and use it in struct timekeeper
  timekeeping: Restructure the timekeeper some more
  clocksource: Get rid of cycle_last
  clocksource: Move cycle_last validation to core code
  clocksource: Make delta calculation a function
  wireless: ath9k: Get rid of timespec conversions
  drm: vmwgfx: Use nsec based interfaces
  drm: i915: Use nsec based interfaces
  timekeeping: Provide ktime_get_raw()
  hangcheck-timer: Use ktime_get_ns()
  ...
This commit is contained in:
Linus Torvalds 2014-08-05 17:46:42 -07:00
commit e7fda6c4c3
108 changed files with 3236 additions and 1938 deletions

View File

@ -54,7 +54,7 @@
!Ikernel/sched/cpupri.c !Ikernel/sched/cpupri.c
!Ikernel/sched/fair.c !Ikernel/sched/fair.c
!Iinclude/linux/completion.h !Iinclude/linux/completion.h
!Ekernel/timer.c !Ekernel/time/timer.c
</sect1> </sect1>
<sect1><title>Wait queues and Wake events</title> <sect1><title>Wait queues and Wake events</title>
!Iinclude/linux/wait.h !Iinclude/linux/wait.h
@ -63,7 +63,7 @@
<sect1><title>High-resolution timers</title> <sect1><title>High-resolution timers</title>
!Iinclude/linux/ktime.h !Iinclude/linux/ktime.h
!Iinclude/linux/hrtimer.h !Iinclude/linux/hrtimer.h
!Ekernel/hrtimer.c !Ekernel/time/hrtimer.c
</sect1> </sect1>
<sect1><title>Workqueues and Kevents</title> <sect1><title>Workqueues and Kevents</title>
!Ekernel/workqueue.c !Ekernel/workqueue.c

View File

@ -0,0 +1,29 @@
* Cirrus Logic CLPS711X Timer Counter
Required properties:
- compatible: Shall contain "cirrus,clps711x-timer".
- reg : Address and length of the register set.
- interrupts: The interrupt number of the timer.
- clocks : phandle of timer reference clock.
Note: Each timer should have an alias correctly numbered in "aliases" node.
Example:
aliases {
timer0 = &timer1;
timer1 = &timer2;
};
timer1: timer@80000300 {
compatible = "cirrus,ep7312-timer", "cirrus,clps711x-timer";
reg = <0x80000300 0x4>;
interrupts = <8>;
clocks = <&clks 5>;
};
timer2: timer@80000340 {
compatible = "cirrus,ep7312-timer", "cirrus,clps711x-timer";
reg = <0x80000340 0x4>;
interrupts = <9>;
clocks = <&clks 6>;
};

View File

@ -0,0 +1,17 @@
Mediatek MT6577, MT6572 and MT6589 Timers
---------------------------------------
Required properties:
- compatible: Should be "mediatek,mt6577-timer"
- reg: Should contain location and length for timers register.
- clocks: Clocks driving the timer hardware. This list should include two
clocks. The order is system clock and as second clock the RTC clock.
Examples:
timer@10008000 {
compatible = "mediatek,mt6577-timer";
reg = <0x10008000 0x80>;
interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_LOW>;
clocks = <&system_clk>, <&rtc_clk>;
};

View File

@ -0,0 +1,47 @@
* Renesas R-Car Compare Match Timer (CMT)
The CMT is a multi-channel 16/32/48-bit timer/counter with configurable clock
inputs and programmable compare match.
Channels share hardware resources but their counter and compare match value
are independent. A particular CMT instance can implement only a subset of the
channels supported by the CMT model. Channel indices represent the hardware
position of the channel in the CMT and don't match the channel numbers in the
datasheets.
Required Properties:
- compatible: must contain one of the following.
- "renesas,cmt-32" for the 32-bit CMT
(CMT0 on sh7372, sh73a0 and r8a7740)
- "renesas,cmt-32-fast" for the 32-bit CMT with fast clock support
(CMT[234] on sh7372, sh73a0 and r8a7740)
- "renesas,cmt-48" for the 48-bit CMT
(CMT1 on sh7372, sh73a0 and r8a7740)
- "renesas,cmt-48-gen2" for the second generation 48-bit CMT
(CMT[01] on r8a73a4, r8a7790 and r8a7791)
- reg: base address and length of the registers block for the timer module.
- interrupts: interrupt-specifier for the timer, one per channel.
- clocks: a list of phandle + clock-specifier pairs, one for each entry
in clock-names.
- clock-names: must contain "fck" for the functional clock.
- renesas,channels-mask: bitmask of the available channels.
Example: R8A7790 (R-Car H2) CMT0 node
CMT0 on R8A7790 implements hardware channels 5 and 6 only and names
them channels 0 and 1 in the documentation.
cmt0: timer@ffca0000 {
compatible = "renesas,cmt-48-gen2";
reg = <0 0xffca0000 0 0x1004>;
interrupts = <0 142 IRQ_TYPE_LEVEL_HIGH>,
<0 142 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp1_clks R8A7790_CLK_CMT0>;
clock-names = "fck";
renesas,channels-mask = <0x60>;
};

View File

@ -0,0 +1,39 @@
* Renesas R-Car Multi-Function Timer Pulse Unit 2 (MTU2)
The MTU2 is a multi-purpose, multi-channel timer/counter with configurable
clock inputs and programmable compare match.
Channels share hardware resources but their counter and compare match value
are independent. The MTU2 hardware supports five channels indexed from 0 to 4.
Required Properties:
- compatible: must contain "renesas,mtu2"
- reg: base address and length of the registers block for the timer module.
- interrupts: interrupt specifiers for the timer, one for each entry in
interrupt-names.
- interrupt-names: must contain one entry named "tgi?a" for each enabled
channel, where "?" is the channel index expressed as one digit from "0" to
"4".
- clocks: a list of phandle + clock-specifier pairs, one for each entry
in clock-names.
- clock-names: must contain "fck" for the functional clock.
Example: R7S72100 (RZ/A1H) MTU2 node
mtu2: timer@fcff0000 {
compatible = "renesas,mtu2";
reg = <0xfcff0000 0x400>;
interrupts = <0 139 IRQ_TYPE_LEVEL_HIGH>,
<0 146 IRQ_TYPE_LEVEL_HIGH>,
<0 150 IRQ_TYPE_LEVEL_HIGH>,
<0 154 IRQ_TYPE_LEVEL_HIGH>,
<0 159 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "tgi0a", "tgi1a", "tgi2a", "tgi3a", "tgi4a";
clocks = <&mstp3_clks R7S72100_CLK_MTU2>;
clock-names = "fck";
};

View File

@ -0,0 +1,39 @@
* Renesas R-Car Timer Unit (TMU)
The TMU is a 32-bit timer/counter with configurable clock inputs and
programmable compare match.
Channels share hardware resources but their counter and compare match value
are independent. The TMU hardware supports up to three channels.
Required Properties:
- compatible: must contain "renesas,tmu"
- reg: base address and length of the registers block for the timer module.
- interrupts: interrupt-specifier for the timer, one per channel.
- clocks: a list of phandle + clock-specifier pairs, one for each entry
in clock-names.
- clock-names: must contain "fck" for the functional clock.
Optional Properties:
- #renesas,channels: number of channels implemented by the timer, must be 2
or 3 (if not specified the value defaults to 3).
Example: R8A7779 (R-Car H1) TMU0 node
tmu0: timer@ffd80000 {
compatible = "renesas,tmu";
reg = <0xffd80000 0x30>;
interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>,
<0 33 IRQ_TYPE_LEVEL_HIGH>,
<0 34 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp0_clks R8A7779_CLK_TMU0>;
clock-names = "fck";
#renesas,channels = <3>;
};

View File

@ -78,6 +78,7 @@ lsi LSI Corp. (LSI Logic)
lltc Linear Technology Corporation lltc Linear Technology Corporation
marvell Marvell Technology Group Ltd. marvell Marvell Technology Group Ltd.
maxim Maxim Integrated Products maxim Maxim Integrated Products
mediatek MediaTek Inc.
micrel Micrel Inc. micrel Micrel Inc.
microchip Microchip Technology Inc. microchip Microchip Technology Inc.
mosaixtech Mosaix Technologies, Inc. mosaixtech Mosaix Technologies, Inc.

View File

@ -1743,6 +1743,25 @@ pair provide additional information particular to the objects they represent.
While the first three lines are mandatory and always printed, the rest is While the first three lines are mandatory and always printed, the rest is
optional and may be omitted if no marks created yet. optional and may be omitted if no marks created yet.
Timerfd files
~~~~~~~~~~~~~
pos: 0
flags: 02
mnt_id: 9
clockid: 0
ticks: 0
settime flags: 01
it_value: (0, 49406829)
it_interval: (1, 0)
where 'clockid' is the clock type and 'ticks' is the number of the timer expirations
that have occurred [see timerfd_create(2) for details]. 'settime flags' are
flags in octal form been used to setup the timer [see timerfd_settime(2) for
details]. 'it_value' is remaining time until the timer exiration.
'it_interval' is the interval for the timer. Note the timer might be set up
with TIMER_ABSTIME option which will be shown in 'settime flags', but 'it_value'
still exhibits timer's remaining time.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
Configuring procfs Configuring procfs

View File

@ -12,6 +12,8 @@ Makefile
- Build and link hpet_example - Build and link hpet_example
NO_HZ.txt NO_HZ.txt
- Summary of the different methods for the scheduler clock-interrupts management. - Summary of the different methods for the scheduler clock-interrupts management.
timekeeping.txt
- Clock sources, clock events, sched_clock() and delay timer notes
timers-howto.txt timers-howto.txt
- how to insert delays in the kernel the right (tm) way. - how to insert delays in the kernel the right (tm) way.
timer_stats.txt timer_stats.txt

View File

@ -0,0 +1,179 @@
Clock sources, Clock events, sched_clock() and delay timers
-----------------------------------------------------------
This document tries to briefly explain some basic kernel timekeeping
abstractions. It partly pertains to the drivers usually found in
drivers/clocksource in the kernel tree, but the code may be spread out
across the kernel.
If you grep through the kernel source you will find a number of architecture-
specific implementations of clock sources, clockevents and several likewise
architecture-specific overrides of the sched_clock() function and some
delay timers.
To provide timekeeping for your platform, the clock source provides
the basic timeline, whereas clock events shoot interrupts on certain points
on this timeline, providing facilities such as high-resolution timers.
sched_clock() is used for scheduling and timestamping, and delay timers
provide an accurate delay source using hardware counters.
Clock sources
-------------
The purpose of the clock source is to provide a timeline for the system that
tells you where you are in time. For example issuing the command 'date' on
a Linux system will eventually read the clock source to determine exactly
what time it is.
Typically the clock source is a monotonic, atomic counter which will provide
n bits which count from 0 to 2^(n-1) and then wraps around to 0 and start over.
It will ideally NEVER stop ticking as long as the system is running. It
may stop during system suspend.
The clock source shall have as high resolution as possible, and the frequency
shall be as stable and correct as possible as compared to a real-world wall
clock. It should not move unpredictably back and forth in time or miss a few
cycles here and there.
It must be immune to the kind of effects that occur in hardware where e.g.
the counter register is read in two phases on the bus lowest 16 bits first
and the higher 16 bits in a second bus cycle with the counter bits
potentially being updated in between leading to the risk of very strange
values from the counter.
When the wall-clock accuracy of the clock source isn't satisfactory, there
are various quirks and layers in the timekeeping code for e.g. synchronizing
the user-visible time to RTC clocks in the system or against networked time
servers using NTP, but all they do basically is update an offset against
the clock source, which provides the fundamental timeline for the system.
These measures does not affect the clock source per se, they only adapt the
system to the shortcomings of it.
The clock source struct shall provide means to translate the provided counter
into a nanosecond value as an unsigned long long (unsigned 64 bit) number.
Since this operation may be invoked very often, doing this in a strict
mathematical sense is not desirable: instead the number is taken as close as
possible to a nanosecond value using only the arithmetic operations
multiply and shift, so in clocksource_cyc2ns() you find:
ns ~= (clocksource * mult) >> shift
You will find a number of helper functions in the clock source code intended
to aid in providing these mult and shift values, such as
clocksource_khz2mult(), clocksource_hz2mult() that help determine the
mult factor from a fixed shift, and clocksource_register_hz() and
clocksource_register_khz() which will help out assigning both shift and mult
factors using the frequency of the clock source as the only input.
For real simple clock sources accessed from a single I/O memory location
there is nowadays even clocksource_mmio_init() which will take a memory
location, bit width, a parameter telling whether the counter in the
register counts up or down, and the timer clock rate, and then conjure all
necessary parameters.
Since a 32-bit counter at say 100 MHz will wrap around to zero after some 43
seconds, the code handling the clock source will have to compensate for this.
That is the reason why the clock source struct also contains a 'mask'
member telling how many bits of the source are valid. This way the timekeeping
code knows when the counter will wrap around and can insert the necessary
compensation code on both sides of the wrap point so that the system timeline
remains monotonic.
Clock events
------------
Clock events are the conceptual reverse of clock sources: they take a
desired time specification value and calculate the values to poke into
hardware timer registers.
Clock events are orthogonal to clock sources. The same hardware
and register range may be used for the clock event, but it is essentially
a different thing. The hardware driving clock events has to be able to
fire interrupts, so as to trigger events on the system timeline. On an SMP
system, it is ideal (and customary) to have one such event driving timer per
CPU core, so that each core can trigger events independently of any other
core.
You will notice that the clock event device code is based on the same basic
idea about translating counters to nanoseconds using mult and shift
arithmetic, and you find the same family of helper functions again for
assigning these values. The clock event driver does not need a 'mask'
attribute however: the system will not try to plan events beyond the time
horizon of the clock event.
sched_clock()
-------------
In addition to the clock sources and clock events there is a special weak
function in the kernel called sched_clock(). This function shall return the
number of nanoseconds since the system was started. An architecture may or
may not provide an implementation of sched_clock() on its own. If a local
implementation is not provided, the system jiffy counter will be used as
sched_clock().
As the name suggests, sched_clock() is used for scheduling the system,
determining the absolute timeslice for a certain process in the CFS scheduler
for example. It is also used for printk timestamps when you have selected to
include time information in printk for things like bootcharts.
Compared to clock sources, sched_clock() has to be very fast: it is called
much more often, especially by the scheduler. If you have to do trade-offs
between accuracy compared to the clock source, you may sacrifice accuracy
for speed in sched_clock(). It however requires some of the same basic
characteristics as the clock source, i.e. it should be monotonic.
The sched_clock() function may wrap only on unsigned long long boundaries,
i.e. after 64 bits. Since this is a nanosecond value this will mean it wraps
after circa 585 years. (For most practical systems this means "never".)
If an architecture does not provide its own implementation of this function,
it will fall back to using jiffies, making its maximum resolution 1/HZ of the
jiffy frequency for the architecture. This will affect scheduling accuracy
and will likely show up in system benchmarks.
The clock driving sched_clock() may stop or reset to zero during system
suspend/sleep. This does not matter to the function it serves of scheduling
events on the system. However it may result in interesting timestamps in
printk().
The sched_clock() function should be callable in any context, IRQ- and
NMI-safe and return a sane value in any context.
Some architectures may have a limited set of time sources and lack a nice
counter to derive a 64-bit nanosecond value, so for example on the ARM
architecture, special helper functions have been created to provide a
sched_clock() nanosecond base from a 16- or 32-bit counter. Sometimes the
same counter that is also used as clock source is used for this purpose.
On SMP systems, it is crucial for performance that sched_clock() can be called
independently on each CPU without any synchronization performance hits.
Some hardware (such as the x86 TSC) will cause the sched_clock() function to
drift between the CPUs on the system. The kernel can work around this by
enabling the CONFIG_HAVE_UNSTABLE_SCHED_CLOCK option. This is another aspect
that makes sched_clock() different from the ordinary clock source.
Delay timers (some architectures only)
--------------------------------------
On systems with variable CPU frequency, the various kernel delay() functions
will sometimes behave strangely. Basically these delays usually use a hard
loop to delay a certain number of jiffy fractions using a "lpj" (loops per
jiffy) value, calibrated on boot.
Let's hope that your system is running on maximum frequency when this value
is calibrated: as an effect when the frequency is geared down to half the
full frequency, any delay() will be twice as long. Usually this does not
hurt, as you're commonly requesting that amount of delay *or more*. But
basically the semantics are quite unpredictable on such systems.
Enter timer-based delays. Using these, a timer read may be used instead of
a hard-coded loop for providing the desired delay.
This is done by declaring a struct delay_timer and assigning the appropriate
function pointers and rate settings for this delay timer.
This is available on some architectures like OpenRISC or ARM.

View File

@ -4237,7 +4237,7 @@ L: linux-kernel@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
S: Maintained S: Maintained
F: Documentation/timers/ F: Documentation/timers/
F: kernel/hrtimer.c F: kernel/time/hrtimer.c
F: kernel/time/clockevents.c F: kernel/time/clockevents.c
F: kernel/time/tick*.* F: kernel/time/tick*.*
F: kernel/time/timer_*.c F: kernel/time/timer_*.c
@ -7053,10 +7053,10 @@ POSIX CLOCKS and TIMERS
M: Thomas Gleixner <tglx@linutronix.de> M: Thomas Gleixner <tglx@linutronix.de>
L: linux-kernel@vger.kernel.org L: linux-kernel@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
S: Supported S: Maintained
F: fs/timerfd.c F: fs/timerfd.c
F: include/linux/timer* F: include/linux/timer*
F: kernel/*timer* F: kernel/time/*timer*
POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS
M: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> M: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>

View File

@ -65,7 +65,6 @@ config ARM
select HAVE_UID16 select HAVE_UID16
select HAVE_VIRT_CPU_ACCOUNTING_GEN select HAVE_VIRT_CPU_ACCOUNTING_GEN
select IRQ_FORCED_THREADING select IRQ_FORCED_THREADING
select KTIME_SCALAR
select MODULES_USE_ELF_REL select MODULES_USE_ELF_REL
select NO_BOOTMEM select NO_BOOTMEM
select OLD_SIGACTION select OLD_SIGACTION
@ -648,6 +647,7 @@ config ARCH_PXA
select AUTO_ZRELADDR select AUTO_ZRELADDR
select CLKDEV_LOOKUP select CLKDEV_LOOKUP
select CLKSRC_MMIO select CLKSRC_MMIO
select CLKSRC_OF
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select GPIO_PXA select GPIO_PXA
select HAVE_IDE select HAVE_IDE

View File

@ -57,16 +57,6 @@ static int read_mpidr(void)
return id & MPIDR_HWID_BITMASK; return id & MPIDR_HWID_BITMASK;
} }
/*
* Get a global nanosecond time stamp for tracing.
*/
static s64 get_ns(void)
{
struct timespec ts;
getnstimeofday(&ts);
return timespec_to_ns(&ts);
}
/* /*
* bL switcher core code. * bL switcher core code.
*/ */
@ -224,7 +214,7 @@ static int bL_switch_to(unsigned int new_cluster_id)
*/ */
local_irq_disable(); local_irq_disable();
local_fiq_disable(); local_fiq_disable();
trace_cpu_migrate_begin(get_ns(), ob_mpidr); trace_cpu_migrate_begin(ktime_get_real_ns(), ob_mpidr);
/* redirect GIC's SGIs to our counterpart */ /* redirect GIC's SGIs to our counterpart */
gic_migrate_target(bL_gic_id[ib_cpu][ib_cluster]); gic_migrate_target(bL_gic_id[ib_cpu][ib_cluster]);
@ -267,7 +257,7 @@ static int bL_switch_to(unsigned int new_cluster_id)
tdev->evtdev->next_event, 1); tdev->evtdev->next_event, 1);
} }
trace_cpu_migrate_finish(get_ns(), ib_mpidr); trace_cpu_migrate_finish(ktime_get_real_ns(), ib_mpidr);
local_fiq_enable(); local_fiq_enable();
local_irq_enable(); local_irq_enable();
@ -558,7 +548,7 @@ int bL_switcher_get_logical_index(u32 mpidr)
static void bL_switcher_trace_trigger_cpu(void *__always_unused info) static void bL_switcher_trace_trigger_cpu(void *__always_unused info)
{ {
trace_cpu_migrate_current(get_ns(), read_mpidr()); trace_cpu_migrate_current(ktime_get_real_ns(), read_mpidr());
} }
int bL_switcher_trace_trigger(void) int bL_switcher_trace_trigger(void)

View File

@ -4,7 +4,7 @@
# Common support (must be linked before board specific support) # Common support (must be linked before board specific support)
obj-y += clock.o devices.o generic.o irq.o \ obj-y += clock.o devices.o generic.o irq.o \
time.o reset.o reset.o
obj-$(CONFIG_PM) += pm.o sleep.o standby.o obj-$(CONFIG_PM) += pm.o sleep.o standby.o
# Generic drivers that other drivers may depend upon # Generic drivers that other drivers may depend upon

View File

@ -25,11 +25,13 @@
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <mach/irqs.h>
#include <mach/reset.h> #include <mach/reset.h>
#include <mach/smemc.h> #include <mach/smemc.h>
#include <mach/pxa3xx-regs.h> #include <mach/pxa3xx-regs.h>
#include "generic.h" #include "generic.h"
#include <clocksource/pxa.h>
void clear_reset_status(unsigned int mask) void clear_reset_status(unsigned int mask)
{ {
@ -56,6 +58,15 @@ unsigned long get_clock_tick_rate(void)
} }
EXPORT_SYMBOL(get_clock_tick_rate); EXPORT_SYMBOL(get_clock_tick_rate);
/*
* For non device-tree builds, keep legacy timer init
*/
void pxa_timer_init(void)
{
pxa_timer_nodt_init(IRQ_OST0, io_p2v(0x40a00000),
get_clock_tick_rate());
}
/* /*
* Get the clock frequency as reflected by CCCR and the turbo flag. * Get the clock frequency as reflected by CCCR and the turbo flag.
* We assume these values have been applied via a fcs. * We assume these values have been applied via a fcs.

View File

@ -1,162 +0,0 @@
/*
* arch/arm/mach-pxa/time.c
*
* PXA clocksource, clockevents, and OST interrupt handlers.
* Copyright (c) 2007 by Bill Gatliff <bgat@billgatliff.com>.
*
* Derived from Nicolas Pitre's PXA timer handler Copyright (c) 2001
* by MontaVista Software, Inc. (Nico, your code rocks!)
*
* 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/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/clockchips.h>
#include <linux/sched_clock.h>
#include <asm/div64.h>
#include <asm/mach/irq.h>
#include <asm/mach/time.h>
#include <mach/regs-ost.h>
#include <mach/irqs.h>
/*
* This is PXA's sched_clock implementation. This has a resolution
* of at least 308 ns and a maximum value of 208 days.
*
* The return value is guaranteed to be monotonic in that range as
* long as there is always less than 582 seconds between successive
* calls to sched_clock() which should always be the case in practice.
*/
static u64 notrace pxa_read_sched_clock(void)
{
return readl_relaxed(OSCR);
}
#define MIN_OSCR_DELTA 16
static irqreturn_t
pxa_ost0_interrupt(int irq, void *dev_id)
{
struct clock_event_device *c = dev_id;
/* Disarm the compare/match, signal the event. */
writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER);
writel_relaxed(OSSR_M0, OSSR);
c->event_handler(c);
return IRQ_HANDLED;
}
static int
pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev)
{
unsigned long next, oscr;
writel_relaxed(readl_relaxed(OIER) | OIER_E0, OIER);
next = readl_relaxed(OSCR) + delta;
writel_relaxed(next, OSMR0);
oscr = readl_relaxed(OSCR);
return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0;
}
static void
pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev)
{
switch (mode) {
case CLOCK_EVT_MODE_ONESHOT:
writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER);
writel_relaxed(OSSR_M0, OSSR);
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
/* initializing, released, or preparing for suspend */
writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER);
writel_relaxed(OSSR_M0, OSSR);
break;
case CLOCK_EVT_MODE_RESUME:
case CLOCK_EVT_MODE_PERIODIC:
break;
}
}
#ifdef CONFIG_PM
static unsigned long osmr[4], oier, oscr;
static void pxa_timer_suspend(struct clock_event_device *cedev)
{
osmr[0] = readl_relaxed(OSMR0);
osmr[1] = readl_relaxed(OSMR1);
osmr[2] = readl_relaxed(OSMR2);
osmr[3] = readl_relaxed(OSMR3);
oier = readl_relaxed(OIER);
oscr = readl_relaxed(OSCR);
}
static void pxa_timer_resume(struct clock_event_device *cedev)
{
/*
* Ensure that we have at least MIN_OSCR_DELTA between match
* register 0 and the OSCR, to guarantee that we will receive
* the one-shot timer interrupt. We adjust OSMR0 in preference
* to OSCR to guarantee that OSCR is monotonically incrementing.
*/
if (osmr[0] - oscr < MIN_OSCR_DELTA)
osmr[0] += MIN_OSCR_DELTA;
writel_relaxed(osmr[0], OSMR0);
writel_relaxed(osmr[1], OSMR1);
writel_relaxed(osmr[2], OSMR2);
writel_relaxed(osmr[3], OSMR3);
writel_relaxed(oier, OIER);
writel_relaxed(oscr, OSCR);
}
#else
#define pxa_timer_suspend NULL
#define pxa_timer_resume NULL
#endif
static struct clock_event_device ckevt_pxa_osmr0 = {
.name = "osmr0",
.features = CLOCK_EVT_FEAT_ONESHOT,
.rating = 200,
.set_next_event = pxa_osmr0_set_next_event,
.set_mode = pxa_osmr0_set_mode,
.suspend = pxa_timer_suspend,
.resume = pxa_timer_resume,
};
static struct irqaction pxa_ost0_irq = {
.name = "ost0",
.flags = IRQF_TIMER | IRQF_IRQPOLL,
.handler = pxa_ost0_interrupt,
.dev_id = &ckevt_pxa_osmr0,
};
void __init pxa_timer_init(void)
{
unsigned long clock_tick_rate = get_clock_tick_rate();
writel_relaxed(0, OIER);
writel_relaxed(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR);
sched_clock_register(pxa_read_sched_clock, 32, clock_tick_rate);
ckevt_pxa_osmr0.cpumask = cpumask_of(0);
setup_irq(IRQ_OST0, &pxa_ost0_irq);
clocksource_mmio_init(OSCR, "oscr0", clock_tick_rate, 200, 32,
clocksource_mmio_readl_up);
clockevents_config_and_register(&ckevt_pxa_osmr0, clock_tick_rate,
MIN_OSCR_DELTA * 2, 0x7fffffff);
}

View File

@ -219,7 +219,7 @@ struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
void update_vsyscall(struct timekeeper *tk) void update_vsyscall(struct timekeeper *tk)
{ {
struct timespec xtime_coarse; struct timespec xtime_coarse;
u32 use_syscall = strcmp(tk->clock->name, "arch_sys_counter"); u32 use_syscall = strcmp(tk->tkr.clock->name, "arch_sys_counter");
++vdso_data->tb_seq_count; ++vdso_data->tb_seq_count;
smp_wmb(); smp_wmb();
@ -232,11 +232,11 @@ void update_vsyscall(struct timekeeper *tk)
vdso_data->wtm_clock_nsec = tk->wall_to_monotonic.tv_nsec; vdso_data->wtm_clock_nsec = tk->wall_to_monotonic.tv_nsec;
if (!use_syscall) { if (!use_syscall) {
vdso_data->cs_cycle_last = tk->clock->cycle_last; vdso_data->cs_cycle_last = tk->tkr.cycle_last;
vdso_data->xtime_clock_sec = tk->xtime_sec; vdso_data->xtime_clock_sec = tk->xtime_sec;
vdso_data->xtime_clock_nsec = tk->xtime_nsec; vdso_data->xtime_clock_nsec = tk->tkr.xtime_nsec;
vdso_data->cs_mult = tk->mult; vdso_data->cs_mult = tk->tkr.mult;
vdso_data->cs_shift = tk->shift; vdso_data->cs_shift = tk->tkr.shift;
} }
smp_wmb(); smp_wmb();

View File

@ -23,7 +23,6 @@ config HEXAGON
select GENERIC_IOMAP select GENERIC_IOMAP
select GENERIC_SMP_IDLE_THREAD select GENERIC_SMP_IDLE_THREAD
select STACKTRACE_SUPPORT select STACKTRACE_SUPPORT
select KTIME_SCALAR
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select GENERIC_CLOCKEVENTS_BROADCAST select GENERIC_CLOCKEVENTS_BROADCAST
select MODULES_USE_ELF_RELA select MODULES_USE_ELF_RELA

View File

@ -441,7 +441,7 @@ void update_vsyscall_tz(void)
} }
void update_vsyscall_old(struct timespec *wall, struct timespec *wtm, void update_vsyscall_old(struct timespec *wall, struct timespec *wtm,
struct clocksource *c, u32 mult) struct clocksource *c, u32 mult, cycle_t cycle_last)
{ {
write_seqcount_begin(&fsyscall_gtod_data.seq); write_seqcount_begin(&fsyscall_gtod_data.seq);
@ -450,7 +450,7 @@ void update_vsyscall_old(struct timespec *wall, struct timespec *wtm,
fsyscall_gtod_data.clk_mult = mult; fsyscall_gtod_data.clk_mult = mult;
fsyscall_gtod_data.clk_shift = c->shift; fsyscall_gtod_data.clk_shift = c->shift;
fsyscall_gtod_data.clk_fsys_mmio = c->archdata.fsys_mmio; fsyscall_gtod_data.clk_fsys_mmio = c->archdata.fsys_mmio;
fsyscall_gtod_data.clk_cycle_last = c->cycle_last; fsyscall_gtod_data.clk_cycle_last = cycle_last;
/* copy kernel time structures */ /* copy kernel time structures */
fsyscall_gtod_data.wall_time.tv_sec = wall->tv_sec; fsyscall_gtod_data.wall_time.tv_sec = wall->tv_sec;

View File

@ -741,7 +741,7 @@ static cycle_t timebase_read(struct clocksource *cs)
} }
void update_vsyscall_old(struct timespec *wall_time, struct timespec *wtm, void update_vsyscall_old(struct timespec *wall_time, struct timespec *wtm,
struct clocksource *clock, u32 mult) struct clocksource *clock, u32 mult, cycle_t cycle_last)
{ {
u64 new_tb_to_xs, new_stamp_xsec; u64 new_tb_to_xs, new_stamp_xsec;
u32 frac_sec; u32 frac_sec;
@ -774,7 +774,7 @@ void update_vsyscall_old(struct timespec *wall_time, struct timespec *wtm,
* We expect the caller to have done the first increment of * We expect the caller to have done the first increment of
* vdso_data->tb_update_count already. * vdso_data->tb_update_count already.
*/ */
vdso_data->tb_orig_stamp = clock->cycle_last; vdso_data->tb_orig_stamp = cycle_last;
vdso_data->stamp_xsec = new_stamp_xsec; vdso_data->stamp_xsec = new_stamp_xsec;
vdso_data->tb_to_xs = new_tb_to_xs; vdso_data->tb_to_xs = new_tb_to_xs;
vdso_data->wtom_clock_sec = wtm->tv_sec; vdso_data->wtom_clock_sec = wtm->tv_sec;

View File

@ -611,7 +611,6 @@ static int __init create_spu(void *data)
int ret; int ret;
static int number; static int number;
unsigned long flags; unsigned long flags;
struct timespec ts;
ret = -ENOMEM; ret = -ENOMEM;
spu = kzalloc(sizeof (*spu), GFP_KERNEL); spu = kzalloc(sizeof (*spu), GFP_KERNEL);
@ -652,8 +651,7 @@ static int __init create_spu(void *data)
mutex_unlock(&spu_full_list_mutex); mutex_unlock(&spu_full_list_mutex);
spu->stats.util_state = SPU_UTIL_IDLE_LOADED; spu->stats.util_state = SPU_UTIL_IDLE_LOADED;
ktime_get_ts(&ts); spu->stats.tstamp = ktime_get_ns();
spu->stats.tstamp = timespec_to_ns(&ts);
INIT_LIST_HEAD(&spu->aff_list); INIT_LIST_HEAD(&spu->aff_list);
@ -676,7 +674,6 @@ static const char *spu_state_names[] = {
static unsigned long long spu_acct_time(struct spu *spu, static unsigned long long spu_acct_time(struct spu *spu,
enum spu_utilization_state state) enum spu_utilization_state state)
{ {
struct timespec ts;
unsigned long long time = spu->stats.times[state]; unsigned long long time = spu->stats.times[state];
/* /*
@ -684,10 +681,8 @@ static unsigned long long spu_acct_time(struct spu *spu,
* statistics are not updated. Apply the time delta from the * statistics are not updated. Apply the time delta from the
* last recorded state of the spu. * last recorded state of the spu.
*/ */
if (spu->stats.util_state == state) { if (spu->stats.util_state == state)
ktime_get_ts(&ts); time += ktime_get_ns() - spu->stats.tstamp;
time += timespec_to_ns(&ts) - spu->stats.tstamp;
}
return time / NSEC_PER_MSEC; return time / NSEC_PER_MSEC;
} }

View File

@ -36,7 +36,6 @@ atomic_t nr_spu_contexts = ATOMIC_INIT(0);
struct spu_context *alloc_spu_context(struct spu_gang *gang) struct spu_context *alloc_spu_context(struct spu_gang *gang)
{ {
struct spu_context *ctx; struct spu_context *ctx;
struct timespec ts;
ctx = kzalloc(sizeof *ctx, GFP_KERNEL); ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
if (!ctx) if (!ctx)
@ -67,8 +66,7 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang)
__spu_update_sched_info(ctx); __spu_update_sched_info(ctx);
spu_set_timeslice(ctx); spu_set_timeslice(ctx);
ctx->stats.util_state = SPU_UTIL_IDLE_LOADED; ctx->stats.util_state = SPU_UTIL_IDLE_LOADED;
ktime_get_ts(&ts); ctx->stats.tstamp = ktime_get_ns();
ctx->stats.tstamp = timespec_to_ns(&ts);
atomic_inc(&nr_spu_contexts); atomic_inc(&nr_spu_contexts);
goto out; goto out;

View File

@ -2338,7 +2338,6 @@ static const char *ctx_state_names[] = {
static unsigned long long spufs_acct_time(struct spu_context *ctx, static unsigned long long spufs_acct_time(struct spu_context *ctx,
enum spu_utilization_state state) enum spu_utilization_state state)
{ {
struct timespec ts;
unsigned long long time = ctx->stats.times[state]; unsigned long long time = ctx->stats.times[state];
/* /*
@ -2351,8 +2350,7 @@ static unsigned long long spufs_acct_time(struct spu_context *ctx,
* of the spu context. * of the spu context.
*/ */
if (ctx->spu && ctx->stats.util_state == state) { if (ctx->spu && ctx->stats.util_state == state) {
ktime_get_ts(&ts); time += ktime_get_ns() - ctx->stats.tstamp;
time += timespec_to_ns(&ts) - ctx->stats.tstamp;
} }
return time / NSEC_PER_MSEC; return time / NSEC_PER_MSEC;

View File

@ -1039,13 +1039,11 @@ void spuctx_switch_state(struct spu_context *ctx,
{ {
unsigned long long curtime; unsigned long long curtime;
signed long long delta; signed long long delta;
struct timespec ts;
struct spu *spu; struct spu *spu;
enum spu_utilization_state old_state; enum spu_utilization_state old_state;
int node; int node;
ktime_get_ts(&ts); curtime = ktime_get_ns();
curtime = timespec_to_ns(&ts);
delta = curtime - ctx->stats.tstamp; delta = curtime - ctx->stats.tstamp;
WARN_ON(!mutex_is_locked(&ctx->state_mutex)); WARN_ON(!mutex_is_locked(&ctx->state_mutex));

View File

@ -136,7 +136,6 @@ config S390
select HAVE_SYSCALL_TRACEPOINTS select HAVE_SYSCALL_TRACEPOINTS
select HAVE_UID16 if 32BIT select HAVE_UID16 if 32BIT
select HAVE_VIRT_CPU_ACCOUNTING select HAVE_VIRT_CPU_ACCOUNTING
select KTIME_SCALAR if 32BIT
select MODULES_USE_ELF_RELA select MODULES_USE_ELF_RELA
select NO_BOOTMEM select NO_BOOTMEM
select OLD_SIGACTION select OLD_SIGACTION

View File

@ -214,26 +214,26 @@ void update_vsyscall(struct timekeeper *tk)
{ {
u64 nsecps; u64 nsecps;
if (tk->clock != &clocksource_tod) if (tk->tkr.clock != &clocksource_tod)
return; return;
/* Make userspace gettimeofday spin until we're done. */ /* Make userspace gettimeofday spin until we're done. */
++vdso_data->tb_update_count; ++vdso_data->tb_update_count;
smp_wmb(); smp_wmb();
vdso_data->xtime_tod_stamp = tk->clock->cycle_last; vdso_data->xtime_tod_stamp = tk->tkr.cycle_last;
vdso_data->xtime_clock_sec = tk->xtime_sec; vdso_data->xtime_clock_sec = tk->xtime_sec;
vdso_data->xtime_clock_nsec = tk->xtime_nsec; vdso_data->xtime_clock_nsec = tk->tkr.xtime_nsec;
vdso_data->wtom_clock_sec = vdso_data->wtom_clock_sec =
tk->xtime_sec + tk->wall_to_monotonic.tv_sec; tk->xtime_sec + tk->wall_to_monotonic.tv_sec;
vdso_data->wtom_clock_nsec = tk->xtime_nsec + vdso_data->wtom_clock_nsec = tk->tkr.xtime_nsec +
+ ((u64) tk->wall_to_monotonic.tv_nsec << tk->shift); + ((u64) tk->wall_to_monotonic.tv_nsec << tk->tkr.shift);
nsecps = (u64) NSEC_PER_SEC << tk->shift; nsecps = (u64) NSEC_PER_SEC << tk->tkr.shift;
while (vdso_data->wtom_clock_nsec >= nsecps) { while (vdso_data->wtom_clock_nsec >= nsecps) {
vdso_data->wtom_clock_nsec -= nsecps; vdso_data->wtom_clock_nsec -= nsecps;
vdso_data->wtom_clock_sec++; vdso_data->wtom_clock_sec++;
} }
vdso_data->tk_mult = tk->mult; vdso_data->tk_mult = tk->tkr.mult;
vdso_data->tk_shift = tk->shift; vdso_data->tk_shift = tk->tkr.shift;
smp_wmb(); smp_wmb();
++vdso_data->tb_update_count; ++vdso_data->tb_update_count;
} }

View File

@ -260,9 +260,8 @@ void update_vsyscall_tz(void)
void update_vsyscall(struct timekeeper *tk) void update_vsyscall(struct timekeeper *tk)
{ {
struct timespec wall_time = tk_xtime(tk);
struct timespec *wtm = &tk->wall_to_monotonic; struct timespec *wtm = &tk->wall_to_monotonic;
struct clocksource *clock = tk->clock; struct clocksource *clock = tk->tkr.clock;
if (clock != &cycle_counter_cs) if (clock != &cycle_counter_cs)
return; return;
@ -270,13 +269,13 @@ void update_vsyscall(struct timekeeper *tk)
/* Userspace gettimeofday will spin while this value is odd. */ /* Userspace gettimeofday will spin while this value is odd. */
++vdso_data->tb_update_count; ++vdso_data->tb_update_count;
smp_wmb(); smp_wmb();
vdso_data->xtime_tod_stamp = clock->cycle_last; vdso_data->xtime_tod_stamp = tk->tkr.cycle_last;
vdso_data->xtime_clock_sec = wall_time.tv_sec; vdso_data->xtime_clock_sec = tk->xtime_sec;
vdso_data->xtime_clock_nsec = wall_time.tv_nsec; vdso_data->xtime_clock_nsec = tk->tkr.xtime_nsec;
vdso_data->wtom_clock_sec = wtm->tv_sec; vdso_data->wtom_clock_sec = wtm->tv_sec;
vdso_data->wtom_clock_nsec = wtm->tv_nsec; vdso_data->wtom_clock_nsec = wtm->tv_nsec;
vdso_data->mult = clock->mult; vdso_data->mult = tk->tkr.mult;
vdso_data->shift = clock->shift; vdso_data->shift = tk->tkr.shift;
smp_wmb(); smp_wmb();
++vdso_data->tb_update_count; ++vdso_data->tb_update_count;
} }

View File

@ -83,10 +83,11 @@ int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
if (count & 1) if (count & 1)
continue; continue;
cycles = (get_cycles() - vdso_data->xtime_tod_stamp);
ns = (cycles * vdso_data->mult) >> vdso_data->shift;
sec = vdso_data->xtime_clock_sec; sec = vdso_data->xtime_clock_sec;
ns += vdso_data->xtime_clock_nsec; cycles = get_cycles() - vdso_data->xtime_tod_stamp;
ns = (cycles * vdso_data->mult) + vdso_data->xtime_clock_nsec;
ns >>= vdso_data->shift;
if (ns >= NSEC_PER_SEC) { if (ns >= NSEC_PER_SEC) {
ns -= NSEC_PER_SEC; ns -= NSEC_PER_SEC;
sec += 1; sec += 1;

View File

@ -108,9 +108,9 @@ config X86
select CLOCKSOURCE_WATCHDOG select CLOCKSOURCE_WATCHDOG
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select ARCH_CLOCKSOURCE_DATA select ARCH_CLOCKSOURCE_DATA
select CLOCKSOURCE_VALIDATE_LAST_CYCLE
select GENERIC_CLOCKEVENTS_BROADCAST if X86_64 || (X86_32 && X86_LOCAL_APIC) select GENERIC_CLOCKEVENTS_BROADCAST if X86_64 || (X86_32 && X86_LOCAL_APIC)
select GENERIC_TIME_VSYSCALL select GENERIC_TIME_VSYSCALL
select KTIME_SCALAR if X86_32
select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER select GENERIC_STRNLEN_USER
select HAVE_CONTEXT_TRACKING if X86_64 select HAVE_CONTEXT_TRACKING if X86_64

View File

@ -950,7 +950,7 @@ core_initcall(cpufreq_tsc);
static struct clocksource clocksource_tsc; static struct clocksource clocksource_tsc;
/* /*
* We compare the TSC to the cycle_last value in the clocksource * We used to compare the TSC to the cycle_last value in the clocksource
* structure to avoid a nasty time-warp. This can be observed in a * structure to avoid a nasty time-warp. This can be observed in a
* very small window right after one CPU updated cycle_last under * very small window right after one CPU updated cycle_last under
* xtime/vsyscall_gtod lock and the other CPU reads a TSC value which * xtime/vsyscall_gtod lock and the other CPU reads a TSC value which
@ -960,26 +960,23 @@ static struct clocksource clocksource_tsc;
* due to the unsigned delta calculation of the time keeping core * due to the unsigned delta calculation of the time keeping core
* code, which is necessary to support wrapping clocksources like pm * code, which is necessary to support wrapping clocksources like pm
* timer. * timer.
*
* This sanity check is now done in the core timekeeping code.
* checking the result of read_tsc() - cycle_last for being negative.
* That works because CLOCKSOURCE_MASK(64) does not mask out any bit.
*/ */
static cycle_t read_tsc(struct clocksource *cs) static cycle_t read_tsc(struct clocksource *cs)
{ {
cycle_t ret = (cycle_t)get_cycles(); return (cycle_t)get_cycles();
return ret >= clocksource_tsc.cycle_last ?
ret : clocksource_tsc.cycle_last;
}
static void resume_tsc(struct clocksource *cs)
{
if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC_S3))
clocksource_tsc.cycle_last = 0;
} }
/*
* .mask MUST be CLOCKSOURCE_MASK(64). See comment above read_tsc()
*/
static struct clocksource clocksource_tsc = { static struct clocksource clocksource_tsc = {
.name = "tsc", .name = "tsc",
.rating = 300, .rating = 300,
.read = read_tsc, .read = read_tsc,
.resume = resume_tsc,
.mask = CLOCKSOURCE_MASK(64), .mask = CLOCKSOURCE_MASK(64),
.flags = CLOCK_SOURCE_IS_CONTINUOUS | .flags = CLOCK_SOURCE_IS_CONTINUOUS |
CLOCK_SOURCE_MUST_VERIFY, CLOCK_SOURCE_MUST_VERIFY,

View File

@ -31,29 +31,30 @@ void update_vsyscall(struct timekeeper *tk)
gtod_write_begin(vdata); gtod_write_begin(vdata);
/* copy vsyscall data */ /* copy vsyscall data */
vdata->vclock_mode = tk->clock->archdata.vclock_mode; vdata->vclock_mode = tk->tkr.clock->archdata.vclock_mode;
vdata->cycle_last = tk->clock->cycle_last; vdata->cycle_last = tk->tkr.cycle_last;
vdata->mask = tk->clock->mask; vdata->mask = tk->tkr.mask;
vdata->mult = tk->mult; vdata->mult = tk->tkr.mult;
vdata->shift = tk->shift; vdata->shift = tk->tkr.shift;
vdata->wall_time_sec = tk->xtime_sec; vdata->wall_time_sec = tk->xtime_sec;
vdata->wall_time_snsec = tk->xtime_nsec; vdata->wall_time_snsec = tk->tkr.xtime_nsec;
vdata->monotonic_time_sec = tk->xtime_sec vdata->monotonic_time_sec = tk->xtime_sec
+ tk->wall_to_monotonic.tv_sec; + tk->wall_to_monotonic.tv_sec;
vdata->monotonic_time_snsec = tk->xtime_nsec vdata->monotonic_time_snsec = tk->tkr.xtime_nsec
+ ((u64)tk->wall_to_monotonic.tv_nsec + ((u64)tk->wall_to_monotonic.tv_nsec
<< tk->shift); << tk->tkr.shift);
while (vdata->monotonic_time_snsec >= while (vdata->monotonic_time_snsec >=
(((u64)NSEC_PER_SEC) << tk->shift)) { (((u64)NSEC_PER_SEC) << tk->tkr.shift)) {
vdata->monotonic_time_snsec -= vdata->monotonic_time_snsec -=
((u64)NSEC_PER_SEC) << tk->shift; ((u64)NSEC_PER_SEC) << tk->tkr.shift;
vdata->monotonic_time_sec++; vdata->monotonic_time_sec++;
} }
vdata->wall_time_coarse_sec = tk->xtime_sec; vdata->wall_time_coarse_sec = tk->xtime_sec;
vdata->wall_time_coarse_nsec = (long)(tk->xtime_nsec >> tk->shift); vdata->wall_time_coarse_nsec = (long)(tk->tkr.xtime_nsec >>
tk->tkr.shift);
vdata->monotonic_time_coarse_sec = vdata->monotonic_time_coarse_sec =
vdata->wall_time_coarse_sec + tk->wall_to_monotonic.tv_sec; vdata->wall_time_coarse_sec + tk->wall_to_monotonic.tv_sec;

View File

@ -1020,9 +1020,8 @@ struct pvclock_gtod_data {
u32 shift; u32 shift;
} clock; } clock;
/* open coded 'struct timespec' */ u64 boot_ns;
u64 monotonic_time_snsec; u64 nsec_base;
time_t monotonic_time_sec;
}; };
static struct pvclock_gtod_data pvclock_gtod_data; static struct pvclock_gtod_data pvclock_gtod_data;
@ -1030,27 +1029,21 @@ static struct pvclock_gtod_data pvclock_gtod_data;
static void update_pvclock_gtod(struct timekeeper *tk) static void update_pvclock_gtod(struct timekeeper *tk)
{ {
struct pvclock_gtod_data *vdata = &pvclock_gtod_data; struct pvclock_gtod_data *vdata = &pvclock_gtod_data;
u64 boot_ns;
boot_ns = ktime_to_ns(ktime_add(tk->tkr.base_mono, tk->offs_boot));
write_seqcount_begin(&vdata->seq); write_seqcount_begin(&vdata->seq);
/* copy pvclock gtod data */ /* copy pvclock gtod data */
vdata->clock.vclock_mode = tk->clock->archdata.vclock_mode; vdata->clock.vclock_mode = tk->tkr.clock->archdata.vclock_mode;
vdata->clock.cycle_last = tk->clock->cycle_last; vdata->clock.cycle_last = tk->tkr.cycle_last;
vdata->clock.mask = tk->clock->mask; vdata->clock.mask = tk->tkr.mask;
vdata->clock.mult = tk->mult; vdata->clock.mult = tk->tkr.mult;
vdata->clock.shift = tk->shift; vdata->clock.shift = tk->tkr.shift;
vdata->monotonic_time_sec = tk->xtime_sec vdata->boot_ns = boot_ns;
+ tk->wall_to_monotonic.tv_sec; vdata->nsec_base = tk->tkr.xtime_nsec;
vdata->monotonic_time_snsec = tk->xtime_nsec
+ (tk->wall_to_monotonic.tv_nsec
<< tk->shift);
while (vdata->monotonic_time_snsec >=
(((u64)NSEC_PER_SEC) << tk->shift)) {
vdata->monotonic_time_snsec -=
((u64)NSEC_PER_SEC) << tk->shift;
vdata->monotonic_time_sec++;
}
write_seqcount_end(&vdata->seq); write_seqcount_end(&vdata->seq);
} }
@ -1145,11 +1138,7 @@ static void kvm_get_time_scale(uint32_t scaled_khz, uint32_t base_khz,
static inline u64 get_kernel_ns(void) static inline u64 get_kernel_ns(void)
{ {
struct timespec ts; return ktime_get_boot_ns();
ktime_get_ts(&ts);
monotonic_to_bootbased(&ts);
return timespec_to_ns(&ts);
} }
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
@ -1414,23 +1403,22 @@ static inline u64 vgettsc(cycle_t *cycle_now)
return v * gtod->clock.mult; return v * gtod->clock.mult;
} }
static int do_monotonic(struct timespec *ts, cycle_t *cycle_now) static int do_monotonic_boot(s64 *t, cycle_t *cycle_now)
{ {
unsigned long seq;
u64 ns;
int mode;
struct pvclock_gtod_data *gtod = &pvclock_gtod_data; struct pvclock_gtod_data *gtod = &pvclock_gtod_data;
unsigned long seq;
int mode;
u64 ns;
ts->tv_nsec = 0;
do { do {
seq = read_seqcount_begin(&gtod->seq); seq = read_seqcount_begin(&gtod->seq);
mode = gtod->clock.vclock_mode; mode = gtod->clock.vclock_mode;
ts->tv_sec = gtod->monotonic_time_sec; ns = gtod->nsec_base;
ns = gtod->monotonic_time_snsec;
ns += vgettsc(cycle_now); ns += vgettsc(cycle_now);
ns >>= gtod->clock.shift; ns >>= gtod->clock.shift;
ns += gtod->boot_ns;
} while (unlikely(read_seqcount_retry(&gtod->seq, seq))); } while (unlikely(read_seqcount_retry(&gtod->seq, seq)));
timespec_add_ns(ts, ns); *t = ns;
return mode; return mode;
} }
@ -1438,19 +1426,11 @@ static int do_monotonic(struct timespec *ts, cycle_t *cycle_now)
/* returns true if host is using tsc clocksource */ /* returns true if host is using tsc clocksource */
static bool kvm_get_time_and_clockread(s64 *kernel_ns, cycle_t *cycle_now) static bool kvm_get_time_and_clockread(s64 *kernel_ns, cycle_t *cycle_now)
{ {
struct timespec ts;
/* checked again under seqlock below */ /* checked again under seqlock below */
if (pvclock_gtod_data.clock.vclock_mode != VCLOCK_TSC) if (pvclock_gtod_data.clock.vclock_mode != VCLOCK_TSC)
return false; return false;
if (do_monotonic(&ts, cycle_now) != VCLOCK_TSC) return do_monotonic_boot(kernel_ns, cycle_now) == VCLOCK_TSC;
return false;
monotonic_to_bootbased(&ts);
*kernel_ns = timespec_to_ns(&ts);
return true;
} }
#endif #endif

View File

@ -49,7 +49,7 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/sysrq.h> #include <linux/sysrq.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/time.h> #include <linux/hrtimer.h>
#define VERSION_STR "0.9.1" #define VERSION_STR "0.9.1"
@ -117,24 +117,7 @@ __setup("hcheck_reboot", hangcheck_parse_reboot);
__setup("hcheck_dump_tasks", hangcheck_parse_dump_tasks); __setup("hcheck_dump_tasks", hangcheck_parse_dump_tasks);
#endif /* not MODULE */ #endif /* not MODULE */
#if defined(CONFIG_S390) #define TIMER_FREQ 1000000000ULL
# define HAVE_MONOTONIC
# define TIMER_FREQ 1000000000ULL
#else
# define TIMER_FREQ 1000000000ULL
#endif
#ifdef HAVE_MONOTONIC
extern unsigned long long monotonic_clock(void);
#else
static inline unsigned long long monotonic_clock(void)
{
struct timespec ts;
getrawmonotonic(&ts);
return timespec_to_ns(&ts);
}
#endif /* HAVE_MONOTONIC */
/* Last time scheduled */ /* Last time scheduled */
static unsigned long long hangcheck_tsc, hangcheck_tsc_margin; static unsigned long long hangcheck_tsc, hangcheck_tsc_margin;
@ -143,12 +126,11 @@ static void hangcheck_fire(unsigned long);
static DEFINE_TIMER(hangcheck_ticktock, hangcheck_fire, 0, 0); static DEFINE_TIMER(hangcheck_ticktock, hangcheck_fire, 0, 0);
static void hangcheck_fire(unsigned long data) static void hangcheck_fire(unsigned long data)
{ {
unsigned long long cur_tsc, tsc_diff; unsigned long long cur_tsc, tsc_diff;
cur_tsc = monotonic_clock(); cur_tsc = ktime_get_ns();
if (cur_tsc > hangcheck_tsc) if (cur_tsc > hangcheck_tsc)
tsc_diff = cur_tsc - hangcheck_tsc; tsc_diff = cur_tsc - hangcheck_tsc;
@ -177,7 +159,7 @@ static void hangcheck_fire(unsigned long data)
tsc_diff, tsc_diff - hangcheck_tick*TIMER_FREQ); tsc_diff, tsc_diff - hangcheck_tick*TIMER_FREQ);
#endif #endif
mod_timer(&hangcheck_ticktock, jiffies + (hangcheck_tick*HZ)); mod_timer(&hangcheck_ticktock, jiffies + (hangcheck_tick*HZ));
hangcheck_tsc = monotonic_clock(); hangcheck_tsc = ktime_get_ns();
} }
@ -185,16 +167,11 @@ static int __init hangcheck_init(void)
{ {
printk("Hangcheck: starting hangcheck timer %s (tick is %d seconds, margin is %d seconds).\n", printk("Hangcheck: starting hangcheck timer %s (tick is %d seconds, margin is %d seconds).\n",
VERSION_STR, hangcheck_tick, hangcheck_margin); VERSION_STR, hangcheck_tick, hangcheck_margin);
#if defined (HAVE_MONOTONIC)
printk("Hangcheck: Using monotonic_clock().\n");
#else
printk("Hangcheck: Using getrawmonotonic().\n");
#endif /* HAVE_MONOTONIC */
hangcheck_tsc_margin = hangcheck_tsc_margin =
(unsigned long long)(hangcheck_margin + hangcheck_tick); (unsigned long long)(hangcheck_margin + hangcheck_tick);
hangcheck_tsc_margin *= (unsigned long long)TIMER_FREQ; hangcheck_tsc_margin *= (unsigned long long)TIMER_FREQ;
hangcheck_tsc = monotonic_clock(); hangcheck_tsc = ktime_get_ns();
mod_timer(&hangcheck_ticktock, jiffies + (hangcheck_tick*HZ)); mod_timer(&hangcheck_ticktock, jiffies + (hangcheck_tick*HZ));
return 0; return 0;

View File

@ -1,3 +1,5 @@
menu "Clock Source drivers"
config CLKSRC_OF config CLKSRC_OF
bool bool
@ -125,6 +127,7 @@ config CLKSRC_METAG_GENERIC
config CLKSRC_EXYNOS_MCT config CLKSRC_EXYNOS_MCT
def_bool y if ARCH_EXYNOS def_bool y if ARCH_EXYNOS
depends on !ARM64
help help
Support for Multi Core Timer controller on Exynos SoCs. Support for Multi Core Timer controller on Exynos SoCs.
@ -149,6 +152,11 @@ config VF_PIT_TIMER
config SYS_SUPPORTS_SH_CMT config SYS_SUPPORTS_SH_CMT
bool bool
config MTK_TIMER
select CLKSRC_OF
select CLKSRC_MMIO
bool
config SYS_SUPPORTS_SH_MTU2 config SYS_SUPPORTS_SH_MTU2
bool bool
@ -173,7 +181,7 @@ config SH_TIMER_MTU2
default SYS_SUPPORTS_SH_MTU2 default SYS_SUPPORTS_SH_MTU2
help help
This enables build of a clockevent driver for the Multi-Function This enables build of a clockevent driver for the Multi-Function
Timer Pulse Unit 2 (TMU2) hardware available on SoCs from Renesas. Timer Pulse Unit 2 (MTU2) hardware available on SoCs from Renesas.
This hardware comes with 16 bit-timer registers. This hardware comes with 16 bit-timer registers.
config SH_TIMER_TMU config SH_TIMER_TMU
@ -187,7 +195,7 @@ config SH_TIMER_TMU
config EM_TIMER_STI config EM_TIMER_STI
bool "Renesas STI timer driver" if COMPILE_TEST bool "Renesas STI timer driver" if COMPILE_TEST
depends on GENERIC_CLOCKEVENTS depends on GENERIC_CLOCKEVENTS && HAS_IOMEM
default SYS_SUPPORTS_EM_STI default SYS_SUPPORTS_EM_STI
help help
This enables build of a clocksource and clockevent driver for This enables build of a clocksource and clockevent driver for
@ -207,3 +215,5 @@ config CLKSRC_VERSATILE
counter available in the "System Registers" block of counter available in the "System Registers" block of
ARM Versatile, RealView and Versatile Express reference ARM Versatile, RealView and Versatile Express reference
platforms. platforms.
endmenu

View File

@ -16,9 +16,11 @@ obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o
obj-$(CONFIG_ORION_TIMER) += time-orion.o obj-$(CONFIG_ORION_TIMER) += time-orion.o
obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
obj-$(CONFIG_ARCH_CLPS711X) += clps711x-timer.o
obj-$(CONFIG_ARCH_MARCO) += timer-marco.o obj-$(CONFIG_ARCH_MARCO) += timer-marco.o
obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o
obj-$(CONFIG_ARCH_MXS) += mxs_timer.o obj-$(CONFIG_ARCH_MXS) += mxs_timer.o
obj-$(CONFIG_ARCH_PXA) += pxa_timer.o
obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o
obj-$(CONFIG_ARCH_U300) += timer-u300.o obj-$(CONFIG_ARCH_U300) += timer-u300.o
obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o
@ -34,6 +36,7 @@ obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o
obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o
obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o
obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o
obj-$(CONFIG_MTK_TIMER) += mtk_timer.o
obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o

View File

@ -0,0 +1,131 @@
/*
* Cirrus Logic CLPS711X clocksource driver
*
* Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/clk.h>
#include <linux/clockchips.h>
#include <linux/clocksource.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/sched_clock.h>
#include <linux/slab.h>
enum {
CLPS711X_CLKSRC_CLOCKSOURCE,
CLPS711X_CLKSRC_CLOCKEVENT,
};
static void __iomem *tcd;
static u64 notrace clps711x_sched_clock_read(void)
{
return ~readw(tcd);
}
static int __init _clps711x_clksrc_init(struct clk *clock, void __iomem *base)
{
unsigned long rate;
if (!base)
return -ENOMEM;
if (IS_ERR(clock))
return PTR_ERR(clock);
rate = clk_get_rate(clock);
tcd = base;
clocksource_mmio_init(tcd, "clps711x-clocksource", rate, 300, 16,
clocksource_mmio_readw_down);
sched_clock_register(clps711x_sched_clock_read, 16, rate);
return 0;
}
static irqreturn_t clps711x_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *evt = dev_id;
evt->event_handler(evt);
return IRQ_HANDLED;
}
static void clps711x_clockevent_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
}
static int __init _clps711x_clkevt_init(struct clk *clock, void __iomem *base,
unsigned int irq)
{
struct clock_event_device *clkevt;
unsigned long rate;
if (!irq)
return -EINVAL;
if (!base)
return -ENOMEM;
if (IS_ERR(clock))
return PTR_ERR(clock);
clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL);
if (!clkevt)
return -ENOMEM;
rate = clk_get_rate(clock);
/* Set Timer prescaler */
writew(DIV_ROUND_CLOSEST(rate, HZ), base);
clkevt->name = "clps711x-clockevent";
clkevt->rating = 300;
clkevt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_C3STOP;
clkevt->set_mode = clps711x_clockevent_set_mode;
clkevt->cpumask = cpumask_of(0);
clockevents_config_and_register(clkevt, HZ, 0, 0);
return request_irq(irq, clps711x_timer_interrupt, IRQF_TIMER,
"clps711x-timer", clkevt);
}
void __init clps711x_clksrc_init(void __iomem *tc1_base, void __iomem *tc2_base,
unsigned int irq)
{
struct clk *tc1 = clk_get_sys("clps711x-timer.0", NULL);
struct clk *tc2 = clk_get_sys("clps711x-timer.1", NULL);
BUG_ON(_clps711x_clksrc_init(tc1, tc1_base));
BUG_ON(_clps711x_clkevt_init(tc2, tc2_base, irq));
}
#ifdef CONFIG_CLKSRC_OF
static void __init clps711x_timer_init(struct device_node *np)
{
unsigned int irq = irq_of_parse_and_map(np, 0);
struct clk *clock = of_clk_get(np, 0);
void __iomem *base = of_iomap(np, 0);
switch (of_alias_get_id(np, "timer")) {
case CLPS711X_CLKSRC_CLOCKSOURCE:
BUG_ON(_clps711x_clksrc_init(clock, base));
break;
case CLPS711X_CLKSRC_CLOCKEVENT:
BUG_ON(_clps711x_clkevt_init(clock, base, irq));
break;
default:
break;
}
}
CLOCKSOURCE_OF_DECLARE(clps711x, "cirrus,clps711x-timer", clps711x_timer_init);
#endif

View File

@ -94,7 +94,7 @@ static void exynos4_mct_write(unsigned int value, unsigned long offset)
u32 mask; u32 mask;
u32 i; u32 i;
__raw_writel(value, reg_base + offset); writel_relaxed(value, reg_base + offset);
if (likely(offset >= EXYNOS4_MCT_L_BASE(0))) { if (likely(offset >= EXYNOS4_MCT_L_BASE(0))) {
stat_addr = (offset & ~EXYNOS4_MCT_L_MASK) + MCT_L_WSTAT_OFFSET; stat_addr = (offset & ~EXYNOS4_MCT_L_MASK) + MCT_L_WSTAT_OFFSET;
@ -144,8 +144,8 @@ static void exynos4_mct_write(unsigned int value, unsigned long offset)
/* Wait maximum 1 ms until written values are applied */ /* Wait maximum 1 ms until written values are applied */
for (i = 0; i < loops_per_jiffy / 1000 * HZ; i++) for (i = 0; i < loops_per_jiffy / 1000 * HZ; i++)
if (__raw_readl(reg_base + stat_addr) & mask) { if (readl_relaxed(reg_base + stat_addr) & mask) {
__raw_writel(mask, reg_base + stat_addr); writel_relaxed(mask, reg_base + stat_addr);
return; return;
} }
@ -157,28 +157,51 @@ static void exynos4_mct_frc_start(void)
{ {
u32 reg; u32 reg;
reg = __raw_readl(reg_base + EXYNOS4_MCT_G_TCON); reg = readl_relaxed(reg_base + EXYNOS4_MCT_G_TCON);
reg |= MCT_G_TCON_START; reg |= MCT_G_TCON_START;
exynos4_mct_write(reg, EXYNOS4_MCT_G_TCON); exynos4_mct_write(reg, EXYNOS4_MCT_G_TCON);
} }
static cycle_t notrace _exynos4_frc_read(void) /**
* exynos4_read_count_64 - Read all 64-bits of the global counter
*
* This will read all 64-bits of the global counter taking care to make sure
* that the upper and lower half match. Note that reading the MCT can be quite
* slow (hundreds of nanoseconds) so you should use the 32-bit (lower half
* only) version when possible.
*
* Returns the number of cycles in the global counter.
*/
static u64 exynos4_read_count_64(void)
{ {
unsigned int lo, hi; unsigned int lo, hi;
u32 hi2 = __raw_readl(reg_base + EXYNOS4_MCT_G_CNT_U); u32 hi2 = readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_U);
do { do {
hi = hi2; hi = hi2;
lo = __raw_readl(reg_base + EXYNOS4_MCT_G_CNT_L); lo = readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_L);
hi2 = __raw_readl(reg_base + EXYNOS4_MCT_G_CNT_U); hi2 = readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_U);
} while (hi != hi2); } while (hi != hi2);
return ((cycle_t)hi << 32) | lo; return ((cycle_t)hi << 32) | lo;
} }
/**
* exynos4_read_count_32 - Read the lower 32-bits of the global counter
*
* This will read just the lower 32-bits of the global counter. This is marked
* as notrace so it can be used by the scheduler clock.
*
* Returns the number of cycles in the global counter (lower 32 bits).
*/
static u32 notrace exynos4_read_count_32(void)
{
return readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_L);
}
static cycle_t exynos4_frc_read(struct clocksource *cs) static cycle_t exynos4_frc_read(struct clocksource *cs)
{ {
return _exynos4_frc_read(); return exynos4_read_count_32();
} }
static void exynos4_frc_resume(struct clocksource *cs) static void exynos4_frc_resume(struct clocksource *cs)
@ -190,21 +213,23 @@ struct clocksource mct_frc = {
.name = "mct-frc", .name = "mct-frc",
.rating = 400, .rating = 400,
.read = exynos4_frc_read, .read = exynos4_frc_read,
.mask = CLOCKSOURCE_MASK(64), .mask = CLOCKSOURCE_MASK(32),
.flags = CLOCK_SOURCE_IS_CONTINUOUS, .flags = CLOCK_SOURCE_IS_CONTINUOUS,
.resume = exynos4_frc_resume, .resume = exynos4_frc_resume,
}; };
static u64 notrace exynos4_read_sched_clock(void) static u64 notrace exynos4_read_sched_clock(void)
{ {
return _exynos4_frc_read(); return exynos4_read_count_32();
} }
static struct delay_timer exynos4_delay_timer; static struct delay_timer exynos4_delay_timer;
static cycles_t exynos4_read_current_timer(void) static cycles_t exynos4_read_current_timer(void)
{ {
return _exynos4_frc_read(); BUILD_BUG_ON_MSG(sizeof(cycles_t) != sizeof(u32),
"cycles_t needs to move to 32-bit for ARM64 usage");
return exynos4_read_count_32();
} }
static void __init exynos4_clocksource_init(void) static void __init exynos4_clocksource_init(void)
@ -218,14 +243,14 @@ static void __init exynos4_clocksource_init(void)
if (clocksource_register_hz(&mct_frc, clk_rate)) if (clocksource_register_hz(&mct_frc, clk_rate))
panic("%s: can't register clocksource\n", mct_frc.name); panic("%s: can't register clocksource\n", mct_frc.name);
sched_clock_register(exynos4_read_sched_clock, 64, clk_rate); sched_clock_register(exynos4_read_sched_clock, 32, clk_rate);
} }
static void exynos4_mct_comp0_stop(void) static void exynos4_mct_comp0_stop(void)
{ {
unsigned int tcon; unsigned int tcon;
tcon = __raw_readl(reg_base + EXYNOS4_MCT_G_TCON); tcon = readl_relaxed(reg_base + EXYNOS4_MCT_G_TCON);
tcon &= ~(MCT_G_TCON_COMP0_ENABLE | MCT_G_TCON_COMP0_AUTO_INC); tcon &= ~(MCT_G_TCON_COMP0_ENABLE | MCT_G_TCON_COMP0_AUTO_INC);
exynos4_mct_write(tcon, EXYNOS4_MCT_G_TCON); exynos4_mct_write(tcon, EXYNOS4_MCT_G_TCON);
@ -238,14 +263,14 @@ static void exynos4_mct_comp0_start(enum clock_event_mode mode,
unsigned int tcon; unsigned int tcon;
cycle_t comp_cycle; cycle_t comp_cycle;
tcon = __raw_readl(reg_base + EXYNOS4_MCT_G_TCON); tcon = readl_relaxed(reg_base + EXYNOS4_MCT_G_TCON);
if (mode == CLOCK_EVT_MODE_PERIODIC) { if (mode == CLOCK_EVT_MODE_PERIODIC) {
tcon |= MCT_G_TCON_COMP0_AUTO_INC; tcon |= MCT_G_TCON_COMP0_AUTO_INC;
exynos4_mct_write(cycles, EXYNOS4_MCT_G_COMP0_ADD_INCR); exynos4_mct_write(cycles, EXYNOS4_MCT_G_COMP0_ADD_INCR);
} }
comp_cycle = exynos4_frc_read(&mct_frc) + cycles; comp_cycle = exynos4_read_count_64() + cycles;
exynos4_mct_write((u32)comp_cycle, EXYNOS4_MCT_G_COMP0_L); exynos4_mct_write((u32)comp_cycle, EXYNOS4_MCT_G_COMP0_L);
exynos4_mct_write((u32)(comp_cycle >> 32), EXYNOS4_MCT_G_COMP0_U); exynos4_mct_write((u32)(comp_cycle >> 32), EXYNOS4_MCT_G_COMP0_U);
@ -327,7 +352,7 @@ static void exynos4_mct_tick_stop(struct mct_clock_event_device *mevt)
unsigned long mask = MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START; unsigned long mask = MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START;
unsigned long offset = mevt->base + MCT_L_TCON_OFFSET; unsigned long offset = mevt->base + MCT_L_TCON_OFFSET;
tmp = __raw_readl(reg_base + offset); tmp = readl_relaxed(reg_base + offset);
if (tmp & mask) { if (tmp & mask) {
tmp &= ~mask; tmp &= ~mask;
exynos4_mct_write(tmp, offset); exynos4_mct_write(tmp, offset);
@ -349,7 +374,7 @@ static void exynos4_mct_tick_start(unsigned long cycles,
/* enable MCT tick interrupt */ /* enable MCT tick interrupt */
exynos4_mct_write(0x1, mevt->base + MCT_L_INT_ENB_OFFSET); exynos4_mct_write(0x1, mevt->base + MCT_L_INT_ENB_OFFSET);
tmp = __raw_readl(reg_base + mevt->base + MCT_L_TCON_OFFSET); tmp = readl_relaxed(reg_base + mevt->base + MCT_L_TCON_OFFSET);
tmp |= MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START | tmp |= MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START |
MCT_L_TCON_INTERVAL_MODE; MCT_L_TCON_INTERVAL_MODE;
exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET); exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET);
@ -401,7 +426,7 @@ static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
exynos4_mct_tick_stop(mevt); exynos4_mct_tick_stop(mevt);
/* Clear the MCT tick interrupt */ /* Clear the MCT tick interrupt */
if (__raw_readl(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) { if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) {
exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET); exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
return 1; return 1;
} else { } else {

View File

@ -0,0 +1,261 @@
/*
* Mediatek SoCs General-Purpose Timer handling.
*
* Copyright (C) 2014 Matthias Brugger
*
* Matthias Brugger <matthias.bgg@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/clk.h>
#include <linux/clockchips.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqreturn.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/slab.h>
#define GPT_IRQ_EN_REG 0x00
#define GPT_IRQ_ENABLE(val) BIT((val) - 1)
#define GPT_IRQ_ACK_REG 0x08
#define GPT_IRQ_ACK(val) BIT((val) - 1)
#define TIMER_CTRL_REG(val) (0x10 * (val))
#define TIMER_CTRL_OP(val) (((val) & 0x3) << 4)
#define TIMER_CTRL_OP_ONESHOT (0)
#define TIMER_CTRL_OP_REPEAT (1)
#define TIMER_CTRL_OP_FREERUN (3)
#define TIMER_CTRL_CLEAR (2)
#define TIMER_CTRL_ENABLE (1)
#define TIMER_CTRL_DISABLE (0)
#define TIMER_CLK_REG(val) (0x04 + (0x10 * (val)))
#define TIMER_CLK_SRC(val) (((val) & 0x1) << 4)
#define TIMER_CLK_SRC_SYS13M (0)
#define TIMER_CLK_SRC_RTC32K (1)
#define TIMER_CLK_DIV1 (0x0)
#define TIMER_CLK_DIV2 (0x1)
#define TIMER_CNT_REG(val) (0x08 + (0x10 * (val)))
#define TIMER_CMP_REG(val) (0x0C + (0x10 * (val)))
#define GPT_CLK_EVT 1
#define GPT_CLK_SRC 2
struct mtk_clock_event_device {
void __iomem *gpt_base;
u32 ticks_per_jiffy;
struct clock_event_device dev;
};
static inline struct mtk_clock_event_device *to_mtk_clk(
struct clock_event_device *c)
{
return container_of(c, struct mtk_clock_event_device, dev);
}
static void mtk_clkevt_time_stop(struct mtk_clock_event_device *evt, u8 timer)
{
u32 val;
val = readl(evt->gpt_base + TIMER_CTRL_REG(timer));
writel(val & ~TIMER_CTRL_ENABLE, evt->gpt_base +
TIMER_CTRL_REG(timer));
}
static void mtk_clkevt_time_setup(struct mtk_clock_event_device *evt,
unsigned long delay, u8 timer)
{
writel(delay, evt->gpt_base + TIMER_CMP_REG(timer));
}
static void mtk_clkevt_time_start(struct mtk_clock_event_device *evt,
bool periodic, u8 timer)
{
u32 val;
/* Acknowledge interrupt */
writel(GPT_IRQ_ACK(timer), evt->gpt_base + GPT_IRQ_ACK_REG);
val = readl(evt->gpt_base + TIMER_CTRL_REG(timer));
/* Clear 2 bit timer operation mode field */
val &= ~TIMER_CTRL_OP(0x3);
if (periodic)
val |= TIMER_CTRL_OP(TIMER_CTRL_OP_REPEAT);
else
val |= TIMER_CTRL_OP(TIMER_CTRL_OP_ONESHOT);
writel(val | TIMER_CTRL_ENABLE | TIMER_CTRL_CLEAR,
evt->gpt_base + TIMER_CTRL_REG(timer));
}
static void mtk_clkevt_mode(enum clock_event_mode mode,
struct clock_event_device *clk)
{
struct mtk_clock_event_device *evt = to_mtk_clk(clk);
mtk_clkevt_time_stop(evt, GPT_CLK_EVT);
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
mtk_clkevt_time_setup(evt, evt->ticks_per_jiffy, GPT_CLK_EVT);
mtk_clkevt_time_start(evt, true, GPT_CLK_EVT);
break;
case CLOCK_EVT_MODE_ONESHOT:
/* Timer is enabled in set_next_event */
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
default:
/* No more interrupts will occur as source is disabled */
break;
}
}
static int mtk_clkevt_next_event(unsigned long event,
struct clock_event_device *clk)
{
struct mtk_clock_event_device *evt = to_mtk_clk(clk);
mtk_clkevt_time_stop(evt, GPT_CLK_EVT);
mtk_clkevt_time_setup(evt, event, GPT_CLK_EVT);
mtk_clkevt_time_start(evt, false, GPT_CLK_EVT);
return 0;
}
static irqreturn_t mtk_timer_interrupt(int irq, void *dev_id)
{
struct mtk_clock_event_device *evt = dev_id;
/* Acknowledge timer0 irq */
writel(GPT_IRQ_ACK(GPT_CLK_EVT), evt->gpt_base + GPT_IRQ_ACK_REG);
evt->dev.event_handler(&evt->dev);
return IRQ_HANDLED;
}
static void mtk_timer_global_reset(struct mtk_clock_event_device *evt)
{
/* Disable all interrupts */
writel(0x0, evt->gpt_base + GPT_IRQ_EN_REG);
/* Acknowledge all interrupts */
writel(0x3f, evt->gpt_base + GPT_IRQ_ACK_REG);
}
static void
mtk_timer_setup(struct mtk_clock_event_device *evt, u8 timer, u8 option)
{
writel(TIMER_CTRL_CLEAR | TIMER_CTRL_DISABLE,
evt->gpt_base + TIMER_CTRL_REG(timer));
writel(TIMER_CLK_SRC(TIMER_CLK_SRC_SYS13M) | TIMER_CLK_DIV1,
evt->gpt_base + TIMER_CLK_REG(timer));
writel(0x0, evt->gpt_base + TIMER_CMP_REG(timer));
writel(TIMER_CTRL_OP(option) | TIMER_CTRL_ENABLE,
evt->gpt_base + TIMER_CTRL_REG(timer));
}
static void mtk_timer_enable_irq(struct mtk_clock_event_device *evt, u8 timer)
{
u32 val;
val = readl(evt->gpt_base + GPT_IRQ_EN_REG);
writel(val | GPT_IRQ_ENABLE(timer),
evt->gpt_base + GPT_IRQ_EN_REG);
}
static void __init mtk_timer_init(struct device_node *node)
{
struct mtk_clock_event_device *evt;
struct resource res;
unsigned long rate = 0;
struct clk *clk;
evt = kzalloc(sizeof(*evt), GFP_KERNEL);
if (!evt) {
pr_warn("Can't allocate mtk clock event driver struct");
return;
}
evt->dev.name = "mtk_tick";
evt->dev.rating = 300;
evt->dev.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
evt->dev.set_mode = mtk_clkevt_mode;
evt->dev.set_next_event = mtk_clkevt_next_event;
evt->dev.cpumask = cpu_possible_mask;
evt->gpt_base = of_io_request_and_map(node, 0, "mtk-timer");
if (IS_ERR(evt->gpt_base)) {
pr_warn("Can't get resource\n");
return;
}
evt->dev.irq = irq_of_parse_and_map(node, 0);
if (evt->dev.irq <= 0) {
pr_warn("Can't parse IRQ");
goto err_mem;
}
clk = of_clk_get(node, 0);
if (IS_ERR(clk)) {
pr_warn("Can't get timer clock");
goto err_irq;
}
if (clk_prepare_enable(clk)) {
pr_warn("Can't prepare clock");
goto err_clk_put;
}
rate = clk_get_rate(clk);
if (request_irq(evt->dev.irq, mtk_timer_interrupt,
IRQF_TIMER | IRQF_IRQPOLL, "mtk_timer", evt)) {
pr_warn("failed to setup irq %d\n", evt->dev.irq);
goto err_clk_disable;
}
evt->ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
mtk_timer_global_reset(evt);
/* Configure clock source */
mtk_timer_setup(evt, GPT_CLK_SRC, TIMER_CTRL_OP_FREERUN);
clocksource_mmio_init(evt->gpt_base + TIMER_CNT_REG(GPT_CLK_SRC),
node->name, rate, 300, 32, clocksource_mmio_readl_up);
/* Configure clock event */
mtk_timer_setup(evt, GPT_CLK_EVT, TIMER_CTRL_OP_REPEAT);
mtk_timer_enable_irq(evt, GPT_CLK_EVT);
clockevents_config_and_register(&evt->dev, rate, 0x3,
0xffffffff);
return;
err_clk_disable:
clk_disable_unprepare(clk);
err_clk_put:
clk_put(clk);
err_irq:
irq_dispose_mapping(evt->dev.irq);
err_mem:
iounmap(evt->gpt_base);
of_address_to_resource(node, 0, &res);
release_mem_region(res.start, resource_size(&res));
}
CLOCKSOURCE_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init);

View File

@ -0,0 +1,227 @@
/*
* arch/arm/mach-pxa/time.c
*
* PXA clocksource, clockevents, and OST interrupt handlers.
* Copyright (c) 2007 by Bill Gatliff <bgat@billgatliff.com>.
*
* Derived from Nicolas Pitre's PXA timer handler Copyright (c) 2001
* by MontaVista Software, Inc. (Nico, your code rocks!)
*
* 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/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/clockchips.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/sched_clock.h>
#include <asm/div64.h>
#define OSMR0 0x00 /* OS Timer 0 Match Register */
#define OSMR1 0x04 /* OS Timer 1 Match Register */
#define OSMR2 0x08 /* OS Timer 2 Match Register */
#define OSMR3 0x0C /* OS Timer 3 Match Register */
#define OSCR 0x10 /* OS Timer Counter Register */
#define OSSR 0x14 /* OS Timer Status Register */
#define OWER 0x18 /* OS Timer Watchdog Enable Register */
#define OIER 0x1C /* OS Timer Interrupt Enable Register */
#define OSSR_M3 (1 << 3) /* Match status channel 3 */
#define OSSR_M2 (1 << 2) /* Match status channel 2 */
#define OSSR_M1 (1 << 1) /* Match status channel 1 */
#define OSSR_M0 (1 << 0) /* Match status channel 0 */
#define OIER_E0 (1 << 0) /* Interrupt enable channel 0 */
/*
* This is PXA's sched_clock implementation. This has a resolution
* of at least 308 ns and a maximum value of 208 days.
*
* The return value is guaranteed to be monotonic in that range as
* long as there is always less than 582 seconds between successive
* calls to sched_clock() which should always be the case in practice.
*/
#define timer_readl(reg) readl_relaxed(timer_base + (reg))
#define timer_writel(val, reg) writel_relaxed((val), timer_base + (reg))
static void __iomem *timer_base;
static u64 notrace pxa_read_sched_clock(void)
{
return timer_readl(OSCR);
}
#define MIN_OSCR_DELTA 16
static irqreturn_t
pxa_ost0_interrupt(int irq, void *dev_id)
{
struct clock_event_device *c = dev_id;
/* Disarm the compare/match, signal the event. */
timer_writel(timer_readl(OIER) & ~OIER_E0, OIER);
timer_writel(OSSR_M0, OSSR);
c->event_handler(c);
return IRQ_HANDLED;
}
static int
pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev)
{
unsigned long next, oscr;
timer_writel(timer_readl(OIER) | OIER_E0, OIER);
next = timer_readl(OSCR) + delta;
timer_writel(next, OSMR0);
oscr = timer_readl(OSCR);
return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0;
}
static void
pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev)
{
switch (mode) {
case CLOCK_EVT_MODE_ONESHOT:
timer_writel(timer_readl(OIER) & ~OIER_E0, OIER);
timer_writel(OSSR_M0, OSSR);
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
/* initializing, released, or preparing for suspend */
timer_writel(timer_readl(OIER) & ~OIER_E0, OIER);
timer_writel(OSSR_M0, OSSR);
break;
case CLOCK_EVT_MODE_RESUME:
case CLOCK_EVT_MODE_PERIODIC:
break;
}
}
#ifdef CONFIG_PM
static unsigned long osmr[4], oier, oscr;
static void pxa_timer_suspend(struct clock_event_device *cedev)
{
osmr[0] = timer_readl(OSMR0);
osmr[1] = timer_readl(OSMR1);
osmr[2] = timer_readl(OSMR2);
osmr[3] = timer_readl(OSMR3);
oier = timer_readl(OIER);
oscr = timer_readl(OSCR);
}
static void pxa_timer_resume(struct clock_event_device *cedev)
{
/*
* Ensure that we have at least MIN_OSCR_DELTA between match
* register 0 and the OSCR, to guarantee that we will receive
* the one-shot timer interrupt. We adjust OSMR0 in preference
* to OSCR to guarantee that OSCR is monotonically incrementing.
*/
if (osmr[0] - oscr < MIN_OSCR_DELTA)
osmr[0] += MIN_OSCR_DELTA;
timer_writel(osmr[0], OSMR0);
timer_writel(osmr[1], OSMR1);
timer_writel(osmr[2], OSMR2);
timer_writel(osmr[3], OSMR3);
timer_writel(oier, OIER);
timer_writel(oscr, OSCR);
}
#else
#define pxa_timer_suspend NULL
#define pxa_timer_resume NULL
#endif
static struct clock_event_device ckevt_pxa_osmr0 = {
.name = "osmr0",
.features = CLOCK_EVT_FEAT_ONESHOT,
.rating = 200,
.set_next_event = pxa_osmr0_set_next_event,
.set_mode = pxa_osmr0_set_mode,
.suspend = pxa_timer_suspend,
.resume = pxa_timer_resume,
};
static struct irqaction pxa_ost0_irq = {
.name = "ost0",
.flags = IRQF_TIMER | IRQF_IRQPOLL,
.handler = pxa_ost0_interrupt,
.dev_id = &ckevt_pxa_osmr0,
};
static void pxa_timer_common_init(int irq, unsigned long clock_tick_rate)
{
timer_writel(0, OIER);
timer_writel(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR);
sched_clock_register(pxa_read_sched_clock, 32, clock_tick_rate);
ckevt_pxa_osmr0.cpumask = cpumask_of(0);
setup_irq(irq, &pxa_ost0_irq);
clocksource_mmio_init(timer_base + OSCR, "oscr0", clock_tick_rate, 200,
32, clocksource_mmio_readl_up);
clockevents_config_and_register(&ckevt_pxa_osmr0, clock_tick_rate,
MIN_OSCR_DELTA * 2, 0x7fffffff);
}
static void __init pxa_timer_dt_init(struct device_node *np)
{
struct clk *clk;
int irq;
/* timer registers are shared with watchdog timer */
timer_base = of_iomap(np, 0);
if (!timer_base)
panic("%s: unable to map resource\n", np->name);
clk = of_clk_get(np, 0);
if (IS_ERR(clk)) {
pr_crit("%s: unable to get clk\n", np->name);
return;
}
clk_prepare_enable(clk);
/* we are only interested in OS-timer0 irq */
irq = irq_of_parse_and_map(np, 0);
if (irq <= 0) {
pr_crit("%s: unable to parse OS-timer0 irq\n", np->name);
return;
}
pxa_timer_common_init(irq, clk_get_rate(clk));
}
CLOCKSOURCE_OF_DECLARE(pxa_timer, "marvell,pxa-timer", pxa_timer_dt_init);
/*
* Legacy timer init for non device-tree boards.
*/
void __init pxa_timer_nodt_init(int irq, void __iomem *base,
unsigned long clock_tick_rate)
{
struct clk *clk;
timer_base = base;
clk = clk_get(NULL, "OSTIMER0");
if (clk && !IS_ERR(clk))
clk_prepare_enable(clk);
else
pr_crit("%s: unable to get clk\n", __func__);
pxa_timer_common_init(irq, clock_tick_rate);
}

View File

@ -24,6 +24,7 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_domain.h> #include <linux/pm_domain.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
@ -114,14 +115,15 @@ struct sh_cmt_device {
struct platform_device *pdev; struct platform_device *pdev;
const struct sh_cmt_info *info; const struct sh_cmt_info *info;
bool legacy;
void __iomem *mapbase_ch;
void __iomem *mapbase; void __iomem *mapbase;
struct clk *clk; struct clk *clk;
raw_spinlock_t lock; /* Protect the shared start/stop register */
struct sh_cmt_channel *channels; struct sh_cmt_channel *channels;
unsigned int num_channels; unsigned int num_channels;
unsigned int hw_channels;
bool has_clockevent; bool has_clockevent;
bool has_clocksource; bool has_clocksource;
@ -301,14 +303,12 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch,
return v2; return v2;
} }
static DEFINE_RAW_SPINLOCK(sh_cmt_lock);
static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start) static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start)
{ {
unsigned long flags, value; unsigned long flags, value;
/* start stop register shared by multiple timer channels */ /* start stop register shared by multiple timer channels */
raw_spin_lock_irqsave(&sh_cmt_lock, flags); raw_spin_lock_irqsave(&ch->cmt->lock, flags);
value = sh_cmt_read_cmstr(ch); value = sh_cmt_read_cmstr(ch);
if (start) if (start)
@ -317,7 +317,7 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start)
value &= ~(1 << ch->timer_bit); value &= ~(1 << ch->timer_bit);
sh_cmt_write_cmstr(ch, value); sh_cmt_write_cmstr(ch, value);
raw_spin_unlock_irqrestore(&sh_cmt_lock, flags); raw_spin_unlock_irqrestore(&ch->cmt->lock, flags);
} }
static int sh_cmt_enable(struct sh_cmt_channel *ch, unsigned long *rate) static int sh_cmt_enable(struct sh_cmt_channel *ch, unsigned long *rate)
@ -792,7 +792,7 @@ static int sh_cmt_register_clockevent(struct sh_cmt_channel *ch,
int irq; int irq;
int ret; int ret;
irq = platform_get_irq(ch->cmt->pdev, ch->cmt->legacy ? 0 : ch->index); irq = platform_get_irq(ch->cmt->pdev, ch->index);
if (irq < 0) { if (irq < 0) {
dev_err(&ch->cmt->pdev->dev, "ch%u: failed to get irq\n", dev_err(&ch->cmt->pdev->dev, "ch%u: failed to get irq\n",
ch->index); ch->index);
@ -863,33 +863,26 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index,
* Compute the address of the channel control register block. For the * Compute the address of the channel control register block. For the
* timers with a per-channel start/stop register, compute its address * timers with a per-channel start/stop register, compute its address
* as well. * as well.
*
* For legacy configuration the address has been mapped explicitly.
*/ */
if (cmt->legacy) { switch (cmt->info->model) {
ch->ioctrl = cmt->mapbase_ch; case SH_CMT_16BIT:
} else { ch->ioctrl = cmt->mapbase + 2 + ch->hwidx * 6;
switch (cmt->info->model) { break;
case SH_CMT_16BIT: case SH_CMT_32BIT:
ch->ioctrl = cmt->mapbase + 2 + ch->hwidx * 6; case SH_CMT_48BIT:
break; ch->ioctrl = cmt->mapbase + 0x10 + ch->hwidx * 0x10;
case SH_CMT_32BIT: break;
case SH_CMT_48BIT: case SH_CMT_32BIT_FAST:
ch->ioctrl = cmt->mapbase + 0x10 + ch->hwidx * 0x10; /*
break; * The 32-bit "fast" timer has a single channel at hwidx 5 but
case SH_CMT_32BIT_FAST: * is located at offset 0x40 instead of 0x60 for some reason.
/* */
* The 32-bit "fast" timer has a single channel at hwidx ch->ioctrl = cmt->mapbase + 0x40;
* 5 but is located at offset 0x40 instead of 0x60 for break;
* some reason. case SH_CMT_48BIT_GEN2:
*/ ch->iostart = cmt->mapbase + ch->hwidx * 0x100;
ch->ioctrl = cmt->mapbase + 0x40; ch->ioctrl = ch->iostart + 0x10;
break; break;
case SH_CMT_48BIT_GEN2:
ch->iostart = cmt->mapbase + ch->hwidx * 0x100;
ch->ioctrl = ch->iostart + 0x10;
break;
}
} }
if (cmt->info->width == (sizeof(ch->max_match_value) * 8)) if (cmt->info->width == (sizeof(ch->max_match_value) * 8))
@ -900,12 +893,7 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index,
ch->match_value = ch->max_match_value; ch->match_value = ch->max_match_value;
raw_spin_lock_init(&ch->lock); raw_spin_lock_init(&ch->lock);
if (cmt->legacy) { ch->timer_bit = cmt->info->model == SH_CMT_48BIT_GEN2 ? 0 : ch->hwidx;
ch->timer_bit = ch->hwidx;
} else {
ch->timer_bit = cmt->info->model == SH_CMT_48BIT_GEN2
? 0 : ch->hwidx;
}
ret = sh_cmt_register(ch, dev_name(&cmt->pdev->dev), ret = sh_cmt_register(ch, dev_name(&cmt->pdev->dev),
clockevent, clocksource); clockevent, clocksource);
@ -938,75 +926,65 @@ static int sh_cmt_map_memory(struct sh_cmt_device *cmt)
return 0; return 0;
} }
static int sh_cmt_map_memory_legacy(struct sh_cmt_device *cmt) static const struct platform_device_id sh_cmt_id_table[] = {
{ "sh-cmt-16", (kernel_ulong_t)&sh_cmt_info[SH_CMT_16BIT] },
{ "sh-cmt-32", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT] },
{ "sh-cmt-32-fast", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT_FAST] },
{ "sh-cmt-48", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT] },
{ "sh-cmt-48-gen2", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT_GEN2] },
{ }
};
MODULE_DEVICE_TABLE(platform, sh_cmt_id_table);
static const struct of_device_id sh_cmt_of_table[] __maybe_unused = {
{ .compatible = "renesas,cmt-32", .data = &sh_cmt_info[SH_CMT_32BIT] },
{ .compatible = "renesas,cmt-32-fast", .data = &sh_cmt_info[SH_CMT_32BIT_FAST] },
{ .compatible = "renesas,cmt-48", .data = &sh_cmt_info[SH_CMT_48BIT] },
{ .compatible = "renesas,cmt-48-gen2", .data = &sh_cmt_info[SH_CMT_48BIT_GEN2] },
{ }
};
MODULE_DEVICE_TABLE(of, sh_cmt_of_table);
static int sh_cmt_parse_dt(struct sh_cmt_device *cmt)
{ {
struct sh_timer_config *cfg = cmt->pdev->dev.platform_data; struct device_node *np = cmt->pdev->dev.of_node;
struct resource *res, *res2;
/* map memory, let mapbase_ch point to our channel */ return of_property_read_u32(np, "renesas,channels-mask",
res = platform_get_resource(cmt->pdev, IORESOURCE_MEM, 0); &cmt->hw_channels);
if (!res) {
dev_err(&cmt->pdev->dev, "failed to get I/O memory\n");
return -ENXIO;
}
cmt->mapbase_ch = ioremap_nocache(res->start, resource_size(res));
if (cmt->mapbase_ch == NULL) {
dev_err(&cmt->pdev->dev, "failed to remap I/O memory\n");
return -ENXIO;
}
/* optional resource for the shared timer start/stop register */
res2 = platform_get_resource(cmt->pdev, IORESOURCE_MEM, 1);
/* map second resource for CMSTR */
cmt->mapbase = ioremap_nocache(res2 ? res2->start :
res->start - cfg->channel_offset,
res2 ? resource_size(res2) : 2);
if (cmt->mapbase == NULL) {
dev_err(&cmt->pdev->dev, "failed to remap I/O second memory\n");
iounmap(cmt->mapbase_ch);
return -ENXIO;
}
/* identify the model based on the resources */
if (resource_size(res) == 6)
cmt->info = &sh_cmt_info[SH_CMT_16BIT];
else if (res2 && (resource_size(res2) == 4))
cmt->info = &sh_cmt_info[SH_CMT_48BIT_GEN2];
else
cmt->info = &sh_cmt_info[SH_CMT_32BIT];
return 0;
}
static void sh_cmt_unmap_memory(struct sh_cmt_device *cmt)
{
iounmap(cmt->mapbase);
if (cmt->mapbase_ch)
iounmap(cmt->mapbase_ch);
} }
static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
{ {
struct sh_timer_config *cfg = pdev->dev.platform_data; unsigned int mask;
const struct platform_device_id *id = pdev->id_entry; unsigned int i;
unsigned int hw_channels;
int ret; int ret;
memset(cmt, 0, sizeof(*cmt)); memset(cmt, 0, sizeof(*cmt));
cmt->pdev = pdev; cmt->pdev = pdev;
raw_spin_lock_init(&cmt->lock);
if (!cfg) { if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
const struct of_device_id *id;
id = of_match_node(sh_cmt_of_table, pdev->dev.of_node);
cmt->info = id->data;
ret = sh_cmt_parse_dt(cmt);
if (ret < 0)
return ret;
} else if (pdev->dev.platform_data) {
struct sh_timer_config *cfg = pdev->dev.platform_data;
const struct platform_device_id *id = pdev->id_entry;
cmt->info = (const struct sh_cmt_info *)id->driver_data;
cmt->hw_channels = cfg->channels_mask;
} else {
dev_err(&cmt->pdev->dev, "missing platform data\n"); dev_err(&cmt->pdev->dev, "missing platform data\n");
return -ENXIO; return -ENXIO;
} }
cmt->info = (const struct sh_cmt_info *)id->driver_data;
cmt->legacy = cmt->info ? false : true;
/* Get hold of clock. */ /* Get hold of clock. */
cmt->clk = clk_get(&cmt->pdev->dev, cmt->legacy ? "cmt_fck" : "fck"); cmt->clk = clk_get(&cmt->pdev->dev, "fck");
if (IS_ERR(cmt->clk)) { if (IS_ERR(cmt->clk)) {
dev_err(&cmt->pdev->dev, "cannot get clock\n"); dev_err(&cmt->pdev->dev, "cannot get clock\n");
return PTR_ERR(cmt->clk); return PTR_ERR(cmt->clk);
@ -1016,28 +994,13 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
if (ret < 0) if (ret < 0)
goto err_clk_put; goto err_clk_put;
/* /* Map the memory resource(s). */
* Map the memory resource(s). We need to support both the legacy ret = sh_cmt_map_memory(cmt);
* platform device configuration (with one device per channel) and the
* new version (with multiple channels per device).
*/
if (cmt->legacy)
ret = sh_cmt_map_memory_legacy(cmt);
else
ret = sh_cmt_map_memory(cmt);
if (ret < 0) if (ret < 0)
goto err_clk_unprepare; goto err_clk_unprepare;
/* Allocate and setup the channels. */ /* Allocate and setup the channels. */
if (cmt->legacy) { cmt->num_channels = hweight8(cmt->hw_channels);
cmt->num_channels = 1;
hw_channels = 0;
} else {
cmt->num_channels = hweight8(cfg->channels_mask);
hw_channels = cfg->channels_mask;
}
cmt->channels = kzalloc(cmt->num_channels * sizeof(*cmt->channels), cmt->channels = kzalloc(cmt->num_channels * sizeof(*cmt->channels),
GFP_KERNEL); GFP_KERNEL);
if (cmt->channels == NULL) { if (cmt->channels == NULL) {
@ -1045,35 +1008,21 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
goto err_unmap; goto err_unmap;
} }
if (cmt->legacy) { /*
ret = sh_cmt_setup_channel(&cmt->channels[0], * Use the first channel as a clock event device and the second channel
cfg->timer_bit, cfg->timer_bit, * as a clock source. If only one channel is available use it for both.
cfg->clockevent_rating != 0, */
cfg->clocksource_rating != 0, cmt); for (i = 0, mask = cmt->hw_channels; i < cmt->num_channels; ++i) {
unsigned int hwidx = ffs(mask) - 1;
bool clocksource = i == 1 || cmt->num_channels == 1;
bool clockevent = i == 0;
ret = sh_cmt_setup_channel(&cmt->channels[i], i, hwidx,
clockevent, clocksource, cmt);
if (ret < 0) if (ret < 0)
goto err_unmap; goto err_unmap;
} else {
unsigned int mask = hw_channels;
unsigned int i;
/* mask &= ~(1 << hwidx);
* Use the first channel as a clock event device and the second
* channel as a clock source. If only one channel is available
* use it for both.
*/
for (i = 0; i < cmt->num_channels; ++i) {
unsigned int hwidx = ffs(mask) - 1;
bool clocksource = i == 1 || cmt->num_channels == 1;
bool clockevent = i == 0;
ret = sh_cmt_setup_channel(&cmt->channels[i], i, hwidx,
clockevent, clocksource,
cmt);
if (ret < 0)
goto err_unmap;
mask &= ~(1 << hwidx);
}
} }
platform_set_drvdata(pdev, cmt); platform_set_drvdata(pdev, cmt);
@ -1082,7 +1031,7 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
err_unmap: err_unmap:
kfree(cmt->channels); kfree(cmt->channels);
sh_cmt_unmap_memory(cmt); iounmap(cmt->mapbase);
err_clk_unprepare: err_clk_unprepare:
clk_unprepare(cmt->clk); clk_unprepare(cmt->clk);
err_clk_put: err_clk_put:
@ -1132,22 +1081,12 @@ static int sh_cmt_remove(struct platform_device *pdev)
return -EBUSY; /* cannot unregister clockevent and clocksource */ return -EBUSY; /* cannot unregister clockevent and clocksource */
} }
static const struct platform_device_id sh_cmt_id_table[] = {
{ "sh_cmt", 0 },
{ "sh-cmt-16", (kernel_ulong_t)&sh_cmt_info[SH_CMT_16BIT] },
{ "sh-cmt-32", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT] },
{ "sh-cmt-32-fast", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT_FAST] },
{ "sh-cmt-48", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT] },
{ "sh-cmt-48-gen2", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT_GEN2] },
{ }
};
MODULE_DEVICE_TABLE(platform, sh_cmt_id_table);
static struct platform_driver sh_cmt_device_driver = { static struct platform_driver sh_cmt_device_driver = {
.probe = sh_cmt_probe, .probe = sh_cmt_probe,
.remove = sh_cmt_remove, .remove = sh_cmt_remove,
.driver = { .driver = {
.name = "sh_cmt", .name = "sh_cmt",
.of_match_table = of_match_ptr(sh_cmt_of_table),
}, },
.id_table = sh_cmt_id_table, .id_table = sh_cmt_id_table,
}; };

View File

@ -23,6 +23,7 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_domain.h> #include <linux/pm_domain.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
@ -37,7 +38,6 @@ struct sh_mtu2_channel {
unsigned int index; unsigned int index;
void __iomem *base; void __iomem *base;
int irq;
struct clock_event_device ced; struct clock_event_device ced;
}; };
@ -48,15 +48,14 @@ struct sh_mtu2_device {
void __iomem *mapbase; void __iomem *mapbase;
struct clk *clk; struct clk *clk;
raw_spinlock_t lock; /* Protect the shared registers */
struct sh_mtu2_channel *channels; struct sh_mtu2_channel *channels;
unsigned int num_channels; unsigned int num_channels;
bool legacy;
bool has_clockevent; bool has_clockevent;
}; };
static DEFINE_RAW_SPINLOCK(sh_mtu2_lock);
#define TSTR -1 /* shared register */ #define TSTR -1 /* shared register */
#define TCR 0 /* channel register */ #define TCR 0 /* channel register */
#define TMDR 1 /* channel register */ #define TMDR 1 /* channel register */
@ -162,12 +161,8 @@ static inline unsigned long sh_mtu2_read(struct sh_mtu2_channel *ch, int reg_nr)
{ {
unsigned long offs; unsigned long offs;
if (reg_nr == TSTR) { if (reg_nr == TSTR)
if (ch->mtu->legacy) return ioread8(ch->mtu->mapbase + 0x280);
return ioread8(ch->mtu->mapbase);
else
return ioread8(ch->mtu->mapbase + 0x280);
}
offs = mtu2_reg_offs[reg_nr]; offs = mtu2_reg_offs[reg_nr];
@ -182,12 +177,8 @@ static inline void sh_mtu2_write(struct sh_mtu2_channel *ch, int reg_nr,
{ {
unsigned long offs; unsigned long offs;
if (reg_nr == TSTR) { if (reg_nr == TSTR)
if (ch->mtu->legacy) return iowrite8(value, ch->mtu->mapbase + 0x280);
return iowrite8(value, ch->mtu->mapbase);
else
return iowrite8(value, ch->mtu->mapbase + 0x280);
}
offs = mtu2_reg_offs[reg_nr]; offs = mtu2_reg_offs[reg_nr];
@ -202,7 +193,7 @@ static void sh_mtu2_start_stop_ch(struct sh_mtu2_channel *ch, int start)
unsigned long flags, value; unsigned long flags, value;
/* start stop register shared by multiple timer channels */ /* start stop register shared by multiple timer channels */
raw_spin_lock_irqsave(&sh_mtu2_lock, flags); raw_spin_lock_irqsave(&ch->mtu->lock, flags);
value = sh_mtu2_read(ch, TSTR); value = sh_mtu2_read(ch, TSTR);
if (start) if (start)
@ -211,7 +202,7 @@ static void sh_mtu2_start_stop_ch(struct sh_mtu2_channel *ch, int start)
value &= ~(1 << ch->index); value &= ~(1 << ch->index);
sh_mtu2_write(ch, TSTR, value); sh_mtu2_write(ch, TSTR, value);
raw_spin_unlock_irqrestore(&sh_mtu2_lock, flags); raw_spin_unlock_irqrestore(&ch->mtu->lock, flags);
} }
static int sh_mtu2_enable(struct sh_mtu2_channel *ch) static int sh_mtu2_enable(struct sh_mtu2_channel *ch)
@ -331,7 +322,6 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_channel *ch,
const char *name) const char *name)
{ {
struct clock_event_device *ced = &ch->ced; struct clock_event_device *ced = &ch->ced;
int ret;
ced->name = name; ced->name = name;
ced->features = CLOCK_EVT_FEAT_PERIODIC; ced->features = CLOCK_EVT_FEAT_PERIODIC;
@ -344,24 +334,12 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_channel *ch,
dev_info(&ch->mtu->pdev->dev, "ch%u: used for clock events\n", dev_info(&ch->mtu->pdev->dev, "ch%u: used for clock events\n",
ch->index); ch->index);
clockevents_register_device(ced); clockevents_register_device(ced);
ret = request_irq(ch->irq, sh_mtu2_interrupt,
IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING,
dev_name(&ch->mtu->pdev->dev), ch);
if (ret) {
dev_err(&ch->mtu->pdev->dev, "ch%u: failed to request irq %d\n",
ch->index, ch->irq);
return;
}
} }
static int sh_mtu2_register(struct sh_mtu2_channel *ch, const char *name, static int sh_mtu2_register(struct sh_mtu2_channel *ch, const char *name)
bool clockevent)
{ {
if (clockevent) { ch->mtu->has_clockevent = true;
ch->mtu->has_clockevent = true; sh_mtu2_register_clockevent(ch, name);
sh_mtu2_register_clockevent(ch, name);
}
return 0; return 0;
} }
@ -372,40 +350,32 @@ static int sh_mtu2_setup_channel(struct sh_mtu2_channel *ch, unsigned int index,
static const unsigned int channel_offsets[] = { static const unsigned int channel_offsets[] = {
0x300, 0x380, 0x000, 0x300, 0x380, 0x000,
}; };
bool clockevent; char name[6];
int irq;
int ret;
ch->mtu = mtu; ch->mtu = mtu;
if (mtu->legacy) { sprintf(name, "tgi%ua", index);
struct sh_timer_config *cfg = mtu->pdev->dev.platform_data; irq = platform_get_irq_byname(mtu->pdev, name);
if (irq < 0) {
clockevent = cfg->clockevent_rating != 0;
ch->irq = platform_get_irq(mtu->pdev, 0);
ch->base = mtu->mapbase - cfg->channel_offset;
ch->index = cfg->timer_bit;
} else {
char name[6];
clockevent = true;
sprintf(name, "tgi%ua", index);
ch->irq = platform_get_irq_byname(mtu->pdev, name);
ch->base = mtu->mapbase + channel_offsets[index];
ch->index = index;
}
if (ch->irq < 0) {
/* Skip channels with no declared interrupt. */ /* Skip channels with no declared interrupt. */
if (!mtu->legacy) return 0;
return 0;
dev_err(&mtu->pdev->dev, "ch%u: failed to get irq\n",
ch->index);
return ch->irq;
} }
return sh_mtu2_register(ch, dev_name(&mtu->pdev->dev), clockevent); ret = request_irq(irq, sh_mtu2_interrupt,
IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING,
dev_name(&ch->mtu->pdev->dev), ch);
if (ret) {
dev_err(&ch->mtu->pdev->dev, "ch%u: failed to request irq %d\n",
index, irq);
return ret;
}
ch->base = mtu->mapbase + channel_offsets[index];
ch->index = index;
return sh_mtu2_register(ch, dev_name(&mtu->pdev->dev));
} }
static int sh_mtu2_map_memory(struct sh_mtu2_device *mtu) static int sh_mtu2_map_memory(struct sh_mtu2_device *mtu)
@ -422,46 +392,21 @@ static int sh_mtu2_map_memory(struct sh_mtu2_device *mtu)
if (mtu->mapbase == NULL) if (mtu->mapbase == NULL)
return -ENXIO; return -ENXIO;
/*
* In legacy platform device configuration (with one device per channel)
* the resource points to the channel base address.
*/
if (mtu->legacy) {
struct sh_timer_config *cfg = mtu->pdev->dev.platform_data;
mtu->mapbase += cfg->channel_offset;
}
return 0; return 0;
} }
static void sh_mtu2_unmap_memory(struct sh_mtu2_device *mtu)
{
if (mtu->legacy) {
struct sh_timer_config *cfg = mtu->pdev->dev.platform_data;
mtu->mapbase -= cfg->channel_offset;
}
iounmap(mtu->mapbase);
}
static int sh_mtu2_setup(struct sh_mtu2_device *mtu, static int sh_mtu2_setup(struct sh_mtu2_device *mtu,
struct platform_device *pdev) struct platform_device *pdev)
{ {
struct sh_timer_config *cfg = pdev->dev.platform_data;
const struct platform_device_id *id = pdev->id_entry;
unsigned int i; unsigned int i;
int ret; int ret;
mtu->pdev = pdev; mtu->pdev = pdev;
mtu->legacy = id->driver_data;
if (mtu->legacy && !cfg) { raw_spin_lock_init(&mtu->lock);
dev_err(&mtu->pdev->dev, "missing platform data\n");
return -ENXIO;
}
/* Get hold of clock. */ /* Get hold of clock. */
mtu->clk = clk_get(&mtu->pdev->dev, mtu->legacy ? "mtu2_fck" : "fck"); mtu->clk = clk_get(&mtu->pdev->dev, "fck");
if (IS_ERR(mtu->clk)) { if (IS_ERR(mtu->clk)) {
dev_err(&mtu->pdev->dev, "cannot get clock\n"); dev_err(&mtu->pdev->dev, "cannot get clock\n");
return PTR_ERR(mtu->clk); return PTR_ERR(mtu->clk);
@ -479,10 +424,7 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu,
} }
/* Allocate and setup the channels. */ /* Allocate and setup the channels. */
if (mtu->legacy) mtu->num_channels = 3;
mtu->num_channels = 1;
else
mtu->num_channels = 3;
mtu->channels = kzalloc(sizeof(*mtu->channels) * mtu->num_channels, mtu->channels = kzalloc(sizeof(*mtu->channels) * mtu->num_channels,
GFP_KERNEL); GFP_KERNEL);
@ -491,16 +433,10 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu,
goto err_unmap; goto err_unmap;
} }
if (mtu->legacy) { for (i = 0; i < mtu->num_channels; ++i) {
ret = sh_mtu2_setup_channel(&mtu->channels[0], 0, mtu); ret = sh_mtu2_setup_channel(&mtu->channels[i], i, mtu);
if (ret < 0) if (ret < 0)
goto err_unmap; goto err_unmap;
} else {
for (i = 0; i < mtu->num_channels; ++i) {
ret = sh_mtu2_setup_channel(&mtu->channels[i], i, mtu);
if (ret < 0)
goto err_unmap;
}
} }
platform_set_drvdata(pdev, mtu); platform_set_drvdata(pdev, mtu);
@ -509,7 +445,7 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu,
err_unmap: err_unmap:
kfree(mtu->channels); kfree(mtu->channels);
sh_mtu2_unmap_memory(mtu); iounmap(mtu->mapbase);
err_clk_unprepare: err_clk_unprepare:
clk_unprepare(mtu->clk); clk_unprepare(mtu->clk);
err_clk_put: err_clk_put:
@ -560,17 +496,23 @@ static int sh_mtu2_remove(struct platform_device *pdev)
} }
static const struct platform_device_id sh_mtu2_id_table[] = { static const struct platform_device_id sh_mtu2_id_table[] = {
{ "sh_mtu2", 1 },
{ "sh-mtu2", 0 }, { "sh-mtu2", 0 },
{ }, { },
}; };
MODULE_DEVICE_TABLE(platform, sh_mtu2_id_table); MODULE_DEVICE_TABLE(platform, sh_mtu2_id_table);
static const struct of_device_id sh_mtu2_of_table[] __maybe_unused = {
{ .compatible = "renesas,mtu2" },
{ }
};
MODULE_DEVICE_TABLE(of, sh_mtu2_of_table);
static struct platform_driver sh_mtu2_device_driver = { static struct platform_driver sh_mtu2_device_driver = {
.probe = sh_mtu2_probe, .probe = sh_mtu2_probe,
.remove = sh_mtu2_remove, .remove = sh_mtu2_remove,
.driver = { .driver = {
.name = "sh_mtu2", .name = "sh_mtu2",
.of_match_table = of_match_ptr(sh_mtu2_of_table),
}, },
.id_table = sh_mtu2_id_table, .id_table = sh_mtu2_id_table,
}; };

View File

@ -24,6 +24,7 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_domain.h> #include <linux/pm_domain.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
@ -32,7 +33,6 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
enum sh_tmu_model { enum sh_tmu_model {
SH_TMU_LEGACY,
SH_TMU, SH_TMU,
SH_TMU_SH3, SH_TMU_SH3,
}; };
@ -62,6 +62,8 @@ struct sh_tmu_device {
enum sh_tmu_model model; enum sh_tmu_model model;
raw_spinlock_t lock; /* Protect the shared start/stop register */
struct sh_tmu_channel *channels; struct sh_tmu_channel *channels;
unsigned int num_channels; unsigned int num_channels;
@ -69,8 +71,6 @@ struct sh_tmu_device {
bool has_clocksource; bool has_clocksource;
}; };
static DEFINE_RAW_SPINLOCK(sh_tmu_lock);
#define TSTR -1 /* shared register */ #define TSTR -1 /* shared register */
#define TCOR 0 /* channel register */ #define TCOR 0 /* channel register */
#define TCNT 1 /* channel register */ #define TCNT 1 /* channel register */
@ -91,8 +91,6 @@ static inline unsigned long sh_tmu_read(struct sh_tmu_channel *ch, int reg_nr)
if (reg_nr == TSTR) { if (reg_nr == TSTR) {
switch (ch->tmu->model) { switch (ch->tmu->model) {
case SH_TMU_LEGACY:
return ioread8(ch->tmu->mapbase);
case SH_TMU_SH3: case SH_TMU_SH3:
return ioread8(ch->tmu->mapbase + 2); return ioread8(ch->tmu->mapbase + 2);
case SH_TMU: case SH_TMU:
@ -115,8 +113,6 @@ static inline void sh_tmu_write(struct sh_tmu_channel *ch, int reg_nr,
if (reg_nr == TSTR) { if (reg_nr == TSTR) {
switch (ch->tmu->model) { switch (ch->tmu->model) {
case SH_TMU_LEGACY:
return iowrite8(value, ch->tmu->mapbase);
case SH_TMU_SH3: case SH_TMU_SH3:
return iowrite8(value, ch->tmu->mapbase + 2); return iowrite8(value, ch->tmu->mapbase + 2);
case SH_TMU: case SH_TMU:
@ -137,7 +133,7 @@ static void sh_tmu_start_stop_ch(struct sh_tmu_channel *ch, int start)
unsigned long flags, value; unsigned long flags, value;
/* start stop register shared by multiple timer channels */ /* start stop register shared by multiple timer channels */
raw_spin_lock_irqsave(&sh_tmu_lock, flags); raw_spin_lock_irqsave(&ch->tmu->lock, flags);
value = sh_tmu_read(ch, TSTR); value = sh_tmu_read(ch, TSTR);
if (start) if (start)
@ -146,7 +142,7 @@ static void sh_tmu_start_stop_ch(struct sh_tmu_channel *ch, int start)
value &= ~(1 << ch->index); value &= ~(1 << ch->index);
sh_tmu_write(ch, TSTR, value); sh_tmu_write(ch, TSTR, value);
raw_spin_unlock_irqrestore(&sh_tmu_lock, flags); raw_spin_unlock_irqrestore(&ch->tmu->lock, flags);
} }
static int __sh_tmu_enable(struct sh_tmu_channel *ch) static int __sh_tmu_enable(struct sh_tmu_channel *ch)
@ -476,27 +472,12 @@ static int sh_tmu_channel_setup(struct sh_tmu_channel *ch, unsigned int index,
return 0; return 0;
ch->tmu = tmu; ch->tmu = tmu;
ch->index = index;
if (tmu->model == SH_TMU_LEGACY) { if (tmu->model == SH_TMU_SH3)
struct sh_timer_config *cfg = tmu->pdev->dev.platform_data; ch->base = tmu->mapbase + 4 + ch->index * 12;
else
/* ch->base = tmu->mapbase + 8 + ch->index * 12;
* The SH3 variant (SH770x, SH7705, SH7710 and SH7720) maps
* channel registers blocks at base + 2 + 12 * index, while all
* other variants map them at base + 4 + 12 * index. We can
* compute the index by just dividing by 12, the 2 bytes or 4
* bytes offset being hidden by the integer division.
*/
ch->index = cfg->channel_offset / 12;
ch->base = tmu->mapbase + cfg->channel_offset;
} else {
ch->index = index;
if (tmu->model == SH_TMU_SH3)
ch->base = tmu->mapbase + 4 + ch->index * 12;
else
ch->base = tmu->mapbase + 8 + ch->index * 12;
}
ch->irq = platform_get_irq(tmu->pdev, index); ch->irq = platform_get_irq(tmu->pdev, index);
if (ch->irq < 0) { if (ch->irq < 0) {
@ -526,46 +507,53 @@ static int sh_tmu_map_memory(struct sh_tmu_device *tmu)
if (tmu->mapbase == NULL) if (tmu->mapbase == NULL)
return -ENXIO; return -ENXIO;
/* return 0;
* In legacy platform device configuration (with one device per channel) }
* the resource points to the channel base address.
*/ static int sh_tmu_parse_dt(struct sh_tmu_device *tmu)
if (tmu->model == SH_TMU_LEGACY) { {
struct sh_timer_config *cfg = tmu->pdev->dev.platform_data; struct device_node *np = tmu->pdev->dev.of_node;
tmu->mapbase -= cfg->channel_offset;
tmu->model = SH_TMU;
tmu->num_channels = 3;
of_property_read_u32(np, "#renesas,channels", &tmu->num_channels);
if (tmu->num_channels != 2 && tmu->num_channels != 3) {
dev_err(&tmu->pdev->dev, "invalid number of channels %u\n",
tmu->num_channels);
return -EINVAL;
} }
return 0; return 0;
} }
static void sh_tmu_unmap_memory(struct sh_tmu_device *tmu)
{
if (tmu->model == SH_TMU_LEGACY) {
struct sh_timer_config *cfg = tmu->pdev->dev.platform_data;
tmu->mapbase += cfg->channel_offset;
}
iounmap(tmu->mapbase);
}
static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev)
{ {
struct sh_timer_config *cfg = pdev->dev.platform_data;
const struct platform_device_id *id = pdev->id_entry;
unsigned int i; unsigned int i;
int ret; int ret;
if (!cfg) { tmu->pdev = pdev;
raw_spin_lock_init(&tmu->lock);
if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
ret = sh_tmu_parse_dt(tmu);
if (ret < 0)
return ret;
} else if (pdev->dev.platform_data) {
const struct platform_device_id *id = pdev->id_entry;
struct sh_timer_config *cfg = pdev->dev.platform_data;
tmu->model = id->driver_data;
tmu->num_channels = hweight8(cfg->channels_mask);
} else {
dev_err(&tmu->pdev->dev, "missing platform data\n"); dev_err(&tmu->pdev->dev, "missing platform data\n");
return -ENXIO; return -ENXIO;
} }
tmu->pdev = pdev;
tmu->model = id->driver_data;
/* Get hold of clock. */ /* Get hold of clock. */
tmu->clk = clk_get(&tmu->pdev->dev, tmu->clk = clk_get(&tmu->pdev->dev, "fck");
tmu->model == SH_TMU_LEGACY ? "tmu_fck" : "fck");
if (IS_ERR(tmu->clk)) { if (IS_ERR(tmu->clk)) {
dev_err(&tmu->pdev->dev, "cannot get clock\n"); dev_err(&tmu->pdev->dev, "cannot get clock\n");
return PTR_ERR(tmu->clk); return PTR_ERR(tmu->clk);
@ -583,11 +571,6 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev)
} }
/* Allocate and setup the channels. */ /* Allocate and setup the channels. */
if (tmu->model == SH_TMU_LEGACY)
tmu->num_channels = 1;
else
tmu->num_channels = hweight8(cfg->channels_mask);
tmu->channels = kzalloc(sizeof(*tmu->channels) * tmu->num_channels, tmu->channels = kzalloc(sizeof(*tmu->channels) * tmu->num_channels,
GFP_KERNEL); GFP_KERNEL);
if (tmu->channels == NULL) { if (tmu->channels == NULL) {
@ -595,23 +578,15 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev)
goto err_unmap; goto err_unmap;
} }
if (tmu->model == SH_TMU_LEGACY) { /*
ret = sh_tmu_channel_setup(&tmu->channels[0], 0, * Use the first channel as a clock event device and the second channel
cfg->clockevent_rating != 0, * as a clock source.
cfg->clocksource_rating != 0, tmu); */
for (i = 0; i < tmu->num_channels; ++i) {
ret = sh_tmu_channel_setup(&tmu->channels[i], i,
i == 0, i == 1, tmu);
if (ret < 0) if (ret < 0)
goto err_unmap; goto err_unmap;
} else {
/*
* Use the first channel as a clock event device and the second
* channel as a clock source.
*/
for (i = 0; i < tmu->num_channels; ++i) {
ret = sh_tmu_channel_setup(&tmu->channels[i], i,
i == 0, i == 1, tmu);
if (ret < 0)
goto err_unmap;
}
} }
platform_set_drvdata(pdev, tmu); platform_set_drvdata(pdev, tmu);
@ -620,7 +595,7 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev)
err_unmap: err_unmap:
kfree(tmu->channels); kfree(tmu->channels);
sh_tmu_unmap_memory(tmu); iounmap(tmu->mapbase);
err_clk_unprepare: err_clk_unprepare:
clk_unprepare(tmu->clk); clk_unprepare(tmu->clk);
err_clk_put: err_clk_put:
@ -671,18 +646,24 @@ static int sh_tmu_remove(struct platform_device *pdev)
} }
static const struct platform_device_id sh_tmu_id_table[] = { static const struct platform_device_id sh_tmu_id_table[] = {
{ "sh_tmu", SH_TMU_LEGACY },
{ "sh-tmu", SH_TMU }, { "sh-tmu", SH_TMU },
{ "sh-tmu-sh3", SH_TMU_SH3 }, { "sh-tmu-sh3", SH_TMU_SH3 },
{ } { }
}; };
MODULE_DEVICE_TABLE(platform, sh_tmu_id_table); MODULE_DEVICE_TABLE(platform, sh_tmu_id_table);
static const struct of_device_id sh_tmu_of_table[] __maybe_unused = {
{ .compatible = "renesas,tmu" },
{ }
};
MODULE_DEVICE_TABLE(of, sh_tmu_of_table);
static struct platform_driver sh_tmu_device_driver = { static struct platform_driver sh_tmu_device_driver = {
.probe = sh_tmu_probe, .probe = sh_tmu_probe,
.remove = sh_tmu_remove, .remove = sh_tmu_remove,
.driver = { .driver = {
.name = "sh_tmu", .name = "sh_tmu",
.of_match_table = of_match_ptr(sh_tmu_of_table),
}, },
.id_table = sh_tmu_id_table, .id_table = sh_tmu_id_table,
}; };

View File

@ -260,6 +260,9 @@ static void __init sirfsoc_marco_timer_init(struct device_node *np)
clk = of_clk_get(np, 0); clk = of_clk_get(np, 0);
BUG_ON(IS_ERR(clk)); BUG_ON(IS_ERR(clk));
BUG_ON(clk_prepare_enable(clk));
rate = clk_get_rate(clk); rate = clk_get_rate(clk);
BUG_ON(rate < MARCO_CLOCK_FREQ); BUG_ON(rate < MARCO_CLOCK_FREQ);

View File

@ -200,6 +200,9 @@ static void __init sirfsoc_prima2_timer_init(struct device_node *np)
clk = of_clk_get(np, 0); clk = of_clk_get(np, 0);
BUG_ON(IS_ERR(clk)); BUG_ON(IS_ERR(clk));
BUG_ON(clk_prepare_enable(clk));
rate = clk_get_rate(clk); rate = clk_get_rate(clk);
BUG_ON(rate < PRIMA2_CLOCK_FREQ); BUG_ON(rate < PRIMA2_CLOCK_FREQ);

View File

@ -69,7 +69,6 @@ void proc_fork_connector(struct task_struct *task)
struct cn_msg *msg; struct cn_msg *msg;
struct proc_event *ev; struct proc_event *ev;
__u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
struct timespec ts;
struct task_struct *parent; struct task_struct *parent;
if (atomic_read(&proc_event_num_listeners) < 1) if (atomic_read(&proc_event_num_listeners) < 1)
@ -79,8 +78,7 @@ void proc_fork_connector(struct task_struct *task)
ev = (struct proc_event *)msg->data; ev = (struct proc_event *)msg->data;
memset(&ev->event_data, 0, sizeof(ev->event_data)); memset(&ev->event_data, 0, sizeof(ev->event_data));
get_seq(&msg->seq, &ev->cpu); get_seq(&msg->seq, &ev->cpu);
ktime_get_ts(&ts); /* get high res monotonic timestamp */ ev->timestamp_ns = ktime_get_ns();
ev->timestamp_ns = timespec_to_ns(&ts);
ev->what = PROC_EVENT_FORK; ev->what = PROC_EVENT_FORK;
rcu_read_lock(); rcu_read_lock();
parent = rcu_dereference(task->real_parent); parent = rcu_dereference(task->real_parent);
@ -102,7 +100,6 @@ void proc_exec_connector(struct task_struct *task)
{ {
struct cn_msg *msg; struct cn_msg *msg;
struct proc_event *ev; struct proc_event *ev;
struct timespec ts;
__u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
if (atomic_read(&proc_event_num_listeners) < 1) if (atomic_read(&proc_event_num_listeners) < 1)
@ -112,8 +109,7 @@ void proc_exec_connector(struct task_struct *task)
ev = (struct proc_event *)msg->data; ev = (struct proc_event *)msg->data;
memset(&ev->event_data, 0, sizeof(ev->event_data)); memset(&ev->event_data, 0, sizeof(ev->event_data));
get_seq(&msg->seq, &ev->cpu); get_seq(&msg->seq, &ev->cpu);
ktime_get_ts(&ts); /* get high res monotonic timestamp */ ev->timestamp_ns = ktime_get_ns();
ev->timestamp_ns = timespec_to_ns(&ts);
ev->what = PROC_EVENT_EXEC; ev->what = PROC_EVENT_EXEC;
ev->event_data.exec.process_pid = task->pid; ev->event_data.exec.process_pid = task->pid;
ev->event_data.exec.process_tgid = task->tgid; ev->event_data.exec.process_tgid = task->tgid;
@ -130,7 +126,6 @@ void proc_id_connector(struct task_struct *task, int which_id)
struct cn_msg *msg; struct cn_msg *msg;
struct proc_event *ev; struct proc_event *ev;
__u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
struct timespec ts;
const struct cred *cred; const struct cred *cred;
if (atomic_read(&proc_event_num_listeners) < 1) if (atomic_read(&proc_event_num_listeners) < 1)
@ -156,8 +151,7 @@ void proc_id_connector(struct task_struct *task, int which_id)
} }
rcu_read_unlock(); rcu_read_unlock();
get_seq(&msg->seq, &ev->cpu); get_seq(&msg->seq, &ev->cpu);
ktime_get_ts(&ts); /* get high res monotonic timestamp */ ev->timestamp_ns = ktime_get_ns();
ev->timestamp_ns = timespec_to_ns(&ts);
memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
msg->ack = 0; /* not used */ msg->ack = 0; /* not used */
@ -170,7 +164,6 @@ void proc_sid_connector(struct task_struct *task)
{ {
struct cn_msg *msg; struct cn_msg *msg;
struct proc_event *ev; struct proc_event *ev;
struct timespec ts;
__u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
if (atomic_read(&proc_event_num_listeners) < 1) if (atomic_read(&proc_event_num_listeners) < 1)
@ -180,8 +173,7 @@ void proc_sid_connector(struct task_struct *task)
ev = (struct proc_event *)msg->data; ev = (struct proc_event *)msg->data;
memset(&ev->event_data, 0, sizeof(ev->event_data)); memset(&ev->event_data, 0, sizeof(ev->event_data));
get_seq(&msg->seq, &ev->cpu); get_seq(&msg->seq, &ev->cpu);
ktime_get_ts(&ts); /* get high res monotonic timestamp */ ev->timestamp_ns = ktime_get_ns();
ev->timestamp_ns = timespec_to_ns(&ts);
ev->what = PROC_EVENT_SID; ev->what = PROC_EVENT_SID;
ev->event_data.sid.process_pid = task->pid; ev->event_data.sid.process_pid = task->pid;
ev->event_data.sid.process_tgid = task->tgid; ev->event_data.sid.process_tgid = task->tgid;
@ -197,7 +189,6 @@ void proc_ptrace_connector(struct task_struct *task, int ptrace_id)
{ {
struct cn_msg *msg; struct cn_msg *msg;
struct proc_event *ev; struct proc_event *ev;
struct timespec ts;
__u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
if (atomic_read(&proc_event_num_listeners) < 1) if (atomic_read(&proc_event_num_listeners) < 1)
@ -207,8 +198,7 @@ void proc_ptrace_connector(struct task_struct *task, int ptrace_id)
ev = (struct proc_event *)msg->data; ev = (struct proc_event *)msg->data;
memset(&ev->event_data, 0, sizeof(ev->event_data)); memset(&ev->event_data, 0, sizeof(ev->event_data));
get_seq(&msg->seq, &ev->cpu); get_seq(&msg->seq, &ev->cpu);
ktime_get_ts(&ts); /* get high res monotonic timestamp */ ev->timestamp_ns = ktime_get_ns();
ev->timestamp_ns = timespec_to_ns(&ts);
ev->what = PROC_EVENT_PTRACE; ev->what = PROC_EVENT_PTRACE;
ev->event_data.ptrace.process_pid = task->pid; ev->event_data.ptrace.process_pid = task->pid;
ev->event_data.ptrace.process_tgid = task->tgid; ev->event_data.ptrace.process_tgid = task->tgid;
@ -232,7 +222,6 @@ void proc_comm_connector(struct task_struct *task)
{ {
struct cn_msg *msg; struct cn_msg *msg;
struct proc_event *ev; struct proc_event *ev;
struct timespec ts;
__u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
if (atomic_read(&proc_event_num_listeners) < 1) if (atomic_read(&proc_event_num_listeners) < 1)
@ -242,8 +231,7 @@ void proc_comm_connector(struct task_struct *task)
ev = (struct proc_event *)msg->data; ev = (struct proc_event *)msg->data;
memset(&ev->event_data, 0, sizeof(ev->event_data)); memset(&ev->event_data, 0, sizeof(ev->event_data));
get_seq(&msg->seq, &ev->cpu); get_seq(&msg->seq, &ev->cpu);
ktime_get_ts(&ts); /* get high res monotonic timestamp */ ev->timestamp_ns = ktime_get_ns();
ev->timestamp_ns = timespec_to_ns(&ts);
ev->what = PROC_EVENT_COMM; ev->what = PROC_EVENT_COMM;
ev->event_data.comm.process_pid = task->pid; ev->event_data.comm.process_pid = task->pid;
ev->event_data.comm.process_tgid = task->tgid; ev->event_data.comm.process_tgid = task->tgid;
@ -261,7 +249,6 @@ void proc_coredump_connector(struct task_struct *task)
struct cn_msg *msg; struct cn_msg *msg;
struct proc_event *ev; struct proc_event *ev;
__u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
struct timespec ts;
if (atomic_read(&proc_event_num_listeners) < 1) if (atomic_read(&proc_event_num_listeners) < 1)
return; return;
@ -270,8 +257,7 @@ void proc_coredump_connector(struct task_struct *task)
ev = (struct proc_event *)msg->data; ev = (struct proc_event *)msg->data;
memset(&ev->event_data, 0, sizeof(ev->event_data)); memset(&ev->event_data, 0, sizeof(ev->event_data));
get_seq(&msg->seq, &ev->cpu); get_seq(&msg->seq, &ev->cpu);
ktime_get_ts(&ts); /* get high res monotonic timestamp */ ev->timestamp_ns = ktime_get_ns();
ev->timestamp_ns = timespec_to_ns(&ts);
ev->what = PROC_EVENT_COREDUMP; ev->what = PROC_EVENT_COREDUMP;
ev->event_data.coredump.process_pid = task->pid; ev->event_data.coredump.process_pid = task->pid;
ev->event_data.coredump.process_tgid = task->tgid; ev->event_data.coredump.process_tgid = task->tgid;
@ -288,7 +274,6 @@ void proc_exit_connector(struct task_struct *task)
struct cn_msg *msg; struct cn_msg *msg;
struct proc_event *ev; struct proc_event *ev;
__u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
struct timespec ts;
if (atomic_read(&proc_event_num_listeners) < 1) if (atomic_read(&proc_event_num_listeners) < 1)
return; return;
@ -297,8 +282,7 @@ void proc_exit_connector(struct task_struct *task)
ev = (struct proc_event *)msg->data; ev = (struct proc_event *)msg->data;
memset(&ev->event_data, 0, sizeof(ev->event_data)); memset(&ev->event_data, 0, sizeof(ev->event_data));
get_seq(&msg->seq, &ev->cpu); get_seq(&msg->seq, &ev->cpu);
ktime_get_ts(&ts); /* get high res monotonic timestamp */ ev->timestamp_ns = ktime_get_ns();
ev->timestamp_ns = timespec_to_ns(&ts);
ev->what = PROC_EVENT_EXIT; ev->what = PROC_EVENT_EXIT;
ev->event_data.exit.process_pid = task->pid; ev->event_data.exit.process_pid = task->pid;
ev->event_data.exit.process_tgid = task->tgid; ev->event_data.exit.process_tgid = task->tgid;
@ -325,7 +309,6 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
struct cn_msg *msg; struct cn_msg *msg;
struct proc_event *ev; struct proc_event *ev;
__u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
struct timespec ts;
if (atomic_read(&proc_event_num_listeners) < 1) if (atomic_read(&proc_event_num_listeners) < 1)
return; return;
@ -334,8 +317,7 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
ev = (struct proc_event *)msg->data; ev = (struct proc_event *)msg->data;
memset(&ev->event_data, 0, sizeof(ev->event_data)); memset(&ev->event_data, 0, sizeof(ev->event_data));
msg->seq = rcvd_seq; msg->seq = rcvd_seq;
ktime_get_ts(&ts); /* get high res monotonic timestamp */ ev->timestamp_ns = ktime_get_ns();
ev->timestamp_ns = timespec_to_ns(&ts);
ev->cpu = -1; ev->cpu = -1;
ev->what = PROC_EVENT_NONE; ev->what = PROC_EVENT_NONE;
ev->event_data.ack.err = err; ev->event_data.ack.err = err;

View File

@ -1214,9 +1214,9 @@ static int ioctl_get_cycle_timer2(struct client *client, union ioctl_arg *arg)
cycle_time = card->driver->read_csr(card, CSR_CYCLE_TIME); cycle_time = card->driver->read_csr(card, CSR_CYCLE_TIME);
switch (a->clk_id) { switch (a->clk_id) {
case CLOCK_REALTIME: getnstimeofday(&ts); break; case CLOCK_REALTIME: getnstimeofday(&ts); break;
case CLOCK_MONOTONIC: do_posix_clock_monotonic_gettime(&ts); break; case CLOCK_MONOTONIC: ktime_get_ts(&ts); break;
case CLOCK_MONOTONIC_RAW: getrawmonotonic(&ts); break; case CLOCK_MONOTONIC_RAW: getrawmonotonic(&ts); break;
default: default:
ret = -EINVAL; ret = -EINVAL;
} }

View File

@ -542,8 +542,8 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
const struct drm_crtc *refcrtc, const struct drm_crtc *refcrtc,
const struct drm_display_mode *mode) const struct drm_display_mode *mode)
{ {
ktime_t stime, etime, mono_time_offset;
struct timeval tv_etime; struct timeval tv_etime;
ktime_t stime, etime;
int vbl_status; int vbl_status;
int vpos, hpos, i; int vpos, hpos, i;
int framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns; int framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns;
@ -588,13 +588,6 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
vbl_status = dev->driver->get_scanout_position(dev, crtc, flags, &vpos, vbl_status = dev->driver->get_scanout_position(dev, crtc, flags, &vpos,
&hpos, &stime, &etime); &hpos, &stime, &etime);
/*
* Get correction for CLOCK_MONOTONIC -> CLOCK_REALTIME if
* CLOCK_REALTIME is requested.
*/
if (!drm_timestamp_monotonic)
mono_time_offset = ktime_get_monotonic_offset();
/* Return as no-op if scanout query unsupported or failed. */ /* Return as no-op if scanout query unsupported or failed. */
if (!(vbl_status & DRM_SCANOUTPOS_VALID)) { if (!(vbl_status & DRM_SCANOUTPOS_VALID)) {
DRM_DEBUG("crtc %d : scanoutpos query failed [%d].\n", DRM_DEBUG("crtc %d : scanoutpos query failed [%d].\n",
@ -633,7 +626,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
delta_ns = vpos * linedur_ns + hpos * pixeldur_ns; delta_ns = vpos * linedur_ns + hpos * pixeldur_ns;
if (!drm_timestamp_monotonic) if (!drm_timestamp_monotonic)
etime = ktime_sub(etime, mono_time_offset); etime = ktime_mono_to_real(etime);
/* save this only for debugging purposes */ /* save this only for debugging purposes */
tv_etime = ktime_to_timeval(etime); tv_etime = ktime_to_timeval(etime);
@ -664,10 +657,7 @@ static struct timeval get_drm_timestamp(void)
{ {
ktime_t now; ktime_t now;
now = ktime_get(); now = drm_timestamp_monotonic ? ktime_get() : ktime_get_real();
if (!drm_timestamp_monotonic)
now = ktime_sub(now, ktime_get_monotonic_offset());
return ktime_to_timeval(now); return ktime_to_timeval(now);
} }

View File

@ -931,7 +931,7 @@ struct intel_ilk_power_mgmt {
unsigned long last_time1; unsigned long last_time1;
unsigned long chipset_power; unsigned long chipset_power;
u64 last_count2; u64 last_count2;
struct timespec last_time2; u64 last_time2;
unsigned long gfx_power; unsigned long gfx_power;
u8 corr; u8 corr;

View File

@ -1149,16 +1149,16 @@ static bool can_wait_boost(struct drm_i915_file_private *file_priv)
static int __wait_seqno(struct intel_engine_cs *ring, u32 seqno, static int __wait_seqno(struct intel_engine_cs *ring, u32 seqno,
unsigned reset_counter, unsigned reset_counter,
bool interruptible, bool interruptible,
struct timespec *timeout, s64 *timeout,
struct drm_i915_file_private *file_priv) struct drm_i915_file_private *file_priv)
{ {
struct drm_device *dev = ring->dev; struct drm_device *dev = ring->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
const bool irq_test_in_progress = const bool irq_test_in_progress =
ACCESS_ONCE(dev_priv->gpu_error.test_irq_rings) & intel_ring_flag(ring); ACCESS_ONCE(dev_priv->gpu_error.test_irq_rings) & intel_ring_flag(ring);
struct timespec before, now;
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
unsigned long timeout_expire; unsigned long timeout_expire;
s64 before, now;
int ret; int ret;
WARN(dev_priv->pm.irqs_disabled, "IRQs disabled\n"); WARN(dev_priv->pm.irqs_disabled, "IRQs disabled\n");
@ -1166,7 +1166,7 @@ static int __wait_seqno(struct intel_engine_cs *ring, u32 seqno,
if (i915_seqno_passed(ring->get_seqno(ring, true), seqno)) if (i915_seqno_passed(ring->get_seqno(ring, true), seqno))
return 0; return 0;
timeout_expire = timeout ? jiffies + timespec_to_jiffies_timeout(timeout) : 0; timeout_expire = timeout ? jiffies + nsecs_to_jiffies((u64)*timeout) : 0;
if (INTEL_INFO(dev)->gen >= 6 && can_wait_boost(file_priv)) { if (INTEL_INFO(dev)->gen >= 6 && can_wait_boost(file_priv)) {
gen6_rps_boost(dev_priv); gen6_rps_boost(dev_priv);
@ -1181,7 +1181,7 @@ static int __wait_seqno(struct intel_engine_cs *ring, u32 seqno,
/* Record current time in case interrupted by signal, or wedged */ /* Record current time in case interrupted by signal, or wedged */
trace_i915_gem_request_wait_begin(ring, seqno); trace_i915_gem_request_wait_begin(ring, seqno);
getrawmonotonic(&before); before = ktime_get_raw_ns();
for (;;) { for (;;) {
struct timer_list timer; struct timer_list timer;
@ -1230,7 +1230,7 @@ static int __wait_seqno(struct intel_engine_cs *ring, u32 seqno,
destroy_timer_on_stack(&timer); destroy_timer_on_stack(&timer);
} }
} }
getrawmonotonic(&now); now = ktime_get_raw_ns();
trace_i915_gem_request_wait_end(ring, seqno); trace_i915_gem_request_wait_end(ring, seqno);
if (!irq_test_in_progress) if (!irq_test_in_progress)
@ -1239,10 +1239,9 @@ static int __wait_seqno(struct intel_engine_cs *ring, u32 seqno,
finish_wait(&ring->irq_queue, &wait); finish_wait(&ring->irq_queue, &wait);
if (timeout) { if (timeout) {
struct timespec sleep_time = timespec_sub(now, before); s64 tres = *timeout - (now - before);
*timeout = timespec_sub(*timeout, sleep_time);
if (!timespec_valid(timeout)) /* i.e. negative time remains */ *timeout = tres < 0 ? 0 : tres;
set_normalized_timespec(timeout, 0, 0);
} }
return ret; return ret;
@ -2746,16 +2745,10 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
struct drm_i915_gem_wait *args = data; struct drm_i915_gem_wait *args = data;
struct drm_i915_gem_object *obj; struct drm_i915_gem_object *obj;
struct intel_engine_cs *ring = NULL; struct intel_engine_cs *ring = NULL;
struct timespec timeout_stack, *timeout = NULL;
unsigned reset_counter; unsigned reset_counter;
u32 seqno = 0; u32 seqno = 0;
int ret = 0; int ret = 0;
if (args->timeout_ns >= 0) {
timeout_stack = ns_to_timespec(args->timeout_ns);
timeout = &timeout_stack;
}
ret = i915_mutex_lock_interruptible(dev); ret = i915_mutex_lock_interruptible(dev);
if (ret) if (ret)
return ret; return ret;
@ -2780,9 +2773,9 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
goto out; goto out;
/* Do this after OLR check to make sure we make forward progress polling /* Do this after OLR check to make sure we make forward progress polling
* on this IOCTL with a 0 timeout (like busy ioctl) * on this IOCTL with a timeout <=0 (like busy ioctl)
*/ */
if (!args->timeout_ns) { if (args->timeout_ns <= 0) {
ret = -ETIME; ret = -ETIME;
goto out; goto out;
} }
@ -2791,10 +2784,8 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
ret = __wait_seqno(ring, seqno, reset_counter, true, timeout, file->driver_priv); return __wait_seqno(ring, seqno, reset_counter, true, &args->timeout_ns,
if (timeout) file->driver_priv);
args->timeout_ns = timespec_to_ns(timeout);
return ret;
out: out:
drm_gem_object_unreference(&obj->base); drm_gem_object_unreference(&obj->base);

View File

@ -2993,7 +2993,7 @@ static void ironlake_enable_drps(struct drm_device *dev)
I915_READ(0x112e0); I915_READ(0x112e0);
dev_priv->ips.last_time1 = jiffies_to_msecs(jiffies); dev_priv->ips.last_time1 = jiffies_to_msecs(jiffies);
dev_priv->ips.last_count2 = I915_READ(0x112f4); dev_priv->ips.last_count2 = I915_READ(0x112f4);
getrawmonotonic(&dev_priv->ips.last_time2); dev_priv->ips.last_time2 = ktime_get_raw_ns();
spin_unlock_irq(&mchdev_lock); spin_unlock_irq(&mchdev_lock);
} }
@ -4314,18 +4314,16 @@ static u16 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid)
static void __i915_update_gfx_val(struct drm_i915_private *dev_priv) static void __i915_update_gfx_val(struct drm_i915_private *dev_priv)
{ {
struct timespec now, diff1; u64 now, diff, diffms;
u64 diff;
unsigned long diffms;
u32 count; u32 count;
assert_spin_locked(&mchdev_lock); assert_spin_locked(&mchdev_lock);
getrawmonotonic(&now); now = ktime_get_raw_ns();
diff1 = timespec_sub(now, dev_priv->ips.last_time2); diffms = now - dev_priv->ips.last_time2;
do_div(diffms, NSEC_PER_MSEC);
/* Don't divide by 0 */ /* Don't divide by 0 */
diffms = diff1.tv_sec * 1000 + diff1.tv_nsec / 1000000;
if (!diffms) if (!diffms)
return; return;

View File

@ -159,8 +159,8 @@ struct vmw_surface {
struct vmw_marker_queue { struct vmw_marker_queue {
struct list_head head; struct list_head head;
struct timespec lag; u64 lag;
struct timespec lag_time; u64 lag_time;
spinlock_t lock; spinlock_t lock;
}; };

View File

@ -31,14 +31,14 @@
struct vmw_marker { struct vmw_marker {
struct list_head head; struct list_head head;
uint32_t seqno; uint32_t seqno;
struct timespec submitted; u64 submitted;
}; };
void vmw_marker_queue_init(struct vmw_marker_queue *queue) void vmw_marker_queue_init(struct vmw_marker_queue *queue)
{ {
INIT_LIST_HEAD(&queue->head); INIT_LIST_HEAD(&queue->head);
queue->lag = ns_to_timespec(0); queue->lag = 0;
getrawmonotonic(&queue->lag_time); queue->lag_time = ktime_get_raw_ns();
spin_lock_init(&queue->lock); spin_lock_init(&queue->lock);
} }
@ -62,7 +62,7 @@ int vmw_marker_push(struct vmw_marker_queue *queue,
return -ENOMEM; return -ENOMEM;
marker->seqno = seqno; marker->seqno = seqno;
getrawmonotonic(&marker->submitted); marker->submitted = ktime_get_raw_ns();
spin_lock(&queue->lock); spin_lock(&queue->lock);
list_add_tail(&marker->head, &queue->head); list_add_tail(&marker->head, &queue->head);
spin_unlock(&queue->lock); spin_unlock(&queue->lock);
@ -74,14 +74,14 @@ int vmw_marker_pull(struct vmw_marker_queue *queue,
uint32_t signaled_seqno) uint32_t signaled_seqno)
{ {
struct vmw_marker *marker, *next; struct vmw_marker *marker, *next;
struct timespec now;
bool updated = false; bool updated = false;
u64 now;
spin_lock(&queue->lock); spin_lock(&queue->lock);
getrawmonotonic(&now); now = ktime_get_raw_ns();
if (list_empty(&queue->head)) { if (list_empty(&queue->head)) {
queue->lag = ns_to_timespec(0); queue->lag = 0;
queue->lag_time = now; queue->lag_time = now;
updated = true; updated = true;
goto out_unlock; goto out_unlock;
@ -91,7 +91,7 @@ int vmw_marker_pull(struct vmw_marker_queue *queue,
if (signaled_seqno - marker->seqno > (1 << 30)) if (signaled_seqno - marker->seqno > (1 << 30))
continue; continue;
queue->lag = timespec_sub(now, marker->submitted); queue->lag = now - marker->submitted;
queue->lag_time = now; queue->lag_time = now;
updated = true; updated = true;
list_del(&marker->head); list_del(&marker->head);
@ -104,27 +104,13 @@ out_unlock:
return (updated) ? 0 : -EBUSY; return (updated) ? 0 : -EBUSY;
} }
static struct timespec vmw_timespec_add(struct timespec t1, static u64 vmw_fifo_lag(struct vmw_marker_queue *queue)
struct timespec t2)
{ {
t1.tv_sec += t2.tv_sec; u64 now;
t1.tv_nsec += t2.tv_nsec;
if (t1.tv_nsec >= 1000000000L) {
t1.tv_sec += 1;
t1.tv_nsec -= 1000000000L;
}
return t1;
}
static struct timespec vmw_fifo_lag(struct vmw_marker_queue *queue)
{
struct timespec now;
spin_lock(&queue->lock); spin_lock(&queue->lock);
getrawmonotonic(&now); now = ktime_get_raw_ns();
queue->lag = vmw_timespec_add(queue->lag, queue->lag += now - queue->lag_time;
timespec_sub(now, queue->lag_time));
queue->lag_time = now; queue->lag_time = now;
spin_unlock(&queue->lock); spin_unlock(&queue->lock);
return queue->lag; return queue->lag;
@ -134,11 +120,9 @@ static struct timespec vmw_fifo_lag(struct vmw_marker_queue *queue)
static bool vmw_lag_lt(struct vmw_marker_queue *queue, static bool vmw_lag_lt(struct vmw_marker_queue *queue,
uint32_t us) uint32_t us)
{ {
struct timespec lag, cond; u64 cond = (u64) us * NSEC_PER_USEC;
cond = ns_to_timespec((s64) us * 1000); return vmw_fifo_lag(queue) <= cond;
lag = vmw_fifo_lag(queue);
return (timespec_compare(&lag, &cond) < 1);
} }
int vmw_wait_lag(struct vmw_private *dev_priv, int vmw_wait_lag(struct vmw_private *dev_priv,

View File

@ -842,11 +842,10 @@ static ssize_t aem_show_power(struct device *dev,
struct aem_data *data = dev_get_drvdata(dev); struct aem_data *data = dev_get_drvdata(dev);
u64 before, after, delta, time; u64 before, after, delta, time;
signed long leftover; signed long leftover;
struct timespec b, a;
mutex_lock(&data->lock); mutex_lock(&data->lock);
update_aem_energy_one(data, attr->index); update_aem_energy_one(data, attr->index);
getnstimeofday(&b); time = ktime_get_ns();
before = data->energy[attr->index]; before = data->energy[attr->index];
leftover = schedule_timeout_interruptible( leftover = schedule_timeout_interruptible(
@ -858,11 +857,10 @@ static ssize_t aem_show_power(struct device *dev,
} }
update_aem_energy_one(data, attr->index); update_aem_energy_one(data, attr->index);
getnstimeofday(&a); time = ktime_get_ns() - time;
after = data->energy[attr->index]; after = data->energy[attr->index];
mutex_unlock(&data->lock); mutex_unlock(&data->lock);
time = timespec_to_ns(&a) - timespec_to_ns(&b);
delta = (after - before) * UJ_PER_MJ; delta = (after - before) * UJ_PER_MJ;
return sprintf(buf, "%llu\n", return sprintf(buf, "%llu\n",

View File

@ -108,9 +108,8 @@ static void evdev_queue_syn_dropped(struct evdev_client *client)
struct input_event ev; struct input_event ev;
ktime_t time; ktime_t time;
time = ktime_get(); time = (client->clkid == CLOCK_MONOTONIC) ?
if (client->clkid != CLOCK_MONOTONIC) ktime_get() : ktime_get_real();
time = ktime_sub(time, ktime_get_monotonic_offset());
ev.time = ktime_to_timeval(time); ev.time = ktime_to_timeval(time);
ev.type = EV_SYN; ev.type = EV_SYN;
@ -202,7 +201,7 @@ static void evdev_events(struct input_handle *handle,
ktime_t time_mono, time_real; ktime_t time_mono, time_real;
time_mono = ktime_get(); time_mono = ktime_get();
time_real = ktime_sub(time_mono, ktime_get_monotonic_offset()); time_real = ktime_mono_to_real(time_mono);
rcu_read_lock(); rcu_read_lock();

View File

@ -225,7 +225,6 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev,
u8 *ptr; u8 *ptr;
int sum; int sum;
int ret = 0, final_ret; int ret = 0, final_ret;
struct timespec ts;
/* /*
* We have the shared ec_dev buffer plus we do lots of separate spi_sync * We have the shared ec_dev buffer plus we do lots of separate spi_sync
@ -239,11 +238,9 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev,
/* If it's too soon to do another transaction, wait */ /* If it's too soon to do another transaction, wait */
if (ec_spi->last_transfer_ns) { if (ec_spi->last_transfer_ns) {
struct timespec ts;
unsigned long delay; /* The delay completed so far */ unsigned long delay; /* The delay completed so far */
ktime_get_ts(&ts); delay = ktime_get_ns() - ec_spi->last_transfer_ns;
delay = timespec_to_ns(&ts) - ec_spi->last_transfer_ns;
if (delay < EC_SPI_RECOVERY_TIME_NS) if (delay < EC_SPI_RECOVERY_TIME_NS)
ndelay(EC_SPI_RECOVERY_TIME_NS - delay); ndelay(EC_SPI_RECOVERY_TIME_NS - delay);
} }
@ -280,8 +277,7 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev,
} }
final_ret = spi_sync(ec_spi->spi, &msg); final_ret = spi_sync(ec_spi->spi, &msg);
ktime_get_ts(&ts); ec_spi->last_transfer_ns = ktime_get_ns();
ec_spi->last_transfer_ns = timespec_to_ns(&ts);
if (!ret) if (!ret)
ret = final_ret; ret = final_ret;
if (ret < 0) { if (ret < 0) {

View File

@ -145,7 +145,6 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd)
union ioc4_int_out int_out; union ioc4_int_out int_out;
union ioc4_gpcr gpcr; union ioc4_gpcr gpcr;
unsigned int state, last_state = 1; unsigned int state, last_state = 1;
struct timespec start_ts, end_ts;
uint64_t start, end, period; uint64_t start, end, period;
unsigned int count = 0; unsigned int count = 0;
@ -174,10 +173,10 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd)
if (!last_state && state) { if (!last_state && state) {
count++; count++;
if (count == IOC4_CALIBRATE_END) { if (count == IOC4_CALIBRATE_END) {
ktime_get_ts(&end_ts); end = ktime_get_ns();
break; break;
} else if (count == IOC4_CALIBRATE_DISCARD) } else if (count == IOC4_CALIBRATE_DISCARD)
ktime_get_ts(&start_ts); start = ktime_get_ns();
} }
last_state = state; last_state = state;
} while (1); } while (1);
@ -192,8 +191,6 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd)
* by which the IOC4 generates the square wave, to get the * by which the IOC4 generates the square wave, to get the
* period of an IOC4 INT_OUT count. * period of an IOC4 INT_OUT count.
*/ */
end = end_ts.tv_sec * NSEC_PER_SEC + end_ts.tv_nsec;
start = start_ts.tv_sec * NSEC_PER_SEC + start_ts.tv_nsec;
period = (end - start) / period = (end - start) /
(IOC4_CALIBRATE_CYCLES * 2 * (IOC4_CALIBRATE_COUNT + 1)); (IOC4_CALIBRATE_CYCLES * 2 * (IOC4_CALIBRATE_COUNT + 1));

View File

@ -548,7 +548,7 @@ static void cmd_work_handler(struct work_struct *work)
lay->status_own = CMD_OWNER_HW; lay->status_own = CMD_OWNER_HW;
set_signature(ent, !cmd->checksum_disabled); set_signature(ent, !cmd->checksum_disabled);
dump_command(dev, ent, 1); dump_command(dev, ent, 1);
ktime_get_ts(&ent->ts1); ent->ts1 = ktime_get_ns();
/* ring doorbell after the descriptor is valid */ /* ring doorbell after the descriptor is valid */
wmb(); wmb();
@ -637,7 +637,6 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,
{ {
struct mlx5_cmd *cmd = &dev->cmd; struct mlx5_cmd *cmd = &dev->cmd;
struct mlx5_cmd_work_ent *ent; struct mlx5_cmd_work_ent *ent;
ktime_t t1, t2, delta;
struct mlx5_cmd_stats *stats; struct mlx5_cmd_stats *stats;
int err = 0; int err = 0;
s64 ds; s64 ds;
@ -668,10 +667,7 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,
if (err == -ETIMEDOUT) if (err == -ETIMEDOUT)
goto out; goto out;
t1 = timespec_to_ktime(ent->ts1); ds = ent->ts2 - ent->ts1;
t2 = timespec_to_ktime(ent->ts2);
delta = ktime_sub(t2, t1);
ds = ktime_to_ns(delta);
op = be16_to_cpu(((struct mlx5_inbox_hdr *)in->first.data)->opcode); op = be16_to_cpu(((struct mlx5_inbox_hdr *)in->first.data)->opcode);
if (op < ARRAY_SIZE(cmd->stats)) { if (op < ARRAY_SIZE(cmd->stats)) {
stats = &cmd->stats[op]; stats = &cmd->stats[op];
@ -1135,7 +1131,6 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector)
void *context; void *context;
int err; int err;
int i; int i;
ktime_t t1, t2, delta;
s64 ds; s64 ds;
struct mlx5_cmd_stats *stats; struct mlx5_cmd_stats *stats;
unsigned long flags; unsigned long flags;
@ -1149,7 +1144,7 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector)
sem = &cmd->pages_sem; sem = &cmd->pages_sem;
else else
sem = &cmd->sem; sem = &cmd->sem;
ktime_get_ts(&ent->ts2); ent->ts2 = ktime_get_ns();
memcpy(ent->out->first.data, ent->lay->out, sizeof(ent->lay->out)); memcpy(ent->out->first.data, ent->lay->out, sizeof(ent->lay->out));
dump_command(dev, ent, 0); dump_command(dev, ent, 0);
if (!ent->ret) { if (!ent->ret) {
@ -1163,10 +1158,7 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector)
} }
free_ent(cmd, ent->idx); free_ent(cmd, ent->idx);
if (ent->callback) { if (ent->callback) {
t1 = timespec_to_ktime(ent->ts1); ds = ent->ts2 - ent->ts1;
t2 = timespec_to_ktime(ent->ts2);
delta = ktime_sub(t2, t1);
ds = ktime_to_ns(delta);
if (ent->op < ARRAY_SIZE(cmd->stats)) { if (ent->op < ARRAY_SIZE(cmd->stats)) {
stats = &cmd->stats[ent->op]; stats = &cmd->stats[ent->op];
spin_lock_irqsave(&stats->lock, flags); spin_lock_irqsave(&stats->lock, flags);

View File

@ -1734,7 +1734,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
struct ath9k_hw_cal_data *caldata, bool fastcc) struct ath9k_hw_cal_data *caldata, bool fastcc)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
struct timespec ts;
u32 saveLedState; u32 saveLedState;
u32 saveDefAntenna; u32 saveDefAntenna;
u32 macStaId1; u32 macStaId1;
@ -1784,8 +1783,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
/* Save TSF before chip reset, a cold reset clears it */ /* Save TSF before chip reset, a cold reset clears it */
tsf = ath9k_hw_gettsf64(ah); tsf = ath9k_hw_gettsf64(ah);
getrawmonotonic(&ts); usec = ktime_to_us(ktime_get_raw());
usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000;
saveLedState = REG_READ(ah, AR_CFG_LED) & saveLedState = REG_READ(ah, AR_CFG_LED) &
(AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL | (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |
@ -1818,8 +1816,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
} }
/* Restore TSF */ /* Restore TSF */
getrawmonotonic(&ts); usec = ktime_to_us(ktime_get_raw()) - usec;
usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000 - usec;
ath9k_hw_settsf64(ah, tsf + usec); ath9k_hw_settsf64(ah, tsf + usec);
if (AR_SREV_9280_20_OR_LATER(ah)) if (AR_SREV_9280_20_OR_LATER(ah))

View File

@ -702,6 +702,42 @@ void __iomem *of_iomap(struct device_node *np, int index)
} }
EXPORT_SYMBOL(of_iomap); EXPORT_SYMBOL(of_iomap);
/*
* of_io_request_and_map - Requests a resource and maps the memory mapped IO
* for a given device_node
* @device: the device whose io range will be mapped
* @index: index of the io range
* @name: name of the resource
*
* Returns a pointer to the requested and mapped memory or an ERR_PTR() encoded
* error code on failure. Usage example:
*
* base = of_io_request_and_map(node, 0, "foo");
* if (IS_ERR(base))
* return PTR_ERR(base);
*/
void __iomem *of_io_request_and_map(struct device_node *np, int index,
char *name)
{
struct resource res;
void __iomem *mem;
if (of_address_to_resource(np, index, &res))
return IOMEM_ERR_PTR(-EINVAL);
if (!request_mem_region(res.start, resource_size(&res), name))
return IOMEM_ERR_PTR(-EBUSY);
mem = ioremap(res.start, resource_size(&res));
if (!mem) {
release_mem_region(res.start, resource_size(&res));
return IOMEM_ERR_PTR(-ENOMEM);
}
return mem;
}
EXPORT_SYMBOL(of_io_request_and_map);
/** /**
* of_dma_get_range - Get DMA range info * of_dma_get_range - Get DMA range info
* @np: device node to get DMA range info * @np: device node to get DMA range info

View File

@ -306,11 +306,9 @@ static struct nsm_handle *nsm_lookup_priv(const struct nsm_private *priv)
static void nsm_init_private(struct nsm_handle *nsm) static void nsm_init_private(struct nsm_handle *nsm)
{ {
u64 *p = (u64 *)&nsm->sm_priv.data; u64 *p = (u64 *)&nsm->sm_priv.data;
struct timespec ts;
s64 ns; s64 ns;
ktime_get_ts(&ts); ns = ktime_get_ns();
ns = timespec_to_ns(&ts);
put_unaligned(ns, p); put_unaligned(ns, p);
put_unaligned((unsigned long)nsm, p + 1); put_unaligned((unsigned long)nsm, p + 1);
} }

View File

@ -473,13 +473,8 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
priority = task_prio(task); priority = task_prio(task);
nice = task_nice(task); nice = task_nice(task);
/* Temporary variable needed for gcc-2.96 */
/* convert timespec -> nsec*/
start_time =
(unsigned long long)task->real_start_time.tv_sec * NSEC_PER_SEC
+ task->real_start_time.tv_nsec;
/* convert nsec -> ticks */ /* convert nsec -> ticks */
start_time = nsec_to_clock_t(start_time); start_time = nsec_to_clock_t(task->real_start_time);
seq_printf(m, "%d (%s) %c", pid_nr_ns(pid, ns), tcomm, state); seq_printf(m, "%d (%s) %c", pid_nr_ns(pid, ns), tcomm, state);
seq_put_decimal_ll(m, ' ', ppid); seq_put_decimal_ll(m, ' ', ppid);

View File

@ -35,8 +35,9 @@ struct timerfd_ctx {
ktime_t moffs; ktime_t moffs;
wait_queue_head_t wqh; wait_queue_head_t wqh;
u64 ticks; u64 ticks;
int expired;
int clockid; int clockid;
short unsigned expired;
short unsigned settime_flags; /* to show in fdinfo */
struct rcu_head rcu; struct rcu_head rcu;
struct list_head clist; struct list_head clist;
bool might_cancel; bool might_cancel;
@ -92,7 +93,7 @@ static enum alarmtimer_restart timerfd_alarmproc(struct alarm *alarm,
*/ */
void timerfd_clock_was_set(void) void timerfd_clock_was_set(void)
{ {
ktime_t moffs = ktime_get_monotonic_offset(); ktime_t moffs = ktime_mono_to_real((ktime_t){ .tv64 = 0 });
struct timerfd_ctx *ctx; struct timerfd_ctx *ctx;
unsigned long flags; unsigned long flags;
@ -125,7 +126,7 @@ static bool timerfd_canceled(struct timerfd_ctx *ctx)
{ {
if (!ctx->might_cancel || ctx->moffs.tv64 != KTIME_MAX) if (!ctx->might_cancel || ctx->moffs.tv64 != KTIME_MAX)
return false; return false;
ctx->moffs = ktime_get_monotonic_offset(); ctx->moffs = ktime_mono_to_real((ktime_t){ .tv64 = 0 });
return true; return true;
} }
@ -196,6 +197,8 @@ static int timerfd_setup(struct timerfd_ctx *ctx, int flags,
if (timerfd_canceled(ctx)) if (timerfd_canceled(ctx))
return -ECANCELED; return -ECANCELED;
} }
ctx->settime_flags = flags & TFD_SETTIME_FLAGS;
return 0; return 0;
} }
@ -284,11 +287,77 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
return res; return res;
} }
#ifdef CONFIG_PROC_FS
static int timerfd_show(struct seq_file *m, struct file *file)
{
struct timerfd_ctx *ctx = file->private_data;
struct itimerspec t;
spin_lock_irq(&ctx->wqh.lock);
t.it_value = ktime_to_timespec(timerfd_get_remaining(ctx));
t.it_interval = ktime_to_timespec(ctx->tintv);
spin_unlock_irq(&ctx->wqh.lock);
return seq_printf(m,
"clockid: %d\n"
"ticks: %llu\n"
"settime flags: 0%o\n"
"it_value: (%llu, %llu)\n"
"it_interval: (%llu, %llu)\n",
ctx->clockid, (unsigned long long)ctx->ticks,
ctx->settime_flags,
(unsigned long long)t.it_value.tv_sec,
(unsigned long long)t.it_value.tv_nsec,
(unsigned long long)t.it_interval.tv_sec,
(unsigned long long)t.it_interval.tv_nsec);
}
#else
#define timerfd_show NULL
#endif
#ifdef CONFIG_CHECKPOINT_RESTORE
static long timerfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct timerfd_ctx *ctx = file->private_data;
int ret = 0;
switch (cmd) {
case TFD_IOC_SET_TICKS: {
u64 ticks;
if (copy_from_user(&ticks, (u64 __user *)arg, sizeof(ticks)))
return -EFAULT;
if (!ticks)
return -EINVAL;
spin_lock_irq(&ctx->wqh.lock);
if (!timerfd_canceled(ctx)) {
ctx->ticks = ticks;
if (ticks)
wake_up_locked(&ctx->wqh);
} else
ret = -ECANCELED;
spin_unlock_irq(&ctx->wqh.lock);
break;
}
default:
ret = -ENOTTY;
break;
}
return ret;
}
#else
#define timerfd_ioctl NULL
#endif
static const struct file_operations timerfd_fops = { static const struct file_operations timerfd_fops = {
.release = timerfd_release, .release = timerfd_release,
.poll = timerfd_poll, .poll = timerfd_poll,
.read = timerfd_read, .read = timerfd_read,
.llseek = noop_llseek, .llseek = noop_llseek,
.show_fdinfo = timerfd_show,
.unlocked_ioctl = timerfd_ioctl,
}; };
static int timerfd_fget(int fd, struct fd *p) static int timerfd_fget(int fd, struct fd *p)
@ -336,7 +405,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
else else
hrtimer_init(&ctx->t.tmr, clockid, HRTIMER_MODE_ABS); hrtimer_init(&ctx->t.tmr, clockid, HRTIMER_MODE_ABS);
ctx->moffs = ktime_get_monotonic_offset(); ctx->moffs = ktime_mono_to_real((ktime_t){ .tv64 = 0 });
ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx, ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx,
O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS)); O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS));

18
include/clocksource/pxa.h Normal file
View File

@ -0,0 +1,18 @@
/*
* PXA clocksource, clockevents, and OST interrupt handlers.
*
* Copyright (C) 2014 Robert Jarzmik
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
*/
#ifndef _CLOCKSOURCE_PXA_H
#define _CLOCKSOURCE_PXA_H
extern void pxa_timer_nodt_init(int irq, void __iomem *base,
unsigned long clock_tick_rate);
#endif

View File

@ -162,7 +162,6 @@ extern u64 timecounter_cyc2time(struct timecounter *tc,
* @archdata: arch-specific data * @archdata: arch-specific data
* @suspend: suspend function for the clocksource, if necessary * @suspend: suspend function for the clocksource, if necessary
* @resume: resume function for the clocksource, if necessary * @resume: resume function for the clocksource, if necessary
* @cycle_last: most recent cycle counter value seen by ::read()
* @owner: module reference, must be set by clocksource in modules * @owner: module reference, must be set by clocksource in modules
*/ */
struct clocksource { struct clocksource {
@ -171,7 +170,6 @@ struct clocksource {
* clocksource itself is cacheline aligned. * clocksource itself is cacheline aligned.
*/ */
cycle_t (*read)(struct clocksource *cs); cycle_t (*read)(struct clocksource *cs);
cycle_t cycle_last;
cycle_t mask; cycle_t mask;
u32 mult; u32 mult;
u32 shift; u32 shift;

View File

@ -165,6 +165,7 @@ enum hrtimer_base_type {
* struct hrtimer_cpu_base - the per cpu clock bases * struct hrtimer_cpu_base - the per cpu clock bases
* @lock: lock protecting the base and associated clock bases * @lock: lock protecting the base and associated clock bases
* and timers * and timers
* @cpu: cpu number
* @active_bases: Bitfield to mark bases with active timers * @active_bases: Bitfield to mark bases with active timers
* @clock_was_set: Indicates that clock was set from irq context. * @clock_was_set: Indicates that clock was set from irq context.
* @expires_next: absolute time of the next event which was scheduled * @expires_next: absolute time of the next event which was scheduled
@ -179,6 +180,7 @@ enum hrtimer_base_type {
*/ */
struct hrtimer_cpu_base { struct hrtimer_cpu_base {
raw_spinlock_t lock; raw_spinlock_t lock;
unsigned int cpu;
unsigned int active_bases; unsigned int active_bases;
unsigned int clock_was_set; unsigned int clock_was_set;
#ifdef CONFIG_HIGH_RES_TIMERS #ifdef CONFIG_HIGH_RES_TIMERS
@ -324,14 +326,6 @@ static inline void timerfd_clock_was_set(void) { }
#endif #endif
extern void hrtimers_resume(void); extern void hrtimers_resume(void);
extern ktime_t ktime_get(void);
extern ktime_t ktime_get_real(void);
extern ktime_t ktime_get_boottime(void);
extern ktime_t ktime_get_monotonic_offset(void);
extern ktime_t ktime_get_clocktai(void);
extern ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot,
ktime_t *offs_tai);
DECLARE_PER_CPU(struct tick_device, tick_cpu_device); DECLARE_PER_CPU(struct tick_device, tick_cpu_device);
@ -452,12 +446,6 @@ extern void hrtimer_run_pending(void);
/* Bootup initialization: */ /* Bootup initialization: */
extern void __init hrtimers_init(void); extern void __init hrtimers_init(void);
#if BITS_PER_LONG < 64
extern u64 ktime_divns(const ktime_t kt, s64 div);
#else /* BITS_PER_LONG < 64 */
# define ktime_divns(kt, div) (u64)((kt).tv64 / (div))
#endif
/* Show pending timers: */ /* Show pending timers: */
extern void sysrq_timer_list_show(void); extern void sysrq_timer_list_show(void);

View File

@ -277,14 +277,7 @@ static inline bool iio_channel_has_info(const struct iio_chan_spec *chan,
**/ **/
static inline s64 iio_get_time_ns(void) static inline s64 iio_get_time_ns(void)
{ {
struct timespec ts; return ktime_get_real_ns();
/*
* calls getnstimeofday.
* If hrtimers then up to ns accurate, if not microsecond.
*/
ktime_get_real_ts(&ts);
return timespec_to_ns(&ts);
} }
/* Device operating modes */ /* Device operating modes */

View File

@ -58,6 +58,8 @@ static inline void devm_ioport_unmap(struct device *dev, void __iomem *addr)
} }
#endif #endif
#define IOMEM_ERR_PTR(err) (__force void __iomem *)ERR_PTR(err)
void __iomem *devm_ioremap(struct device *dev, resource_size_t offset, void __iomem *devm_ioremap(struct device *dev, resource_size_t offset,
unsigned long size); unsigned long size);
void __iomem *devm_ioremap_nocache(struct device *dev, resource_size_t offset, void __iomem *devm_ioremap_nocache(struct device *dev, resource_size_t offset,

View File

@ -27,43 +27,19 @@
/* /*
* ktime_t: * ktime_t:
* *
* On 64-bit CPUs a single 64-bit variable is used to store the hrtimers * A single 64-bit variable is used to store the hrtimers
* internal representation of time values in scalar nanoseconds. The * internal representation of time values in scalar nanoseconds. The
* design plays out best on 64-bit CPUs, where most conversions are * design plays out best on 64-bit CPUs, where most conversions are
* NOPs and most arithmetic ktime_t operations are plain arithmetic * NOPs and most arithmetic ktime_t operations are plain arithmetic
* operations. * operations.
* *
* On 32-bit CPUs an optimized representation of the timespec structure
* is used to avoid expensive conversions from and to timespecs. The
* endian-aware order of the tv struct members is chosen to allow
* mathematical operations on the tv64 member of the union too, which
* for certain operations produces better code.
*
* For architectures with efficient support for 64/32-bit conversions the
* plain scalar nanosecond based representation can be selected by the
* config switch CONFIG_KTIME_SCALAR.
*/ */
union ktime { union ktime {
s64 tv64; s64 tv64;
#if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR)
struct {
# ifdef __BIG_ENDIAN
s32 sec, nsec;
# else
s32 nsec, sec;
# endif
} tv;
#endif
}; };
typedef union ktime ktime_t; /* Kill this */ typedef union ktime ktime_t; /* Kill this */
/*
* ktime_t definitions when using the 64-bit scalar representation:
*/
#if (BITS_PER_LONG == 64) || defined(CONFIG_KTIME_SCALAR)
/** /**
* ktime_set - Set a ktime_t variable from a seconds/nanoseconds value * ktime_set - Set a ktime_t variable from a seconds/nanoseconds value
* @secs: seconds to set * @secs: seconds to set
@ -71,13 +47,12 @@ typedef union ktime ktime_t; /* Kill this */
* *
* Return: The ktime_t representation of the value. * Return: The ktime_t representation of the value.
*/ */
static inline ktime_t ktime_set(const long secs, const unsigned long nsecs) static inline ktime_t ktime_set(const s64 secs, const unsigned long nsecs)
{ {
#if (BITS_PER_LONG == 64)
if (unlikely(secs >= KTIME_SEC_MAX)) if (unlikely(secs >= KTIME_SEC_MAX))
return (ktime_t){ .tv64 = KTIME_MAX }; return (ktime_t){ .tv64 = KTIME_MAX };
#endif
return (ktime_t) { .tv64 = (s64)secs * NSEC_PER_SEC + (s64)nsecs }; return (ktime_t) { .tv64 = secs * NSEC_PER_SEC + (s64)nsecs };
} }
/* Subtract two ktime_t variables. rem = lhs -rhs: */ /* Subtract two ktime_t variables. rem = lhs -rhs: */
@ -108,6 +83,12 @@ static inline ktime_t timespec_to_ktime(struct timespec ts)
return ktime_set(ts.tv_sec, ts.tv_nsec); return ktime_set(ts.tv_sec, ts.tv_nsec);
} }
/* convert a timespec64 to ktime_t format: */
static inline ktime_t timespec64_to_ktime(struct timespec64 ts)
{
return ktime_set(ts.tv_sec, ts.tv_nsec);
}
/* convert a timeval to ktime_t format: */ /* convert a timeval to ktime_t format: */
static inline ktime_t timeval_to_ktime(struct timeval tv) static inline ktime_t timeval_to_ktime(struct timeval tv)
{ {
@ -117,159 +98,15 @@ static inline ktime_t timeval_to_ktime(struct timeval tv)
/* Map the ktime_t to timespec conversion to ns_to_timespec function */ /* Map the ktime_t to timespec conversion to ns_to_timespec function */
#define ktime_to_timespec(kt) ns_to_timespec((kt).tv64) #define ktime_to_timespec(kt) ns_to_timespec((kt).tv64)
/* Map the ktime_t to timespec conversion to ns_to_timespec function */
#define ktime_to_timespec64(kt) ns_to_timespec64((kt).tv64)
/* Map the ktime_t to timeval conversion to ns_to_timeval function */ /* Map the ktime_t to timeval conversion to ns_to_timeval function */
#define ktime_to_timeval(kt) ns_to_timeval((kt).tv64) #define ktime_to_timeval(kt) ns_to_timeval((kt).tv64)
/* Convert ktime_t to nanoseconds - NOP in the scalar storage format: */ /* Convert ktime_t to nanoseconds - NOP in the scalar storage format: */
#define ktime_to_ns(kt) ((kt).tv64) #define ktime_to_ns(kt) ((kt).tv64)
#else /* !((BITS_PER_LONG == 64) || defined(CONFIG_KTIME_SCALAR)) */
/*
* Helper macros/inlines to get the ktime_t math right in the timespec
* representation. The macros are sometimes ugly - their actual use is
* pretty okay-ish, given the circumstances. We do all this for
* performance reasons. The pure scalar nsec_t based code was nice and
* simple, but created too many 64-bit / 32-bit conversions and divisions.
*
* Be especially aware that negative values are represented in a way
* that the tv.sec field is negative and the tv.nsec field is greater
* or equal to zero but less than nanoseconds per second. This is the
* same representation which is used by timespecs.
*
* tv.sec < 0 and 0 >= tv.nsec < NSEC_PER_SEC
*/
/* Set a ktime_t variable to a value in sec/nsec representation: */
static inline ktime_t ktime_set(const long secs, const unsigned long nsecs)
{
return (ktime_t) { .tv = { .sec = secs, .nsec = nsecs } };
}
/**
* ktime_sub - subtract two ktime_t variables
* @lhs: minuend
* @rhs: subtrahend
*
* Return: The remainder of the subtraction.
*/
static inline ktime_t ktime_sub(const ktime_t lhs, const ktime_t rhs)
{
ktime_t res;
res.tv64 = lhs.tv64 - rhs.tv64;
if (res.tv.nsec < 0)
res.tv.nsec += NSEC_PER_SEC;
return res;
}
/**
* ktime_add - add two ktime_t variables
* @add1: addend1
* @add2: addend2
*
* Return: The sum of @add1 and @add2.
*/
static inline ktime_t ktime_add(const ktime_t add1, const ktime_t add2)
{
ktime_t res;
res.tv64 = add1.tv64 + add2.tv64;
/*
* performance trick: the (u32) -NSEC gives 0x00000000Fxxxxxxx
* so we subtract NSEC_PER_SEC and add 1 to the upper 32 bit.
*
* it's equivalent to:
* tv.nsec -= NSEC_PER_SEC
* tv.sec ++;
*/
if (res.tv.nsec >= NSEC_PER_SEC)
res.tv64 += (u32)-NSEC_PER_SEC;
return res;
}
/**
* ktime_add_ns - Add a scalar nanoseconds value to a ktime_t variable
* @kt: addend
* @nsec: the scalar nsec value to add
*
* Return: The sum of @kt and @nsec in ktime_t format.
*/
extern ktime_t ktime_add_ns(const ktime_t kt, u64 nsec);
/**
* ktime_sub_ns - Subtract a scalar nanoseconds value from a ktime_t variable
* @kt: minuend
* @nsec: the scalar nsec value to subtract
*
* Return: The subtraction of @nsec from @kt in ktime_t format.
*/
extern ktime_t ktime_sub_ns(const ktime_t kt, u64 nsec);
/**
* timespec_to_ktime - convert a timespec to ktime_t format
* @ts: the timespec variable to convert
*
* Return: A ktime_t variable with the converted timespec value.
*/
static inline ktime_t timespec_to_ktime(const struct timespec ts)
{
return (ktime_t) { .tv = { .sec = (s32)ts.tv_sec,
.nsec = (s32)ts.tv_nsec } };
}
/**
* timeval_to_ktime - convert a timeval to ktime_t format
* @tv: the timeval variable to convert
*
* Return: A ktime_t variable with the converted timeval value.
*/
static inline ktime_t timeval_to_ktime(const struct timeval tv)
{
return (ktime_t) { .tv = { .sec = (s32)tv.tv_sec,
.nsec = (s32)(tv.tv_usec *
NSEC_PER_USEC) } };
}
/**
* ktime_to_timespec - convert a ktime_t variable to timespec format
* @kt: the ktime_t variable to convert
*
* Return: The timespec representation of the ktime value.
*/
static inline struct timespec ktime_to_timespec(const ktime_t kt)
{
return (struct timespec) { .tv_sec = (time_t) kt.tv.sec,
.tv_nsec = (long) kt.tv.nsec };
}
/**
* ktime_to_timeval - convert a ktime_t variable to timeval format
* @kt: the ktime_t variable to convert
*
* Return: The timeval representation of the ktime value.
*/
static inline struct timeval ktime_to_timeval(const ktime_t kt)
{
return (struct timeval) {
.tv_sec = (time_t) kt.tv.sec,
.tv_usec = (suseconds_t) (kt.tv.nsec / NSEC_PER_USEC) };
}
/**
* ktime_to_ns - convert a ktime_t variable to scalar nanoseconds
* @kt: the ktime_t variable to convert
*
* Return: The scalar nanoseconds representation of @kt.
*/
static inline s64 ktime_to_ns(const ktime_t kt)
{
return (s64) kt.tv.sec * NSEC_PER_SEC + kt.tv.nsec;
}
#endif /* !((BITS_PER_LONG == 64) || defined(CONFIG_KTIME_SCALAR)) */
/** /**
* ktime_equal - Compares two ktime_t variables to see if they are equal * ktime_equal - Compares two ktime_t variables to see if they are equal
@ -328,16 +165,20 @@ static inline bool ktime_before(const ktime_t cmp1, const ktime_t cmp2)
return ktime_compare(cmp1, cmp2) < 0; return ktime_compare(cmp1, cmp2) < 0;
} }
#if BITS_PER_LONG < 64
extern u64 ktime_divns(const ktime_t kt, s64 div);
#else /* BITS_PER_LONG < 64 */
# define ktime_divns(kt, div) (u64)((kt).tv64 / (div))
#endif
static inline s64 ktime_to_us(const ktime_t kt) static inline s64 ktime_to_us(const ktime_t kt)
{ {
struct timeval tv = ktime_to_timeval(kt); return ktime_divns(kt, NSEC_PER_USEC);
return (s64) tv.tv_sec * USEC_PER_SEC + tv.tv_usec;
} }
static inline s64 ktime_to_ms(const ktime_t kt) static inline s64 ktime_to_ms(const ktime_t kt)
{ {
struct timeval tv = ktime_to_timeval(kt); return ktime_divns(kt, NSEC_PER_MSEC);
return (s64) tv.tv_sec * MSEC_PER_SEC + tv.tv_usec / USEC_PER_MSEC;
} }
static inline s64 ktime_us_delta(const ktime_t later, const ktime_t earlier) static inline s64 ktime_us_delta(const ktime_t later, const ktime_t earlier)
@ -381,6 +222,25 @@ static inline __must_check bool ktime_to_timespec_cond(const ktime_t kt,
} }
} }
/**
* ktime_to_timespec64_cond - convert a ktime_t variable to timespec64
* format only if the variable contains data
* @kt: the ktime_t variable to convert
* @ts: the timespec variable to store the result in
*
* Return: %true if there was a successful conversion, %false if kt was 0.
*/
static inline __must_check bool ktime_to_timespec64_cond(const ktime_t kt,
struct timespec64 *ts)
{
if (kt.tv64) {
*ts = ktime_to_timespec64(kt);
return true;
} else {
return false;
}
}
/* /*
* The resolution of the clocks. The resolution value is returned in * The resolution of the clocks. The resolution value is returned in
* the clock_getres() system call to give application programmers an * the clock_getres() system call to give application programmers an
@ -390,12 +250,6 @@ static inline __must_check bool ktime_to_timespec_cond(const ktime_t kt,
#define LOW_RES_NSEC TICK_NSEC #define LOW_RES_NSEC TICK_NSEC
#define KTIME_LOW_RES (ktime_t){ .tv64 = LOW_RES_NSEC } #define KTIME_LOW_RES (ktime_t){ .tv64 = LOW_RES_NSEC }
/* Get the monotonic time in timespec format: */
extern void ktime_get_ts(struct timespec *ts);
/* Get the real (wall-) time in timespec format: */
#define ktime_get_real_ts(ts) getnstimeofday(ts)
static inline ktime_t ns_to_ktime(u64 ns) static inline ktime_t ns_to_ktime(u64 ns)
{ {
static const ktime_t ktime_zero = { .tv64 = 0 }; static const ktime_t ktime_zero = { .tv64 = 0 };
@ -410,4 +264,6 @@ static inline ktime_t ms_to_ktime(u64 ms)
return ktime_add_ms(ktime_zero, ms); return ktime_add_ms(ktime_zero, ms);
} }
# include <linux/timekeeping.h>
#endif #endif

View File

@ -604,8 +604,8 @@ struct mlx5_cmd_work_ent {
int page_queue; int page_queue;
u8 status; u8 status;
u8 token; u8 token;
struct timespec ts1; u64 ts1;
struct timespec ts2; u64 ts2;
u16 op; u16 op;
}; };

View File

@ -109,7 +109,12 @@ static inline bool of_dma_is_coherent(struct device_node *np)
extern int of_address_to_resource(struct device_node *dev, int index, extern int of_address_to_resource(struct device_node *dev, int index,
struct resource *r); struct resource *r);
void __iomem *of_iomap(struct device_node *node, int index); void __iomem *of_iomap(struct device_node *node, int index);
void __iomem *of_io_request_and_map(struct device_node *device,
int index, char *name);
#else #else
#include <linux/io.h>
static inline int of_address_to_resource(struct device_node *dev, int index, static inline int of_address_to_resource(struct device_node *dev, int index,
struct resource *r) struct resource *r)
{ {
@ -120,6 +125,12 @@ static inline void __iomem *of_iomap(struct device_node *device, int index)
{ {
return NULL; return NULL;
} }
static inline void __iomem *of_io_request_and_map(struct device_node *device,
int index, char *name)
{
return IOMEM_ERR_PTR(-EINVAL);
}
#endif #endif
#if defined(CONFIG_OF_ADDRESS) && defined(CONFIG_PCI) #if defined(CONFIG_OF_ADDRESS) && defined(CONFIG_PCI)

View File

@ -813,7 +813,7 @@ struct task_delay_info {
* associated with the operation is added to XXX_delay. * associated with the operation is added to XXX_delay.
* XXX_delay contains the accumulated delay time in nanoseconds. * XXX_delay contains the accumulated delay time in nanoseconds.
*/ */
struct timespec blkio_start, blkio_end; /* Shared by blkio, swapin */ u64 blkio_start; /* Shared by blkio, swapin */
u64 blkio_delay; /* wait for sync block io completion */ u64 blkio_delay; /* wait for sync block io completion */
u64 swapin_delay; /* wait for swapin block io completion */ u64 swapin_delay; /* wait for swapin block io completion */
u32 blkio_count; /* total count of the number of sync block */ u32 blkio_count; /* total count of the number of sync block */
@ -821,7 +821,7 @@ struct task_delay_info {
u32 swapin_count; /* total count of the number of swapin block */ u32 swapin_count; /* total count of the number of swapin block */
/* io operations performed */ /* io operations performed */
struct timespec freepages_start, freepages_end; u64 freepages_start;
u64 freepages_delay; /* wait for memory reclaim */ u64 freepages_delay; /* wait for memory reclaim */
u32 freepages_count; /* total count of memory reclaim */ u32 freepages_count; /* total count of memory reclaim */
}; };
@ -1364,8 +1364,8 @@ struct task_struct {
} vtime_snap_whence; } vtime_snap_whence;
#endif #endif
unsigned long nvcsw, nivcsw; /* context switch counts */ unsigned long nvcsw, nivcsw; /* context switch counts */
struct timespec start_time; /* monotonic time */ u64 start_time; /* monotonic time in nsec */
struct timespec real_start_time; /* boot based time */ u64 real_start_time; /* boot based time in nsec */
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */ /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
unsigned long min_flt, maj_flt; unsigned long min_flt, maj_flt;

View File

@ -116,6 +116,22 @@ repeat:
return ret; return ret;
} }
/**
* raw_read_seqcount - Read the raw seqcount
* @s: pointer to seqcount_t
* Returns: count to be passed to read_seqcount_retry
*
* raw_read_seqcount opens a read critical section of the given
* seqcount without any lockdep checking and without checking or
* masking the LSB. Calling code is responsible for handling that.
*/
static inline unsigned raw_read_seqcount(const seqcount_t *s)
{
unsigned ret = ACCESS_ONCE(s->sequence);
smp_rmb();
return ret;
}
/** /**
* raw_read_seqcount_begin - start seq-read critical section w/o lockdep * raw_read_seqcount_begin - start seq-read critical section w/o lockdep
* @s: pointer to seqcount_t * @s: pointer to seqcount_t
@ -217,6 +233,17 @@ static inline void raw_write_seqcount_end(seqcount_t *s)
s->sequence++; s->sequence++;
} }
/*
* raw_write_seqcount_latch - redirect readers to even/odd copy
* @s: pointer to seqcount_t
*/
static inline void raw_write_seqcount_latch(seqcount_t *s)
{
smp_wmb(); /* prior stores before incrementing "sequence" */
s->sequence++;
smp_wmb(); /* increment "sequence" before following stores */
}
/* /*
* Sequence counter only version assumes that callers are using their * Sequence counter only version assumes that callers are using their
* own mutexing. * own mutexing.

View File

@ -2,11 +2,6 @@
#define __SH_TIMER_H__ #define __SH_TIMER_H__
struct sh_timer_config { struct sh_timer_config {
char *name;
long channel_offset;
int timer_bit;
unsigned long clockevent_rating;
unsigned long clocksource_rating;
unsigned int channels_mask; unsigned int channels_mask;
}; };

View File

@ -4,19 +4,10 @@
# include <linux/cache.h> # include <linux/cache.h>
# include <linux/seqlock.h> # include <linux/seqlock.h>
# include <linux/math64.h> # include <linux/math64.h>
#include <uapi/linux/time.h> # include <linux/time64.h>
extern struct timezone sys_tz; extern struct timezone sys_tz;
/* Parameters used to convert the timespec values: */
#define MSEC_PER_SEC 1000L
#define USEC_PER_MSEC 1000L
#define NSEC_PER_USEC 1000L
#define NSEC_PER_MSEC 1000000L
#define USEC_PER_SEC 1000000L
#define NSEC_PER_SEC 1000000000L
#define FSEC_PER_SEC 1000000000000000LL
#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1) #define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
static inline int timespec_equal(const struct timespec *a, static inline int timespec_equal(const struct timespec *a,
@ -84,13 +75,6 @@ static inline struct timespec timespec_sub(struct timespec lhs,
return ts_delta; return ts_delta;
} }
#define KTIME_MAX ((s64)~((u64)1 << 63))
#if (BITS_PER_LONG == 64)
# define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC)
#else
# define KTIME_SEC_MAX LONG_MAX
#endif
/* /*
* Returns true if the timespec is norm, false if denorm: * Returns true if the timespec is norm, false if denorm:
*/ */
@ -115,27 +99,7 @@ static inline bool timespec_valid_strict(const struct timespec *ts)
return true; return true;
} }
extern bool persistent_clock_exist; extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
static inline bool has_persistent_clock(void)
{
return persistent_clock_exist;
}
extern void read_persistent_clock(struct timespec *ts);
extern void read_boot_clock(struct timespec *ts);
extern int persistent_clock_is_local;
extern int update_persistent_clock(struct timespec now);
void timekeeping_init(void);
extern int timekeeping_suspended;
unsigned long get_seconds(void);
struct timespec current_kernel_time(void);
struct timespec __current_kernel_time(void); /* does not take xtime_lock */
struct timespec get_monotonic_coarse(void);
void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim,
struct timespec *wtom, struct timespec *sleep);
void timekeeping_inject_sleeptime(struct timespec *delta);
#define CURRENT_TIME (current_kernel_time()) #define CURRENT_TIME (current_kernel_time())
#define CURRENT_TIME_SEC ((struct timespec) { get_seconds(), 0 }) #define CURRENT_TIME_SEC ((struct timespec) { get_seconds(), 0 })
@ -153,33 +117,14 @@ void timekeeping_inject_sleeptime(struct timespec *delta);
extern u32 (*arch_gettimeoffset)(void); extern u32 (*arch_gettimeoffset)(void);
#endif #endif
extern void do_gettimeofday(struct timeval *tv);
extern int do_settimeofday(const struct timespec *tv);
extern int do_sys_settimeofday(const struct timespec *tv,
const struct timezone *tz);
#define do_posix_clock_monotonic_gettime(ts) ktime_get_ts(ts)
extern long do_utimes(int dfd, const char __user *filename, struct timespec *times, int flags);
struct itimerval; struct itimerval;
extern int do_setitimer(int which, struct itimerval *value, extern int do_setitimer(int which, struct itimerval *value,
struct itimerval *ovalue); struct itimerval *ovalue);
extern unsigned int alarm_setitimer(unsigned int seconds);
extern int do_getitimer(int which, struct itimerval *value); extern int do_getitimer(int which, struct itimerval *value);
extern int __getnstimeofday(struct timespec *tv);
extern void getnstimeofday(struct timespec *tv);
extern void getrawmonotonic(struct timespec *ts);
extern void getnstime_raw_and_real(struct timespec *ts_raw,
struct timespec *ts_real);
extern void getboottime(struct timespec *ts);
extern void monotonic_to_bootbased(struct timespec *ts);
extern void get_monotonic_boottime(struct timespec *ts);
extern struct timespec timespec_trunc(struct timespec t, unsigned gran); extern unsigned int alarm_setitimer(unsigned int seconds);
extern int timekeeping_valid_for_hres(void);
extern u64 timekeeping_max_deferment(void); extern long do_utimes(int dfd, const char __user *filename, struct timespec *times, int flags);
extern int timekeeping_inject_offset(struct timespec *ts);
extern s32 timekeeping_get_tai_offset(void);
extern void timekeeping_set_tai_offset(s32 tai_offset);
extern void timekeeping_clocktai(struct timespec *ts);
struct tms; struct tms;
extern void do_sys_times(struct tms *); extern void do_sys_times(struct tms *);

190
include/linux/time64.h Normal file
View File

@ -0,0 +1,190 @@
#ifndef _LINUX_TIME64_H
#define _LINUX_TIME64_H
#include <uapi/linux/time.h>
typedef __s64 time64_t;
/*
* This wants to go into uapi/linux/time.h once we agreed about the
* userspace interfaces.
*/
#if __BITS_PER_LONG == 64
# define timespec64 timespec
#else
struct timespec64 {
time64_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
#endif
/* Parameters used to convert the timespec values: */
#define MSEC_PER_SEC 1000L
#define USEC_PER_MSEC 1000L
#define NSEC_PER_USEC 1000L
#define NSEC_PER_MSEC 1000000L
#define USEC_PER_SEC 1000000L
#define NSEC_PER_SEC 1000000000L
#define FSEC_PER_SEC 1000000000000000LL
/* Located here for timespec[64]_valid_strict */
#define KTIME_MAX ((s64)~((u64)1 << 63))
#define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC)
#if __BITS_PER_LONG == 64
static inline struct timespec timespec64_to_timespec(const struct timespec64 ts64)
{
return ts64;
}
static inline struct timespec64 timespec_to_timespec64(const struct timespec ts)
{
return ts;
}
# define timespec64_equal timespec_equal
# define timespec64_compare timespec_compare
# define set_normalized_timespec64 set_normalized_timespec
# define timespec64_add_safe timespec_add_safe
# define timespec64_add timespec_add
# define timespec64_sub timespec_sub
# define timespec64_valid timespec_valid
# define timespec64_valid_strict timespec_valid_strict
# define timespec64_to_ns timespec_to_ns
# define ns_to_timespec64 ns_to_timespec
# define timespec64_add_ns timespec_add_ns
#else
static inline struct timespec timespec64_to_timespec(const struct timespec64 ts64)
{
struct timespec ret;
ret.tv_sec = (time_t)ts64.tv_sec;
ret.tv_nsec = ts64.tv_nsec;
return ret;
}
static inline struct timespec64 timespec_to_timespec64(const struct timespec ts)
{
struct timespec64 ret;
ret.tv_sec = ts.tv_sec;
ret.tv_nsec = ts.tv_nsec;
return ret;
}
static inline int timespec64_equal(const struct timespec64 *a,
const struct timespec64 *b)
{
return (a->tv_sec == b->tv_sec) && (a->tv_nsec == b->tv_nsec);
}
/*
* lhs < rhs: return <0
* lhs == rhs: return 0
* lhs > rhs: return >0
*/
static inline int timespec64_compare(const struct timespec64 *lhs, const struct timespec64 *rhs)
{
if (lhs->tv_sec < rhs->tv_sec)
return -1;
if (lhs->tv_sec > rhs->tv_sec)
return 1;
return lhs->tv_nsec - rhs->tv_nsec;
}
extern void set_normalized_timespec64(struct timespec64 *ts, time64_t sec, s64 nsec);
/*
* timespec64_add_safe assumes both values are positive and checks for
* overflow. It will return TIME_T_MAX if the returned value would be
* smaller then either of the arguments.
*/
extern struct timespec64 timespec64_add_safe(const struct timespec64 lhs,
const struct timespec64 rhs);
static inline struct timespec64 timespec64_add(struct timespec64 lhs,
struct timespec64 rhs)
{
struct timespec64 ts_delta;
set_normalized_timespec64(&ts_delta, lhs.tv_sec + rhs.tv_sec,
lhs.tv_nsec + rhs.tv_nsec);
return ts_delta;
}
/*
* sub = lhs - rhs, in normalized form
*/
static inline struct timespec64 timespec64_sub(struct timespec64 lhs,
struct timespec64 rhs)
{
struct timespec64 ts_delta;
set_normalized_timespec64(&ts_delta, lhs.tv_sec - rhs.tv_sec,
lhs.tv_nsec - rhs.tv_nsec);
return ts_delta;
}
/*
* Returns true if the timespec64 is norm, false if denorm:
*/
static inline bool timespec64_valid(const struct timespec64 *ts)
{
/* Dates before 1970 are bogus */
if (ts->tv_sec < 0)
return false;
/* Can't have more nanoseconds then a second */
if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC)
return false;
return true;
}
static inline bool timespec64_valid_strict(const struct timespec64 *ts)
{
if (!timespec64_valid(ts))
return false;
/* Disallow values that could overflow ktime_t */
if ((unsigned long long)ts->tv_sec >= KTIME_SEC_MAX)
return false;
return true;
}
/**
* timespec64_to_ns - Convert timespec64 to nanoseconds
* @ts: pointer to the timespec64 variable to be converted
*
* Returns the scalar nanosecond representation of the timespec64
* parameter.
*/
static inline s64 timespec64_to_ns(const struct timespec64 *ts)
{
return ((s64) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec;
}
/**
* ns_to_timespec64 - Convert nanoseconds to timespec64
* @nsec: the nanoseconds value to be converted
*
* Returns the timespec64 representation of the nsec parameter.
*/
extern struct timespec64 ns_to_timespec64(const s64 nsec);
/**
* timespec64_add_ns - Adds nanoseconds to a timespec64
* @a: pointer to timespec64 to be incremented
* @ns: unsigned nanoseconds value to be added
*
* This must always be inlined because its used from the x86-64 vdso,
* which cannot call other kernel functions.
*/
static __always_inline void timespec64_add_ns(struct timespec64 *a, u64 ns)
{
a->tv_sec += __iter_div_u64_rem(a->tv_nsec + ns, NSEC_PER_SEC, &ns);
a->tv_nsec = ns;
}
#endif
#endif /* _LINUX_TIME64_H */

View File

@ -10,77 +10,100 @@
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/time.h> #include <linux/time.h>
/* Structure holding internal timekeeping values. */ /**
struct timekeeper { * struct tk_read_base - base structure for timekeeping readout
/* Current clocksource used for timekeeping. */ * @clock: Current clocksource used for timekeeping.
* @read: Read function of @clock
* @mask: Bitmask for two's complement subtraction of non 64bit clocks
* @cycle_last: @clock cycle value at last update
* @mult: NTP adjusted multiplier for scaled math conversion
* @shift: Shift value for scaled math conversion
* @xtime_nsec: Shifted (fractional) nano seconds offset for readout
* @base_mono: ktime_t (nanoseconds) base time for readout
*
* This struct has size 56 byte on 64 bit. Together with a seqcount it
* occupies a single 64byte cache line.
*
* The struct is separate from struct timekeeper as it is also used
* for a fast NMI safe accessor to clock monotonic.
*/
struct tk_read_base {
struct clocksource *clock; struct clocksource *clock;
/* NTP adjusted clock multiplier */ cycle_t (*read)(struct clocksource *cs);
u32 mult; cycle_t mask;
/* The shift value of the current clocksource. */
u32 shift;
/* Number of clock cycles in one NTP interval. */
cycle_t cycle_interval;
/* Last cycle value (also stored in clock->cycle_last) */
cycle_t cycle_last; cycle_t cycle_last;
/* Number of clock shifted nano seconds in one NTP interval. */ u32 mult;
u64 xtime_interval; u32 shift;
/* shifted nano seconds left over when rounding cycle_interval */
s64 xtime_remainder;
/* Raw nano seconds accumulated per NTP interval. */
u32 raw_interval;
/* Current CLOCK_REALTIME time in seconds */
u64 xtime_sec;
/* Clock shifted nano seconds */
u64 xtime_nsec; u64 xtime_nsec;
ktime_t base_mono;
};
/**
* struct timekeeper - Structure holding internal timekeeping values.
* @tkr: The readout base structure
* @xtime_sec: Current CLOCK_REALTIME time in seconds
* @wall_to_monotonic: CLOCK_REALTIME to CLOCK_MONOTONIC offset
* @offs_real: Offset clock monotonic -> clock realtime
* @offs_boot: Offset clock monotonic -> clock boottime
* @offs_tai: Offset clock monotonic -> clock tai
* @tai_offset: The current UTC to TAI offset in seconds
* @base_raw: Monotonic raw base time in ktime_t format
* @raw_time: Monotonic raw base time in timespec64 format
* @cycle_interval: Number of clock cycles in one NTP interval
* @xtime_interval: Number of clock shifted nano seconds in one NTP
* interval.
* @xtime_remainder: Shifted nano seconds left over when rounding
* @cycle_interval
* @raw_interval: Raw nano seconds accumulated per NTP interval.
* @ntp_error: Difference between accumulated time and NTP time in ntp
* shifted nano seconds.
* @ntp_error_shift: Shift conversion between clock shifted nano seconds and
* ntp shifted nano seconds.
*
* Note: For timespec(64) based interfaces wall_to_monotonic is what
* we need to add to xtime (or xtime corrected for sub jiffie times)
* to get to monotonic time. Monotonic is pegged at zero at system
* boot time, so wall_to_monotonic will be negative, however, we will
* ALWAYS keep the tv_nsec part positive so we can use the usual
* normalization.
*
* wall_to_monotonic is moved after resume from suspend for the
* monotonic time not to jump. We need to add total_sleep_time to
* wall_to_monotonic to get the real boot based time offset.
*
* wall_to_monotonic is no longer the boot time, getboottime must be
* used instead.
*/
struct timekeeper {
struct tk_read_base tkr;
u64 xtime_sec;
struct timespec64 wall_to_monotonic;
ktime_t offs_real;
ktime_t offs_boot;
ktime_t offs_tai;
s32 tai_offset;
ktime_t base_raw;
struct timespec64 raw_time;
/* The following members are for timekeeping internal use */
cycle_t cycle_interval;
u64 xtime_interval;
s64 xtime_remainder;
u32 raw_interval;
/* The ntp_tick_length() value currently being used.
* This cached copy ensures we consistently apply the tick
* length for an entire tick, as ntp_tick_length may change
* mid-tick, and we don't want to apply that new value to
* the tick in progress.
*/
u64 ntp_tick;
/* Difference between accumulated time and NTP time in ntp /* Difference between accumulated time and NTP time in ntp
* shifted nano seconds. */ * shifted nano seconds. */
s64 ntp_error; s64 ntp_error;
/* Shift conversion between clock shifted nano seconds and
* ntp shifted nano seconds. */
u32 ntp_error_shift; u32 ntp_error_shift;
u32 ntp_err_mult;
/*
* wall_to_monotonic is what we need to add to xtime (or xtime corrected
* for sub jiffie times) to get to monotonic time. Monotonic is pegged
* at zero at system boot time, so wall_to_monotonic will be negative,
* however, we will ALWAYS keep the tv_nsec part positive so we can use
* the usual normalization.
*
* wall_to_monotonic is moved after resume from suspend for the
* monotonic time not to jump. We need to add total_sleep_time to
* wall_to_monotonic to get the real boot based time offset.
*
* - wall_to_monotonic is no longer the boot time, getboottime must be
* used instead.
*/
struct timespec wall_to_monotonic;
/* Offset clock monotonic -> clock realtime */
ktime_t offs_real;
/* time spent in suspend */
struct timespec total_sleep_time;
/* Offset clock monotonic -> clock boottime */
ktime_t offs_boot;
/* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */
struct timespec raw_time;
/* The current UTC to TAI offset in seconds */
s32 tai_offset;
/* Offset clock monotonic -> clock tai */
ktime_t offs_tai;
}; };
static inline struct timespec tk_xtime(struct timekeeper *tk)
{
struct timespec ts;
ts.tv_sec = tk->xtime_sec;
ts.tv_nsec = (long)(tk->xtime_nsec >> tk->shift);
return ts;
}
#ifdef CONFIG_GENERIC_TIME_VSYSCALL #ifdef CONFIG_GENERIC_TIME_VSYSCALL
extern void update_vsyscall(struct timekeeper *tk); extern void update_vsyscall(struct timekeeper *tk);
@ -89,17 +112,10 @@ extern void update_vsyscall_tz(void);
#elif defined(CONFIG_GENERIC_TIME_VSYSCALL_OLD) #elif defined(CONFIG_GENERIC_TIME_VSYSCALL_OLD)
extern void update_vsyscall_old(struct timespec *ts, struct timespec *wtm, extern void update_vsyscall_old(struct timespec *ts, struct timespec *wtm,
struct clocksource *c, u32 mult); struct clocksource *c, u32 mult,
cycle_t cycle_last);
extern void update_vsyscall_tz(void); extern void update_vsyscall_tz(void);
static inline void update_vsyscall(struct timekeeper *tk)
{
struct timespec xt;
xt = tk_xtime(tk);
update_vsyscall_old(&xt, &tk->wall_to_monotonic, tk->clock, tk->mult);
}
#else #else
static inline void update_vsyscall(struct timekeeper *tk) static inline void update_vsyscall(struct timekeeper *tk)

209
include/linux/timekeeping.h Normal file
View File

@ -0,0 +1,209 @@
#ifndef _LINUX_TIMEKEEPING_H
#define _LINUX_TIMEKEEPING_H
/* Included from linux/ktime.h */
void timekeeping_init(void);
extern int timekeeping_suspended;
/*
* Get and set timeofday
*/
extern void do_gettimeofday(struct timeval *tv);
extern int do_settimeofday(const struct timespec *tv);
extern int do_sys_settimeofday(const struct timespec *tv,
const struct timezone *tz);
/*
* Kernel time accessors
*/
unsigned long get_seconds(void);
struct timespec current_kernel_time(void);
/* does not take xtime_lock */
struct timespec __current_kernel_time(void);
/*
* timespec based interfaces
*/
struct timespec get_monotonic_coarse(void);
extern void getrawmonotonic(struct timespec *ts);
extern void ktime_get_ts64(struct timespec64 *ts);
extern int __getnstimeofday64(struct timespec64 *tv);
extern void getnstimeofday64(struct timespec64 *tv);
#if BITS_PER_LONG == 64
static inline int __getnstimeofday(struct timespec *ts)
{
return __getnstimeofday64(ts);
}
static inline void getnstimeofday(struct timespec *ts)
{
getnstimeofday64(ts);
}
static inline void ktime_get_ts(struct timespec *ts)
{
ktime_get_ts64(ts);
}
static inline void ktime_get_real_ts(struct timespec *ts)
{
getnstimeofday64(ts);
}
#else
static inline int __getnstimeofday(struct timespec *ts)
{
struct timespec64 ts64;
int ret = __getnstimeofday64(&ts64);
*ts = timespec64_to_timespec(ts64);
return ret;
}
static inline void getnstimeofday(struct timespec *ts)
{
struct timespec64 ts64;
getnstimeofday64(&ts64);
*ts = timespec64_to_timespec(ts64);
}
static inline void ktime_get_ts(struct timespec *ts)
{
struct timespec64 ts64;
ktime_get_ts64(&ts64);
*ts = timespec64_to_timespec(ts64);
}
static inline void ktime_get_real_ts(struct timespec *ts)
{
struct timespec64 ts64;
getnstimeofday64(&ts64);
*ts = timespec64_to_timespec(ts64);
}
#endif
extern void getboottime(struct timespec *ts);
#define do_posix_clock_monotonic_gettime(ts) ktime_get_ts(ts)
#define ktime_get_real_ts64(ts) getnstimeofday64(ts)
/*
* ktime_t based interfaces
*/
enum tk_offsets {
TK_OFFS_REAL,
TK_OFFS_BOOT,
TK_OFFS_TAI,
TK_OFFS_MAX,
};
extern ktime_t ktime_get(void);
extern ktime_t ktime_get_with_offset(enum tk_offsets offs);
extern ktime_t ktime_mono_to_any(ktime_t tmono, enum tk_offsets offs);
extern ktime_t ktime_get_raw(void);
/**
* ktime_get_real - get the real (wall-) time in ktime_t format
*/
static inline ktime_t ktime_get_real(void)
{
return ktime_get_with_offset(TK_OFFS_REAL);
}
/**
* ktime_get_boottime - Returns monotonic time since boot in ktime_t format
*
* This is similar to CLOCK_MONTONIC/ktime_get, but also includes the
* time spent in suspend.
*/
static inline ktime_t ktime_get_boottime(void)
{
return ktime_get_with_offset(TK_OFFS_BOOT);
}
/**
* ktime_get_clocktai - Returns the TAI time of day in ktime_t format
*/
static inline ktime_t ktime_get_clocktai(void)
{
return ktime_get_with_offset(TK_OFFS_TAI);
}
/**
* ktime_mono_to_real - Convert monotonic time to clock realtime
*/
static inline ktime_t ktime_mono_to_real(ktime_t mono)
{
return ktime_mono_to_any(mono, TK_OFFS_REAL);
}
static inline u64 ktime_get_ns(void)
{
return ktime_to_ns(ktime_get());
}
static inline u64 ktime_get_real_ns(void)
{
return ktime_to_ns(ktime_get_real());
}
static inline u64 ktime_get_boot_ns(void)
{
return ktime_to_ns(ktime_get_boottime());
}
static inline u64 ktime_get_raw_ns(void)
{
return ktime_to_ns(ktime_get_raw());
}
extern u64 ktime_get_mono_fast_ns(void);
/*
* Timespec interfaces utilizing the ktime based ones
*/
static inline void get_monotonic_boottime(struct timespec *ts)
{
*ts = ktime_to_timespec(ktime_get_boottime());
}
static inline void timekeeping_clocktai(struct timespec *ts)
{
*ts = ktime_to_timespec(ktime_get_clocktai());
}
/*
* RTC specific
*/
extern void timekeeping_inject_sleeptime(struct timespec *delta);
/*
* PPS accessor
*/
extern void getnstime_raw_and_real(struct timespec *ts_raw,
struct timespec *ts_real);
/*
* Persistent clock related interfaces
*/
extern bool persistent_clock_exist;
extern int persistent_clock_is_local;
static inline bool has_persistent_clock(void)
{
return persistent_clock_exist;
}
extern void read_persistent_clock(struct timespec *ts);
extern void read_boot_clock(struct timespec *ts);
extern int update_persistent_clock(struct timespec now);
#endif

View File

@ -11,6 +11,9 @@
/* For O_CLOEXEC and O_NONBLOCK */ /* For O_CLOEXEC and O_NONBLOCK */
#include <linux/fcntl.h> #include <linux/fcntl.h>
/* For _IO helpers */
#include <linux/ioctl.h>
/* /*
* CAREFUL: Check include/asm-generic/fcntl.h when defining * CAREFUL: Check include/asm-generic/fcntl.h when defining
* new flags, since they might collide with O_* ones. We want * new flags, since they might collide with O_* ones. We want
@ -29,4 +32,6 @@
/* Flags for timerfd_settime. */ /* Flags for timerfd_settime. */
#define TFD_SETTIME_FLAGS (TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET) #define TFD_SETTIME_FLAGS (TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET)
#define TFD_IOC_SET_TICKS _IOW('T', 0, u64)
#endif /* _LINUX_TIMERFD_H */ #endif /* _LINUX_TIMERFD_H */

View File

@ -3,12 +3,11 @@
# #
obj-y = fork.o exec_domain.o panic.o \ obj-y = fork.o exec_domain.o panic.o \
cpu.o exit.o itimer.o time.o softirq.o resource.o \ cpu.o exit.o softirq.o resource.o \
sysctl.o sysctl_binary.o capability.o ptrace.o timer.o user.o \ sysctl.o sysctl_binary.o capability.o ptrace.o user.o \
signal.o sys.o kmod.o workqueue.o pid.o task_work.o \ signal.o sys.o kmod.o workqueue.o pid.o task_work.o \
extable.o params.o posix-timers.o \ extable.o params.o \
kthread.o sys_ni.o posix-cpu-timers.o \ kthread.o sys_ni.o nsproxy.o \
hrtimer.o nsproxy.o \
notifier.o ksysfs.o cred.o reboot.o \ notifier.o ksysfs.o cred.o reboot.o \
async.o range.o groups.o smpboot.o async.o range.o groups.o smpboot.o
@ -110,22 +109,6 @@ targets += config_data.h
$(obj)/config_data.h: $(obj)/config_data.gz FORCE $(obj)/config_data.h: $(obj)/config_data.gz FORCE
$(call filechk,ikconfiggz) $(call filechk,ikconfiggz)
$(obj)/time.o: $(obj)/timeconst.h
quiet_cmd_hzfile = HZFILE $@
cmd_hzfile = echo "hz=$(CONFIG_HZ)" > $@
targets += hz.bc
$(obj)/hz.bc: $(objtree)/include/config/hz.h FORCE
$(call if_changed,hzfile)
quiet_cmd_bc = BC $@
cmd_bc = bc -q $(filter-out FORCE,$^) > $@
targets += timeconst.h
$(obj)/timeconst.h: $(obj)/hz.bc $(src)/timeconst.bc FORCE
$(call if_changed,bc)
############################################################################### ###############################################################################
# #
# Roll all the X.509 certificates that we can find together and pull them into # Roll all the X.509 certificates that we can find together and pull them into

View File

@ -458,9 +458,7 @@ static void do_acct_process(struct bsd_acct_struct *acct,
acct_t ac; acct_t ac;
mm_segment_t fs; mm_segment_t fs;
unsigned long flim; unsigned long flim;
u64 elapsed; u64 elapsed, run_time;
u64 run_time;
struct timespec uptime;
struct tty_struct *tty; struct tty_struct *tty;
const struct cred *orig_cred; const struct cred *orig_cred;
@ -484,10 +482,8 @@ static void do_acct_process(struct bsd_acct_struct *acct,
strlcpy(ac.ac_comm, current->comm, sizeof(ac.ac_comm)); strlcpy(ac.ac_comm, current->comm, sizeof(ac.ac_comm));
/* calculate run_time in nsec*/ /* calculate run_time in nsec*/
do_posix_clock_monotonic_gettime(&uptime); run_time = ktime_get_ns();
run_time = (u64)uptime.tv_sec*NSEC_PER_SEC + uptime.tv_nsec; run_time -= current->group_leader->start_time;
run_time -= (u64)current->group_leader->start_time.tv_sec * NSEC_PER_SEC
+ current->group_leader->start_time.tv_nsec;
/* convert nsec -> AHZ */ /* convert nsec -> AHZ */
elapsed = nsec_to_AHZ(run_time); elapsed = nsec_to_AHZ(run_time);
#if ACCT_VERSION==3 #if ACCT_VERSION==3

View File

@ -2472,7 +2472,7 @@ static void kdb_gmtime(struct timespec *tv, struct kdb_tm *tm)
static void kdb_sysinfo(struct sysinfo *val) static void kdb_sysinfo(struct sysinfo *val)
{ {
struct timespec uptime; struct timespec uptime;
do_posix_clock_monotonic_gettime(&uptime); ktime_get_ts(&uptime);
memset(val, 0, sizeof(*val)); memset(val, 0, sizeof(*val));
val->uptime = uptime.tv_sec; val->uptime = uptime.tv_sec;
val->loads[0] = avenrun[0]; val->loads[0] = avenrun[0];

View File

@ -46,42 +46,25 @@ void __delayacct_tsk_init(struct task_struct *tsk)
} }
/* /*
* Start accounting for a delay statistic using * Finish delay accounting for a statistic using its timestamps (@start),
* its starting timestamp (@start) * accumalator (@total) and @count
*/ */
static void delayacct_end(u64 *start, u64 *total, u32 *count)
static inline void delayacct_start(struct timespec *start)
{ {
do_posix_clock_monotonic_gettime(start); s64 ns = ktime_get_ns() - *start;
}
/*
* Finish delay accounting for a statistic using
* its timestamps (@start, @end), accumalator (@total) and @count
*/
static void delayacct_end(struct timespec *start, struct timespec *end,
u64 *total, u32 *count)
{
struct timespec ts;
s64 ns;
unsigned long flags; unsigned long flags;
do_posix_clock_monotonic_gettime(end); if (ns > 0) {
ts = timespec_sub(*end, *start); spin_lock_irqsave(&current->delays->lock, flags);
ns = timespec_to_ns(&ts); *total += ns;
if (ns < 0) (*count)++;
return; spin_unlock_irqrestore(&current->delays->lock, flags);
}
spin_lock_irqsave(&current->delays->lock, flags);
*total += ns;
(*count)++;
spin_unlock_irqrestore(&current->delays->lock, flags);
} }
void __delayacct_blkio_start(void) void __delayacct_blkio_start(void)
{ {
delayacct_start(&current->delays->blkio_start); current->delays->blkio_start = ktime_get_ns();
} }
void __delayacct_blkio_end(void) void __delayacct_blkio_end(void)
@ -89,35 +72,29 @@ void __delayacct_blkio_end(void)
if (current->delays->flags & DELAYACCT_PF_SWAPIN) if (current->delays->flags & DELAYACCT_PF_SWAPIN)
/* Swapin block I/O */ /* Swapin block I/O */
delayacct_end(&current->delays->blkio_start, delayacct_end(&current->delays->blkio_start,
&current->delays->blkio_end,
&current->delays->swapin_delay, &current->delays->swapin_delay,
&current->delays->swapin_count); &current->delays->swapin_count);
else /* Other block I/O */ else /* Other block I/O */
delayacct_end(&current->delays->blkio_start, delayacct_end(&current->delays->blkio_start,
&current->delays->blkio_end,
&current->delays->blkio_delay, &current->delays->blkio_delay,
&current->delays->blkio_count); &current->delays->blkio_count);
} }
int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk) int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk)
{ {
s64 tmp;
unsigned long t1;
unsigned long long t2, t3;
unsigned long flags;
struct timespec ts;
cputime_t utime, stime, stimescaled, utimescaled; cputime_t utime, stime, stimescaled, utimescaled;
unsigned long long t2, t3;
unsigned long flags, t1;
s64 tmp;
tmp = (s64)d->cpu_run_real_total;
task_cputime(tsk, &utime, &stime); task_cputime(tsk, &utime, &stime);
cputime_to_timespec(utime + stime, &ts); tmp = (s64)d->cpu_run_real_total;
tmp += timespec_to_ns(&ts); tmp += cputime_to_nsecs(utime + stime);
d->cpu_run_real_total = (tmp < (s64)d->cpu_run_real_total) ? 0 : tmp; d->cpu_run_real_total = (tmp < (s64)d->cpu_run_real_total) ? 0 : tmp;
tmp = (s64)d->cpu_scaled_run_real_total;
task_cputime_scaled(tsk, &utimescaled, &stimescaled); task_cputime_scaled(tsk, &utimescaled, &stimescaled);
cputime_to_timespec(utimescaled + stimescaled, &ts); tmp = (s64)d->cpu_scaled_run_real_total;
tmp += timespec_to_ns(&ts); tmp += cputime_to_nsecs(utimescaled + stimescaled);
d->cpu_scaled_run_real_total = d->cpu_scaled_run_real_total =
(tmp < (s64)d->cpu_scaled_run_real_total) ? 0 : tmp; (tmp < (s64)d->cpu_scaled_run_real_total) ? 0 : tmp;
@ -169,13 +146,12 @@ __u64 __delayacct_blkio_ticks(struct task_struct *tsk)
void __delayacct_freepages_start(void) void __delayacct_freepages_start(void)
{ {
delayacct_start(&current->delays->freepages_start); current->delays->freepages_start = ktime_get_ns();
} }
void __delayacct_freepages_end(void) void __delayacct_freepages_end(void)
{ {
delayacct_end(&current->delays->freepages_start, delayacct_end(&current->delays->freepages_start,
&current->delays->freepages_end,
&current->delays->freepages_delay, &current->delays->freepages_delay,
&current->delays->freepages_count); &current->delays->freepages_count);
} }

View File

@ -1261,9 +1261,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
posix_cpu_timers_init(p); posix_cpu_timers_init(p);
do_posix_clock_monotonic_gettime(&p->start_time); p->start_time = ktime_get_ns();
p->real_start_time = p->start_time; p->real_start_time = ktime_get_boot_ns();
monotonic_to_bootbased(&p->real_start_time);
p->io_context = NULL; p->io_context = NULL;
p->audit_context = NULL; p->audit_context = NULL;
if (clone_flags & CLONE_THREAD) if (clone_flags & CLONE_THREAD)

View File

@ -12,6 +12,11 @@ config CLOCKSOURCE_WATCHDOG
config ARCH_CLOCKSOURCE_DATA config ARCH_CLOCKSOURCE_DATA
bool bool
# Clocksources require validation of the clocksource against the last
# cycle update - x86/TSC misfeature
config CLOCKSOURCE_VALIDATE_LAST_CYCLE
bool
# Timekeeping vsyscall support # Timekeeping vsyscall support
config GENERIC_TIME_VSYSCALL config GENERIC_TIME_VSYSCALL
bool bool
@ -20,10 +25,6 @@ config GENERIC_TIME_VSYSCALL
config GENERIC_TIME_VSYSCALL_OLD config GENERIC_TIME_VSYSCALL_OLD
bool bool
# ktime_t scalar 64bit nsec representation
config KTIME_SCALAR
bool
# Old style timekeeping # Old style timekeeping
config ARCH_USES_GETTIMEOFFSET config ARCH_USES_GETTIMEOFFSET
bool bool

View File

@ -1,3 +1,4 @@
obj-y += time.o timer.o hrtimer.o itimer.o posix-timers.o posix-cpu-timers.o
obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o
obj-y += timeconv.o posix-clock.o alarmtimer.o obj-y += timeconv.o posix-clock.o alarmtimer.o
@ -12,3 +13,21 @@ obj-$(CONFIG_TICK_ONESHOT) += tick-oneshot.o
obj-$(CONFIG_TICK_ONESHOT) += tick-sched.o obj-$(CONFIG_TICK_ONESHOT) += tick-sched.o
obj-$(CONFIG_TIMER_STATS) += timer_stats.o obj-$(CONFIG_TIMER_STATS) += timer_stats.o
obj-$(CONFIG_DEBUG_FS) += timekeeping_debug.o obj-$(CONFIG_DEBUG_FS) += timekeeping_debug.o
obj-$(CONFIG_TEST_UDELAY) += udelay_test.o
$(obj)/time.o: $(obj)/timeconst.h
quiet_cmd_hzfile = HZFILE $@
cmd_hzfile = echo "hz=$(CONFIG_HZ)" > $@
targets += hz.bc
$(obj)/hz.bc: $(objtree)/include/config/hz.h FORCE
$(call if_changed,hzfile)
quiet_cmd_bc = BC $@
cmd_bc = bc -q $(filter-out FORCE,$^) > $@
targets += timeconst.h
$(obj)/timeconst.h: $(obj)/hz.bc $(src)/timeconst.bc FORCE
$(call if_changed,bc)

View File

@ -32,6 +32,7 @@
#include <linux/kthread.h> #include <linux/kthread.h>
#include "tick-internal.h" #include "tick-internal.h"
#include "timekeeping_internal.h"
void timecounter_init(struct timecounter *tc, void timecounter_init(struct timecounter *tc,
const struct cyclecounter *cc, const struct cyclecounter *cc,
@ -249,7 +250,7 @@ void clocksource_mark_unstable(struct clocksource *cs)
static void clocksource_watchdog(unsigned long data) static void clocksource_watchdog(unsigned long data)
{ {
struct clocksource *cs; struct clocksource *cs;
cycle_t csnow, wdnow; cycle_t csnow, wdnow, delta;
int64_t wd_nsec, cs_nsec; int64_t wd_nsec, cs_nsec;
int next_cpu, reset_pending; int next_cpu, reset_pending;
@ -282,11 +283,12 @@ static void clocksource_watchdog(unsigned long data)
continue; continue;
} }
wd_nsec = clocksource_cyc2ns((wdnow - cs->wd_last) & watchdog->mask, delta = clocksource_delta(wdnow, cs->wd_last, watchdog->mask);
watchdog->mult, watchdog->shift); wd_nsec = clocksource_cyc2ns(delta, watchdog->mult,
watchdog->shift);
cs_nsec = clocksource_cyc2ns((csnow - cs->cs_last) & delta = clocksource_delta(csnow, cs->cs_last, cs->mask);
cs->mask, cs->mult, cs->shift); cs_nsec = clocksource_cyc2ns(delta, cs->mult, cs->shift);
cs->cs_last = csnow; cs->cs_last = csnow;
cs->wd_last = wdnow; cs->wd_last = wdnow;

View File

@ -54,6 +54,8 @@
#include <trace/events/timer.h> #include <trace/events/timer.h>
#include "timekeeping.h"
/* /*
* The timer bases: * The timer bases:
* *
@ -114,21 +116,18 @@ static inline int hrtimer_clockid_to_base(clockid_t clock_id)
*/ */
static void hrtimer_get_softirq_time(struct hrtimer_cpu_base *base) static void hrtimer_get_softirq_time(struct hrtimer_cpu_base *base)
{ {
ktime_t xtim, mono, boot; ktime_t xtim, mono, boot, tai;
struct timespec xts, tom, slp; ktime_t off_real, off_boot, off_tai;
s32 tai_offset;
get_xtime_and_monotonic_and_sleep_offset(&xts, &tom, &slp); mono = ktime_get_update_offsets_tick(&off_real, &off_boot, &off_tai);
tai_offset = timekeeping_get_tai_offset(); boot = ktime_add(mono, off_boot);
xtim = ktime_add(mono, off_real);
tai = ktime_add(xtim, off_tai);
xtim = timespec_to_ktime(xts);
mono = ktime_add(xtim, timespec_to_ktime(tom));
boot = ktime_add(mono, timespec_to_ktime(slp));
base->clock_base[HRTIMER_BASE_REALTIME].softirq_time = xtim; base->clock_base[HRTIMER_BASE_REALTIME].softirq_time = xtim;
base->clock_base[HRTIMER_BASE_MONOTONIC].softirq_time = mono; base->clock_base[HRTIMER_BASE_MONOTONIC].softirq_time = mono;
base->clock_base[HRTIMER_BASE_BOOTTIME].softirq_time = boot; base->clock_base[HRTIMER_BASE_BOOTTIME].softirq_time = boot;
base->clock_base[HRTIMER_BASE_TAI].softirq_time = base->clock_base[HRTIMER_BASE_TAI].softirq_time = tai;
ktime_add(xtim, ktime_set(tai_offset, 0));
} }
/* /*
@ -264,60 +263,6 @@ lock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags)
* too large for inlining: * too large for inlining:
*/ */
#if BITS_PER_LONG < 64 #if BITS_PER_LONG < 64
# ifndef CONFIG_KTIME_SCALAR
/**
* ktime_add_ns - Add a scalar nanoseconds value to a ktime_t variable
* @kt: addend
* @nsec: the scalar nsec value to add
*
* Returns the sum of kt and nsec in ktime_t format
*/
ktime_t ktime_add_ns(const ktime_t kt, u64 nsec)
{
ktime_t tmp;
if (likely(nsec < NSEC_PER_SEC)) {
tmp.tv64 = nsec;
} else {
unsigned long rem = do_div(nsec, NSEC_PER_SEC);
/* Make sure nsec fits into long */
if (unlikely(nsec > KTIME_SEC_MAX))
return (ktime_t){ .tv64 = KTIME_MAX };
tmp = ktime_set((long)nsec, rem);
}
return ktime_add(kt, tmp);
}
EXPORT_SYMBOL_GPL(ktime_add_ns);
/**
* ktime_sub_ns - Subtract a scalar nanoseconds value from a ktime_t variable
* @kt: minuend
* @nsec: the scalar nsec value to subtract
*
* Returns the subtraction of @nsec from @kt in ktime_t format
*/
ktime_t ktime_sub_ns(const ktime_t kt, u64 nsec)
{
ktime_t tmp;
if (likely(nsec < NSEC_PER_SEC)) {
tmp.tv64 = nsec;
} else {
unsigned long rem = do_div(nsec, NSEC_PER_SEC);
tmp = ktime_set((long)nsec, rem);
}
return ktime_sub(kt, tmp);
}
EXPORT_SYMBOL_GPL(ktime_sub_ns);
# endif /* !CONFIG_KTIME_SCALAR */
/* /*
* Divide a ktime value by a nanosecond value * Divide a ktime value by a nanosecond value
*/ */
@ -337,6 +282,7 @@ u64 ktime_divns(const ktime_t kt, s64 div)
return dclc; return dclc;
} }
EXPORT_SYMBOL_GPL(ktime_divns);
#endif /* BITS_PER_LONG >= 64 */ #endif /* BITS_PER_LONG >= 64 */
/* /*
@ -602,6 +548,11 @@ hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal)
* timers, we have to check, whether it expires earlier than the timer for * timers, we have to check, whether it expires earlier than the timer for
* which the clock event device was armed. * which the clock event device was armed.
* *
* Note, that in case the state has HRTIMER_STATE_CALLBACK set, no reprogramming
* and no expiry check happens. The timer gets enqueued into the rbtree. The
* reprogramming and expiry check is done in the hrtimer_interrupt or in the
* softirq.
*
* Called with interrupts disabled and base->cpu_base.lock held * Called with interrupts disabled and base->cpu_base.lock held
*/ */
static int hrtimer_reprogram(struct hrtimer *timer, static int hrtimer_reprogram(struct hrtimer *timer,
@ -662,25 +613,13 @@ static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base)
base->hres_active = 0; base->hres_active = 0;
} }
/*
* When High resolution timers are active, try to reprogram. Note, that in case
* the state has HRTIMER_STATE_CALLBACK set, no reprogramming and no expiry
* check happens. The timer gets enqueued into the rbtree. The reprogramming
* and expiry check is done in the hrtimer_interrupt or in the softirq.
*/
static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
struct hrtimer_clock_base *base)
{
return base->cpu_base->hres_active && hrtimer_reprogram(timer, base);
}
static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base) static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base)
{ {
ktime_t *offs_real = &base->clock_base[HRTIMER_BASE_REALTIME].offset; ktime_t *offs_real = &base->clock_base[HRTIMER_BASE_REALTIME].offset;
ktime_t *offs_boot = &base->clock_base[HRTIMER_BASE_BOOTTIME].offset; ktime_t *offs_boot = &base->clock_base[HRTIMER_BASE_BOOTTIME].offset;
ktime_t *offs_tai = &base->clock_base[HRTIMER_BASE_TAI].offset; ktime_t *offs_tai = &base->clock_base[HRTIMER_BASE_TAI].offset;
return ktime_get_update_offsets(offs_real, offs_boot, offs_tai); return ktime_get_update_offsets_now(offs_real, offs_boot, offs_tai);
} }
/* /*
@ -755,8 +694,8 @@ static inline int hrtimer_is_hres_enabled(void) { return 0; }
static inline int hrtimer_switch_to_hres(void) { return 0; } static inline int hrtimer_switch_to_hres(void) { return 0; }
static inline void static inline void
hrtimer_force_reprogram(struct hrtimer_cpu_base *base, int skip_equal) { } hrtimer_force_reprogram(struct hrtimer_cpu_base *base, int skip_equal) { }
static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, static inline int hrtimer_reprogram(struct hrtimer *timer,
struct hrtimer_clock_base *base) struct hrtimer_clock_base *base)
{ {
return 0; return 0;
} }
@ -1013,14 +952,25 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
leftmost = enqueue_hrtimer(timer, new_base); leftmost = enqueue_hrtimer(timer, new_base);
/* if (!leftmost) {
* Only allow reprogramming if the new base is on this CPU. unlock_hrtimer_base(timer, &flags);
* (it might still be on another CPU if the timer was pending) return ret;
* }
* XXX send_remote_softirq() ?
*/ if (!hrtimer_is_hres_active(timer)) {
if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases) /*
&& hrtimer_enqueue_reprogram(timer, new_base)) { * Kick to reschedule the next tick to handle the new timer
* on dynticks target.
*/
wake_up_nohz_cpu(new_base->cpu_base->cpu);
} else if (new_base->cpu_base == &__get_cpu_var(hrtimer_bases) &&
hrtimer_reprogram(timer, new_base)) {
/*
* Only allow reprogramming if the new base is on this CPU.
* (it might still be on another CPU if the timer was pending)
*
* XXX send_remote_softirq() ?
*/
if (wakeup) { if (wakeup) {
/* /*
* We need to drop cpu_base->lock to avoid a * We need to drop cpu_base->lock to avoid a
@ -1680,6 +1630,7 @@ static void init_hrtimers_cpu(int cpu)
timerqueue_init_head(&cpu_base->clock_base[i].active); timerqueue_init_head(&cpu_base->clock_base[i].active);
} }
cpu_base->cpu = cpu;
hrtimer_init_hres(cpu_base); hrtimer_init_hres(cpu_base);
} }

View File

@ -466,7 +466,8 @@ static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock);
static void sync_cmos_clock(struct work_struct *work) static void sync_cmos_clock(struct work_struct *work)
{ {
struct timespec now, next; struct timespec64 now;
struct timespec next;
int fail = 1; int fail = 1;
/* /*
@ -485,9 +486,9 @@ static void sync_cmos_clock(struct work_struct *work)
return; return;
} }
getnstimeofday(&now); getnstimeofday64(&now);
if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec * 5) { if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec * 5) {
struct timespec adjust = now; struct timespec adjust = timespec64_to_timespec(now);
fail = -ENODEV; fail = -ENODEV;
if (persistent_clock_is_local) if (persistent_clock_is_local)
@ -531,7 +532,7 @@ void ntp_notify_cmos_timer(void) { }
/* /*
* Propagate a new txc->status value into the NTP state: * Propagate a new txc->status value into the NTP state:
*/ */
static inline void process_adj_status(struct timex *txc, struct timespec *ts) static inline void process_adj_status(struct timex *txc, struct timespec64 *ts)
{ {
if ((time_status & STA_PLL) && !(txc->status & STA_PLL)) { if ((time_status & STA_PLL) && !(txc->status & STA_PLL)) {
time_state = TIME_OK; time_state = TIME_OK;
@ -554,7 +555,7 @@ static inline void process_adj_status(struct timex *txc, struct timespec *ts)
static inline void process_adjtimex_modes(struct timex *txc, static inline void process_adjtimex_modes(struct timex *txc,
struct timespec *ts, struct timespec64 *ts,
s32 *time_tai) s32 *time_tai)
{ {
if (txc->modes & ADJ_STATUS) if (txc->modes & ADJ_STATUS)
@ -640,7 +641,7 @@ int ntp_validate_timex(struct timex *txc)
* adjtimex mainly allows reading (and writing, if superuser) of * adjtimex mainly allows reading (and writing, if superuser) of
* kernel time-keeping variables. used by xntpd. * kernel time-keeping variables. used by xntpd.
*/ */
int __do_adjtimex(struct timex *txc, struct timespec *ts, s32 *time_tai) int __do_adjtimex(struct timex *txc, struct timespec64 *ts, s32 *time_tai)
{ {
int result; int result;
@ -684,7 +685,7 @@ int __do_adjtimex(struct timex *txc, struct timespec *ts, s32 *time_tai)
/* fill PPS status fields */ /* fill PPS status fields */
pps_fill_timex(txc); pps_fill_timex(txc);
txc->time.tv_sec = ts->tv_sec; txc->time.tv_sec = (time_t)ts->tv_sec;
txc->time.tv_usec = ts->tv_nsec; txc->time.tv_usec = ts->tv_nsec;
if (!(time_status & STA_NANO)) if (!(time_status & STA_NANO))
txc->time.tv_usec /= NSEC_PER_USEC; txc->time.tv_usec /= NSEC_PER_USEC;

View File

@ -7,6 +7,6 @@ extern void ntp_clear(void);
extern u64 ntp_tick_length(void); extern u64 ntp_tick_length(void);
extern int second_overflow(unsigned long secs); extern int second_overflow(unsigned long secs);
extern int ntp_validate_timex(struct timex *); extern int ntp_validate_timex(struct timex *);
extern int __do_adjtimex(struct timex *, struct timespec *, s32 *); extern int __do_adjtimex(struct timex *, struct timespec64 *, s32 *);
extern void __hardpps(const struct timespec *, const struct timespec *); extern void __hardpps(const struct timespec *, const struct timespec *);
#endif /* _LINUX_NTP_INTERNAL_H */ #endif /* _LINUX_NTP_INTERNAL_H */

View File

@ -49,6 +49,8 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/hashtable.h> #include <linux/hashtable.h>
#include "timekeeping.h"
/* /*
* Management arrays for POSIX timers. Timers are now kept in static hash table * Management arrays for POSIX timers. Timers are now kept in static hash table
* with 512 entries. * with 512 entries.

View File

@ -4,6 +4,8 @@
#include <linux/hrtimer.h> #include <linux/hrtimer.h>
#include <linux/tick.h> #include <linux/tick.h>
#include "timekeeping.h"
extern seqlock_t jiffies_lock; extern seqlock_t jiffies_lock;
#define CS_NAME_LEN 32 #define CS_NAME_LEN 32

View File

@ -42,6 +42,7 @@
#include <asm/unistd.h> #include <asm/unistd.h>
#include "timeconst.h" #include "timeconst.h"
#include "timekeeping.h"
/* /*
* The timezone where the local system is located. Used as a default by some * The timezone where the local system is located. Used as a default by some
@ -420,6 +421,68 @@ struct timeval ns_to_timeval(const s64 nsec)
} }
EXPORT_SYMBOL(ns_to_timeval); EXPORT_SYMBOL(ns_to_timeval);
#if BITS_PER_LONG == 32
/**
* set_normalized_timespec - set timespec sec and nsec parts and normalize
*
* @ts: pointer to timespec variable to be set
* @sec: seconds to set
* @nsec: nanoseconds to set
*
* Set seconds and nanoseconds field of a timespec variable and
* normalize to the timespec storage format
*
* Note: The tv_nsec part is always in the range of
* 0 <= tv_nsec < NSEC_PER_SEC
* For negative values only the tv_sec field is negative !
*/
void set_normalized_timespec64(struct timespec64 *ts, time64_t sec, s64 nsec)
{
while (nsec >= NSEC_PER_SEC) {
/*
* The following asm() prevents the compiler from
* optimising this loop into a modulo operation. See
* also __iter_div_u64_rem() in include/linux/time.h
*/
asm("" : "+rm"(nsec));
nsec -= NSEC_PER_SEC;
++sec;
}
while (nsec < 0) {
asm("" : "+rm"(nsec));
nsec += NSEC_PER_SEC;
--sec;
}
ts->tv_sec = sec;
ts->tv_nsec = nsec;
}
EXPORT_SYMBOL(set_normalized_timespec64);
/**
* ns_to_timespec64 - Convert nanoseconds to timespec64
* @nsec: the nanoseconds value to be converted
*
* Returns the timespec64 representation of the nsec parameter.
*/
struct timespec64 ns_to_timespec64(const s64 nsec)
{
struct timespec64 ts;
s32 rem;
if (!nsec)
return (struct timespec64) {0, 0};
ts.tv_sec = div_s64_rem(nsec, NSEC_PER_SEC, &rem);
if (unlikely(rem < 0)) {
ts.tv_sec--;
rem += NSEC_PER_SEC;
}
ts.tv_nsec = rem;
return ts;
}
EXPORT_SYMBOL(ns_to_timespec64);
#endif
/* /*
* When we convert to jiffies then we interpret incoming values * When we convert to jiffies then we interpret incoming values
* the following way: * the following way:
@ -694,6 +757,7 @@ unsigned long nsecs_to_jiffies(u64 n)
{ {
return (unsigned long)nsecs_to_jiffies64(n); return (unsigned long)nsecs_to_jiffies64(n);
} }
EXPORT_SYMBOL_GPL(nsecs_to_jiffies);
/* /*
* Add two timespec values and do a safety check for overflow. * Add two timespec values and do a safety check for overflow.

File diff suppressed because it is too large Load Diff

20
kernel/time/timekeeping.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef _KERNEL_TIME_TIMEKEEPING_H
#define _KERNEL_TIME_TIMEKEEPING_H
/*
* Internal interfaces for kernel/time/
*/
extern ktime_t ktime_get_update_offsets_tick(ktime_t *offs_real,
ktime_t *offs_boot,
ktime_t *offs_tai);
extern ktime_t ktime_get_update_offsets_now(ktime_t *offs_real,
ktime_t *offs_boot,
ktime_t *offs_tai);
extern int timekeeping_valid_for_hres(void);
extern u64 timekeeping_max_deferment(void);
extern int timekeeping_inject_offset(struct timespec *ts);
extern s32 timekeeping_get_tai_offset(void);
extern void timekeeping_set_tai_offset(s32 tai_offset);
extern void timekeeping_clocktai(struct timespec *ts);
#endif

View File

@ -67,7 +67,7 @@ static int __init tk_debug_sleep_time_init(void)
} }
late_initcall(tk_debug_sleep_time_init); late_initcall(tk_debug_sleep_time_init);
void tk_debug_account_sleep_time(struct timespec *t) void tk_debug_account_sleep_time(struct timespec64 *t)
{ {
sleep_time_bin[fls(t->tv_sec)]++; sleep_time_bin[fls(t->tv_sec)]++;
} }

View File

@ -3,12 +3,27 @@
/* /*
* timekeeping debug functions * timekeeping debug functions
*/ */
#include <linux/clocksource.h>
#include <linux/time.h> #include <linux/time.h>
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
extern void tk_debug_account_sleep_time(struct timespec *t); extern void tk_debug_account_sleep_time(struct timespec64 *t);
#else #else
#define tk_debug_account_sleep_time(x) #define tk_debug_account_sleep_time(x)
#endif #endif
#ifdef CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE
static inline cycle_t clocksource_delta(cycle_t now, cycle_t last, cycle_t mask)
{
cycle_t ret = (now - last) & mask;
return (s64) ret > 0 ? ret : 0;
}
#else
static inline cycle_t clocksource_delta(cycle_t now, cycle_t last, cycle_t mask)
{
return (now - last) & mask;
}
#endif
#endif /* _TIMEKEEPING_INTERNAL_H */ #endif /* _TIMEKEEPING_INTERNAL_H */

View File

@ -82,6 +82,7 @@ struct tvec_base {
unsigned long next_timer; unsigned long next_timer;
unsigned long active_timers; unsigned long active_timers;
unsigned long all_timers; unsigned long all_timers;
int cpu;
struct tvec_root tv1; struct tvec_root tv1;
struct tvec tv2; struct tvec tv2;
struct tvec tv3; struct tvec tv3;
@ -409,6 +410,22 @@ static void internal_add_timer(struct tvec_base *base, struct timer_list *timer)
base->next_timer = timer->expires; base->next_timer = timer->expires;
} }
base->all_timers++; base->all_timers++;
/*
* Check whether the other CPU is in dynticks mode and needs
* to be triggered to reevaluate the timer wheel.
* We are protected against the other CPU fiddling
* with the timer by holding the timer base lock. This also
* makes sure that a CPU on the way to stop its tick can not
* evaluate the timer wheel.
*
* Spare the IPI for deferrable timers on idle targets though.
* The next busy ticks will take care of it. Except full dynticks
* require special care against races with idle_cpu(), lets deal
* with that later.
*/
if (!tbase_get_deferrable(base) || tick_nohz_full_cpu(base->cpu))
wake_up_nohz_cpu(base->cpu);
} }
#ifdef CONFIG_TIMER_STATS #ifdef CONFIG_TIMER_STATS
@ -948,22 +965,6 @@ void add_timer_on(struct timer_list *timer, int cpu)
timer_set_base(timer, base); timer_set_base(timer, base);
debug_activate(timer, timer->expires); debug_activate(timer, timer->expires);
internal_add_timer(base, timer); internal_add_timer(base, timer);
/*
* Check whether the other CPU is in dynticks mode and needs
* to be triggered to reevaluate the timer wheel.
* We are protected against the other CPU fiddling
* with the timer by holding the timer base lock. This also
* makes sure that a CPU on the way to stop its tick can not
* evaluate the timer wheel.
*
* Spare the IPI for deferrable timers on idle targets though.
* The next busy ticks will take care of it. Except full dynticks
* require special care against races with idle_cpu(), lets deal
* with that later.
*/
if (!tbase_get_deferrable(timer->base) || tick_nohz_full_cpu(cpu))
wake_up_nohz_cpu(cpu);
spin_unlock_irqrestore(&base->lock, flags); spin_unlock_irqrestore(&base->lock, flags);
} }
EXPORT_SYMBOL_GPL(add_timer_on); EXPORT_SYMBOL_GPL(add_timer_on);
@ -1568,6 +1569,7 @@ static int init_timers_cpu(int cpu)
} }
spin_lock_init(&base->lock); spin_lock_init(&base->lock);
tvec_base_done[cpu] = 1; tvec_base_done[cpu] = 1;
base->cpu = cpu;
} else { } else {
base = per_cpu(tvec_bases, cpu); base = per_cpu(tvec_bases, cpu);
} }

Some files were not shown because too many files have changed in this diff Show More