The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/osfmk/i386/tsc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2005-2007 Apple Inc. All rights reserved.
    3  *
    4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
    5  * 
    6  * This file contains Original Code and/or Modifications of Original Code
    7  * as defined in and that are subject to the Apple Public Source License
    8  * Version 2.0 (the 'License'). You may not use this file except in
    9  * compliance with the License. The rights granted to you under the License
   10  * may not be used to create, or enable the creation or redistribution of,
   11  * unlawful or unlicensed copies of an Apple operating system, or to
   12  * circumvent, violate, or enable the circumvention or violation of, any
   13  * terms of an Apple operating system software license agreement.
   14  * 
   15  * Please obtain a copy of the License at
   16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
   17  * 
   18  * The Original Code and all software distributed under the License are
   19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   23  * Please see the License for the specific language governing rights and
   24  * limitations under the License.
   25  * 
   26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
   27  */
   28 /*
   29  * @OSF_COPYRIGHT@
   30  */
   31 
   32 /*
   33  *      File:           i386/tsc.c
   34  *      Purpose:        Initializes the TSC and the various conversion
   35  *                      factors needed by other parts of the system.
   36  */
   37 
   38 #include <platforms.h>
   39 
   40 #include <mach/mach_types.h>
   41 
   42 #include <kern/cpu_data.h>
   43 #include <kern/cpu_number.h>
   44 #include <kern/clock.h>
   45 #include <kern/host_notify.h>
   46 #include <kern/macro_help.h>
   47 #include <kern/misc_protos.h>
   48 #include <kern/spl.h>
   49 #include <kern/assert.h>
   50 #include <mach/vm_prot.h>
   51 #include <vm/pmap.h>
   52 #include <vm/vm_kern.h>         /* for kernel_map */
   53 #include <architecture/i386/pio.h>
   54 #include <i386/machine_cpu.h>
   55 #include <i386/cpuid.h>
   56 #include <i386/mp.h>
   57 #include <i386/machine_routines.h>
   58 #include <i386/proc_reg.h>
   59 #include <i386/tsc.h>
   60 #include <i386/misc_protos.h>
   61 #include <pexpert/pexpert.h>
   62 #include <machine/limits.h>
   63 #include <machine/commpage.h>
   64 #include <sys/kdebug.h>
   65 #include <pexpert/device_tree.h>
   66 
   67 uint64_t        busFCvtt2n = 0;
   68 uint64_t        busFCvtn2t = 0;
   69 uint64_t        tscFreq = 0;
   70 uint64_t        tscFCvtt2n = 0;
   71 uint64_t        tscFCvtn2t = 0;
   72 uint64_t        tscGranularity = 0;
   73 uint64_t        bus2tsc = 0;
   74 uint64_t        busFreq = 0;
   75 uint32_t        flex_ratio = 0;
   76 uint32_t        flex_ratio_min = 0;
   77 uint32_t        flex_ratio_max = 0;
   78 
   79 
   80 #define bit(n)          (1ULL << (n))
   81 #define bitmask(h,l)    ((bit(h)|(bit(h)-1)) & ~(bit(l)-1))
   82 #define bitfield(x,h,l) (((x) & bitmask(h,l)) >> l)
   83 
   84 /* Decimal powers: */
   85 #define kilo (1000ULL)
   86 #define Mega (kilo * kilo)
   87 #define Giga (kilo * Mega)
   88 #define Tera (kilo * Giga)
   89 #define Peta (kilo * Tera)
   90 
   91 #define CPU_FAMILY_PENTIUM_M    (0x6)
   92 
   93 static const char       FSB_Frequency_prop[] = "FSBFrequency";
   94 /*
   95  * This routine extracts the bus frequency in Hz from the device tree.
   96  */
   97 static uint64_t
   98 EFI_FSB_frequency(void)
   99 {
  100         uint64_t        frequency = 0;
  101         DTEntry         entry;
  102         void            *value;
  103         unsigned int    size;
  104 
  105         if (DTLookupEntry(0, "/efi/platform", &entry) != kSuccess) {
  106                 kprintf("EFI_FSB_frequency: didn't find /efi/platform\n");
  107                 return 0;
  108         }
  109         if (DTGetProperty(entry,FSB_Frequency_prop,&value,&size) != kSuccess) {
  110                 kprintf("EFI_FSB_frequency: property %s not found\n",
  111                         FSB_Frequency_prop);
  112                 return 0;
  113         }
  114         if (size == sizeof(uint64_t)) {
  115                 frequency = *(uint64_t *) value;
  116                 kprintf("EFI_FSB_frequency: read %s value: %llu\n",
  117                         FSB_Frequency_prop, frequency);
  118                 if (!(90*Mega < frequency && frequency < 10*Giga)) {
  119                         kprintf("EFI_FSB_frequency: value out of range\n");
  120                         frequency = 0;
  121                 }
  122         } else {
  123                 kprintf("EFI_FSB_frequency: unexpected size %d\n", size);
  124         }
  125         return frequency;
  126 }
  127 
  128 /*
  129  * Initialize the various conversion factors needed by code referencing
  130  * the TSC.
  131  */
  132 void
  133 tsc_init(void)
  134 {
  135         boolean_t       N_by_2_bus_ratio = FALSE;
  136 
  137         if (cpuid_vmm_present()) {
  138                 kprintf("VMM vendor %u TSC frequency %u KHz bus frequency %u KHz\n",
  139                                 cpuid_vmm_info()->cpuid_vmm_family,
  140                                 cpuid_vmm_info()->cpuid_vmm_tsc_frequency,
  141                                 cpuid_vmm_info()->cpuid_vmm_bus_frequency);
  142 
  143                 if (cpuid_vmm_info()->cpuid_vmm_tsc_frequency &&
  144                         cpuid_vmm_info()->cpuid_vmm_bus_frequency) {
  145 
  146                         busFreq = (uint64_t)cpuid_vmm_info()->cpuid_vmm_bus_frequency * kilo;
  147                         busFCvtt2n = ((1 * Giga) << 32) / busFreq;
  148                         busFCvtn2t = 0xFFFFFFFFFFFFFFFFULL / busFCvtt2n;
  149                         
  150                         tscFreq = (uint64_t)cpuid_vmm_info()->cpuid_vmm_tsc_frequency * kilo;
  151                         tscFCvtt2n = ((1 * Giga) << 32) / tscFreq;
  152                         tscFCvtn2t = 0xFFFFFFFFFFFFFFFFULL / tscFCvtt2n;
  153                         
  154                         tscGranularity = tscFreq / busFreq;
  155                         
  156                         bus2tsc = tmrCvt(busFCvtt2n, tscFCvtn2t);
  157 
  158                         return;
  159                 }
  160         }
  161 
  162         /*
  163          * Get the FSB frequency and conversion factors from EFI.
  164          */
  165         busFreq = EFI_FSB_frequency();
  166 
  167         switch (cpuid_cpufamily()) {
  168         case CPUFAMILY_INTEL_IVYBRIDGE:
  169         case CPUFAMILY_INTEL_SANDYBRIDGE:
  170         case CPUFAMILY_INTEL_WESTMERE:
  171         case CPUFAMILY_INTEL_NEHALEM: {
  172                 uint64_t msr_flex_ratio;
  173                 uint64_t msr_platform_info;
  174 
  175                 /* See if FLEX_RATIO is being used */
  176                 msr_flex_ratio = rdmsr64(MSR_FLEX_RATIO);
  177                 msr_platform_info = rdmsr64(MSR_PLATFORM_INFO);
  178                 flex_ratio_min = (uint32_t)bitfield(msr_platform_info, 47, 40);
  179                 flex_ratio_max = (uint32_t)bitfield(msr_platform_info, 15, 8);
  180                 /* No BIOS-programed flex ratio. Use hardware max as default */
  181                 tscGranularity = flex_ratio_max;
  182                 if (msr_flex_ratio & bit(16)) {
  183                         /* Flex Enabled: Use this MSR if less than max */
  184                         flex_ratio = (uint32_t)bitfield(msr_flex_ratio, 15, 8);
  185                         if (flex_ratio < flex_ratio_max)
  186                                 tscGranularity = flex_ratio;
  187                 }
  188 
  189                 /* If EFI isn't configured correctly, use a constant 
  190                  * value. See 6036811.
  191                  */
  192                 if (busFreq == 0)
  193                     busFreq = BASE_NHM_CLOCK_SOURCE;
  194 
  195                 break;
  196             }
  197         default: {
  198                 uint64_t        prfsts;
  199 
  200                 prfsts = rdmsr64(IA32_PERF_STS);
  201                 tscGranularity = (uint32_t)bitfield(prfsts, 44, 40);
  202                 N_by_2_bus_ratio = (prfsts & bit(46)) != 0;
  203             }
  204         }
  205 
  206         if (busFreq != 0) {
  207                 busFCvtt2n = ((1 * Giga) << 32) / busFreq;
  208                 busFCvtn2t = 0xFFFFFFFFFFFFFFFFULL / busFCvtt2n;
  209         } else {
  210                 panic("tsc_init: EFI not supported!\n");
  211         }
  212 
  213         kprintf(" BUS: Frequency = %6d.%06dMHz, "
  214                 "cvtt2n = %08Xx.%08Xx, cvtn2t = %08Xx.%08Xx\n",
  215                 (uint32_t)(busFreq / Mega),
  216                 (uint32_t)(busFreq % Mega), 
  217                 (uint32_t)(busFCvtt2n >> 32), (uint32_t)busFCvtt2n,
  218                 (uint32_t)(busFCvtn2t >> 32), (uint32_t)busFCvtn2t);
  219 
  220         /*
  221          * Get the TSC increment.  The TSC is incremented by this
  222          * on every bus tick.  Calculate the TSC conversion factors
  223          * to and from nano-seconds.
  224          * The tsc granularity is also called the "bus ratio". If the N/2 bit
  225          * is set this indicates the bus ration is 0.5 more than this - i.e.
  226          * that the true bus ratio is (2*tscGranularity + 1)/2. If we cannot
  227          * determine the TSC conversion, assume it ticks at the bus frequency.
  228          */
  229         if (tscGranularity == 0)
  230                 tscGranularity = 1;
  231 
  232         if (N_by_2_bus_ratio)
  233                 tscFCvtt2n = busFCvtt2n * 2 / (1 + 2*tscGranularity);
  234         else
  235                 tscFCvtt2n = busFCvtt2n / tscGranularity;
  236 
  237         tscFreq = ((1 * Giga)  << 32) / tscFCvtt2n;
  238         tscFCvtn2t = 0xFFFFFFFFFFFFFFFFULL / tscFCvtt2n;
  239 
  240         kprintf(" TSC: Frequency = %6d.%06dMHz, "
  241                 "cvtt2n = %08Xx.%08Xx, cvtn2t = %08Xx.%08Xx, gran = %lld%s\n",
  242                 (uint32_t)(tscFreq / Mega),
  243                 (uint32_t)(tscFreq % Mega), 
  244                 (uint32_t)(tscFCvtt2n >> 32), (uint32_t)tscFCvtt2n,
  245                 (uint32_t)(tscFCvtn2t >> 32), (uint32_t)tscFCvtn2t,
  246                 tscGranularity, N_by_2_bus_ratio ? " (N/2)" : "");
  247 
  248         /*
  249          * Calculate conversion from BUS to TSC
  250          */
  251         bus2tsc = tmrCvt(busFCvtt2n, tscFCvtn2t);
  252 }
  253 
  254 void
  255 tsc_get_info(tscInfo_t *info)
  256 {
  257         info->busFCvtt2n     = busFCvtt2n;
  258         info->busFCvtn2t     = busFCvtn2t;
  259         info->tscFreq        = tscFreq;
  260         info->tscFCvtt2n     = tscFCvtt2n;
  261         info->tscFCvtn2t     = tscFCvtn2t;
  262         info->tscGranularity = tscGranularity;
  263         info->bus2tsc        = bus2tsc;
  264         info->busFreq        = busFreq;
  265         info->flex_ratio     = flex_ratio;
  266         info->flex_ratio_min = flex_ratio_min;
  267         info->flex_ratio_max = flex_ratio_max;
  268 }

Cache object: f337f0458a9c46cae67f7e1c739d1883


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.