Subversion Repositories shark

Rev

Rev 646 | Rev 649 | 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/sys/ll/ll-data.h>
29
#include <ll/sys/ll/ll-func.h>
30
#include <ll/i386/pic.h>
299 giacomo 31
#include <ll/i386/apic.h>
305 giacomo 32
#include <ll/i386/64bit.h>
120 giacomo 33
#include <ll/sys/ll/event.h>
34
#include <ll/sys/ll/time.h>
305 giacomo 35
#include <ll/i386/advtimer.h>
120 giacomo 36
 
264 giacomo 37
#define CALIBRATE_USING_CMOS
38
 
305 giacomo 39
unsigned long long init_tsc;
40
unsigned long long * ptr_init_tsc = &init_tsc;
120 giacomo 41
 
648 mauro 42
struct timespec init_time;
43
struct timespec * ptr_init_time = &init_time;
120 giacomo 44
 
305 giacomo 45
unsigned int clk_per_msec = 0;
46
unsigned int apic_clk_per_msec = 0;
47
unsigned int apic_set_limit = 0;
194 giacomo 48
 
336 giacomo 49
/* Precalcolated const
50
   used in ll_read_timer */
51
unsigned int clk_opt_0 = 0;
329 giacomo 52
unsigned int clk_opt_1 = 0;
53
unsigned int clk_opt_2 = 0;
54
unsigned int clk_opt_3 = 0;
55
unsigned int clk_opt_4 = 0;
336 giacomo 56
unsigned int clk_opt_5 = 0;
329 giacomo 57
 
120 giacomo 58
unsigned char save_CMOS_regA;
59
unsigned char save_CMOS_regB;
60
 
619 mauro 61
unsigned char X86_tsc = 0;
62
unsigned char X86_apic = 0;
63
unsigned char use_tsc = 0;
64
unsigned char use_apic = 0;
65
 
120 giacomo 66
#ifdef CONFIG_MELAN
67
#  define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
68
#else
249 giacomo 69
#  define CLOCK_TICK_RATE 1193182 /* Underlying HZ */
120 giacomo 70
#endif
71
 
248 giacomo 72
#define COUNTER_END 100
120 giacomo 73
 
245 giacomo 74
#define barrier() __asm__ __volatile__("" ::: "memory");
75
 
120 giacomo 76
//TSC Calibration (idea from the linux kernel code)
77
void ll_calibrate_tsc(void)
78
{
79
 
305 giacomo 80
        unsigned long long start;
81
        unsigned long long end;
82
        unsigned long long dtsc;
120 giacomo 83
 
305 giacomo 84
        unsigned int start_8253, end_8253, delta_8253;
120 giacomo 85
 
248 giacomo 86
        outp(0x61, (inp(0x61) & ~0x02) | 0x01);
120 giacomo 87
 
88
        outp(0x43,0xB0);                        /* binary, mode 0, LSB/MSB, Ch 2 */
238 giacomo 89
        outp(0x42,0xFF);                        /* LSB of count */
90
        outp(0x42,0xFF);                        /* MSB of count */
242 giacomo 91
 
619 mauro 92
        barrier();
93
        rdtscll(start);
94
        barrier();
95
        outp(0x43,0x00);
243 giacomo 96
        start_8253 = inp(0x42);
97
        start_8253 |= inp(0x42) << 8;
619 mauro 98
        barrier();
99
        rdtscll(start);
100
        barrier();
243 giacomo 101
 
102
        do {
103
            outp(0x43,0x00);
104
            end_8253 = inp(0x42);
105
            end_8253 |= inp(0x42) << 8;
106
        } while (end_8253 > COUNTER_END);
107
 
619 mauro 108
        barrier();
109
        rdtscll(end);
110
        barrier();
243 giacomo 111
        outp(0x43,0x00);
112
        end_8253 = inp(0x42);
113
        end_8253 |= inp(0x42) << 8;
619 mauro 114
        barrier();
115
        rdtscll(end);
116
        barrier();
243 giacomo 117
 
118
        //Delta TSC
619 mauro 119
        dtsc = end - start;
243 giacomo 120
 
121
        //Delta PIT
264 giacomo 122
        delta_8253 = start_8253 - end_8253;
243 giacomo 123
 
242 giacomo 124
        if (delta_8253 > 0x20000) {
120 giacomo 125
                message("Error calculating Delta PIT\n");
126
                ll_abort(10);
127
        }
128
 
305 giacomo 129
        message("Delta TSC               = %10d\n",(int)dtsc);
120 giacomo 130
 
305 giacomo 131
        message("Delta PIT               = %10d\n",delta_8253);
120 giacomo 132
 
252 giacomo 133
        clk_per_msec = dtsc * CLOCK_TICK_RATE / delta_8253 / 1000;
120 giacomo 134
 
305 giacomo 135
        message("Calibrated Clk_per_msec = %10d\n",clk_per_msec);
120 giacomo 136
}
137
 
264 giacomo 138
#define CMOS_INIT  0
139
#define CMOS_BEGIN 1
140
#define CMOS_START 2
141
#define CMOS_END   3
142
 
143
int cmos_calibrate_status = CMOS_INIT;
305 giacomo 144
unsigned long long irq8_start;
145
unsigned long long irq8_end;
264 giacomo 146
 
299 giacomo 147
void calibrate_tsc_IRQ8(void *p)
264 giacomo 148
{
619 mauro 149
        unsigned char set;
264 giacomo 150
 
619 mauro 151
        CMOS_READ(0x0C,set);
264 giacomo 152
 
619 mauro 153
        barrier();
154
        rdtscll(irq8_end);
155
        barrier();
264 giacomo 156
 
619 mauro 157
        if (cmos_calibrate_status == CMOS_START) {
158
                cmos_calibrate_status = CMOS_END;
159
        }
264 giacomo 160
 
619 mauro 161
        if (cmos_calibrate_status == CMOS_BEGIN) {
162
                irq8_start = irq8_end;
163
                cmos_calibrate_status = CMOS_START;
164
        }
264 giacomo 165
 
619 mauro 166
        if (cmos_calibrate_status == CMOS_INIT) {
167
                cmos_calibrate_status = CMOS_BEGIN;
168
        }
264 giacomo 169
}
170
 
171
//TSC Calibration using RTC
172
void ll_calibrate_tsc_cmos(void)
173
{
619 mauro 174
        unsigned long long dtsc;
264 giacomo 175
 
619 mauro 176
        irq_bind(8, calibrate_tsc_IRQ8, INT_FORCE);
264 giacomo 177
 
619 mauro 178
        CMOS_READ(0x0A,save_CMOS_regA);
179
        CMOS_READ(0x0B,save_CMOS_regB);
180
 
181
        CMOS_WRITE(0x0A,0x2F); // Set 2 Hz Periodic Interrupt
182
        CMOS_WRITE(0x0B,0x42); // Enable Interrupt
264 giacomo 183
 
619 mauro 184
        irq_unmask(8);
317 giacomo 185
 
619 mauro 186
        sti();
264 giacomo 187
 
619 mauro 188
        while (cmos_calibrate_status != CMOS_END) {
189
                barrier();
190
        }
317 giacomo 191
 
619 mauro 192
        cli();
264 giacomo 193
 
619 mauro 194
        dtsc = irq8_end - irq8_start;
264 giacomo 195
 
619 mauro 196
        clk_per_msec = dtsc / 500;
197
        clk_opt_0 = (unsigned int)(dtsc);
198
        clk_opt_1 = (unsigned int)((unsigned long long)(dtsc << 1));
199
        clk_opt_2 = (unsigned int)((unsigned long long)(dtsc << 33) / 1000000000L);
200
        clk_opt_3 = (unsigned int)((unsigned long long)(dtsc << 32) / 1000000000L);
201
        clk_opt_4 = (unsigned int)((unsigned long long)(dtsc << 31) / 1000000000L);
202
        clk_opt_5 = (unsigned int)((unsigned long long)(dtsc << 30) / 1000000000L);
264 giacomo 203
 
619 mauro 204
        message("Calibrated CPU Clk/msec  = %10u\n",clk_per_msec);
264 giacomo 205
 
619 mauro 206
#ifdef __O1000__
207
        if (clk_per_msec < 1000000) {
208
                message("Timer Optimization CPU < 1 GHz\n");
209
        } else {
210
                message("Bad Timer Optimization\n");
211
                ll_abort(66);
212
        }
213
#endif
329 giacomo 214
 
619 mauro 215
#ifdef __O2000__
216
        if (clk_per_msec < 2000000 && clk_per_msec >= 1000000) {
217
                message("Timer Optimization 1 GHz < CPU < 2 GHz\n");
218
        } else {
219
                message("Bad Timer Optimization\n");
220
                ll_abort(66);
221
        }
222
#endif
329 giacomo 223
 
619 mauro 224
#ifdef __O4000__
225
        if (clk_per_msec < 4000000 && clk_per_msec >= 2000000) {
226
                message("Timer Optimization 2 GHz < CPU < 4 GHz\n");
227
        } else {
228
                message("Bad Timer Optimization\n");
229
                ll_abort(66);
230
        }
231
#endif
329 giacomo 232
 
619 mauro 233
        irq_mask(8);
264 giacomo 234
 
619 mauro 235
        CMOS_WRITE(0x0A,save_CMOS_regA);
236
        CMOS_WRITE(0x0B,save_CMOS_regB);
264 giacomo 237
}
238
 
299 giacomo 239
int apic_get_maxlvt(void)
240
{
241
        unsigned int v, ver, maxlvt;
242
 
243
        v = apic_read(APIC_LVR);
244
        ver = GET_APIC_VERSION(v);
245
        /* 82489DXs do not report # of LVT entries. */
246
        maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(v) : 2;
247
        return maxlvt;
248
}
249
 
304 giacomo 250
/* Clear local APIC, from Linux kernel */
299 giacomo 251
void clear_local_APIC(void)
252
{
253
        int maxlvt;
254
        unsigned long v;
255
 
256
        maxlvt = apic_get_maxlvt();
257
 
258
        /*
259
         * Masking an LVT entry on a P6 can trigger a local APIC error
260
         * if the vector is zero. Mask LVTERR first to prevent this.
261
         */
262
        if (maxlvt >= 3) {
263
                v = 0xFF; /* any non-zero vector will do */
264
                apic_write_around(APIC_LVTERR, v | APIC_LVT_MASKED);
265
        }
266
        /*
267
         * Careful: we have to set masks only first to deassert
268
         * any level-triggered sources.
269
         */
270
        v = apic_read(APIC_LVTT);
271
        apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED);
272
        v = apic_read(APIC_LVT0);
273
        apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
274
        v = apic_read(APIC_LVT1);
275
        apic_write_around(APIC_LVT1, v | APIC_LVT_MASKED);
276
        if (maxlvt >= 4) {
277
                v = apic_read(APIC_LVTPC);
278
                apic_write_around(APIC_LVTPC, v | APIC_LVT_MASKED);
279
        }
280
 
281
        /*
282
         * Clean APIC state for other OSs:
283
         */
284
        apic_write_around(APIC_LVTT, APIC_LVT_MASKED);
285
        apic_write_around(APIC_LVT0, APIC_LVT_MASKED);
286
        apic_write_around(APIC_LVT1, APIC_LVT_MASKED);
287
        if (maxlvt >= 3)
288
                apic_write_around(APIC_LVTERR, APIC_LVT_MASKED);
289
        if (maxlvt >= 4)
290
                apic_write_around(APIC_LVTPC, APIC_LVT_MASKED);
291
        v = GET_APIC_VERSION(apic_read(APIC_LVR));
292
        if (APIC_INTEGRATED(v)) {       /* !82489DX */
293
                if (maxlvt > 3)
294
                        apic_write(APIC_ESR, 0);
295
                apic_read(APIC_ESR);
296
        }
297
}
298
 
299
void disable_local_APIC(void)
300
{
301
        unsigned long value;
302
 
303
        clear_local_APIC();
304
 
305
        /*
306
         * Disable APIC (implies clearing of registers
307
         * for 82489DX!).
308
         */
309
        value = apic_read(APIC_SPIV);
310
        value &= ~APIC_SPIV_APIC_ENABLED;
311
        apic_write_around(APIC_SPIV, value);
312
}
313
 
314
#define SPURIOUS_APIC_VECTOR 0xFF
315
 
316
/*
302 giacomo 317
 * Setup the local APIC, minimal code to run P6 APIC
299 giacomo 318
 */
319
void setup_local_APIC (void)
320
{
301 giacomo 321
        unsigned long value;
299 giacomo 322
 
323
        /* Pound the ESR really hard over the head with a big hammer - mbligh */
619 mauro 324
 
299 giacomo 325
        apic_write(APIC_ESR, 0);
326
        apic_write(APIC_ESR, 0);
327
        apic_write(APIC_ESR, 0);
328
        apic_write(APIC_ESR, 0);
619 mauro 329
 
301 giacomo 330
        value = APIC_SPIV_FOCUS_DISABLED | APIC_SPIV_APIC_ENABLED | SPURIOUS_APIC_VECTOR;
331
        apic_write_around(APIC_SPIV, value);
299 giacomo 332
 
619 mauro 333
        value = APIC_DM_EXTINT | APIC_LVT_LEVEL_TRIGGER;
334
        apic_write_around(APIC_LVT0, value);
299 giacomo 335
 
619 mauro 336
        value = APIC_DM_NMI;
337
        apic_write_around(APIC_LVT1, value);
299 giacomo 338
 
619 mauro 339
        apic_write(APIC_ESR, 0);
299 giacomo 340
}
341
 
342
void disable_APIC_timer(void)
343
{
619 mauro 344
        unsigned long v;
299 giacomo 345
 
619 mauro 346
        v = apic_read(APIC_LVTT);
347
        apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED);
299 giacomo 348
}
349
 
350
void enable_APIC_timer(void)
351
{
619 mauro 352
        unsigned long v;
299 giacomo 353
 
619 mauro 354
        v = apic_read(APIC_LVTT);
355
        apic_write_around(APIC_LVTT, v & ~APIC_LVT_MASKED);
299 giacomo 356
}
357
 
304 giacomo 358
#define LOCAL_TIMER_VECTOR 0x39
302 giacomo 359
 
303 giacomo 360
/* Set APIC Timer... from Linux kernel */
361
void setup_APIC_timer()
299 giacomo 362
{
619 mauro 363
        unsigned int lvtt1_value;
303 giacomo 364
 
619 mauro 365
        lvtt1_value = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) |
366
                        APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
367
        apic_write_around(APIC_LVTT, lvtt1_value);
303 giacomo 368
 
619 mauro 369
        /*
370
        * Divide PICLK by 1
371
        */
372
        apic_write_around(APIC_TDCR, APIC_TDR_DIV_1);
373
 
374
        apic_write_around(APIC_TMICT, MAX_DWORD);
375
 
376
        disable_APIC_timer();                                                                                                                            
299 giacomo 377
}
378
 
379
#define APIC_LIMIT 0xFF000000
303 giacomo 380
#define APIC_SET_LIMIT 10
299 giacomo 381
 
382
void ll_calibrate_apic(void)
383
{
619 mauro 384
        unsigned int apic_start = 0, apic_end = 0, dapic;
385
        unsigned long long tsc_start = 0, tsc_end = 0, dtsc;
386
        unsigned int tmp_value;
299 giacomo 387
 
619 mauro 388
        tmp_value = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | LOCAL_TIMER_VECTOR;
389
        apic_write_around(APIC_LVTT, tmp_value);
299 giacomo 390
 
619 mauro 391
        apic_write_around(APIC_TDCR, APIC_TDR_DIV_1);
299 giacomo 392
 
619 mauro 393
        apic_write(APIC_TMICT, MAX_DWORD);
312 giacomo 394
 
619 mauro 395
        enable_APIC_timer();
299 giacomo 396
 
619 mauro 397
        barrier();
398
        rdtscll(tsc_start);
399
        barrier();
400
        apic_start = apic_read(APIC_TMCCT);
401
        barrier();            
312 giacomo 402
 
619 mauro 403
        while (apic_read(APIC_TMCCT) > APIC_LIMIT) {
404
                barrier();
405
                rdtscll(tsc_end);
406
        }
299 giacomo 407
 
619 mauro 408
        barrier();
409
        rdtscll(tsc_end);
410
        barrier();
411
        apic_end = apic_read(APIC_TMCCT);
412
        barrier();    
299 giacomo 413
 
619 mauro 414
        disable_APIC_timer();
312 giacomo 415
 
619 mauro 416
        dtsc = tsc_end - tsc_start;
417
        dapic = apic_start - apic_end;
418
 
419
        apic_clk_per_msec = (unsigned long long)(clk_per_msec) * (unsigned long long)(dapic) / dtsc;
420
        apic_set_limit = ((apic_clk_per_msec / 100) != 0) ? (apic_clk_per_msec/100) : APIC_SET_LIMIT;  
299 giacomo 421
 
619 mauro 422
        message("Calibrated APIC Clk/msec = %10d\n",apic_clk_per_msec);
299 giacomo 423
}
424
 
120 giacomo 425
void ll_init_advtimer()
426
{
619 mauro 427
        unsigned long msr_low_orig, tmp;
120 giacomo 428
 
619 mauro 429
#ifdef __APIC__
430
        use_apic = X86_apic;
431
#endif
432
 
433
#ifdef __TSC__
434
        use_tsc = X86_tsc;
435
#endif
436
 
437
        if (use_tsc) {
120 giacomo 438
 
619 mauro 439
#ifdef CALIBRATE_USING_CMOS
440
                ll_calibrate_tsc_cmos();
441
#else
442
                ll_calibrate_tsc();
443
#endif  
264 giacomo 444
 
619 mauro 445
                rdtscll(init_tsc); // Read start TSC
648 mauro 446
                init_time.tv_sec = 0;
447
                init_time.tv_nsec = 0;
120 giacomo 448
 
619 mauro 449
                if (use_apic) {
450
                        rdmsr(APIC_BASE_MSR, msr_low_orig, tmp);
451
                        wrmsr(APIC_BASE_MSR, msr_low_orig|(1<<11), 0);
299 giacomo 452
 
619 mauro 453
                        clear_local_APIC();
299 giacomo 454
 
619 mauro 455
                        ll_calibrate_apic();
299 giacomo 456
 
619 mauro 457
                        setup_local_APIC();
303 giacomo 458
 
619 mauro 459
                        setup_APIC_timer();
460
                }
461
        }
120 giacomo 462
}
463
 
301 giacomo 464
void ll_restore_adv()
120 giacomo 465
{
646 mauro 466
        SYS_FLAGS f;
467
 
468
        /* Disable APIC */
619 mauro 469
        if (use_apic) {
646 mauro 470
                unsigned int msr_low_orig, tmp;
301 giacomo 471
 
646 mauro 472
                f = ll_fsave();
301 giacomo 473
 
646 mauro 474
                disable_APIC_timer();
301 giacomo 475
 
476
                rdmsr(APIC_BASE_MSR, msr_low_orig, tmp);
646 mauro 477
                wrmsr(APIC_BASE_MSR, msr_low_orig&~(1<<11), 0);
301 giacomo 478
 
646 mauro 479
                ll_frestore(f);
619 mauro 480
        }
120 giacomo 481
}
646 mauro 482
 
483
void ll_scale_advtimer(unsigned int old_f, unsigned int new_f)
484
{
485
        unsigned long long dtsc;
486
        unsigned long temp;
487
        SYS_FLAGS f;
488
 
648 mauro 489
        if (use_tsc) {
490
                f = ll_fsave();
646 mauro 491
 
648 mauro 492
                rdtscll(init_tsc);              // Set new start TSC
493
                ll_read_timespec(&init_time);   // Set new start TimeSpec
494
 
495
                mul32div32to32(clk_per_msec,new_f,old_f,temp);
496
                clk_per_msec = temp;
497
                dtsc = (unsigned long long)(clk_per_msec) * 500;
498
                clk_opt_0 = (unsigned int)(dtsc);
499
                clk_opt_1 = (unsigned int)((unsigned long long)(dtsc << 1));
500
                clk_opt_2 = (unsigned int)((unsigned long long)(dtsc << 33) / 1000000000L);
501
                clk_opt_3 = (unsigned int)((unsigned long long)(dtsc << 32) / 1000000000L);
502
                clk_opt_4 = (unsigned int)((unsigned long long)(dtsc << 31) / 1000000000L);
503
                clk_opt_5 = (unsigned int)((unsigned long long)(dtsc << 30) / 1000000000L);
646 mauro 504
 
648 mauro 505
                ll_frestore(f);
506
        }
646 mauro 507
}