Home | History | Annotate | Line # | Download | only in x86
      1 /*	$NetBSD: intel_busclock.c,v 1.26 2023/01/20 01:35:03 msaitoh Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Frank van der Linden,  and by Jason R. Thorpe.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: intel_busclock.c,v 1.26 2023/01/20 01:35:03 msaitoh Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/systm.h>
     37 #include <sys/device.h>
     38 #include <sys/cpu.h>
     39 
     40 #include <machine/specialreg.h>
     41 #include <machine/pio.h>
     42 
     43 #include <x86/cpuvar.h>
     44 #include <x86/cpufunc.h>
     45 #include <x86/est.h>
     46 
     47 int
     48 via_get_bus_clock(struct cpu_info *ci)
     49 {
     50 	uint64_t msr;
     51 	int bus, bus_clock = 0;
     52 
     53 	msr = rdmsr(MSR_EBL_CR_POWERON);
     54 	bus = (msr >> 18) & 0x3;
     55 	switch (bus) {
     56 	case 0:
     57 		bus_clock = 10000;
     58 		break;
     59 	case 1:
     60 		bus_clock = 13333;
     61 		break;
     62 	case 2:
     63 		bus_clock = 20000;
     64 		break;
     65 	case 3:
     66 		bus_clock = 16667;
     67 		break;
     68 	default:
     69 		break;
     70 	}
     71 
     72 	return bus_clock;
     73 }
     74 
     75 int
     76 viac7_get_bus_clock(struct cpu_info *ci)
     77 {
     78 	uint64_t msr;
     79 	int mult;
     80 
     81 	msr = rdmsr(MSR_PERF_STATUS);
     82 	mult = (msr >> 8) & 0xff;
     83 	if (mult == 0)
     84 		return 0;
     85 
     86 	return ((ci->ci_data.cpu_cc_freq + 10000000) / 10000000 * 10000000) /
     87 		 mult / 10000;
     88 }
     89 
     90 int
     91 p3_get_bus_clock(struct cpu_info *ci)
     92 {
     93 	uint64_t msr;
     94 	int bus, bus_clock = 0;
     95 	uint32_t model;
     96 
     97 	model = CPUID_TO_MODEL(ci->ci_signature);
     98 
     99 	switch (model) {
    100 	case 0x9: /* Pentium M (130 nm, Banias) */
    101 		bus_clock = 10000;
    102 		break;
    103 	case 0xc: /* Core i7, Atom, model 1 */
    104 		/*
    105 		 * Newer CPUs will GP when attempting to access MSR_FSB_FREQ.
    106 		 * In the long-term, use ACPI instead of all this.
    107 		 */
    108 		if (rdmsr_safe(MSR_FSB_FREQ, &msr) == EFAULT) {
    109 			aprint_debug_dev(ci->ci_dev,
    110 			    "unable to determine bus speed");
    111 			goto print_msr;
    112 		}
    113 		bus = (msr >> 0) & 0x7;
    114 		switch (bus) {
    115 		case 1:
    116 			bus_clock = 13333;
    117 			break;
    118 		default:
    119 			aprint_debug("%s: unknown Atom FSB_FREQ "
    120 			    "value %d", device_xname(ci->ci_dev), bus);
    121 			goto print_msr;
    122 		}
    123 		break;
    124 	case 0xd: /* Pentium M (90 nm, Dothan) */
    125 		if (rdmsr_safe(MSR_FSB_FREQ, &msr) == EFAULT) {
    126 			aprint_debug_dev(ci->ci_dev,
    127 			    "unable to determine bus speed");
    128 			goto print_msr;
    129 		}
    130 		bus = (msr >> 0) & 0x7;
    131 		switch (bus) {
    132 		case 0:
    133 			bus_clock = 10000;
    134 			break;
    135 		case 1:
    136 			bus_clock = 13333;
    137 			break;
    138 		default:
    139 			aprint_debug("%s: unknown Pentium M FSB_FREQ "
    140 			    "value %d", device_xname(ci->ci_dev), bus);
    141 			goto print_msr;
    142 		}
    143 		break;
    144 	case 0xe: /* Core Duo/Solo */
    145 	case 0xf: /* Core Xeon */
    146 	case 0x17: /* Xeon [35]000, Core 2 Quad [89]00 */
    147 		if (rdmsr_safe(MSR_FSB_FREQ, &msr) == EFAULT) {
    148 			aprint_debug_dev(ci->ci_dev,
    149 			    "unable to determine bus speed");
    150 			goto print_msr;
    151 		}
    152 		bus = (msr >> 0) & 0x7;
    153 		switch (bus) {
    154 		case 5:
    155 			bus_clock = 10000;
    156 			break;
    157 		case 1:
    158 			bus_clock = 13333;
    159 			break;
    160 		case 3:
    161 			bus_clock = 16667;
    162 			break;
    163 		case 2:
    164 			bus_clock = 20000;
    165 			break;
    166 		case 0:
    167 			bus_clock = 26667;
    168 			break;
    169 		case 4:
    170 			bus_clock = 33333;
    171 			break;
    172 		case 6:
    173 			bus_clock = 40000;
    174 			break;
    175 		default:
    176 			aprint_debug("%s: unknown Core FSB_FREQ value %d",
    177 			    device_xname(ci->ci_dev), bus);
    178 			goto print_msr;
    179 		}
    180 		break;
    181 	case 0x1: /* Pentium Pro, model 1 */
    182 	case 0x3: /* Pentium II, model 3 */
    183 	case 0x5: /* Pentium II, II Xeon, Celeron, model 5 */
    184 	case 0x6: /* Celeron, model 6 */
    185 	case 0x7: /* Pentium III, III Xeon, model 7 */
    186 	case 0x8: /* Pentium III, III Xeon, Celeron, model 8 */
    187 	case 0xa: /* Pentium III Xeon, model A */
    188 	case 0xb: /* Pentium III, model B */
    189 		msr = rdmsr(MSR_EBL_CR_POWERON);
    190 		bus = (msr >> 18) & 0x3;
    191 		switch (bus) {
    192 		case 0:
    193 			bus_clock = 6666;
    194 			break;
    195 		case 1:
    196 			bus_clock = 13333;
    197 			break;
    198 		case 2:
    199 			bus_clock = 10000;
    200 			break;
    201 		case 3:
    202 			bus_clock = 10666;
    203 			break;
    204 		default:
    205 			aprint_debug("%s: unknown i686 EBL_CR_POWERON "
    206 			    "value %d ", device_xname(ci->ci_dev), bus);
    207 			goto print_msr;
    208 		}
    209 		break;
    210 	case 0x1c: /* Atom */
    211 	case 0x26:
    212 	case 0x27:
    213 	case 0x35:
    214 	case 0x36:
    215 		if (rdmsr_safe(MSR_FSB_FREQ, &msr) == EFAULT) {
    216 			aprint_debug_dev(ci->ci_dev,
    217 			    "unable to determine bus speed");
    218 			goto print_msr;
    219 		}
    220 		bus = (msr >> 0) & 0x7;
    221 		switch (bus) {
    222 		case 7:
    223 			bus_clock =  8333;
    224 			break;
    225 		case 5:
    226 			bus_clock = 10000;
    227 			break;
    228 		case 1:
    229 			bus_clock = 13333;
    230 			break;
    231 		case 3:
    232 			bus_clock = 16667;
    233 			break;
    234 		default:
    235 			aprint_debug("%s: unknown Atom FSB_FREQ value %d",
    236 			    device_xname(ci->ci_dev), bus);
    237 			goto print_msr;
    238 		}
    239 		break;
    240 	case 0x37: /* Silvermont */
    241 	case 0x4a:
    242 	case 0x4d:
    243 	case 0x5a:
    244 	case 0x5d:
    245 		if (rdmsr_safe(MSR_FSB_FREQ, &msr) == EFAULT) {
    246 			aprint_debug_dev(ci->ci_dev,
    247 			    "unable to determine bus speed");
    248 			goto print_msr;
    249 		}
    250 		bus = (msr >> 0) & 0x7;
    251 		switch (bus) {
    252 		case 4:
    253 			bus_clock =  8000;
    254 			break;
    255 		case 0:
    256 			bus_clock =  8333;
    257 			break;
    258 		case 1:
    259 			bus_clock = 10000;
    260 			break;
    261 		case 2:
    262 			bus_clock = 13333;
    263 			break;
    264 		case 3:
    265 			bus_clock = 11667;
    266 			break;
    267 		default:
    268 			aprint_debug("%s: unknown Silvermont FSB_FREQ value %d",
    269 			    device_xname(ci->ci_dev), bus);
    270 			goto print_msr;
    271 		}
    272 		break;
    273 	case 0x4c: /* Airmont */
    274 		if (rdmsr_safe(MSR_FSB_FREQ, &msr) == EFAULT) {
    275 			aprint_debug_dev(ci->ci_dev,
    276 			    "unable to determine bus speed");
    277 			goto print_msr;
    278 		}
    279 		bus = (msr >> 0) & 0x0f;
    280 		switch (bus) {
    281 		case 0:
    282 			bus_clock =  8333;
    283 			break;
    284 		case 1:
    285 			bus_clock = 10000;
    286 			break;
    287 		case 2:
    288 			bus_clock = 13333;
    289 			break;
    290 		case 3:
    291 			bus_clock = 11666;
    292 			break;
    293 		case 4:
    294 			bus_clock =  8000;
    295 			break;
    296 		case 5:
    297 			bus_clock =  9333;
    298 			break;
    299 		case 6:
    300 			bus_clock =  9000;
    301 			break;
    302 		case 7:
    303 			bus_clock =  8888;
    304 			break;
    305 		case 8:
    306 			bus_clock =  8750;
    307 			break;
    308 		default:
    309 			aprint_debug("%s: unknown Airmont FSB_FREQ value %d",
    310 			    device_xname(ci->ci_dev), bus);
    311 			goto print_msr;
    312 		}
    313 		break;
    314 	default:
    315 		aprint_debug("%s: unknown i686 model %02x, can't get bus clock",
    316 		    device_xname(ci->ci_dev),
    317 		    CPUID_TO_MODEL(ci->ci_signature));
    318 print_msr:
    319 		/*
    320 		 * Show the EBL_CR_POWERON MSR, so we'll at least have
    321 		 * some extra information, such as clock ratio, etc.
    322 		 */
    323 		aprint_debug(" (0x%" PRIu64 ")\n", rdmsr(MSR_EBL_CR_POWERON));
    324 		break;
    325 	}
    326 
    327 	return bus_clock;
    328 }
    329 
    330 int
    331 p4_get_bus_clock(struct cpu_info *ci)
    332 {
    333 	uint64_t msr;
    334 	int bus, bus_clock = 0;
    335 
    336 	msr = rdmsr(MSR_EBC_FREQUENCY_ID);
    337 	if (CPUID_TO_MODEL(ci->ci_signature) < 2) {
    338 		bus = (msr >> 21) & 0x7;
    339 		switch (bus) {
    340 		case 0:
    341 			bus_clock = 10000;
    342 			break;
    343 		case 1:
    344 			bus_clock = 13333;
    345 			break;
    346 		default:
    347 			aprint_debug("%s: unknown Pentium 4 (model %d) "
    348 			    "EBC_FREQUENCY_ID value %d\n",
    349 			    device_xname(ci->ci_dev),
    350 			    CPUID_TO_MODEL(ci->ci_signature), bus);
    351 			break;
    352 		}
    353 	} else {
    354 		bus = (msr >> 16) & 0x7;
    355 		switch (bus) {
    356 		case 0:
    357 			bus_clock = (CPUID_TO_MODEL(ci->ci_signature) == 2) ?
    358 			    10000 : 26667;
    359 			break;
    360 		case 1:
    361 			bus_clock = 13333;
    362 			break;
    363 		case 2:
    364 			bus_clock = 20000;
    365 			break;
    366 		case 3:
    367 			bus_clock = 16667;
    368 			break;
    369 		case 4:
    370 			bus_clock = 33333;
    371 			break;
    372 		default:
    373 			aprint_debug("%s: unknown Pentium 4 (model %d) "
    374 			    "EBC_FREQUENCY_ID value %d\n",
    375 			    device_xname(ci->ci_dev),
    376 			    CPUID_TO_MODEL(ci->ci_signature), bus);
    377 			break;
    378 		}
    379 	}
    380 
    381 	return bus_clock;
    382 }
    383