* art_to_mono64
* art_to_rawmono64
* art_to_realtime64
Intel audio and PCH ethernet devices use the Always Running Timer (ART) to
relate their device clock to system time
Signed-off-by: Christopher Hall <christopher.s.hall@xxxxxxxxx>
---
arch/x86/Kconfig | 12 ++++
arch/x86/include/asm/art.h | 42 ++++++++++++++
arch/x86/kernel/Makefile | 1 +
arch/x86/kernel/art.c | 134 +++++++++++++++++++++++++++++++++++++++++++++
arch/x86/kernel/tsc.c | 4 ++
5 files changed, 193 insertions(+)
create mode 100644 arch/x86/include/asm/art.h
create mode 100644 arch/x86/kernel/art.c
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index b3a1a5d..1ef9985 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1175,6 +1175,18 @@ config X86_CPUID
with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to
/dev/cpu/31/cpuid.
+config X86_ART
+ bool "Always Running Timer"
+ default y
+ depends on X86_TSC
+ ---help---
+ This option provides functionality to drivers and devices that use
+ the always-running-timer (ART) to correlate their device clock
+ counter with the system clock counter. The TSC is *exactly* related
+ to the ART by a ratio m/n specified by CPUID leaf 0x15
+ (n=EAX,m=EBX). If ART is unused or unavailable there isn't any
+ performance impact. It's safe to say Y.
+
choice
prompt "High Memory Support"
default HIGHMEM4G
diff --git a/arch/x86/include/asm/art.h b/arch/x86/include/asm/art.h
new file mode 100644
index 0000000..da58ce4
--- /dev/null
+++ b/arch/x86/include/asm/art.h
@@ -0,0 +1,42 @@
+/*
+ * x86 ART related functions
+ */
+#ifndef _ASM_X86_ART_H
+#define _ASM_X86_ART_H
+
+#ifndef CONFIG_X86_ART
+
+static inline int setup_art(void)
+{
+ return 0;
+}
+
+static inline bool has_art(void)
+{
+ return false;
+}
+
+static inline int art_to_rawmono64(struct timespec64 *rawmono, cycle_t art)
+{
+ return -ENXIO;
+}
+static inline int art_to_realtime64(struct timespec64 *realtime, cycle_t art)
+{
+ return -ENXIO;
+}
+static inline int art_to_mono64(struct timespec64 *mono, cycle_t art)
+{
+ return -ENXIO;
+}
+
+#else
+
+extern int setup_art(void);
+extern bool has_art(void);
+extern int art_to_rawmono64(struct timespec64 *rawmono, cycle_t art);
+extern int art_to_realtime64(struct timespec64 *realtime, cycle_t art);
+extern int art_to_mono64(struct timespec64 *mono, cycle_t art);
+
+#endif
+
+#endif/*_ASM_X86_ART_H*/
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 0f15af4..0908311 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -109,6 +109,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_regs.o
obj-$(CONFIG_TRACING) += tracepoint.o
obj-$(CONFIG_IOSF_MBI) += iosf_mbi.o
obj-$(CONFIG_PMC_ATOM) += pmc_atom.o
+obj-$(CONFIG_X86_ART) += art.o
###
# 64 bit specific files
diff --git a/arch/x86/kernel/art.c b/arch/x86/kernel/art.c
new file mode 100644
index 0000000..1906cf0
--- /dev/null
+++ b/arch/x86/kernel/art.c
@@ -0,0 +1,134 @@
+#include <asm/tsc.h>
+#include <asm/cpufeature.h>
+#include <asm/processor.h>
+#include <linux/spinlock.h>
+#include <linux/seqlock.h>
+
+#define CPUID_ART_LEAF 0x15
+
+static bool art_present;
+
+static struct art_state {
+ seqcount_t seq;
+ u32 art_ratio_numerator;
+ u32 art_ratio_denominator;
+
+ cycle_t prev_art;
+ cycle_t prev_tsc_corr_art; /*This is the TSC value corresponding to
+ prev_art */
+ u32 tsc_remainder;
+} art_state ____cacheline_aligned;
+
+static DEFINE_RAW_SPINLOCK(art_lock);
+
+#define MIN_DENOMINATOR 2
+int setup_art(void)
+{
+ if (boot_cpu_data.cpuid_level < CPUID_ART_LEAF)
+ return 0;
+ art_state.art_ratio_denominator = cpuid_eax(CPUID_ART_LEAF);
+ if (art_state.art_ratio_denominator < MIN_DENOMINATOR)
+ return 0;
+ art_state.art_ratio_numerator = cpuid_ebx(CPUID_ART_LEAF);
+
+ art_present = true;
+ return 0;
+}
+
+static bool has_art(void)
+{
+ return art_present;
+}
+EXPORT_SYMBOL(has_art);
+
+#define ROLLOVER_THRESHOLD (2ULL << 23)
+
+static u32 art_scale(struct art_state *art_state, cycle_t *art)
+{
+ u32 rem;
+
+ *art *= art_state->art_ratio_numerator;
+static cycle_t art_to_tsc(cycle_t art)
+{