aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-10-03 20:27:17 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-03 20:27:17 -0400
commit6aebe7f9e8697531a11b007d1e8126ba1b6e0a53 (patch)
tree66952e4f08ceb24dad146790800d539fe642e3ce /arch/x86
parenta6c4e4cd44649b696038326f90161113d8569170 (diff)
parent6baf3d61821f5b38f27b4e9f044ad4d1e8f3d14f (diff)
Merge branch 'x86-timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 timer updates from Ingo Molnar: "This tree includes a HPET overhead micro-optimization plus new TSC frequencies for newer Intel CPUs" * 'x86-timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/tsc: Add additional Intel CPU models to the crystal quirk list x86/tsc: Use cpu id defines instead of hex constants x86/hpet: Reduce HPET counter read contention
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/kernel/hpet.c94
-rw-r--r--arch/x86/kernel/tsc.c12
2 files changed, 103 insertions, 3 deletions
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index c6dfd801df97..274fab99169d 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -756,10 +756,104 @@ static void hpet_reserve_msi_timers(struct hpet_data *hd)
756/* 756/*
757 * Clock source related code 757 * Clock source related code
758 */ 758 */
759#if defined(CONFIG_SMP) && defined(CONFIG_64BIT)
760/*
761 * Reading the HPET counter is a very slow operation. If a large number of
762 * CPUs are trying to access the HPET counter simultaneously, it can cause
763 * massive delay and slow down system performance dramatically. This may
764 * happen when HPET is the default clock source instead of TSC. For a
765 * really large system with hundreds of CPUs, the slowdown may be so
766 * severe that it may actually crash the system because of a NMI watchdog
767 * soft lockup, for example.
768 *
769 * If multiple CPUs are trying to access the HPET counter at the same time,
770 * we don't actually need to read the counter multiple times. Instead, the
771 * other CPUs can use the counter value read by the first CPU in the group.
772 *
773 * This special feature is only enabled on x86-64 systems. It is unlikely
774 * that 32-bit x86 systems will have enough CPUs to require this feature
775 * with its associated locking overhead. And we also need 64-bit atomic
776 * read.
777 *
778 * The lock and the hpet value are stored together and can be read in a
779 * single atomic 64-bit read. It is explicitly assumed that arch_spinlock_t
780 * is 32 bits in size.
781 */
782union hpet_lock {
783 struct {
784 arch_spinlock_t lock;
785 u32 value;
786 };
787 u64 lockval;
788};
789
790static union hpet_lock hpet __cacheline_aligned = {
791 { .lock = __ARCH_SPIN_LOCK_UNLOCKED, },
792};
793
794static cycle_t read_hpet(struct clocksource *cs)
795{
796 unsigned long flags;
797 union hpet_lock old, new;
798
799 BUILD_BUG_ON(sizeof(union hpet_lock) != 8);
800
801 /*
802 * Read HPET directly if in NMI.
803 */
804 if (in_nmi())
805 return (cycle_t)hpet_readl(HPET_COUNTER);
806
807 /*
808 * Read the current state of the lock and HPET value atomically.
809 */
810 old.lockval = READ_ONCE(hpet.lockval);
811
812 if (arch_spin_is_locked(&old.lock))
813 goto contended;
814
815 local_irq_save(flags);
816 if (arch_spin_trylock(&hpet.lock)) {
817 new.value = hpet_readl(HPET_COUNTER);
818 /*
819 * Use WRITE_ONCE() to prevent store tearing.
820 */
821 WRITE_ONCE(hpet.value, new.value);
822 arch_spin_unlock(&hpet.lock);
823 local_irq_restore(flags);
824 return (cycle_t)new.value;
825 }
826 local_irq_restore(flags);
827
828contended:
829 /*
830 * Contended case
831 * --------------
832 * Wait until the HPET value change or the lock is free to indicate
833 * its value is up-to-date.
834 *
835 * It is possible that old.value has already contained the latest
836 * HPET value while the lock holder was in the process of releasing
837 * the lock. Checking for lock state change will enable us to return
838 * the value immediately instead of waiting for the next HPET reader
839 * to come along.
840 */
841 do {
842 cpu_relax();
843 new.lockval = READ_ONCE(hpet.lockval);
844 } while ((new.value == old.value) && arch_spin_is_locked(&new.lock));
845
846 return (cycle_t)new.value;
847}
848#else
849/*
850 * For UP or 32-bit.
851 */
759static cycle_t read_hpet(struct clocksource *cs) 852static cycle_t read_hpet(struct clocksource *cs)
760{ 853{
761 return (cycle_t)hpet_readl(HPET_COUNTER); 854 return (cycle_t)hpet_readl(HPET_COUNTER);
762} 855}
856#endif
763 857
764static struct clocksource clocksource_hpet = { 858static struct clocksource clocksource_hpet = {
765 .name = "hpet", 859 .name = "hpet",
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 78b9cb5a26af..46b2f41f8b05 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -23,6 +23,7 @@
23#include <asm/x86_init.h> 23#include <asm/x86_init.h>
24#include <asm/geode.h> 24#include <asm/geode.h>
25#include <asm/apic.h> 25#include <asm/apic.h>
26#include <asm/intel-family.h>
26 27
27unsigned int __read_mostly cpu_khz; /* TSC clocks / usec, not used here */ 28unsigned int __read_mostly cpu_khz; /* TSC clocks / usec, not used here */
28EXPORT_SYMBOL(cpu_khz); 29EXPORT_SYMBOL(cpu_khz);
@@ -686,11 +687,16 @@ unsigned long native_calibrate_tsc(void)
686 687
687 if (crystal_khz == 0) { 688 if (crystal_khz == 0) {
688 switch (boot_cpu_data.x86_model) { 689 switch (boot_cpu_data.x86_model) {
689 case 0x4E: /* SKL */ 690 case INTEL_FAM6_SKYLAKE_MOBILE:
690 case 0x5E: /* SKL */ 691 case INTEL_FAM6_SKYLAKE_DESKTOP:
692 case INTEL_FAM6_KABYLAKE_MOBILE:
693 case INTEL_FAM6_KABYLAKE_DESKTOP:
691 crystal_khz = 24000; /* 24.0 MHz */ 694 crystal_khz = 24000; /* 24.0 MHz */
692 break; 695 break;
693 case 0x5C: /* BXT */ 696 case INTEL_FAM6_SKYLAKE_X:
697 crystal_khz = 25000; /* 25.0 MHz */
698 break;
699 case INTEL_FAM6_ATOM_GOLDMONT:
694 crystal_khz = 19200; /* 19.2 MHz */ 700 crystal_khz = 19200; /* 19.2 MHz */
695 break; 701 break;
696 } 702 }