Subversion Repositories shark

Rev

Rev 302 | Rev 304 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
120 giacomo 1
/* Project:     OSLib
2
 * Description: The OS Construction Kit
3
 * Date:                1.6.2000
4
 * Idea by:             Luca Abeni & Gerardo Lamastra
5
 *
6
 * OSLib is an SO project aimed at developing a common, easy-to-use
7
 * low-level infrastructure for developing OS kernels and Embedded
8
 * Applications; it partially derives from the HARTIK project but it
9
 * currently is independently developed.
10
 *
11
 * OSLib is distributed under GPL License, and some of its code has
12
 * been derived from the Linux kernel source; also some important
13
 * ideas come from studying the DJGPP go32 extender.
14
 *
15
 * We acknowledge the Linux Community, Free Software Foundation,
16
 * D.J. Delorie and all the other developers who believe in the
17
 * freedom of software and ideas.
18
 *
19
 * For legalese, check out the included GPL license.
20
 */
21
 
22
/*      Advanced Timer Managment
23
 *      Author: Giacomo Guidi <giacomo@gandalf.sssup.it>
24
 */
25
 
26
#include <ll/i386/stdlib.h>
27
#include <ll/i386/error.h>
28
#include <ll/i386/advtimer.h>
29
#include <ll/sys/ll/ll-data.h>
30
#include <ll/sys/ll/ll-func.h>
31
#include <ll/i386/pic.h>
299 giacomo 32
#include <ll/i386/apic.h>
120 giacomo 33
#include <ll/sys/ll/event.h>
34
#include <ll/sys/ll/time.h>
35
 
264 giacomo 36
#define CALIBRATE_USING_CMOS
37
 
130 giacomo 38
unsigned char use_tsc = 1; //Enable the TSC counter mode
120 giacomo 39
unsigned char use_cmos = 0; //Enable the RTC correction
303 giacomo 40
unsigned char use_apic = 1; //Enable the APIC for P6 only
120 giacomo 41
 
126 giacomo 42
//Max single delta_clk_per_msec increment = clk_per_msec / MAX_DIV_INK;
43
#define MAX_DIV_INK 30000
120 giacomo 44
 
45
signed long long init_tsc;
194 giacomo 46
signed long long * ptr_init_tsc = &init_tsc;
47
 
238 giacomo 48
signed long long init_nsec; //Wraparound 292 years
194 giacomo 49
signed long long * ptr_init_nsec = &init_nsec;
50
 
120 giacomo 51
signed long long clk_per_msec;
194 giacomo 52
signed long long * ptr_clk_per_msec = &clk_per_msec;
120 giacomo 53
 
299 giacomo 54
signed long long apic_clk_per_msec;
303 giacomo 55
unsigned int apic_set_limit;
299 giacomo 56
 
120 giacomo 57
signed long last_delta_clk_per_msec;
58
signed long total_delta_clk_per_msec;
59
 
60
unsigned char save_CMOS_regA;
61
unsigned char save_CMOS_regB;
62
 
242 giacomo 63
//#define IRQ8_DEBUG
64
 
120 giacomo 65
void HandlerIRQ8(void *p)
66
{
67
 
68
   unsigned char set;
194 giacomo 69
 
70
   static unsigned long Mconst = 1000000;
120 giacomo 71
 
72
   static unsigned long init_step = 0;
73
 
126 giacomo 74
   signed long max_dcms = clk_per_msec / MAX_DIV_INK;
120 giacomo 75
 
194 giacomo 76
   static signed long long dn;
77
   static signed long long * ptr_dn = &dn;
120 giacomo 78
   signed long delta_clk_per_msec;
126 giacomo 79
 
120 giacomo 80
   cli();
242 giacomo 81
 
82
   #ifdef IRQ8_DEBUG
83
     message("(IRQ8");
84
   #endif   
85
 
120 giacomo 86
   CMOS_READ(0x0C,set);
194 giacomo 87
 
242 giacomo 88
   __asm__("xorl %%eax,%%eax\n\t"
89
           "cpuid\n\t"
90
           "rdtsc\n\t"
194 giacomo 91
           "pushl %%eax\n\t"
92
           "pushl %%edx\n\t"
242 giacomo 93
           "pushl %%eax\n\t"
94
           "pushl %%edx\n\t"
95
           "xorl %%eax,%%eax\n\t"
96
           "cpuid\n\t"
97
           "popl %%edx\n\t"
98
           "popl %%eax\n\t"
194 giacomo 99
           "subl (%%edi),%%eax\n\t"
100
           "sbbl 4(%%edi),%%edx\n\t"
101
           "popl 4(%%edi)\n\t"
102
           "popl (%%edi)\n\t"
103
           "movl %%edx,%%ecx\n\t"
104
           "mull %4\n\t"
105
           "pushl %%eax\n\t"
106
           "movl %%ecx,%%eax\n\t"
107
           "movl %%edx,%%ecx\n\t"
108
           "mull %4\n\t"
109
           "addl %%ecx,%%eax\n\t"
110
           "adcl $0,%%edx\n\t"
242 giacomo 111
           "movl %7,%%ebx\n\t"
194 giacomo 112
           "divl (%%ebx)\n\t"
113
           "movl %%eax,4(%%esi)\n\t"
114
           "popl %%eax\n\t"
115
           "divl (%%ebx)\n\t"
116
           "movl %%eax,(%%esi)\n\t"
117
 
118
            :
242 giacomo 119
            : "D" (ptr_init_tsc), "S" (ptr_dn), "b" (0),
120
              "c" (0), "m" (Mconst), "a" (0), "d" (0), "m" (ptr_clk_per_msec));
120 giacomo 121
 
122
   //Offset
123
   init_nsec += dn;
194 giacomo 124
 
120 giacomo 125
   if (init_step < 5) {
126
           init_step++;
242 giacomo 127
           #ifdef IRQ8_DEBUG
128
             message(")");
129
           #endif
130
 
244 giacomo 131
           sti();
132
 
120 giacomo 133
           return;
134
   }
135
 
136
   dn = dn % 1000000000 - 500000000;
137
 
138
   //Delta clk/msec
139
   delta_clk_per_msec = dn * clk_per_msec / (500000000 - dn);
140
 
141
   //clk_per_msec adjustment
142
   if (delta_clk_per_msec < 0) {
143
 
126 giacomo 144
        if (delta_clk_per_msec > -max_dcms)
120 giacomo 145
                clk_per_msec += delta_clk_per_msec;
146
        else
126 giacomo 147
                clk_per_msec -= max_dcms;
120 giacomo 148
   } else {
149
 
126 giacomo 150
        if (delta_clk_per_msec < max_dcms)
120 giacomo 151
                clk_per_msec += delta_clk_per_msec;
152
        else
126 giacomo 153
                clk_per_msec += max_dcms;
120 giacomo 154
   }
155
 
156
   last_delta_clk_per_msec = delta_clk_per_msec;
157
   total_delta_clk_per_msec += delta_clk_per_msec;
158
 
242 giacomo 159
   #ifdef IRQ8_DEBUG
160
      message(")");
161
   #endif
162
 
120 giacomo 163
   sti();
164
 
165
}
166
 
167
#ifdef CONFIG_MELAN
168
#  define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
169
#else
249 giacomo 170
#  define CLOCK_TICK_RATE 1193182 /* Underlying HZ */
120 giacomo 171
#endif
172
 
248 giacomo 173
#define COUNTER_END 100
120 giacomo 174
 
245 giacomo 175
#define barrier() __asm__ __volatile__("" ::: "memory");
176
 
120 giacomo 177
//TSC Calibration (idea from the linux kernel code)
178
void ll_calibrate_tsc(void)
179
{
180
 
181
        signed long long start;
182
        signed long long end;
244 giacomo 183
        signed long long dtsc;
120 giacomo 184
 
244 giacomo 185
        signed long start_8253, end_8253, delta_8253;
120 giacomo 186
 
187
        cli();
188
 
248 giacomo 189
        outp(0x61, (inp(0x61) & ~0x02) | 0x01);
120 giacomo 190
 
191
        outp(0x43,0xB0);                        /* binary, mode 0, LSB/MSB, Ch 2 */
238 giacomo 192
        outp(0x42,0xFF);                        /* LSB of count */
193
        outp(0x42,0xFF);                        /* MSB of count */
242 giacomo 194
 
245 giacomo 195
        barrier();
196
        rdtscll(start);
197
        barrier();
243 giacomo 198
        outp(0x43,0x00);
199
        start_8253 = inp(0x42);
200
        start_8253 |= inp(0x42) << 8;
245 giacomo 201
        barrier();
264 giacomo 202
        rdtscll(start);
203
        barrier();
243 giacomo 204
 
205
        do {
206
 
207
            outp(0x43,0x00);
208
            end_8253 = inp(0x42);
209
            end_8253 |= inp(0x42) << 8;
210
 
211
        } while (end_8253 > COUNTER_END);
212
 
245 giacomo 213
        barrier();
214
        rdtscll(end);
215
        barrier();
243 giacomo 216
        outp(0x43,0x00);
217
        end_8253 = inp(0x42);
218
        end_8253 |= inp(0x42) << 8;
245 giacomo 219
        barrier();
264 giacomo 220
        rdtscll(end);
221
        barrier();
243 giacomo 222
 
223
        //Delta TSC
244 giacomo 224
        dtsc = end - start;
243 giacomo 225
 
226
        //Delta PIT
264 giacomo 227
        delta_8253 = start_8253 - end_8253;
243 giacomo 228
 
242 giacomo 229
        if (delta_8253 > 0x20000) {
120 giacomo 230
                message("Error calculating Delta PIT\n");
231
                ll_abort(10);
232
        }
233
 
234
        message("Delta TSC               = %10ld\n",(long)dtsc);
235
 
236
        message("Delta PIT               = %10ld\n",(long)delta_8253);
237
 
252 giacomo 238
        clk_per_msec = dtsc * CLOCK_TICK_RATE / delta_8253 / 1000;
120 giacomo 239
 
240
        message("Calibrated Clk_per_msec = %10ld\n",(long)clk_per_msec);
241
 
242
        sti();
243
 
244
}
245
 
264 giacomo 246
#define CMOS_INIT  0
247
#define CMOS_BEGIN 1
248
#define CMOS_START 2
249
#define CMOS_END   3
250
 
251
int cmos_calibrate_status = CMOS_INIT;
252
signed long long irq8_start;
253
signed long long irq8_end;
254
 
299 giacomo 255
void calibrate_tsc_IRQ8(void *p)
264 giacomo 256
{
257
 
258
  unsigned char set;
259
 
260
  cli();
261
 
262
  CMOS_READ(0x0C,set);
263
 
264
  barrier();
265
  rdtscll(irq8_end);
266
  barrier();
267
 
268
  if (cmos_calibrate_status == CMOS_START) {
269
    cmos_calibrate_status = CMOS_END;
270
  }
271
 
272
  if (cmos_calibrate_status == CMOS_BEGIN) {
273
    irq8_start = irq8_end;
274
    cmos_calibrate_status = CMOS_START;
275
  }
276
 
277
  if (cmos_calibrate_status == CMOS_INIT) {
278
    cmos_calibrate_status = CMOS_BEGIN;
279
  }
280
 
281
  sti();
282
 
283
}
284
 
285
//TSC Calibration using RTC
286
void ll_calibrate_tsc_cmos(void)
287
{
288
 
289
  signed long long dtsc;
290
 
291
  cli();           
292
 
299 giacomo 293
  irq_bind(8, calibrate_tsc_IRQ8, INT_FORCE);
264 giacomo 294
 
295
  CMOS_READ(0x0A,save_CMOS_regA);
296
  CMOS_READ(0x0B,save_CMOS_regB);
297
 
298
  CMOS_WRITE(0x0A,0x2F); // Set 2 Hz Periodic Interrupt
299
  CMOS_WRITE(0x0B,0x42); // Enable Interrupt
300
 
301
  irq_unmask(8);
302
 
303
  sti();
304
 
305
  while (cmos_calibrate_status != CMOS_END) {
306
    barrier();
307
  }
308
 
309
  dtsc = irq8_end - irq8_start;
310
 
311
  clk_per_msec = dtsc / 500;
312
 
299 giacomo 313
  message("Calibrated CPU Clk/msec  = %10ld\n",(long)clk_per_msec);
264 giacomo 314
 
315
  cli();
316
 
317
  irq_mask(8);
318
 
319
  CMOS_WRITE(0x0A,save_CMOS_regA);
320
  CMOS_WRITE(0x0B,save_CMOS_regB);
321
 
322
  sti();
323
 
324
}
325
 
120 giacomo 326
//Low level time read function
131 giacomo 327
void ll_read_timespec(struct timespec *tspec)
120 giacomo 328
{
329
 
194 giacomo 330
    static unsigned long Gconst = 1000000000;
331
    static unsigned long Mconst = 1000000;
120 giacomo 332
 
124 giacomo 333
    if (clk_per_msec <= 0) {
334
            NULL_TIMESPEC(tspec);
335
            return;
336
    }
337
 
242 giacomo 338
    __asm__("xorl %%eax,%%eax\n\t"
339
            "cpuid\n\t"  
340
            "rdtsc\n\t"
341
            "pushl %%eax\n\t"
342
            "pushl %%edx\n\t"
343
            "xorl %%eax,%%eax\n\t"
344
            "cpuid\n\t"
345
            "popl %%edx\n\t"
346
            "popl %%eax\n\t"
347
            "subl (%%edi),%%eax\n\t"
194 giacomo 348
            "sbbl 4(%%edi),%%edx\n\t"
349
            "movl %%edx,%%ecx\n\t"
350
            "mull %6\n\t"
351
            "pushl %%eax\n\t"
352
            "movl %%ecx,%%eax\n\t"
353
            "movl %%edx,%%ecx\n\t"
354
            "mull %6\n\t"
355
            "addl %%ecx,%%eax\n\t"
356
            "adcl $0,%%edx\n\t"
242 giacomo 357
            "movl %8,%%ebx\n\t"
194 giacomo 358
            "divl (%%ebx)\n\t"
359
            "movl %%eax,%%ecx\n\t"
360
            "popl %%eax\n\t"
361
            "divl (%%ebx)\n\t"
362
            "movl %%ecx,%%edx\n\t"
363
            "addl (%%esi),%%eax\n\t"
364
            "adcl 4(%%esi),%%edx\n\t"
365
            "divl %7\n\t"
366
 
367
            : "=a" (tspec->tv_sec), "=d" (tspec->tv_nsec)
242 giacomo 368
            : "D" (ptr_init_tsc), "S" (ptr_init_nsec), "b" (0),
369
              "c" (0), "m" (Mconst), "m" (Gconst), "m" (ptr_clk_per_msec));
194 giacomo 370
 
120 giacomo 371
}
372
 
299 giacomo 373
int apic_get_maxlvt(void)
374
{
375
        unsigned int v, ver, maxlvt;
376
 
377
        v = apic_read(APIC_LVR);
378
        ver = GET_APIC_VERSION(v);
379
        /* 82489DXs do not report # of LVT entries. */
380
        maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(v) : 2;
381
        return maxlvt;
382
}
383
 
302 giacomo 384
/* Clear local APIC, grom Linux kernel */
299 giacomo 385
void clear_local_APIC(void)
386
{
387
        int maxlvt;
388
        unsigned long v;
389
 
390
        maxlvt = apic_get_maxlvt();
391
 
392
        /*
393
         * Masking an LVT entry on a P6 can trigger a local APIC error
394
         * if the vector is zero. Mask LVTERR first to prevent this.
395
         */
396
        if (maxlvt >= 3) {
397
                v = 0xFF; /* any non-zero vector will do */
398
                apic_write_around(APIC_LVTERR, v | APIC_LVT_MASKED);
399
        }
400
        /*
401
         * Careful: we have to set masks only first to deassert
402
         * any level-triggered sources.
403
         */
404
        v = apic_read(APIC_LVTT);
405
        apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED);
406
        v = apic_read(APIC_LVT0);
407
        apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
408
        v = apic_read(APIC_LVT1);
409
        apic_write_around(APIC_LVT1, v | APIC_LVT_MASKED);
410
        if (maxlvt >= 4) {
411
                v = apic_read(APIC_LVTPC);
412
                apic_write_around(APIC_LVTPC, v | APIC_LVT_MASKED);
413
        }
414
 
415
        /*
416
         * Clean APIC state for other OSs:
417
         */
418
        apic_write_around(APIC_LVTT, APIC_LVT_MASKED);
419
        apic_write_around(APIC_LVT0, APIC_LVT_MASKED);
420
        apic_write_around(APIC_LVT1, APIC_LVT_MASKED);
421
        if (maxlvt >= 3)
422
                apic_write_around(APIC_LVTERR, APIC_LVT_MASKED);
423
        if (maxlvt >= 4)
424
                apic_write_around(APIC_LVTPC, APIC_LVT_MASKED);
425
        v = GET_APIC_VERSION(apic_read(APIC_LVR));
426
        if (APIC_INTEGRATED(v)) {       /* !82489DX */
427
                if (maxlvt > 3)
428
                        apic_write(APIC_ESR, 0);
429
                apic_read(APIC_ESR);
430
        }
431
}
432
 
433
void disable_local_APIC(void)
434
{
435
        unsigned long value;
436
 
437
        clear_local_APIC();
438
 
439
        /*
440
         * Disable APIC (implies clearing of registers
441
         * for 82489DX!).
442
         */
443
        value = apic_read(APIC_SPIV);
444
        value &= ~APIC_SPIV_APIC_ENABLED;
445
        apic_write_around(APIC_SPIV, value);
446
}
447
 
448
#define SPURIOUS_APIC_VECTOR 0xFF
449
 
450
/*
302 giacomo 451
 * Setup the local APIC, minimal code to run P6 APIC
299 giacomo 452
 */
453
void setup_local_APIC (void)
454
{
301 giacomo 455
        unsigned long value;
299 giacomo 456
 
457
        /* Pound the ESR really hard over the head with a big hammer - mbligh */
458
 
459
        apic_write(APIC_ESR, 0);
460
        apic_write(APIC_ESR, 0);
461
        apic_write(APIC_ESR, 0);
462
        apic_write(APIC_ESR, 0);
463
 
301 giacomo 464
        value = APIC_SPIV_FOCUS_DISABLED | APIC_SPIV_APIC_ENABLED | SPURIOUS_APIC_VECTOR;
465
        apic_write_around(APIC_SPIV, value);
299 giacomo 466
 
301 giacomo 467
        value = APIC_DM_EXTINT | APIC_LVT_LEVEL_TRIGGER;
468
        apic_write_around(APIC_LVT0, value);
299 giacomo 469
 
301 giacomo 470
        value = APIC_DM_NMI;
471
        apic_write_around(APIC_LVT1, value);
299 giacomo 472
 
301 giacomo 473
        apic_write(APIC_ESR, 0);
299 giacomo 474
 
475
}
476
 
477
void disable_APIC_timer(void)
478
{
479
        unsigned long v;
480
 
481
        v = apic_read(APIC_LVTT);
482
        apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED);
483
 
484
}
485
 
486
void enable_APIC_timer(void)
487
{
488
        unsigned long v;
489
 
490
        v = apic_read(APIC_LVTT);
491
        apic_write_around(APIC_LVTT, v & ~APIC_LVT_MASKED);
492
 
493
}
494
 
301 giacomo 495
#define LOCAL_TIMER_VECTOR 0x66
302 giacomo 496
 
303 giacomo 497
/* Set APIC Timer... from Linux kernel */
498
void setup_APIC_timer()
299 giacomo 499
{
500
        unsigned int lvtt1_value, tmp_value;
501
 
502
        lvtt1_value = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) |
503
                        APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
504
        apic_write_around(APIC_LVTT, lvtt1_value);
505
 
506
        /*
507
         * Divide PICLK by 1
508
         */
509
        tmp_value = apic_read(APIC_TDCR);
510
        apic_write_around(APIC_TDCR, (tmp_value
511
                                & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
512
                                | APIC_TDR_DIV_1);
303 giacomo 513
 
514
        apic_write_around(APIC_TMICT, 0xFFFFFFFF);
515
 
516
        disable_APIC_timer();                                                                                                                            
299 giacomo 517
}
518
 
519
#define APIC_LIMIT 0xFF000000
303 giacomo 520
#define APIC_SET_LIMIT 10
299 giacomo 521
 
522
void ll_calibrate_apic(void)
523
{
524
 
525
  unsigned int apic_start = 0, apic_end = 0, dapic;
526
  signed long long tsc_start = 0, tsc_end = 0, dtsc;
527
  unsigned int tmp_value;
528
 
529
  cli();
530
 
531
  tmp_value = apic_read(APIC_TDCR);
532
  apic_write_around(APIC_TDCR, (tmp_value
533
                                 & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
534
                                 | APIC_TDR_DIV_1);
535
 
536
  apic_write(APIC_TMICT, MAX_DWORD);
537
 
538
  barrier();
539
  rdtscll(tsc_start);
540
  barrier();
541
  apic_start = apic_read(APIC_TMCCT);
542
  barrier();            
543
 
544
  while (apic_read(APIC_TMCCT) > APIC_LIMIT) {
545
    barrier();
546
    rdtscll(tsc_end);
547
  }
548
 
549
  barrier();
550
  rdtscll(tsc_end);
551
  barrier();
552
  apic_end = apic_read(APIC_TMCCT);
553
  barrier();    
554
 
555
  sti();
556
 
557
  dtsc = tsc_end - tsc_start;
558
  dapic = apic_start - apic_end;
559
 
560
  apic_clk_per_msec = clk_per_msec * (signed long long)(dapic) / dtsc;
303 giacomo 561
  apic_set_limit = ((apic_clk_per_msec / 100) == 0) ? (apic_clk_per_msec/100) : APIC_SET_LIMIT;  
562
 
299 giacomo 563
  message("Calibrated APIC Clk/msec = %10ld\n",(long)apic_clk_per_msec);
564
 
565
}
566
 
120 giacomo 567
void ll_init_advtimer()
568
{
569
 
570
    if (use_tsc) {
571
 
264 giacomo 572
        #ifdef CALIBRATE_USING_CMOS
573
          ll_calibrate_tsc_cmos();
574
        #else
575
          ll_calibrate_tsc();
576
        #endif  
577
 
120 giacomo 578
        last_delta_clk_per_msec = 0;
579
        total_delta_clk_per_msec = 0;
580
 
581
        rdtscll(init_tsc); // Read start TSC
582
        init_nsec = 0;
583
 
299 giacomo 584
        if (use_apic) {
585
          unsigned long msr_low_orig, tmp;
586
 
587
          rdmsr(APIC_BASE_MSR, msr_low_orig, tmp);
588
          wrmsr(APIC_BASE_MSR, msr_low_orig|(1<<11), 0);
589
 
301 giacomo 590
          clear_local_APIC();
299 giacomo 591
 
301 giacomo 592
          ll_calibrate_apic();
593
 
299 giacomo 594
          setup_local_APIC();
303 giacomo 595
 
596
          setup_APIC_timer();
299 giacomo 597
 
598
        }
599
 
120 giacomo 600
        if (use_cmos) {
601
 
131 giacomo 602
            message("CMOS adjustement enabled\n");
120 giacomo 603
 
604
            cli();         
605
 
606
            irq_bind(8, HandlerIRQ8, INT_FORCE);
607
 
608
            CMOS_READ(0x0A,save_CMOS_regA);
609
            CMOS_READ(0x0B,save_CMOS_regB);
610
 
611
            CMOS_WRITE(0x0A,0x2F); // Set 2 Hz Periodic Interrupt
612
            CMOS_WRITE(0x0B,0x42); // Enable Interrupt
613
 
614
            irq_unmask(8);
615
 
616
            sti();
617
 
618
        }
619
 
620
    } else {
621
 
622
        use_cmos = 0;
623
 
624
   }
625
 
626
}
627
 
301 giacomo 628
void ll_restore_adv()
120 giacomo 629
{
302 giacomo 630
        /* Restore CMOS setting */
120 giacomo 631
        if (use_cmos) {
632
                cli();
633
 
634
                irq_mask(8);
635
 
636
                CMOS_WRITE(0x0A,save_CMOS_regA);
637
                CMOS_WRITE(0x0B,save_CMOS_regB);
638
 
639
                sti();         
640
        }
301 giacomo 641
 
302 giacomo 642
        /* Disable APIC */
301 giacomo 643
        if (use_apic) {
644
                unsigned int msr_low_orig, tmp;
645
 
646
                cli();
647
 
648
                disable_APIC_timer();
649
 
650
                clear_local_APIC();
651
 
652
                rdmsr(APIC_BASE_MSR, msr_low_orig, tmp);
653
                wrmsr(APIC_BASE_MSR, msr_low_orig&~(1<<11), 0);
654
 
655
                sti();
656
 
657
        }
658
 
120 giacomo 659
}