proc.c 5.97 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5
#include <linux/smp.h>
#include <linux/timex.h>
#include <linux/string.h>
#include <asm/semaphore.h>
#include <linux/seq_file.h>
6
#include <linux/cpufreq.h>
Linus Torvalds's avatar
Linus Torvalds committed
7 8 9 10 11 12 13 14 15 16 17 18 19 20

/*
 *	Get CPU information for use by the procfs.
 */
static int show_cpuinfo(struct seq_file *m, void *v)
{
	/* 
	 * These flag bits must match the definitions in <asm/cpufeature.h>.
	 * NULL means this bit is undefined or reserved; either way it doesn't
	 * have meaning as far as Linux is concerned.  Note that it's important
	 * to realize there is a difference between this table and CPUID -- if
	 * applications want to get the raw CPUID data, they should access
	 * /dev/cpu/<cpu_nr>/cpuid instead.
	 */
21
	static const char * const x86_cap_flags[] = {
Linus Torvalds's avatar
Linus Torvalds committed
22 23 24 25 26 27 28
		/* Intel-defined */
	        "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
	        "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
	        "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
	        "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",

		/* AMD-defined */
29
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Linus Torvalds's avatar
Linus Torvalds committed
30 31
		NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
		NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL,
32 33
		NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm",
		"3dnowext", "3dnow",
Linus Torvalds's avatar
Linus Torvalds committed
34 35 36 37 38 39 40 41 42 43

		/* Transmeta-defined */
		"recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

		/* Other (Linux-defined) */
		"cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
		NULL, NULL, NULL, NULL,
44 45 46
		"constant_tsc", "up", NULL, "arch_perfmon",
		"pebs", "bts", NULL, "sync_rdtsc",
		"rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Linus Torvalds's avatar
Linus Torvalds committed
47 48 49
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

		/* Intel-defined (#2) */
50
		"pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
51
		"tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
52
		NULL, NULL, "dca", "sse4_1", "sse4_2", NULL, NULL, "popcnt",
Linus Torvalds's avatar
Linus Torvalds committed
53 54 55 56
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

		/* VIA/Cyrix/Centaur-defined */
		NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
57
		"ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
Linus Torvalds's avatar
Linus Torvalds committed
58 59 60 61
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

		/* AMD-defined (#2) */
62 63 64 65
		"lahf_lm", "cmp_legacy", "svm", "extapic",
		"cr8_legacy", "abm", "sse4a", "misalignsse",
		"3dnowprefetch", "osvw", "ibs", "sse5",
		"skinit", "wdt", NULL, NULL,
Linus Torvalds's avatar
Linus Torvalds committed
66 67
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
68 69 70 71 72 73

		/* Auxiliary (Linux-defined) */
		"ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
Linus Torvalds's avatar
Linus Torvalds committed
74
	};
75
	static const char * const x86_power_flags[] = {
76 77 78 79 80 81
		"ts",	/* temperature sensor */
		"fid",  /* frequency id control */
		"vid",  /* voltage id control */
		"ttp",  /* thermal trip */
		"tm",
		"stc",
82 83
		"100mhzsteps",
		"hwpstate",
84
		"",	/* constant_tsc - moved to flags */
85
		/* nothing */
86
	};
Linus Torvalds's avatar
Linus Torvalds committed
87
	struct cpuinfo_x86 *c = v;
88
	int i, n = 0;
Linus Torvalds's avatar
Linus Torvalds committed
89 90 91
	int fpu_exception;

#ifdef CONFIG_SMP
92
	n = c->cpu_index;
Linus Torvalds's avatar
Linus Torvalds committed
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
#endif
	seq_printf(m, "processor\t: %d\n"
		"vendor_id\t: %s\n"
		"cpu family\t: %d\n"
		"model\t\t: %d\n"
		"model name\t: %s\n",
		n,
		c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown",
		c->x86,
		c->x86_model,
		c->x86_model_id[0] ? c->x86_model_id : "unknown");

	if (c->x86_mask || c->cpuid_level >= 0)
		seq_printf(m, "stepping\t: %d\n", c->x86_mask);
	else
		seq_printf(m, "stepping\t: unknown\n");

	if ( cpu_has(c, X86_FEATURE_TSC) ) {
111 112 113
		unsigned int freq = cpufreq_quick_get(n);
		if (!freq)
			freq = cpu_khz;
114
		seq_printf(m, "cpu MHz\t\t: %u.%03u\n",
115
			freq / 1000, (freq % 1000));
Linus Torvalds's avatar
Linus Torvalds committed
116 117 118 119 120 121
	}

	/* Cache size */
	if (c->x86_cache_size >= 0)
		seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
#ifdef CONFIG_X86_HT
122
	if (c->x86_max_cores * smp_num_siblings > 1) {
123
		seq_printf(m, "physical id\t: %d\n", c->phys_proc_id);
124 125
		seq_printf(m, "siblings\t: %d\n",
				cpus_weight(per_cpu(cpu_core_map, n)));
126
		seq_printf(m, "core id\t\t: %d\n", c->cpu_core_id);
127
		seq_printf(m, "cpu cores\t: %d\n", c->booted_cores);
128
	}
Linus Torvalds's avatar
Linus Torvalds committed
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
#endif
	
	/* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */
	fpu_exception = c->hard_math && (ignore_fpu_irq || cpu_has_fpu);
	seq_printf(m, "fdiv_bug\t: %s\n"
			"hlt_bug\t\t: %s\n"
			"f00f_bug\t: %s\n"
			"coma_bug\t: %s\n"
			"fpu\t\t: %s\n"
			"fpu_exception\t: %s\n"
			"cpuid level\t: %d\n"
			"wp\t\t: %s\n"
			"flags\t\t:",
		     c->fdiv_bug ? "yes" : "no",
		     c->hlt_works_ok ? "no" : "yes",
		     c->f00f_bug ? "yes" : "no",
		     c->coma_bug ? "yes" : "no",
		     c->hard_math ? "yes" : "no",
		     fpu_exception ? "yes" : "no",
		     c->cpuid_level,
		     c->wp_works_ok ? "yes" : "no");

	for ( i = 0 ; i < 32*NCAPINTS ; i++ )
		if ( test_bit(i, c->x86_capability) &&
		     x86_cap_flags[i] != NULL )
			seq_printf(m, " %s", x86_cap_flags[i]);

156 157 158 159 160 161 162 163 164 165 166
	for (i = 0; i < 32; i++)
		if (c->x86_power & (1 << i)) {
			if (i < ARRAY_SIZE(x86_power_flags) &&
			    x86_power_flags[i])
				seq_printf(m, "%s%s",
					   x86_power_flags[i][0]?" ":"",
					   x86_power_flags[i]);
			else
				seq_printf(m, " [%d]", i);
		}

167
	seq_printf(m, "\nbogomips\t: %lu.%02lu\n",
Linus Torvalds's avatar
Linus Torvalds committed
168 169
		     c->loops_per_jiffy/(500000/HZ),
		     (c->loops_per_jiffy/(5000/HZ)) % 100);
170
	seq_printf(m, "clflush size\t: %u\n\n", c->x86_clflush_size);
171

Linus Torvalds's avatar
Linus Torvalds committed
172 173 174 175 176
	return 0;
}

static void *c_start(struct seq_file *m, loff_t *pos)
{
177
	if (*pos == 0)	/* just in case, cpu 0 is not the first */
178 179
		*pos = first_cpu(cpu_online_map);
	if ((*pos) < NR_CPUS && cpu_online(*pos))
180 181
		return &cpu_data(*pos);
	return NULL;
Linus Torvalds's avatar
Linus Torvalds committed
182 183 184
}
static void *c_next(struct seq_file *m, void *v, loff_t *pos)
{
185
	*pos = next_cpu(*pos, cpu_online_map);
Linus Torvalds's avatar
Linus Torvalds committed
186 187 188 189 190 191 192 193 194 195 196
	return c_start(m, pos);
}
static void c_stop(struct seq_file *m, void *v)
{
}
struct seq_operations cpuinfo_op = {
	.start	= c_start,
	.next	= c_next,
	.stop	= c_stop,
	.show	= show_cpuinfo,
};