1 | /*␊ |
2 | * Copyright 2008 Islam Ahmed Zaid. All rights reserved. <azismed@gmail.com>␊ |
3 | * AsereBLN: 2009: cleanup and bugfix␊ |
4 | */␊ |
5 | ␊ |
6 | #ifndef __LIBSAIO_CPU_H␊ |
7 | #define __LIBSAIO_CPU_H␊ |
8 | ␊ |
9 | #include "libsaio.h"␊ |
10 | ␊ |
11 | extern void scan_cpu(PlatformInfo_t *);␊ |
12 | ␊ |
13 | #define␉MSR_IA32_PERF_STATUS␉0x198␊ |
14 | #define MSR_IA32_PERF_CONTROL␉0x199␊ |
15 | #define MSR_IA32_EXT_CONFIG␉␉0x00EE␊ |
16 | #define MSR_FLEX_RATIO␉␉␉0x194␊ |
17 | #define␉MSR_PLATFORM_INFO␉␉0xCE␊ |
18 | #define MSR_TURBO_RATIO_LIMIT␉0x1AD␊ |
19 | #define MSR_IA32_BIOS_SIGN_ID 0x08B␊ |
20 | #define MSR_CORE_THREAD_COUNT 0x035␊ |
21 | #define K8_FIDVID_STATUS␉␉0xC0010042␊ |
22 | #define K10_COFVID_STATUS␉␉0xC0010071␊ |
23 | ␊ |
24 | #define DEFAULT_FSB␉␉100000 /* for now, hardcoding 100MHz for old CPUs */␊ |
25 | ␊ |
26 | // DFE: This constant comes from older xnu:␊ |
27 | #define CLKNUM␉␉␉1193182␉␉/* formerly 1193167 */␊ |
28 | ␊ |
29 | // DFE: These two constants come from Linux except CLOCK_TICK_RATE replaced with CLKNUM␊ |
30 | #define CALIBRATE_TIME_MSEC␉30␉␉/* 30 msecs */␊ |
31 | #define CALIBRATE_LATCH␉␉((CLKNUM * CALIBRATE_TIME_MSEC + 1000/2)/1000)␊ |
32 | ␊ |
33 | static inline uint64_t rdtsc64(void)␊ |
34 | {␊ |
35 | ␉uint64_t ret;␊ |
36 | ␉__asm__ volatile("rdtsc" : "=A" (ret));␊ |
37 | ␉return ret;␊ |
38 | }␊ |
39 | ␊ |
40 | static inline uint64_t rdmsr64(uint32_t msr)␊ |
41 | {␊ |
42 | uint64_t ret;␊ |
43 | __asm__ volatile("rdmsr" : "=A" (ret) : "c" (msr));␊ |
44 | return ret;␊ |
45 | }␊ |
46 | ␊ |
47 | static inline void wrmsr64(uint32_t msr, uint64_t val)␊ |
48 | {␊ |
49 | ␉__asm__ volatile("wrmsr" : : "c" (msr), "A" (val));␊ |
50 | }␊ |
51 | ␊ |
52 | static inline void intel_waitforsts(void) {␊ |
53 | ␉uint32_t inline_timeout = 100000;␊ |
54 | ␉while (rdmsr64(MSR_IA32_PERF_STATUS) & (1 << 21)) { if (!inline_timeout--) break; }␊ |
55 | }␊ |
56 | ␊ |
57 | static inline void do_cpuid2(uint32_t selector, uint32_t selector2, uint32_t *data)␊ |
58 | {␊ |
59 | ␉asm volatile ("cpuid"␊ |
60 | ␉␉␉␉ : "=a" (data[0]),␊ |
61 | ␉␉␉␉ "=b" (data[1]),␊ |
62 | ␉␉␉␉ "=c" (data[2]),␊ |
63 | ␉␉␉␉ "=d" (data[3])␊ |
64 | ␉␉␉␉ : "a" (selector), "c" (selector2),␊ |
65 | ␉␉␉␉ "b" (0),␊ |
66 | ␉␉␉␉ "d" (0));␊ |
67 | }␊ |
68 | ␊ |
69 | // DFE: enable_PIT2 and disable_PIT2 come from older xnu␊ |
70 | ␊ |
71 | /*␊ |
72 | * Enable or disable timer 2.␊ |
73 | * Port 0x61 controls timer 2:␊ |
74 | * bit 0 gates the clock,␊ |
75 | * bit 1 gates output to speaker.␊ |
76 | */␊ |
77 | static inline void enable_PIT2(void)␊ |
78 | {␊ |
79 | /* Enable gate, disable speaker */␊ |
80 | __asm__ volatile(␊ |
81 | ␉␉␉␉␉ " inb $0x61,%%al \n\t"␊ |
82 | ␉␉␉␉␉ " and $0xFC,%%al \n\t" /* & ~0x03 */␊ |
83 | ␉␉␉␉␉ " or $1,%%al \n\t"␊ |
84 | ␉␉␉␉␉ " outb %%al,$0x61 \n\t"␊ |
85 | ␉␉␉␉␉ : : : "%al" );␊ |
86 | }␊ |
87 | ␊ |
88 | static inline void disable_PIT2(void)␊ |
89 | {␊ |
90 | /* Disable gate and output to speaker */␊ |
91 | __asm__ volatile(␊ |
92 | ␉␉␉␉␉ " inb $0x61,%%al \n\t"␊ |
93 | ␉␉␉␉␉ " and $0xFC,%%al \n\t"␉/* & ~0x03 */␊ |
94 | ␉␉␉␉␉ " outb %%al,$0x61 \n\t"␊ |
95 | ␉␉␉␉␉ : : : "%al" );␊ |
96 | }␊ |
97 | ␊ |
98 | // DFE: set_PIT2_mode0, poll_PIT2_gate, and measure_tsc_frequency are␊ |
99 | // roughly based on Linux code␊ |
100 | ␊ |
101 | /* Set the 8254 channel 2 to mode 0 with the specified value.␊ |
102 | In mode 0, the counter will initially set its gate low when the␊ |
103 | timer expires. For this to be useful, you ought to set it high␊ |
104 | before calling this function. The enable_PIT2 function does this.␊ |
105 | */␊ |
106 | static inline void set_PIT2_mode0(uint16_t value)␊ |
107 | {␊ |
108 | __asm__ volatile(␊ |
109 | ␉␉␉␉␉ " movb $0xB0,%%al \n\t"␊ |
110 | ␉␉␉␉␉ " outb␉%%al,$0x43␉\n\t"␊ |
111 | ␉␉␉␉␉ " movb␉%%dl,%%al␉\n\t"␊ |
112 | ␉␉␉␉␉ " outb␉%%al,$0x42␉\n\t"␊ |
113 | ␉␉␉␉␉ " movb␉%%dh,%%al␉\n\t"␊ |
114 | ␉␉␉␉␉ " outb␉%%al,$0x42"␊ |
115 | ␉␉␉␉␉ : : "d"(value) /*: no clobber */ );␊ |
116 | }␊ |
117 | ␊ |
118 | /* Returns the number of times the loop ran before the PIT2 signaled */␊ |
119 | static inline unsigned long poll_PIT2_gate(void)␊ |
120 | {␊ |
121 | unsigned long count = 0;␊ |
122 | unsigned char nmi_sc_val;␊ |
123 | do {␊ |
124 | ++count;␊ |
125 | __asm__ volatile(␊ |
126 | ␉␉␉␉␉␉ "inb␉$0x61,%0"␊ |
127 | ␉␉␉␉␉␉ : "=q"(nmi_sc_val) /*:*/ /* no input */ /*:*/ /* no clobber */);␊ |
128 | } while( (nmi_sc_val & 0x20) == 0);␊ |
129 | return count;␊ |
130 | }␊ |
131 | ␊ |
132 | #endif /* !__LIBSAIO_CPU_H */␊ |
133 | |