Skip to content

Commit

Permalink
Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/…
Browse files Browse the repository at this point in the history
…linux/kernel/git/tip/tip

Pull timer updates from Thomas Gleixner:
 "The timer department delivers this time:

   - Support for cross clock domain timestamps in the core code plus a
     first user.  That allows more precise timestamping for PTP and
     later for audio and other peripherals.

     The ptp/e1000e patches have been acked by the relevant maintainers
     and are carried in the timer tree to avoid merge ordering issues.

   - Support for unregistering the current clocksource watchdog.  That
     lifts a limitation for switching clocksources which has been there
     from day 1

   - The usual pile of fixes and updates to the core and the drivers.
     Nothing outstanding and exciting"

* 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (26 commits)
  time/timekeeping: Work around false positive GCC warning
  e1000e: Adds hardware supported cross timestamp on e1000e nic
  ptp: Add PTP_SYS_OFFSET_PRECISE for driver crosstimestamping
  x86/tsc: Always Running Timer (ART) correlated clocksource
  hrtimer: Revert CLOCK_MONOTONIC_RAW support
  time: Add history to cross timestamp interface supporting slower devices
  time: Add driver cross timestamp interface for higher precision time synchronization
  time: Remove duplicated code in ktime_get_raw_and_real()
  time: Add timekeeping snapshot code capturing system time and counter
  time: Add cycles to nanoseconds translation
  jiffies: Use CLOCKSOURCE_MASK instead of constant
  clocksource: Introduce clocksource_freq2mult()
  clockevents/drivers/exynos_mct: Implement ->set_state_oneshot_stopped()
  clockevents/drivers/arm_global_timer: Implement ->set_state_oneshot_stopped()
  clockevents/drivers/arm_arch_timer: Implement ->set_state_oneshot_stopped()
  clocksource/drivers/arm_global_timer: Register delay timer
  clocksource/drivers/lpc32xx: Support timer-based ARM delay
  clocksource/drivers/lpc32xx: Support periodic mode
  clocksource/drivers/lpc32xx: Don't use the prescaler counter for clockevents
  clocksource/drivers/rockchip: Add err handle for rk_timer_init
  ...
  • Loading branch information
torvalds committed Mar 15, 2016
2 parents 208de21 + 6436257 commit 8a284c0
Show file tree
Hide file tree
Showing 25 changed files with 728 additions and 106 deletions.
6 changes: 4 additions & 2 deletions Documentation/ptp/testptp.c
Original file line number Diff line number Diff line change
Expand Up @@ -277,13 +277,15 @@ int main(int argc, char *argv[])
" %d external time stamp channels\n"
" %d programmable periodic signals\n"
" %d pulse per second\n"
" %d programmable pins\n",
" %d programmable pins\n"
" %d cross timestamping\n",
caps.max_adj,
caps.n_alarm,
caps.n_ext_ts,
caps.n_per_out,
caps.pps,
caps.n_pins);
caps.n_pins,
caps.cross_timestamping);
}
}

Expand Down
2 changes: 1 addition & 1 deletion arch/x86/include/asm/cpufeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
#define X86_FEATURE_P4 ( 3*32+ 7) /* "" P4 */
#define X86_FEATURE_CONSTANT_TSC ( 3*32+ 8) /* TSC ticks at a constant rate */
#define X86_FEATURE_UP ( 3*32+ 9) /* smp kernel running on up */
/* free, was #define X86_FEATURE_FXSAVE_LEAK ( 3*32+10) * "" FXSAVE leaks FOP/FIP/FOP */
#define X86_FEATURE_ART ( 3*32+10) /* Platform has always running timer (ART) */
#define X86_FEATURE_ARCH_PERFMON ( 3*32+11) /* Intel Architectural PerfMon */
#define X86_FEATURE_PEBS ( 3*32+12) /* Precise-Event Based Sampling */
#define X86_FEATURE_BTS ( 3*32+13) /* Branch Trace Store */
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/include/asm/tsc.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ static inline cycles_t get_cycles(void)
return rdtsc();
}

extern struct system_counterval_t convert_art_to_tsc(cycle_t art);

extern void tsc_init(void);
extern void mark_tsc_unstable(char *reason);
extern int unsynchronized_tsc(void);
Expand Down
59 changes: 59 additions & 0 deletions arch/x86/kernel/tsc.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ static DEFINE_STATIC_KEY_FALSE(__use_tsc);

int tsc_clocksource_reliable;

static u32 art_to_tsc_numerator;
static u32 art_to_tsc_denominator;
static u64 art_to_tsc_offset;
struct clocksource *art_related_clocksource;

/*
* Use a ring-buffer like data structure, where a writer advances the head by
* writing a new data entry and a reader advances the tail when it observes a
Expand Down Expand Up @@ -964,6 +969,37 @@ core_initcall(cpufreq_tsc);

#endif /* CONFIG_CPU_FREQ */

#define ART_CPUID_LEAF (0x15)
#define ART_MIN_DENOMINATOR (1)


/*
* If ART is present detect the numerator:denominator to convert to TSC
*/
static void detect_art(void)
{
unsigned int unused[2];

if (boot_cpu_data.cpuid_level < ART_CPUID_LEAF)
return;

cpuid(ART_CPUID_LEAF, &art_to_tsc_denominator,
&art_to_tsc_numerator, unused, unused+1);

/* Don't enable ART in a VM, non-stop TSC required */
if (boot_cpu_has(X86_FEATURE_HYPERVISOR) ||
!boot_cpu_has(X86_FEATURE_NONSTOP_TSC) ||
art_to_tsc_denominator < ART_MIN_DENOMINATOR)
return;

if (rdmsrl_safe(MSR_IA32_TSC_ADJUST, &art_to_tsc_offset))
return;

/* Make this sticky over multiple CPU init calls */
setup_force_cpu_cap(X86_FEATURE_ART);
}


/* clocksource code */

static struct clocksource clocksource_tsc;
Expand Down Expand Up @@ -1071,6 +1107,25 @@ int unsynchronized_tsc(void)
return 0;
}

/*
* Convert ART to TSC given numerator/denominator found in detect_art()
*/
struct system_counterval_t convert_art_to_tsc(cycle_t art)
{
u64 tmp, res, rem;

rem = do_div(art, art_to_tsc_denominator);

res = art * art_to_tsc_numerator;
tmp = rem * art_to_tsc_numerator;

do_div(tmp, art_to_tsc_denominator);
res += tmp + art_to_tsc_offset;

return (struct system_counterval_t) {.cs = art_related_clocksource,
.cycles = res};
}
EXPORT_SYMBOL(convert_art_to_tsc);

static void tsc_refine_calibration_work(struct work_struct *work);
static DECLARE_DELAYED_WORK(tsc_irqwork, tsc_refine_calibration_work);
Expand Down Expand Up @@ -1142,6 +1197,8 @@ static void tsc_refine_calibration_work(struct work_struct *work)
(unsigned long)tsc_khz % 1000);

out:
if (boot_cpu_has(X86_FEATURE_ART))
art_related_clocksource = &clocksource_tsc;
clocksource_register_khz(&clocksource_tsc, tsc_khz);
}

Expand Down Expand Up @@ -1235,6 +1292,8 @@ void __init tsc_init(void)
mark_tsc_unstable("TSCs unsynchronized");

check_system_tsc_reliable();

detect_art();
}

#ifdef CONFIG_SMP
Expand Down
1 change: 1 addition & 0 deletions drivers/clocksource/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ config CLKSRC_EFM32
config CLKSRC_LPC32XX
bool "Clocksource for LPC32XX" if COMPILE_TEST
depends on GENERIC_CLOCKEVENTS && HAS_IOMEM
depends on ARM
select CLKSRC_MMIO
select CLKSRC_OF
help
Expand Down
40 changes: 32 additions & 8 deletions drivers/clocksource/arm_arch_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@
#define CNTTIDR 0x08
#define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4))

#define CNTACR(n) (0x40 + ((n) * 4))
#define CNTACR_RPCT BIT(0)
#define CNTACR_RVCT BIT(1)
#define CNTACR_RFRQ BIT(2)
#define CNTACR_RVOFF BIT(3)
#define CNTACR_RWVT BIT(4)
#define CNTACR_RWPT BIT(5)

#define CNTVCT_LO 0x08
#define CNTVCT_HI 0x0c
#define CNTFRQ 0x10
Expand Down Expand Up @@ -266,10 +274,12 @@ static void __arch_timer_setup(unsigned type,
if (arch_timer_use_virtual) {
clk->irq = arch_timer_ppi[VIRT_PPI];
clk->set_state_shutdown = arch_timer_shutdown_virt;
clk->set_state_oneshot_stopped = arch_timer_shutdown_virt;
clk->set_next_event = arch_timer_set_next_event_virt;
} else {
clk->irq = arch_timer_ppi[PHYS_SECURE_PPI];
clk->set_state_shutdown = arch_timer_shutdown_phys;
clk->set_state_oneshot_stopped = arch_timer_shutdown_phys;
clk->set_next_event = arch_timer_set_next_event_phys;
}
} else {
Expand All @@ -279,10 +289,12 @@ static void __arch_timer_setup(unsigned type,
clk->cpumask = cpu_all_mask;
if (arch_timer_mem_use_virtual) {
clk->set_state_shutdown = arch_timer_shutdown_virt_mem;
clk->set_state_oneshot_stopped = arch_timer_shutdown_virt_mem;
clk->set_next_event =
arch_timer_set_next_event_virt_mem;
} else {
clk->set_state_shutdown = arch_timer_shutdown_phys_mem;
clk->set_state_oneshot_stopped = arch_timer_shutdown_phys_mem;
clk->set_next_event =
arch_timer_set_next_event_phys_mem;
}
Expand Down Expand Up @@ -757,53 +769,65 @@ static void __init arch_timer_mem_init(struct device_node *np)
}

cnttidr = readl_relaxed(cntctlbase + CNTTIDR);
iounmap(cntctlbase);

/*
* Try to find a virtual capable frame. Otherwise fall back to a
* physical capable frame.
*/
for_each_available_child_of_node(np, frame) {
int n;
u32 cntacr;

if (of_property_read_u32(frame, "frame-number", &n)) {
pr_err("arch_timer: Missing frame-number\n");
of_node_put(best_frame);
of_node_put(frame);
return;
goto out;
}

if (cnttidr & CNTTIDR_VIRT(n)) {
/* Try enabling everything, and see what sticks */
cntacr = CNTACR_RFRQ | CNTACR_RWPT | CNTACR_RPCT |
CNTACR_RWVT | CNTACR_RVOFF | CNTACR_RVCT;
writel_relaxed(cntacr, cntctlbase + CNTACR(n));
cntacr = readl_relaxed(cntctlbase + CNTACR(n));

if ((cnttidr & CNTTIDR_VIRT(n)) &&
!(~cntacr & (CNTACR_RWVT | CNTACR_RVCT))) {
of_node_put(best_frame);
best_frame = frame;
arch_timer_mem_use_virtual = true;
break;
}

if (~cntacr & (CNTACR_RWPT | CNTACR_RPCT))
continue;

of_node_put(best_frame);
best_frame = of_node_get(frame);
}

base = arch_counter_base = of_iomap(best_frame, 0);
if (!base) {
pr_err("arch_timer: Can't map frame's registers\n");
of_node_put(best_frame);
return;
goto out;
}

if (arch_timer_mem_use_virtual)
irq = irq_of_parse_and_map(best_frame, 1);
else
irq = irq_of_parse_and_map(best_frame, 0);
of_node_put(best_frame);

if (!irq) {
pr_err("arch_timer: Frame missing %s irq",
arch_timer_mem_use_virtual ? "virt" : "phys");
return;
goto out;
}

arch_timer_detect_rate(base, np);
arch_timer_mem_register(base, irq);
arch_timer_common_init();
out:
iounmap(cntctlbase);
of_node_put(best_frame);
}
CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem",
arch_timer_mem_init);
Expand Down
18 changes: 18 additions & 0 deletions drivers/clocksource/arm_global_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <linux/clockchips.h>
#include <linux/cpu.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
Expand Down Expand Up @@ -174,6 +175,7 @@ static int gt_clockevents_init(struct clock_event_device *clk)
clk->set_state_shutdown = gt_clockevent_shutdown;
clk->set_state_periodic = gt_clockevent_set_periodic;
clk->set_state_oneshot = gt_clockevent_shutdown;
clk->set_state_oneshot_stopped = gt_clockevent_shutdown;
clk->set_next_event = gt_clockevent_set_next_event;
clk->cpumask = cpumask_of(cpu);
clk->rating = 300;
Expand Down Expand Up @@ -221,6 +223,21 @@ static u64 notrace gt_sched_clock_read(void)
}
#endif

static unsigned long gt_read_long(void)
{
return readl_relaxed(gt_base + GT_COUNTER0);
}

static struct delay_timer gt_delay_timer = {
.read_current_timer = gt_read_long,
};

static void __init gt_delay_timer_init(void)
{
gt_delay_timer.freq = gt_clk_rate;
register_current_timer_delay(&gt_delay_timer);
}

static void __init gt_clocksource_init(void)
{
writel(0, gt_base + GT_CONTROL);
Expand Down Expand Up @@ -317,6 +334,7 @@ static void __init global_timer_of_register(struct device_node *np)
/* Immediately configure the timer on the boot CPU */
gt_clocksource_init();
gt_clockevents_init(this_cpu_ptr(gt_evt));
gt_delay_timer_init();

return;

Expand Down
2 changes: 2 additions & 0 deletions drivers/clocksource/exynos_mct.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ static struct clock_event_device mct_comp_device = {
.set_state_periodic = mct_set_state_periodic,
.set_state_shutdown = mct_set_state_shutdown,
.set_state_oneshot = mct_set_state_shutdown,
.set_state_oneshot_stopped = mct_set_state_shutdown,
.tick_resume = mct_set_state_shutdown,
};

Expand Down Expand Up @@ -452,6 +453,7 @@ static int exynos4_local_timer_setup(struct mct_clock_event_device *mevt)
evt->set_state_periodic = set_state_periodic;
evt->set_state_shutdown = set_state_shutdown;
evt->set_state_oneshot = set_state_shutdown;
evt->set_state_oneshot_stopped = set_state_shutdown;
evt->tick_resume = set_state_shutdown;
evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
evt->rating = 450;
Expand Down
21 changes: 15 additions & 6 deletions drivers/clocksource/rockchip_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,31 +122,31 @@ static void __init rk_timer_init(struct device_node *np)
pclk = of_clk_get_by_name(np, "pclk");
if (IS_ERR(pclk)) {
pr_err("Failed to get pclk for '%s'\n", TIMER_NAME);
return;
goto out_unmap;
}

if (clk_prepare_enable(pclk)) {
pr_err("Failed to enable pclk for '%s'\n", TIMER_NAME);
return;
goto out_unmap;
}

timer_clk = of_clk_get_by_name(np, "timer");
if (IS_ERR(timer_clk)) {
pr_err("Failed to get timer clock for '%s'\n", TIMER_NAME);
return;
goto out_timer_clk;
}

if (clk_prepare_enable(timer_clk)) {
pr_err("Failed to enable timer clock\n");
return;
goto out_timer_clk;
}

bc_timer.freq = clk_get_rate(timer_clk);

irq = irq_of_parse_and_map(np, 0);
if (!irq) {
pr_err("Failed to map interrupts for '%s'\n", TIMER_NAME);
return;
goto out_irq;
}

ce->name = TIMER_NAME;
Expand All @@ -164,10 +164,19 @@ static void __init rk_timer_init(struct device_node *np)
ret = request_irq(irq, rk_timer_interrupt, IRQF_TIMER, TIMER_NAME, ce);
if (ret) {
pr_err("Failed to initialize '%s': %d\n", TIMER_NAME, ret);
return;
goto out_irq;
}

clockevents_config_and_register(ce, bc_timer.freq, 1, UINT_MAX);

return;

out_irq:
clk_disable_unprepare(timer_clk);
out_timer_clk:
clk_disable_unprepare(pclk);
out_unmap:
iounmap(bc_timer.base);
}

CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init);
Loading

0 comments on commit 8a284c0

Please sign in to comment.