~smartboyhw/wubi/bug-1080090-new

« back to all changes in this revision

Viewing changes to src/grub4dos/netboot/.svn/text-base/timer.c.svn-base

  • Committer: Howard Chan
  • Date: 2012-11-20 10:16:05 UTC
  • Revision ID: smartboyhw@gmail.com-20121120101605-qfmjfsdynpzg9an9
Added images

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* A couple of routines to implement a low-overhead timer for drivers */
2
 
 
3
 
 /*
4
 
 * This program is free software; you can redistribute it and/or
5
 
 * modify it under the terms of the GNU General Public License as
6
 
 * published by the Free Software Foundation; either version 2, or (at
7
 
 * your option) any later version.
8
 
 */
9
 
 
10
 
#include        "etherboot.h"
11
 
#include        "timer.h"
12
 
 
13
 
void load_timer2(unsigned int ticks)
14
 
{
15
 
        /* Set up the timer gate, turn off the speaker */
16
 
        outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB);
17
 
        outb(TIMER2_SEL|WORD_ACCESS|MODE0|BINARY_COUNT, TIMER_MODE_PORT);
18
 
        outb(ticks & 0xFF, TIMER2_PORT);
19
 
        outb(ticks >> 8, TIMER2_PORT);
20
 
}
21
 
 
22
 
#if defined(CONFIG_TSC_CURRTICKS)
23
 
#define rdtsc(low,high) \
24
 
     __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
25
 
 
26
 
#define rdtscll(val) \
27
 
     __asm__ __volatile__ ("rdtsc" : "=A" (val))
28
 
 
29
 
 
30
 
#define HZ TICKS_PER_SEC
31
 
#define CLOCK_TICK_RATE 1193180U /* Underlying HZ */
32
 
/* LATCH is used in the interval timer and ftape setup. */
33
 
#define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ)  /* For divider */
34
 
 
35
 
 
36
 
/* ------ Calibrate the TSC ------- 
37
 
 * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset().
38
 
 * Too much 64-bit arithmetic here to do this cleanly in C, and for
39
 
 * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2)
40
 
 * output busy loop as low as possible. We avoid reading the CTC registers
41
 
 * directly because of the awkward 8-bit access mechanism of the 82C54
42
 
 * device.
43
 
 */
44
 
 
45
 
#define CALIBRATE_LATCH (5 * LATCH)
46
 
 
47
 
static unsigned long long calibrate_tsc(void)
48
 
{
49
 
        /* Set the Gate high, disable speaker */
50
 
        outb((inb(0x61) & ~0x02) | 0x01, 0x61);
51
 
 
52
 
        /*
53
 
         * Now let's take care of CTC channel 2
54
 
         *
55
 
         * Set the Gate high, program CTC channel 2 for mode 0,
56
 
         * (interrupt on terminal count mode), binary count,
57
 
         * load 5 * LATCH count, (LSB and MSB) to begin countdown.
58
 
         */
59
 
        outb(0xb0, 0x43);                       /* binary, mode 0, LSB/MSB, Ch 2 */
60
 
        outb(CALIBRATE_LATCH & 0xff, 0x42);     /* LSB of count */
61
 
        outb(CALIBRATE_LATCH >> 8, 0x42);       /* MSB of count */
62
 
 
63
 
        {
64
 
                unsigned long startlow, starthigh;
65
 
                unsigned long endlow, endhigh;
66
 
                unsigned long count;
67
 
 
68
 
                rdtsc(startlow,starthigh);
69
 
                count = 0;
70
 
                do {
71
 
                        count++;
72
 
                } while ((inb(0x61) & 0x20) == 0);
73
 
                rdtsc(endlow,endhigh);
74
 
 
75
 
                /* Error: ECTCNEVERSET */
76
 
                if (count <= 1)
77
 
                        goto bad_ctc;
78
 
 
79
 
                /* 64-bit subtract - gcc just messes up with long longs */
80
 
                __asm__("subl %2,%0\n\t"
81
 
                        "sbbl %3,%1"
82
 
                        :"=a" (endlow), "=d" (endhigh)
83
 
                        :"g" (startlow), "g" (starthigh),
84
 
                         "0" (endlow), "1" (endhigh));
85
 
 
86
 
                /* Error: ECPUTOOFAST */
87
 
                if (endhigh)
88
 
                        goto bad_ctc;
89
 
 
90
 
                endlow /= 5;
91
 
                return endlow;
92
 
        }
93
 
 
94
 
        /*
95
 
         * The CTC wasn't reliable: we got a hit on the very first read,
96
 
         * or the CPU was so fast/slow that the quotient wouldn't fit in
97
 
         * 32 bits..
98
 
         */
99
 
bad_ctc:
100
 
        printf("bad_ctc\n");
101
 
        return 0;
102
 
}
103
 
 
104
 
 
105
 
unsigned long currticks(void)
106
 
{
107
 
        static unsigned long clocks_per_tick;
108
 
        unsigned long clocks_high, clocks_low;
109
 
        unsigned long currticks;
110
 
        if (!clocks_per_tick) {
111
 
                clocks_per_tick = calibrate_tsc();
112
 
                printf("clocks_per_tick = %d\n", clocks_per_tick);
113
 
        }
114
 
 
115
 
        /* Read the Time Stamp Counter */
116
 
        rdtsc(clocks_low, clocks_high);
117
 
 
118
 
        /* currticks = clocks / clocks_per_tick; */
119
 
        __asm__("divl %1"
120
 
                :"=a" (currticks)
121
 
                :"r" (clocks_per_tick), "0" (clocks_low), "d" (clocks_high));
122
 
 
123
 
 
124
 
        return currticks;
125
 
}
126
 
 
127
 
#endif /* RTC_CURRTICKS */