Subversion Repositories shark

Rev

Rev 264 | Rev 301 | 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
299 giacomo 40
unsigned char use_apic = 0; //Enable the APIC
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;
55
 
120 giacomo 56
signed long last_delta_clk_per_msec;
57
signed long total_delta_clk_per_msec;
58
 
59
unsigned char save_CMOS_regA;
60
unsigned char save_CMOS_regB;
61
 
242 giacomo 62
//#define IRQ8_DEBUG
63
 
120 giacomo 64
void HandlerIRQ8(void *p)
65
{
66
 
67
   unsigned char set;
194 giacomo 68
 
69
   static unsigned long Mconst = 1000000;
120 giacomo 70
 
71
   static unsigned long init_step = 0;
72
 
126 giacomo 73
   signed long max_dcms = clk_per_msec / MAX_DIV_INK;
120 giacomo 74
 
194 giacomo 75
   static signed long long dn;
76
   static signed long long * ptr_dn = &dn;
120 giacomo 77
   signed long delta_clk_per_msec;
126 giacomo 78
 
120 giacomo 79
   cli();
242 giacomo 80
 
81
   #ifdef IRQ8_DEBUG
82
     message("(IRQ8");
83
   #endif   
84
 
120 giacomo 85
   CMOS_READ(0x0C,set);
194 giacomo 86
 
242 giacomo 87
   __asm__("xorl %%eax,%%eax\n\t"
88
           "cpuid\n\t"
89
           "rdtsc\n\t"
194 giacomo 90
           "pushl %%eax\n\t"
91
           "pushl %%edx\n\t"
242 giacomo 92
           "pushl %%eax\n\t"
93
           "pushl %%edx\n\t"
94
           "xorl %%eax,%%eax\n\t"
95
           "cpuid\n\t"
96
           "popl %%edx\n\t"
97
           "popl %%eax\n\t"
194 giacomo 98
           "subl (%%edi),%%eax\n\t"
99
           "sbbl 4(%%edi),%%edx\n\t"
100
           "popl 4(%%edi)\n\t"
101
           "popl (%%edi)\n\t"
102
           "movl %%edx,%%ecx\n\t"
103
           "mull %4\n\t"
104
           "pushl %%eax\n\t"
105
           "movl %%ecx,%%eax\n\t"
106
           "movl %%edx,%%ecx\n\t"
107
           "mull %4\n\t"
108
           "addl %%ecx,%%eax\n\t"
109
           "adcl $0,%%edx\n\t"
242 giacomo 110
           "movl %7,%%ebx\n\t"
194 giacomo 111
           "divl (%%ebx)\n\t"
112
           "movl %%eax,4(%%esi)\n\t"
113
           "popl %%eax\n\t"
114
           "divl (%%ebx)\n\t"
115
           "movl %%eax,(%%esi)\n\t"
116
 
117
            :
242 giacomo 118
            : "D" (ptr_init_tsc), "S" (ptr_dn), "b" (0),
119
              "c" (0), "m" (Mconst), "a" (0), "d" (0), "m" (ptr_clk_per_msec));
120 giacomo 120
 
121
   //Offset
122
   init_nsec += dn;
194 giacomo 123
 
120 giacomo 124
   if (init_step < 5) {
125
           init_step++;
242 giacomo 126
           #ifdef IRQ8_DEBUG
127
             message(")");
128
           #endif
129
 
244 giacomo 130
           sti();
131
 
120 giacomo 132
           return;
133
   }
134
 
135
   dn = dn % 1000000000 - 500000000;
136
 
137
   //Delta clk/msec
138
   delta_clk_per_msec = dn * clk_per_msec / (500000000 - dn);
139
 
140
   //clk_per_msec adjustment
141
   if (delta_clk_per_msec < 0) {
142
 
126 giacomo 143
        if (delta_clk_per_msec > -max_dcms)
120 giacomo 144
                clk_per_msec += delta_clk_per_msec;
145
        else
126 giacomo 146
                clk_per_msec -= max_dcms;
120 giacomo 147
   } else {
148
 
126 giacomo 149
        if (delta_clk_per_msec < max_dcms)
120 giacomo 150
                clk_per_msec += delta_clk_per_msec;
151
        else
126 giacomo 152
                clk_per_msec += max_dcms;
120 giacomo 153
   }
154
 
155
   last_delta_clk_per_msec = delta_clk_per_msec;
156
   total_delta_clk_per_msec += delta_clk_per_msec;
157
 
242 giacomo 158
   #ifdef IRQ8_DEBUG
159
      message(")");
160
   #endif
161
 
120 giacomo 162
   sti();
163
 
164
}
165
 
166
#ifdef CONFIG_MELAN
167
#  define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
168
#else
249 giacomo 169
#  define CLOCK_TICK_RATE 1193182 /* Underlying HZ */
120 giacomo 170
#endif
171
 
248 giacomo 172
#define COUNTER_END 100
120 giacomo 173
 
245 giacomo 174
#define barrier() __asm__ __volatile__("" ::: "memory");
175
 
120 giacomo 176
//TSC Calibration (idea from the linux kernel code)
177
void ll_calibrate_tsc(void)
178
{
179
 
180
        signed long long start;
181
        signed long long end;
244 giacomo 182
        signed long long dtsc;
120 giacomo 183
 
244 giacomo 184
        signed long start_8253, end_8253, delta_8253;
120 giacomo 185
 
186
        cli();
187
 
248 giacomo 188
        outp(0x61, (inp(0x61) & ~0x02) | 0x01);
120 giacomo 189
 
190
        outp(0x43,0xB0);                        /* binary, mode 0, LSB/MSB, Ch 2 */
238 giacomo 191
        outp(0x42,0xFF);                        /* LSB of count */
192
        outp(0x42,0xFF);                        /* MSB of count */
242 giacomo 193
 
245 giacomo 194
        barrier();
195
        rdtscll(start);
196
        barrier();
243 giacomo 197
        outp(0x43,0x00);
198
        start_8253 = inp(0x42);
199
        start_8253 |= inp(0x42) << 8;
245 giacomo 200
        barrier();
264 giacomo 201
        rdtscll(start);
202
        barrier();
243 giacomo 203
 
204
        do {
205
 
206
            outp(0x43,0x00);
207
            end_8253 = inp(0x42);
208
            end_8253 |= inp(0x42) << 8;
209
 
210
        } while (end_8253 > COUNTER_END);
211
 
245 giacomo 212
        barrier();
213
        rdtscll(end);
214
        barrier();
243 giacomo 215
        outp(0x43,0x00);
216
        end_8253 = inp(0x42);
217
        end_8253 |= inp(0x42) << 8;
245 giacomo 218
        barrier();
264 giacomo 219
        rdtscll(end);
220
        barrier();
243 giacomo 221
 
222
        //Delta TSC
244 giacomo 223
        dtsc = end - start;
243 giacomo 224
 
225
        //Delta PIT
264 giacomo 226
        delta_8253 = start_8253 - end_8253;
243 giacomo 227
 
242 giacomo 228
        if (delta_8253 > 0x20000) {
120 giacomo 229
                message("Error calculating Delta PIT\n");
230
                ll_abort(10);
231
        }
232
 
233
        message("Delta TSC               = %10ld\n",(long)dtsc);
234
 
235
        message("Delta PIT               = %10ld\n",(long)delta_8253);
236
 
252 giacomo 237
        clk_per_msec = dtsc * CLOCK_TICK_RATE / delta_8253 / 1000;
120 giacomo 238
 
239
        message("Calibrated Clk_per_msec = %10ld\n",(long)clk_per_msec);
240
 
241
        sti();
242
 
243
}
244
 
264 giacomo 245
#define CMOS_INIT  0
246
#define CMOS_BEGIN 1
247
#define CMOS_START 2
248
#define CMOS_END   3
249
 
250
int cmos_calibrate_status = CMOS_INIT;
251
signed long long irq8_start;
252
signed long long irq8_end;
253
 
299 giacomo 254
void calibrate_tsc_IRQ8(void *p)
264 giacomo 255
{
256
 
257
  unsigned char set;
258
 
259
  cli();
260
 
261
  CMOS_READ(0x0C,set);
262
 
263
  barrier();
264
  rdtscll(irq8_end);
265
  barrier();
266
 
267
  if (cmos_calibrate_status == CMOS_START) {
268
    cmos_calibrate_status = CMOS_END;
269
  }
270
 
271
  if (cmos_calibrate_status == CMOS_BEGIN) {
272
    irq8_start = irq8_end;
273
    cmos_calibrate_status = CMOS_START;
274
  }
275
 
276
  if (cmos_calibrate_status == CMOS_INIT) {
277
    cmos_calibrate_status = CMOS_BEGIN;
278
  }
279
 
280
  sti();
281
 
282
}
283
 
284
//TSC Calibration using RTC
285
void ll_calibrate_tsc_cmos(void)
286
{
287
 
288
  signed long long dtsc;
289
 
290
  cli();           
291
 
299 giacomo 292
  irq_bind(8, calibrate_tsc_IRQ8, INT_FORCE);
264 giacomo 293
 
294
  CMOS_READ(0x0A,save_CMOS_regA);
295
  CMOS_READ(0x0B,save_CMOS_regB);
296
 
297
  CMOS_WRITE(0x0A,0x2F); // Set 2 Hz Periodic Interrupt
298
  CMOS_WRITE(0x0B,0x42); // Enable Interrupt
299
 
300
  irq_unmask(8);
301
 
302
  sti();
303
 
304
  while (cmos_calibrate_status != CMOS_END) {
305
    barrier();
306
  }
307
 
308
  dtsc = irq8_end - irq8_start;
309
 
310
  clk_per_msec = dtsc / 500;
311
 
299 giacomo 312
  message("Calibrated CPU Clk/msec  = %10ld\n",(long)clk_per_msec);
264 giacomo 313
 
314
  cli();
315
 
316
  irq_mask(8);
317
 
318
  CMOS_WRITE(0x0A,save_CMOS_regA);
319
  CMOS_WRITE(0x0B,save_CMOS_regB);
320
 
321
  sti();
322
 
323
}
324
 
120 giacomo 325
//Low level time read function
131 giacomo 326
void ll_read_timespec(struct timespec *tspec)
120 giacomo 327
{
328
 
194 giacomo 329
    static unsigned long Gconst = 1000000000;
330
    static unsigned long Mconst = 1000000;
120 giacomo 331
 
124 giacomo 332
    if (clk_per_msec <= 0) {
333
            NULL_TIMESPEC(tspec);
334
            return;
335
    }
336
 
242 giacomo 337
    __asm__("xorl %%eax,%%eax\n\t"
338
            "cpuid\n\t"  
339
            "rdtsc\n\t"
340
            "pushl %%eax\n\t"
341
            "pushl %%edx\n\t"
342
            "xorl %%eax,%%eax\n\t"
343
            "cpuid\n\t"
344
            "popl %%edx\n\t"
345
            "popl %%eax\n\t"
346
            "subl (%%edi),%%eax\n\t"
194 giacomo 347
            "sbbl 4(%%edi),%%edx\n\t"
348
            "movl %%edx,%%ecx\n\t"
349
            "mull %6\n\t"
350
            "pushl %%eax\n\t"
351
            "movl %%ecx,%%eax\n\t"
352
            "movl %%edx,%%ecx\n\t"
353
            "mull %6\n\t"
354
            "addl %%ecx,%%eax\n\t"
355
            "adcl $0,%%edx\n\t"
242 giacomo 356
            "movl %8,%%ebx\n\t"
194 giacomo 357
            "divl (%%ebx)\n\t"
358
            "movl %%eax,%%ecx\n\t"
359
            "popl %%eax\n\t"
360
            "divl (%%ebx)\n\t"
361
            "movl %%ecx,%%edx\n\t"
362
            "addl (%%esi),%%eax\n\t"
363
            "adcl 4(%%esi),%%edx\n\t"
364
            "divl %7\n\t"
365
 
366
            : "=a" (tspec->tv_sec), "=d" (tspec->tv_nsec)
242 giacomo 367
            : "D" (ptr_init_tsc), "S" (ptr_init_nsec), "b" (0),
368
              "c" (0), "m" (Mconst), "m" (Gconst), "m" (ptr_clk_per_msec));
194 giacomo 369
 
120 giacomo 370
}
371
 
299 giacomo 372
int apic_get_maxlvt(void)
373
{
374
        unsigned int v, ver, maxlvt;
375
 
376
        v = apic_read(APIC_LVR);
377
        ver = GET_APIC_VERSION(v);
378
        /* 82489DXs do not report # of LVT entries. */
379
        maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(v) : 2;
380
        return maxlvt;
381
}
382
 
383
void clear_local_APIC(void)
384
{
385
        int maxlvt;
386
        unsigned long v;
387
 
388
        maxlvt = apic_get_maxlvt();
389
 
390
        /*
391
         * Masking an LVT entry on a P6 can trigger a local APIC error
392
         * if the vector is zero. Mask LVTERR first to prevent this.
393
         */
394
        if (maxlvt >= 3) {
395
                v = 0xFF; /* any non-zero vector will do */
396
                apic_write_around(APIC_LVTERR, v | APIC_LVT_MASKED);
397
        }
398
        /*
399
         * Careful: we have to set masks only first to deassert
400
         * any level-triggered sources.
401
         */
402
        v = apic_read(APIC_LVTT);
403
        apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED);
404
        v = apic_read(APIC_LVT0);
405
        apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
406
        v = apic_read(APIC_LVT1);
407
        apic_write_around(APIC_LVT1, v | APIC_LVT_MASKED);
408
        if (maxlvt >= 4) {
409
                v = apic_read(APIC_LVTPC);
410
                apic_write_around(APIC_LVTPC, v | APIC_LVT_MASKED);
411
        }
412
 
413
        /*
414
         * Clean APIC state for other OSs:
415
         */
416
        apic_write_around(APIC_LVTT, APIC_LVT_MASKED);
417
        apic_write_around(APIC_LVT0, APIC_LVT_MASKED);
418
        apic_write_around(APIC_LVT1, APIC_LVT_MASKED);
419
        if (maxlvt >= 3)
420
                apic_write_around(APIC_LVTERR, APIC_LVT_MASKED);
421
        if (maxlvt >= 4)
422
                apic_write_around(APIC_LVTPC, APIC_LVT_MASKED);
423
        v = GET_APIC_VERSION(apic_read(APIC_LVR));
424
        if (APIC_INTEGRATED(v)) {       /* !82489DX */
425
                if (maxlvt > 3)
426
                        apic_write(APIC_ESR, 0);
427
                apic_read(APIC_ESR);
428
        }
429
}
430
 
431
void connect_bsp_APIC(void)
432
{
433
        /*
434
         * Do not trust the local APIC being empty at bootup.
435
         */
436
        clear_local_APIC();
437
        /*
438
         * PIC mode, enable APIC mode in the IMCR, i.e.
439
         * connect BSP's local APIC to INT and NMI lines.
440
         */
441
        outp(0x22, 0x70);
442
        outp(0x23, 0x01);
443
 
444
}
445
 
446
void disconnect_bsp_APIC(void)
447
{
448
 
449
        /*
450
         * Put the board back into PIC mode (has an effect
451
         * only on certain older boards).  Note that APIC
452
         * interrupts, including IPIs, won't work beyond
453
         * this point!  The only exception are INIT IPIs.
454
         */
455
 
456
        outp(0x22, 0x70);
457
        outp(0x23, 0x00);
458
 
459
}
460
 
461
void disable_local_APIC(void)
462
{
463
        unsigned long value;
464
 
465
        clear_local_APIC();
466
 
467
        /*
468
         * Disable APIC (implies clearing of registers
469
         * for 82489DX!).
470
         */
471
        value = apic_read(APIC_SPIV);
472
        value &= ~APIC_SPIV_APIC_ENABLED;
473
        apic_write_around(APIC_SPIV, value);
474
}
475
 
476
#define SPURIOUS_APIC_VECTOR 0xFF
477
 
478
/*
479
 * An initial setup of the virtual wire mode.
480
 */
481
 
482
void setup_local_APIC (void)
483
{
484
        unsigned long value, ver;
485
 
486
        /* Pound the ESR really hard over the head with a big hammer - mbligh */
487
 
488
        apic_write(APIC_ESR, 0);
489
        apic_write(APIC_ESR, 0);
490
        apic_write(APIC_ESR, 0);
491
        apic_write(APIC_ESR, 0);
492
 
493
        value = apic_read(APIC_LVR);
494
        ver = GET_APIC_VERSION(value);
495
 
496
        /*
497
         * Set Task Priority to 'accept all'. We never change this
498
         * later on.
499
         */
500
        value = apic_read(APIC_TASKPRI);
501
        value &= ~APIC_TPRI_MASK;
502
        apic_write_around(APIC_TASKPRI, value);
503
 
504
        /*
505
         * Now that we are all set up, enable the APIC
506
         */
507
        value = apic_read(APIC_SPIV);
508
        value &= ~APIC_VECTOR_MASK;
509
        /*
510
         * Enable APIC
511
         */
512
        value |= APIC_SPIV_APIC_ENABLED;
513
 
514
        /*
515
         * Some unknown Intel IO/APIC (or APIC) errata is biting us with
516
         * certain networking cards. If high frequency interrupts are
517
         * happening on a particular IOAPIC pin, plus the IOAPIC routing
518
         * entry is masked/unmasked at a high rate as well then sooner or
519
         * later IOAPIC line gets 'stuck', no more interrupts are received
520
         * from the device. If focus CPU is disabled then the hang goes
521
         * away, oh well :-(
522
         *
523
         * [ This bug can be reproduced easily with a level-triggered
524
         *   PCI Ne2000 networking cards and PII/PIII processors, dual
525
         *   BX chipset. ]
526
         */
527
        /*
528
         * Actually disabling the focus CPU check just makes the hang less
529
         * frequent as it makes the interrupt distributon model be more
530
         * like LRU than MRU (the short-term load is more even across CPUs).
531
         * See also the comment in end_level_ioapic_irq().  --macro
532
         */
533
#if 1
534
        /* Enable focus processor (bit==0) */
535
        value &= ~APIC_SPIV_FOCUS_DISABLED;
536
#else
537
        /* Disable focus processor (bit==1) */
538
        value |= APIC_SPIV_FOCUS_DISABLED;
539
#endif
540
        /*
541
         * Set spurious IRQ vector
542
         */
543
        value |= SPURIOUS_APIC_VECTOR;
544
        apic_write_around(APIC_SPIV, value);
545
 
546
        /*
547
         * Set up LVT0, LVT1:
548
         *
549
         * set up through-local-APIC on the BP's LINT0. This is not
550
         * strictly necessery in pure symmetric-IO mode, but sometimes
551
         * we delegate interrupts to the 8259A.
552
         */
553
        /*
554
         * TODO: set up through-local-APIC from through-I/O-APIC? --macro
555
         */
556
        value = APIC_DM_EXTINT;
557
        apic_write_around(APIC_LVT0, value);
558
 
559
        value = APIC_DM_NMI | APIC_LVT_MASKED;
560
        if (!APIC_INTEGRATED(ver))              /* 82489DX */
561
                value |= APIC_LVT_LEVEL_TRIGGER;
562
        apic_write_around(APIC_LVT1, value);
563
 
564
}
565
 
566
void disable_APIC_timer(void)
567
{
568
        unsigned long v;
569
 
570
        v = apic_read(APIC_LVTT);
571
        apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED);
572
 
573
}
574
 
575
void enable_APIC_timer(void)
576
{
577
        unsigned long v;
578
 
579
        v = apic_read(APIC_LVTT);
580
        apic_write_around(APIC_LVTT, v & ~APIC_LVT_MASKED);
581
 
582
}
583
 
584
#define LOCAL_TIMER_VECTOR 0x40
585
 
586
void setup_APIC_LVTT(unsigned int clocks)
587
{
588
        unsigned int lvtt1_value, tmp_value;
589
 
590
        lvtt1_value = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) |
591
                        APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
592
        apic_write_around(APIC_LVTT, lvtt1_value);
593
 
594
        /*
595
         * Divide PICLK by 1
596
         */
597
        tmp_value = apic_read(APIC_TDCR);
598
        apic_write_around(APIC_TDCR, (tmp_value
599
                                & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
600
                                | APIC_TDR_DIV_1);
601
 
602
        apic_write_around(APIC_TMICT, clocks);
603
}
604
 
605
#define APIC_LIMIT 0xFF000000
606
 
607
void ll_calibrate_apic(void)
608
{
609
 
610
  unsigned int apic_start = 0, apic_end = 0, dapic;
611
  signed long long tsc_start = 0, tsc_end = 0, dtsc;
612
  unsigned int tmp_value;
613
 
614
  cli();
615
 
616
  tmp_value = apic_read(APIC_TDCR);
617
  apic_write_around(APIC_TDCR, (tmp_value
618
                                 & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
619
                                 | APIC_TDR_DIV_1);
620
 
621
  apic_write(APIC_TMICT, MAX_DWORD);
622
 
623
  barrier();
624
  rdtscll(tsc_start);
625
  barrier();
626
  apic_start = apic_read(APIC_TMCCT);
627
  barrier();            
628
 
629
  while (apic_read(APIC_TMCCT) > APIC_LIMIT) {
630
    barrier();
631
    rdtscll(tsc_end);
632
  }
633
 
634
  barrier();
635
  rdtscll(tsc_end);
636
  barrier();
637
  apic_end = apic_read(APIC_TMCCT);
638
  barrier();    
639
 
640
  sti();
641
 
642
  dtsc = tsc_end - tsc_start;
643
  dapic = apic_start - apic_end;
644
 
645
  apic_clk_per_msec = clk_per_msec * (signed long long)(dapic) / dtsc;
646
 
647
  message("Calibrated APIC Clk/msec = %10ld\n",(long)apic_clk_per_msec);
648
 
649
}
650
 
120 giacomo 651
void ll_init_advtimer()
652
{
653
 
654
    if (use_tsc) {
655
 
264 giacomo 656
        #ifdef CALIBRATE_USING_CMOS
657
          ll_calibrate_tsc_cmos();
658
        #else
659
          ll_calibrate_tsc();
660
        #endif  
661
 
120 giacomo 662
        last_delta_clk_per_msec = 0;
663
        total_delta_clk_per_msec = 0;
664
 
665
        rdtscll(init_tsc); // Read start TSC
666
        init_nsec = 0;
667
 
299 giacomo 668
        if (use_apic) {
669
          unsigned long msr_low_orig, tmp;
670
 
671
          cli();
672
 
673
          rdmsr(APIC_BASE_MSR, msr_low_orig, tmp);
674
          wrmsr(APIC_BASE_MSR, msr_low_orig|(1<<11), 0);
675
 
676
          connect_bsp_APIC();
677
 
678
          setup_local_APIC();
679
 
680
          sti();
681
 
682
          ll_calibrate_apic();
683
 
684
        }
685
 
120 giacomo 686
        if (use_cmos) {
687
 
131 giacomo 688
            message("CMOS adjustement enabled\n");
120 giacomo 689
 
690
            cli();         
691
 
692
            irq_bind(8, HandlerIRQ8, INT_FORCE);
693
 
694
            CMOS_READ(0x0A,save_CMOS_regA);
695
            CMOS_READ(0x0B,save_CMOS_regB);
696
 
697
            CMOS_WRITE(0x0A,0x2F); // Set 2 Hz Periodic Interrupt
698
            CMOS_WRITE(0x0B,0x42); // Enable Interrupt
699
 
700
            irq_unmask(8);
701
 
702
            sti();
703
 
704
        }
705
 
706
    } else {
707
 
708
        use_cmos = 0;
709
 
710
   }
711
 
712
}
713
 
131 giacomo 714
void ll_restore_CMOS()
120 giacomo 715
{
716
        if (use_cmos) {
717
                cli();
718
 
719
                irq_mask(8);
720
 
721
                CMOS_WRITE(0x0A,save_CMOS_regA);
722
                CMOS_WRITE(0x0B,save_CMOS_regB);
723
 
724
                sti();         
725
        }
726
}