aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2008-10-09 16:31:56 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2008-10-09 16:31:56 -0400
commit6a4690c22f5da1eb1c898b61b6a80da52fbd976f (patch)
treea03891a32abe0da191fb765fe669a597e07423c6 /arch/x86/kernel
parent90bb28b0644f7324f8bd1feb27b35146e6785ba2 (diff)
parent8ec53663d2698076468b3e1edc4e1b418bd54de3 (diff)
Merge branch 'ptebits' into devel
Conflicts: arch/arm/Kconfig
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r--arch/x86/kernel/cpuid.c15
-rw-r--r--arch/x86/kernel/msr.c38
-rw-r--r--arch/x86/kernel/tsc.c235
3 files changed, 218 insertions, 70 deletions
diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c
index 14b11b3be31..8e9cd6a8ec1 100644
--- a/arch/x86/kernel/cpuid.c
+++ b/arch/x86/kernel/cpuid.c
@@ -89,6 +89,8 @@ static ssize_t cpuid_read(struct file *file, char __user *buf,
89 struct cpuid_regs cmd; 89 struct cpuid_regs cmd;
90 int cpu = iminor(file->f_path.dentry->d_inode); 90 int cpu = iminor(file->f_path.dentry->d_inode);
91 u64 pos = *ppos; 91 u64 pos = *ppos;
92 ssize_t bytes = 0;
93 int err = 0;
92 94
93 if (count % 16) 95 if (count % 16)
94 return -EINVAL; /* Invalid chunk size */ 96 return -EINVAL; /* Invalid chunk size */
@@ -96,14 +98,19 @@ static ssize_t cpuid_read(struct file *file, char __user *buf,
96 for (; count; count -= 16) { 98 for (; count; count -= 16) {
97 cmd.eax = pos; 99 cmd.eax = pos;
98 cmd.ecx = pos >> 32; 100 cmd.ecx = pos >> 32;
99 smp_call_function_single(cpu, cpuid_smp_cpuid, &cmd, 1); 101 err = smp_call_function_single(cpu, cpuid_smp_cpuid, &cmd, 1);
100 if (copy_to_user(tmp, &cmd, 16)) 102 if (err)
101 return -EFAULT; 103 break;
104 if (copy_to_user(tmp, &cmd, 16)) {
105 err = -EFAULT;
106 break;
107 }
102 tmp += 16; 108 tmp += 16;
109 bytes += 16;
103 *ppos = ++pos; 110 *ppos = ++pos;
104 } 111 }
105 112
106 return tmp - buf; 113 return bytes ? bytes : err;
107} 114}
108 115
109static int cpuid_open(struct inode *inode, struct file *file) 116static int cpuid_open(struct inode *inode, struct file *file)
diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c
index e4393808688..2e2af5d1819 100644
--- a/arch/x86/kernel/msr.c
+++ b/arch/x86/kernel/msr.c
@@ -72,21 +72,28 @@ static ssize_t msr_read(struct file *file, char __user *buf,
72 u32 data[2]; 72 u32 data[2];
73 u32 reg = *ppos; 73 u32 reg = *ppos;
74 int cpu = iminor(file->f_path.dentry->d_inode); 74 int cpu = iminor(file->f_path.dentry->d_inode);
75 int err; 75 int err = 0;
76 ssize_t bytes = 0;
76 77
77 if (count % 8) 78 if (count % 8)
78 return -EINVAL; /* Invalid chunk size */ 79 return -EINVAL; /* Invalid chunk size */
79 80
80 for (; count; count -= 8) { 81 for (; count; count -= 8) {
81 err = rdmsr_safe_on_cpu(cpu, reg, &data[0], &data[1]); 82 err = rdmsr_safe_on_cpu(cpu, reg, &data[0], &data[1]);
82 if (err) 83 if (err) {
83 return -EIO; 84 if (err == -EFAULT) /* Fix idiotic error code */
84 if (copy_to_user(tmp, &data, 8)) 85 err = -EIO;
85 return -EFAULT; 86 break;
87 }
88 if (copy_to_user(tmp, &data, 8)) {
89 err = -EFAULT;
90 break;
91 }
86 tmp += 2; 92 tmp += 2;
93 bytes += 8;
87 } 94 }
88 95
89 return ((char __user *)tmp) - buf; 96 return bytes ? bytes : err;
90} 97}
91 98
92static ssize_t msr_write(struct file *file, const char __user *buf, 99static ssize_t msr_write(struct file *file, const char __user *buf,
@@ -96,21 +103,28 @@ static ssize_t msr_write(struct file *file, const char __user *buf,
96 u32 data[2]; 103 u32 data[2];
97 u32 reg = *ppos; 104 u32 reg = *ppos;
98 int cpu = iminor(file->f_path.dentry->d_inode); 105 int cpu = iminor(file->f_path.dentry->d_inode);
99 int err; 106 int err = 0;
107 ssize_t bytes = 0;
100 108
101 if (count % 8) 109 if (count % 8)
102 return -EINVAL; /* Invalid chunk size */ 110 return -EINVAL; /* Invalid chunk size */
103 111
104 for (; count; count -= 8) { 112 for (; count; count -= 8) {
105 if (copy_from_user(&data, tmp, 8)) 113 if (copy_from_user(&data, tmp, 8)) {
106 return -EFAULT; 114 err = -EFAULT;
115 break;
116 }
107 err = wrmsr_safe_on_cpu(cpu, reg, data[0], data[1]); 117 err = wrmsr_safe_on_cpu(cpu, reg, data[0], data[1]);
108 if (err) 118 if (err) {
109 return -EIO; 119 if (err == -EFAULT) /* Fix idiotic error code */
120 err = -EIO;
121 break;
122 }
110 tmp += 2; 123 tmp += 2;
124 bytes += 8;
111 } 125 }
112 126
113 return ((char __user *)tmp) - buf; 127 return bytes ? bytes : err;
114} 128}
115 129
116static int msr_open(struct inode *inode, struct file *file) 130static int msr_open(struct inode *inode, struct file *file)
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 8e786b0d665..ac79bd143da 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -127,75 +127,202 @@ static u64 tsc_read_refs(u64 *pm, u64 *hpet)
127 */ 127 */
128unsigned long native_calibrate_tsc(void) 128unsigned long native_calibrate_tsc(void)
129{ 129{
130 unsigned long flags; 130 u64 tsc1, tsc2, tr1, tr2, tsc, delta, pm1, pm2, hpet1, hpet2;
131 u64 tsc1, tsc2, tr1, tr2, delta, pm1, pm2, hpet1, hpet2; 131 unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX;
132 int hpet = is_hpet_enabled(); 132 unsigned long flags, tscmin, tscmax;
133 unsigned int tsc_khz_val = 0; 133 int hpet = is_hpet_enabled(), pitcnt, i;
134 134
135 local_irq_save(flags); 135 /*
136 136 * Run 5 calibration loops to get the lowest frequency value
137 tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL); 137 * (the best estimate). We use two different calibration modes
138 138 * here:
139 outb((inb(0x61) & ~0x02) | 0x01, 0x61); 139 *
140 140 * 1) PIT loop. We set the PIT Channel 2 to oneshot mode and
141 outb(0xb0, 0x43); 141 * load a timeout of 50ms. We read the time right after we
142 outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42); 142 * started the timer and wait until the PIT count down reaches
143 outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42); 143 * zero. In each wait loop iteration we read the TSC and check
144 tr1 = get_cycles(); 144 * the delta to the previous read. We keep track of the min
145 while ((inb(0x61) & 0x20) == 0); 145 * and max values of that delta. The delta is mostly defined
146 tr2 = get_cycles(); 146 * by the IO time of the PIT access, so we can detect when a
147 147 * SMI/SMM disturbance happend between the two reads. If the
148 tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL); 148 * maximum time is significantly larger than the minimum time,
149 149 * then we discard the result and have another try.
150 local_irq_restore(flags); 150 *
151 * 2) Reference counter. If available we use the HPET or the
152 * PMTIMER as a reference to check the sanity of that value.
153 * We use separate TSC readouts and check inside of the
154 * reference read for a SMI/SMM disturbance. We dicard
155 * disturbed values here as well. We do that around the PIT
156 * calibration delay loop as we have to wait for a certain
157 * amount of time anyway.
158 */
159 for (i = 0; i < 5; i++) {
160
161 tscmin = ULONG_MAX;
162 tscmax = 0;
163 pitcnt = 0;
164
165 local_irq_save(flags);
166
167 /*
168 * Read the start value and the reference count of
169 * hpet/pmtimer when available:
170 */
171 tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL);
172
173 /* Set the Gate high, disable speaker */
174 outb((inb(0x61) & ~0x02) | 0x01, 0x61);
175
176 /*
177 * Setup CTC channel 2* for mode 0, (interrupt on terminal
178 * count mode), binary count. Set the latch register to 50ms
179 * (LSB then MSB) to begin countdown.
180 *
181 * Some devices need a delay here.
182 */
183 outb(0xb0, 0x43);
184 outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42);
185 outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42);
186
187 tsc = tr1 = tr2 = get_cycles();
188
189 while ((inb(0x61) & 0x20) == 0) {
190 tr2 = get_cycles();
191 delta = tr2 - tsc;
192 tsc = tr2;
193 if ((unsigned int) delta < tscmin)
194 tscmin = (unsigned int) delta;
195 if ((unsigned int) delta > tscmax)
196 tscmax = (unsigned int) delta;
197 pitcnt++;
198 }
199
200 /*
201 * We waited at least 50ms above. Now read
202 * pmtimer/hpet reference again
203 */
204 tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL);
205
206 local_irq_restore(flags);
207
208 /*
209 * Sanity checks:
210 *
211 * If we were not able to read the PIT more than 5000
212 * times, then we have been hit by a massive SMI
213 *
214 * If the maximum is 10 times larger than the minimum,
215 * then we got hit by an SMI as well.
216 */
217 if (pitcnt > 5000 && tscmax < 10 * tscmin) {
218
219 /* Calculate the PIT value */
220 delta = tr2 - tr1;
221 do_div(delta, 50);
222
223 /* We take the smallest value into account */
224 tsc_pit_min = min(tsc_pit_min, (unsigned long) delta);
225 }
226
227 /* hpet or pmtimer available ? */
228 if (!hpet && !pm1 && !pm2)
229 continue;
230
231 /* Check, whether the sampling was disturbed by an SMI */
232 if (tsc1 == ULLONG_MAX || tsc2 == ULLONG_MAX)
233 continue;
234
235 tsc2 = (tsc2 - tsc1) * 1000000LL;
236
237 if (hpet) {
238 if (hpet2 < hpet1)
239 hpet2 += 0x100000000ULL;
240 hpet2 -= hpet1;
241 tsc1 = ((u64)hpet2 * hpet_readl(HPET_PERIOD));
242 do_div(tsc1, 1000000);
243 } else {
244 if (pm2 < pm1)
245 pm2 += (u64)ACPI_PM_OVRRUN;
246 pm2 -= pm1;
247 tsc1 = pm2 * 1000000000LL;
248 do_div(tsc1, PMTMR_TICKS_PER_SEC);
249 }
250
251 do_div(tsc2, tsc1);
252 tsc_ref_min = min(tsc_ref_min, (unsigned long) tsc2);
253 }
151 254
152 /* 255 /*
153 * Preset the result with the raw and inaccurate PIT 256 * Now check the results.
154 * calibration value
155 */ 257 */
156 delta = (tr2 - tr1); 258 if (tsc_pit_min == ULONG_MAX) {
157 do_div(delta, 50); 259 /* PIT gave no useful value */
158 tsc_khz_val = delta; 260 printk(KERN_WARNING "TSC: PIT calibration failed due to "
261 "SMI disturbance.\n");
262
263 /* We don't have an alternative source, disable TSC */
264 if (!hpet && !pm1 && !pm2) {
265 printk("TSC: No reference (HPET/PMTIMER) available\n");
266 return 0;
267 }
268
269 /* The alternative source failed as well, disable TSC */
270 if (tsc_ref_min == ULONG_MAX) {
271 printk(KERN_WARNING "TSC: HPET/PMTIMER calibration "
272 "failed due to SMI disturbance.\n");
273 return 0;
274 }
275
276 /* Use the alternative source */
277 printk(KERN_INFO "TSC: using %s reference calibration\n",
278 hpet ? "HPET" : "PMTIMER");
279
280 return tsc_ref_min;
281 }
159 282
160 /* hpet or pmtimer available ? */ 283 /* We don't have an alternative source, use the PIT calibration value */
161 if (!hpet && !pm1 && !pm2) { 284 if (!hpet && !pm1 && !pm2) {
162 printk(KERN_INFO "TSC calibrated against PIT\n"); 285 printk(KERN_INFO "TSC: Using PIT calibration value\n");
163 goto out; 286 return tsc_pit_min;
164 } 287 }
165 288
166 /* Check, whether the sampling was disturbed by an SMI */ 289 /* The alternative source failed, use the PIT calibration value */
167 if (tsc1 == ULLONG_MAX || tsc2 == ULLONG_MAX) { 290 if (tsc_ref_min == ULONG_MAX) {
168 printk(KERN_WARNING "TSC calibration disturbed by SMI, " 291 printk(KERN_WARNING "TSC: HPET/PMTIMER calibration failed due "
169 "using PIT calibration result\n"); 292 "to SMI disturbance. Using PIT calibration\n");
170 goto out; 293 return tsc_pit_min;
171 } 294 }
172 295
173 tsc2 = (tsc2 - tsc1) * 1000000LL; 296 /* Check the reference deviation */
174 297 delta = ((u64) tsc_pit_min) * 100;
175 if (hpet) { 298 do_div(delta, tsc_ref_min);
176 printk(KERN_INFO "TSC calibrated against HPET\n"); 299
177 if (hpet2 < hpet1) 300 /*
178 hpet2 += 0x100000000ULL; 301 * If both calibration results are inside a 5% window, the we
179 hpet2 -= hpet1; 302 * use the lower frequency of those as it is probably the
180 tsc1 = ((u64)hpet2 * hpet_readl(HPET_PERIOD)); 303 * closest estimate.
181 do_div(tsc1, 1000000); 304 */
182 } else { 305 if (delta >= 95 && delta <= 105) {
183 printk(KERN_INFO "TSC calibrated against PM_TIMER\n"); 306 printk(KERN_INFO "TSC: PIT calibration confirmed by %s.\n",
184 if (pm2 < pm1) 307 hpet ? "HPET" : "PMTIMER");
185 pm2 += (u64)ACPI_PM_OVRRUN; 308 printk(KERN_INFO "TSC: using %s calibration value\n",
186 pm2 -= pm1; 309 tsc_pit_min <= tsc_ref_min ? "PIT" :
187 tsc1 = pm2 * 1000000000LL; 310 hpet ? "HPET" : "PMTIMER");
188 do_div(tsc1, PMTMR_TICKS_PER_SEC); 311 return tsc_pit_min <= tsc_ref_min ? tsc_pit_min : tsc_ref_min;
189 } 312 }
190 313
191 do_div(tsc2, tsc1); 314 printk(KERN_WARNING "TSC: PIT calibration deviates from %s: %lu %lu.\n",
192 tsc_khz_val = tsc2; 315 hpet ? "HPET" : "PMTIMER", tsc_pit_min, tsc_ref_min);
193 316
194out: 317 /*
195 return tsc_khz_val; 318 * The calibration values differ too much. In doubt, we use
319 * the PIT value as we know that there are PMTIMERs around
320 * running at double speed.
321 */
322 printk(KERN_INFO "TSC: Using PIT calibration value\n");
323 return tsc_pit_min;
196} 324}
197 325
198
199#ifdef CONFIG_X86_32 326#ifdef CONFIG_X86_32
200/* Only called from the Powernow K7 cpu freq driver */ 327/* Only called from the Powernow K7 cpu freq driver */
201int recalibrate_cpu_khz(void) 328int recalibrate_cpu_khz(void)