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, &current_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