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  -  FREEBSD11  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
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 #include <mach_kdb.h>
   40 
   41 #include <mach/mach_types.h>
   42 
   43 #include <kern/cpu_data.h>
   44 #include <kern/cpu_number.h>
   45 #include <kern/clock.h>
   46 #include <kern/host_notify.h>
   47 #include <kern/macro_help.h>
   48 #include <kern/misc_protos.h>
   49 #include <kern/spl.h>
   50 #include <kern/assert.h>
   51 #include <mach/vm_prot.h>
   52 #include <vm/pmap.h>
   53 #include <vm/vm_kern.h>         /* for kernel_map */
   54 #include <i386/ipl.h>
   55 #include <architecture/i386/pio.h>
   56 #include <i386/machine_cpu.h>
   57 #include <i386/cpuid.h>
   58 #include <i386/mp.h>
   59 #include <i386/machine_routines.h>
   60 #include <i386/proc_reg.h>
   61 #include <i386/tsc.h>
   62 #include <i386/misc_protos.h>
   63 #include <pexpert/pexpert.h>
   64 #include <machine/limits.h>
   65 #include <machine/commpage.h>
   66 #include <sys/kdebug.h>
   67 #include <pexpert/device_tree.h>
   68 
   69 uint64_t        busFCvtt2n = 0;
   70 uint64_t        busFCvtn2t = 0;
   71 uint64_t        tscFreq = 0;
   72 uint64_t        tscFCvtt2n = 0;
   73 uint64_t        tscFCvtn2t = 0;
   74 uint64_t        tscGranularity = 0;
   75 uint64_t        bus2tsc = 0;
   76 uint64_t        busFreq = 0;
   77 uint32_t        flex_ratio = 0;
   78 uint32_t        flex_ratio_min = 0;
   79 uint32_t        flex_ratio_max = 0;
   80 
   81 
   82 #define bit(n)          (1ULL << (n))
   83 #define bitmask(h,l)    ((bit(h)|(bit(h)-1)) & ~(bit(l)-1))
   84 #define bitfield(x,h,l) (((x) & bitmask(h,l)) >> l)
   85 
   86 /* Decimal powers: */
   87 #define kilo (1000ULL)
   88 #define Mega (kilo * kilo)
   89 #define Giga (kilo * Mega)
   90 #define Tera (kilo * Giga)
   91 #define Peta (kilo * Tera)
   92 
   93 #define CPU_FAMILY_PENTIUM_M    (0x6)
   94 
   95 static const char       FSB_Frequency_prop[] = "FSBFrequency";
   96 /*
   97  * This routine extracts the bus frequency in Hz from the device tree.
   98  */
   99 static uint64_t
  100 EFI_FSB_frequency(void)
  101 {
  102         uint64_t        frequency = 0;
  103         DTEntry         entry;
  104         void            *value;
  105         unsigned int    size;
  106 
  107         if (DTLookupEntry(0, "/efi/platform", &entry) != kSuccess) {
  108                 kprintf("EFI_FSB_frequency: didn't find /efi/platform\n");
  109                 return 0;
  110         }
  111         if (DTGetProperty(entry,FSB_Frequency_prop,&value,&size) != kSuccess) {
  112                 kprintf("EFI_FSB_frequency: property %s not found\n",
  113                         FSB_Frequency_prop);
  114                 return 0;
  115         }
  116         if (size == sizeof(uint64_t)) {
  117                 frequency = *(uint64_t *) value;
  118                 kprintf("EFI_FSB_frequency: read %s value: %llu\n",
  119                         FSB_Frequency_prop, frequency);
  120                 if (!(90*Mega < frequency && frequency < 10*Giga)) {
  121                         kprintf("EFI_FSB_frequency: value out of range\n");
  122                         frequency = 0;
  123                 }
  124         } else {
  125                 kprintf("EFI_FSB_frequency: unexpected size %d\n", size);
  126         }
  127         return frequency;
  128 }
  129 
  130 /*
  131  * Initialize the various conversion factors needed by code referencing
  132  * the TSC.
  133  */
  134 void
  135 tsc_init(void)
  136 {
  137         uint64_t        busFCvtInt = 0;
  138         boolean_t       N_by_2_bus_ratio = FALSE;
  139 
  140         /*
  141          * Get the FSB frequency and conversion factors from EFI.
  142          */
  143         busFreq = EFI_FSB_frequency();
  144 
  145         if (cpuid_info()->cpuid_family != CPU_FAMILY_PENTIUM_M) {
  146                 panic("tsc_init: unknown CPU family: 0x%X\n",
  147                         cpuid_info()->cpuid_family);
  148         }
  149 
  150         switch (cpuid_info()->cpuid_model) {
  151         case CPUID_MODEL_NEHALEM: {
  152                 uint64_t cpu_mhz;
  153                 uint64_t msr_flex_ratio;
  154                 uint64_t msr_platform_info;
  155 
  156                 /* See if FLEX_RATIO is being used */
  157                 msr_flex_ratio = rdmsr64(MSR_FLEX_RATIO);
  158                 msr_platform_info = rdmsr64(MSR_PLATFORM_INFO);
  159                 flex_ratio_min = (uint32_t)bitfield(msr_platform_info, 47, 40);
  160                 flex_ratio_max = (uint32_t)bitfield(msr_platform_info, 15, 8);
  161                 /* No BIOS-programed flex ratio. Use hardware max as default */
  162                 tscGranularity = flex_ratio_max;
  163                 if (msr_flex_ratio & bit(16)) {
  164                         /* Flex Enabled: Use this MSR if less than max */
  165                         flex_ratio = (uint32_t)bitfield(msr_flex_ratio, 15, 8);
  166                         if (flex_ratio < flex_ratio_max)
  167                                 tscGranularity = flex_ratio;
  168                 }
  169 
  170                 /* If EFI isn't configured correctly, use a constant 
  171                  * value. See 6036811.
  172                  */
  173                 if (busFreq == 0)
  174                     busFreq = BASE_NHM_CLOCK_SOURCE;
  175 
  176                 cpu_mhz = tscGranularity * BASE_NHM_CLOCK_SOURCE;
  177 
  178                 break;
  179             }
  180         default: {
  181                 uint64_t        prfsts;
  182 
  183                 prfsts = rdmsr64(IA32_PERF_STS);
  184                 tscGranularity = (uint32_t)bitfield(prfsts, 44, 40);
  185                 N_by_2_bus_ratio = (prfsts & bit(46)) != 0;
  186             }
  187         }
  188 
  189         if (busFreq != 0) {
  190                 busFCvtt2n = ((1 * Giga) << 32) / busFreq;
  191                 busFCvtn2t = 0xFFFFFFFFFFFFFFFFULL / busFCvtt2n;
  192                 busFCvtInt = tmrCvt(1 * Peta, 0xFFFFFFFFFFFFFFFFULL / busFreq); 
  193         } else {
  194                 panic("tsc_init: EFI not supported!\n");
  195         }
  196 
  197         kprintf(" BUS: Frequency = %6d.%04dMHz, "
  198                 "cvtt2n = %08X.%08X, cvtn2t = %08X.%08X, "
  199                 "cvtInt = %08X.%08X\n",
  200                 (uint32_t)(busFreq / Mega),
  201                 (uint32_t)(busFreq % Mega), 
  202                 (uint32_t)(busFCvtt2n >> 32), (uint32_t)busFCvtt2n,
  203                 (uint32_t)(busFCvtn2t >> 32), (uint32_t)busFCvtn2t,
  204                 (uint32_t)(busFCvtInt >> 32), (uint32_t)busFCvtInt);
  205 
  206         /*
  207          * Get the TSC increment.  The TSC is incremented by this
  208          * on every bus tick.  Calculate the TSC conversion factors
  209          * to and from nano-seconds.
  210          * The tsc granularity is also called the "bus ratio". If the N/2 bit
  211          * is set this indicates the bus ration is 0.5 more than this - i.e.
  212          * that the true bus ratio is (2*tscGranularity + 1)/2.
  213          */
  214         if (N_by_2_bus_ratio)
  215                 tscFCvtt2n = busFCvtt2n * 2 / (1 + 2*tscGranularity);
  216         else
  217                 tscFCvtt2n = busFCvtt2n / tscGranularity;
  218 
  219         tscFreq = ((1 * Giga)  << 32) / tscFCvtt2n;
  220         tscFCvtn2t = 0xFFFFFFFFFFFFFFFFULL / tscFCvtt2n;
  221 
  222         kprintf(" TSC: Frequency = %6d.%04dMHz, "
  223                 "cvtt2n = %08X.%08X, cvtn2t = %08X.%08X, gran = %lld%s\n",
  224                 (uint32_t)(tscFreq / Mega),
  225                 (uint32_t)(tscFreq % Mega), 
  226                 (uint32_t)(tscFCvtt2n >> 32), (uint32_t)tscFCvtt2n,
  227                 (uint32_t)(tscFCvtn2t >> 32), (uint32_t)tscFCvtn2t,
  228                 tscGranularity, N_by_2_bus_ratio ? " (N/2)" : "");
  229 
  230         /*
  231          * Calculate conversion from BUS to TSC
  232          */
  233         bus2tsc = tmrCvt(busFCvtt2n, tscFCvtn2t);
  234 }
  235 
  236 void
  237 tsc_get_info(tscInfo_t *info)
  238 {
  239         info->busFCvtt2n     = busFCvtt2n;
  240         info->busFCvtn2t     = busFCvtn2t;
  241         info->tscFreq        = tscFreq;
  242         info->tscFCvtt2n     = tscFCvtt2n;
  243         info->tscFCvtn2t     = tscFCvtn2t;
  244         info->tscGranularity = tscGranularity;
  245         info->bus2tsc        = bus2tsc;
  246         info->busFreq        = busFreq;
  247         info->flex_ratio     = flex_ratio;
  248         info->flex_ratio_min = flex_ratio_min;
  249         info->flex_ratio_max = flex_ratio_max;
  250 }

Cache object: c641ea80e789b556f2916c8a2ac6bf08


[ 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.