1 /*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * Copyright (c) 2008 The DragonFly Project. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * William Jolitz and Don Ahn. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 34 * $FreeBSD: src/sys/i386/isa/clock.c,v 1.149.2.6 2002/11/02 04:41:50 iwasaki Exp $ 35 */ 36 37 /* 38 * TSC cputimer. 39 */ 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/kernel.h> 44 #include <sys/sysctl.h> 45 #include <sys/systimer.h> 46 #include <sys/globaldata.h> 47 48 #include <machine/clock.h> 49 #include <machine/cputypes.h> 50 51 static sysclock_t tsc_cputimer_count_mfence(void); 52 static sysclock_t tsc_cputimer_count_lfence(void); 53 static void tsc_cputimer_construct(struct cputimer *, sysclock_t); 54 55 static struct cputimer tsc_cputimer = { 56 .next = SLIST_ENTRY_INITIALIZER, 57 .name = "TSC", 58 .pri = CPUTIMER_PRI_TSC, 59 .type = CPUTIMER_TSC, 60 .count = NULL, /* determined later */ 61 .fromhz = cputimer_default_fromhz, 62 .fromus = cputimer_default_fromus, 63 .construct = tsc_cputimer_construct, 64 .destruct = cputimer_default_destruct, 65 .freq = 0 /* determined later */ 66 }; 67 68 static struct cpucounter tsc_cpucounter = { 69 .freq = 0, /* determined later */ 70 .count = NULL, /* determined later */ 71 .flags = 0, /* adjusted later */ 72 .prio = CPUCOUNTER_PRIO_TSC, 73 .type = CPUCOUNTER_TSC 74 }; 75 76 #ifdef _KERNEL_VIRTUAL 77 #define TSC_CPUTIMER_FREQMAX 2000000 /* 2MHz */ 78 #else 79 #define TSC_CPUTIMER_FREQMAX 128000000 /* 128Mhz */ 80 #endif 81 82 static int tsc_cputimer_shift; 83 84 static void 85 tsc_cputimer_construct(struct cputimer *timer, sysclock_t oldclock) 86 { 87 timer->base = 0; 88 timer->base = oldclock - timer->count(); 89 } 90 91 static __inline sysclock_t 92 tsc_cputimer_count(void) 93 { 94 uint64_t tsc; 95 96 tsc = rdtsc(); 97 tsc >>= tsc_cputimer_shift; 98 99 return (tsc + tsc_cputimer.base); 100 } 101 102 static sysclock_t 103 tsc_cputimer_count_lfence(void) 104 { 105 cpu_lfence(); 106 return tsc_cputimer_count(); 107 } 108 109 static sysclock_t 110 tsc_cputimer_count_mfence(void) 111 { 112 cpu_mfence(); 113 return tsc_cputimer_count(); 114 } 115 116 static uint64_t 117 tsc_cpucounter_count_lfence(void) 118 { 119 120 cpu_lfence(); 121 return (rdtsc()); 122 } 123 124 static uint64_t 125 tsc_cpucounter_count_mfence(void) 126 { 127 128 cpu_mfence(); 129 return (rdtsc()); 130 } 131 132 static void 133 tsc_cputimer_register(void) 134 { 135 uint64_t freq; 136 int enable = 1; 137 138 if (!tsc_mpsync) { 139 #ifndef _KERNEL_VIRTUAL 140 if (tsc_invariant) { 141 /* Per-cpu cpucounter still works. */ 142 goto regcnt; 143 } 144 #endif 145 return; 146 } 147 148 TUNABLE_INT_FETCH("hw.tsc_cputimer_enable", &enable); 149 if (!enable) 150 return; 151 152 freq = tsc_frequency; 153 while (freq > TSC_CPUTIMER_FREQMAX) { 154 freq >>= 1; 155 ++tsc_cputimer_shift; 156 } 157 kprintf("TSC: cputimer freq %ju, shift %d\n", 158 (uintmax_t)freq, tsc_cputimer_shift); 159 160 tsc_cputimer.freq = freq; 161 162 if (cpu_vendor_id == CPU_VENDOR_INTEL) 163 tsc_cputimer.count = tsc_cputimer_count_lfence; 164 else 165 tsc_cputimer.count = tsc_cputimer_count_mfence; /* safe bet */ 166 167 cputimer_register(&tsc_cputimer); 168 cputimer_select(&tsc_cputimer, 0); 169 170 tsc_cpucounter.flags |= CPUCOUNTER_FLAG_MPSYNC; 171 #ifndef _KERNEL_VIRTUAL 172 regcnt: 173 #endif 174 tsc_cpucounter.freq = tsc_frequency; 175 if (cpu_vendor_id == CPU_VENDOR_INTEL) { 176 tsc_cpucounter.count = 177 tsc_cpucounter_count_lfence; 178 } else { 179 tsc_cpucounter.count = 180 tsc_cpucounter_count_mfence; /* safe bet */ 181 } 182 cpucounter_register(&tsc_cpucounter); 183 } 184 SYSINIT(tsc_cputimer_reg, SI_BOOT2_POST_SMP, SI_ORDER_FIRST, 185 tsc_cputimer_register, NULL); 186