c79d4593cb12e0995260e45655187d0c5ac77209
[tpg/acess2.git] / KernelLand / Kernel / arch / x86 / time.c
1 /*
2  * Acess2 Kernel
3  * Timekeeping
4  * arch/x86/time.c
5  */
6 #include <acess.h>
7
8 // === MACROS ===
9 #define TIMER_QUANTUM   100
10 // 2^(15-rate), 14: 2Hz, 5: 1024Hz, 2: 8192Hz
11 // (Max: 14, Min: 2) - 14 = 2Hz, 13 = 4Hz, 12 = 8Hz, 11 = 16Hz 10 = 32Hz, 2 = 8192Hz
12 //#define TIMER_RATE    10      // 32 Hz
13 //#define TIMER_RATE    12      // 8 Hz
14 #define TIMER_RATE      14      // 2 Hz - Lowest
15 #define TIMER_FREQ      (0x8000>>TIMER_RATE)    //Hz
16 #define MS_PER_TICK_WHOLE       (1000/(TIMER_FREQ))
17 #define MS_PER_TICK_FRACT       ((0x80000000*(1000%TIMER_FREQ))/TIMER_FREQ)
18 #define US_PER_TICK     (1000*1000/(TIMER_FREQ))
19
20 // === IMPORTS ===
21 extern volatile Sint64  giTimestamp;
22 extern volatile Uint64  giTicks;
23 extern volatile Uint64  giPartMiliseconds;
24 extern void     Timer_CallTimers(void);
25
26 // === GLOBALS ===
27 volatile Uint64 giTime_TSCAtLastTick = 0;
28 volatile Uint64 giTime_TSCPerTick = 0;
29
30 // === PROTOTYPES ===
31 //Sint64        now(void);
32  int    Time_Setup(void);
33 void    Time_Interrupt(int IRQ, void *Ptr);
34 Uint64  Time_ReadTSC(void);
35
36 // === CODE ===
37 /**
38  * \fn Sint64 now()
39  * \brief Return the current timestamp
40  */
41 Sint64 now(void)
42 {
43         Uint64  tsc = Time_ReadTSC();
44         tsc -= giTime_TSCAtLastTick;
45         tsc *= MS_PER_TICK_WHOLE;
46         if( giTime_TSCPerTick ) {
47                 tsc /= giTime_TSCPerTick;
48         }
49         else
50                 tsc = 0;
51         return giTimestamp + tsc;
52 }
53
54 /**
55  * \fn int Time_Setup(void)
56  * \brief Sets the system time from the Realtime-Clock
57  */
58 int Time_Setup(void)
59 {
60         Uint8   val;
61         
62         Log_Log("Timer", "RTC Timer firing at %iHz (%i divisor), %i.0x%08x",
63                 TIMER_FREQ, TIMER_RATE, MS_PER_TICK_WHOLE, MS_PER_TICK_FRACT);
64         
65         outb(0x70, inb(0x70)&0x7F);     // Disable NMIs
66         __asm__ __volatile__ ("cli");   // Disable normal interrupts
67         
68         // Set IRQ8 firing rate
69         outb(0x70, 0x0A);       // Set the index to register A
70         val = inb(0x71); // Get the current value of register A
71         val &= 0xF0;
72         val |= TIMER_RATE+1;
73         outb(0x70, 0x0A); // Reset index to A
74         outb(0x71, val);        // Update the timer rate
75                 
76         // Enable IRQ8
77         outb(0x70, 0x0B);       // Set the index to register B
78         val = inb(0x71);        // Read the current value of register B
79         outb(0x70, 0x0B);       // Set the index again (a read will reset the index to register D)
80         outb(0x71, val | 0x40); // Write the previous value or'd with 0x40. This turns on bit 6 of register D
81         
82         __asm__ __volatile__ ("sti");   // Re-enable normal interrupts
83         outb(0x70, inb(0x70)|0x80);     // Re-enable NMIs
84         
85         // Install IRQ Handler
86         IRQ_AddHandler(8, Time_Interrupt, NULL);
87         
88         // Make sure the RTC actually fires
89         outb(0x70, 0x0C); // Select register C
90         inb(0x71);      // Just throw away contents.
91         
92         return 0;
93 }
94
95 /**
96  * \brief Called on the timekeeping IRQ
97  */
98 void Time_Interrupt(int IRQ, void *Ptr)
99 {
100         Uint64  curTSC = Time_ReadTSC();
101         
102         if( giTime_TSCAtLastTick )
103         {
104                 giTime_TSCPerTick = curTSC - giTime_TSCAtLastTick;
105         }
106         giTime_TSCAtLastTick = curTSC;
107         
108         giTicks ++;
109         giTimestamp += MS_PER_TICK_WHOLE;
110         giPartMiliseconds += MS_PER_TICK_FRACT;
111         if(giPartMiliseconds > 0x80000000) {
112                 giTimestamp ++;
113                 giPartMiliseconds -= 0x80000000;
114         }
115         
116         Timer_CallTimers();
117
118         // Make sure the RTC Fires again
119         outb(0x70, 0x0C); // Select register C
120         inb(0x71);      // Just throw away contents.
121 }
122
123 void Time_MicroSleep(Uint16 Microsecs)  // max 64 ms
124 {
125         Uint64  cur_tsc = Time_ReadTSC();
126         // tsc_per_us * Microsec
127         Uint64  delta_tsc = (Uint64)Microsecs * giTime_TSCPerTick / US_PER_TICK;
128         Uint64  tgt_tsc = cur_tsc + delta_tsc;
129
130         if( tgt_tsc < cur_tsc )
131                 while(Time_ReadTSC() > cur_tsc)
132                         ;       
133
134         while( Time_ReadTSC() < tgt_tsc )
135                 ;
136 }
137
138 Uint64 Time_ReadTSC(void)
139 {
140         Uint32  a, d;
141         __asm__ __volatile__ ("rdtsc" : "=a" (a), "=d" (d));
142         return ((Uint64)d << 32) | a;
143 }

UCC git Repository :: git.ucc.asn.au