18cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/** 28cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @file cpu_type.c 38cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * CPU determination 48cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 58cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @remark Copyright 2002 OProfile authors 68cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @remark Read the file COPYING 78cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 88cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @author John Levon 98cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @author Philippe Elie 108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */ 118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "oprofile.h" 138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "op_msr.h" 148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <linux/smp.h> 168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike DoddEXPORT_NO_SYMBOLS; 188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike DoddMODULE_PARM(force_rtc, "i"); 208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike DoddMODULE_PARM_DESC(force_rtc, "force RTC mode."); 218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int force_rtc; 228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#ifndef HT_SUPPORT 248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/** 258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * p4_threads - determines the number of logical processor threads in a die 268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * returns number of threads in p4 die (1 for non-HT processors) 288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */ 298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int p4_threads(void) 308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int processor_threads = 1; 328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#ifdef CONFIG_SMP 348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (test_bit(X86_FEATURE_HT, ¤t_cpu_data.x86_capability)) { 358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* This it a Pentium 4 with HT, find number of threads */ 368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int eax, ebx, ecx, edx; 378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd cpuid (1, &eax, &ebx, &ecx, &edx); 398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd processor_threads = (ebx >> 16) & 0xff; 408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif /* CONFIG_SMP */ 428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return processor_threads; 448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#ifdef CONFIG_SMP 478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/** 488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * do_cpu_id - Call the cpuid instruction and fill in data at passed address 498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * We expect that data is pointing to an array of unsigned chars as big as there 518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * are cpus in an smp system. 528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */ 538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic void do_cpu_id(void * data) 548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int eax, ebx, ecx, edx; 568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd unsigned char * ptr = (unsigned char *) data; 578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd cpuid(1, &eax, &ebx, &ecx, &edx); 598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* bits EBX[31:24] define APIC ID */ 618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd ptr[smp_processor_id()] = (unsigned char) ((ebx & 0xff000000) >> 24); 628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif 648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/** 668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * p4_ht_enabled - Determines if Hyper Threading is enabled or not. 678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * A P4 can be capable of HT, but not enabled via BIOS. The check for 698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * this is unfortunately not simple and involves running cpuid on all 708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * logical processors and checking for bits in the APIC_ID fields. 718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * As per Intel docs. Returns 1 if enabled, 0 otherwise. 728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */ 748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstatic int p4_ht_enabled(void) 758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#ifndef CONFIG_SMP 778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return 0; 788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#else 798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int enabled, threads, i; 808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd unsigned char mask; 818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd unsigned char apic_id[smp_num_cpus]; 828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd unsigned int cpu; 838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* First check for capability */ 858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd threads = p4_threads(); 868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (threads == 1) return 0; 878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* Create mask for low order bits */ 888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd mask = 0xff; 898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd i = 1; 908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd while (i < threads) { 918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd i *= 2; 928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd mask <<= 1; 938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* Get APIC_ID from all logial procs and self */ 958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd smp_call_function(do_cpu_id, apic_id, 1, 1); 968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd do_cpu_id(apic_id); 978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* If the low order bits are on, then HT is enabled */ 988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd enabled = 0; 998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd cpu = 0; 1008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd do { 1018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (apic_id[cpu] & ~mask) { 1028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd enabled = 1; 1038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd break; 1048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd cpu++; 1068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } while (cpu < smp_num_cpus); 1078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return enabled; 1098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif /* CONFIG_SMP */ 1108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 1118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif /* !HT_SUPPORT */ 1128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddop_cpu p4_cpu_type(void) 1158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 1168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd __u8 model = current_cpu_data.x86_model; 1178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (model <= 4) { 1188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#ifdef HT_SUPPORT 1198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (smp_num_siblings == 1) { 1208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return CPU_P4; 1218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } else if (smp_num_siblings == 2) { 1228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return CPU_P4_HT2; 1238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } else { 1248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd printk(KERN_INFO 1258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd "oprofile: P4 HT unsupported number of siblings" 1268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd "processor, reverting to RTC\n"); 1278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return CPU_RTC; 1288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#else 1308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* Cannot handle enabled HT P4 hardware */ 1318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if ((p4_threads() > 1) && p4_ht_enabled()) { 1328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd printk(KERN_INFO 1338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd "oprofile: P4 HT enabled, reverting to RTC\n"); 1348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return CPU_RTC; 1358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd else 1378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return CPU_P4; 1388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#endif 1398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } else 1408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* Do not know what it is */ 1418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return CPU_RTC; 1428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 1438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd__init op_cpu get_cpu_type(void) 1468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 1478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd __u8 vendor = current_cpu_data.x86_vendor; 1488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd __u8 family = current_cpu_data.x86; 1498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd __u8 model = current_cpu_data.x86_model; 1508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd __u16 val; 1518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (force_rtc) 1538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return CPU_RTC; 1548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd switch (vendor) { 1568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd case X86_VENDOR_AMD: 1578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (family == 6) { 1588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* certain models of K7 does not have apic. 1598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Check if apic is really present before enabling it. 1608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * IA32 V3, 7.4.1 */ 1618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd val = cpuid_edx(1); 1628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (!(val & (1 << 9))) 1638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return CPU_RTC; 1648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return CPU_ATHLON; 1658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (family == 15) 1678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return CPU_HAMMER; 1688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return CPU_RTC; 1698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd case X86_VENDOR_INTEL: 1718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd switch (family) { 1728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd default: 1738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return CPU_RTC; 1748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd case 6: 1758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* A P6-class processor */ 1768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (model == 14) 1778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return CPU_CORE; 1788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (model > 0xd) 1798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return CPU_RTC; 1808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (model > 5) 1818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return CPU_PIII; 1828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd else if (model > 2) 1838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return CPU_PII; 1848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return CPU_PPRO; 1858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd case 0xf: 1868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return p4_cpu_type(); 1878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd default: 1908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return CPU_RTC; 1918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 193