]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4re-core/l4util/lib/src/ARCH-amd64/apic.c
Update
[l4.git] / l4 / pkg / l4re-core / l4util / lib / src / ARCH-amd64 / apic.c
1 /*
2  * (c) 2008-2009 Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
3  *     economic rights: Technische Universität Dresden (Germany)
4  * This file is part of TUD:OS and distributed under the terms of the
5  * GNU Lesser General Public License 2.1.
6  * Please see the COPYING-LGPL-2.1 file for details.
7  */
8
9 #include <l4/sys/ipc.h>
10 #include <l4/sys/syscalls.h>
11 #include <l4/sys/kdebug.h>
12 #include <l4/util/port_io.h>
13 #include <l4/util/irq.h>
14 #include <l4/util/apic.h>
15
16
17 unsigned long apic_map_base = 0;
18 unsigned long apic_timer_divisor = 1;
19 unsigned long l4_scaler_apic_to_ms = 0;
20
21 void
22 apic_show_registers(void)
23 {
24   static void
25   apic_show_register_block(unsigned int beg, unsigned int len)
26   {
27     unsigned int i;
28     outhex16(beg);
29     outchar(':');
30     for (i=beg; i<beg+len; i+=0x10)
31       {
32         outchar(' ');
33         outhex32(apic_read(i));
34       }
35     outstring("\r\n");
36   }
37
38   if (!apic_map_base)
39     return;
40
41   apic_show_register_block( 0x00, 0x80);  // ID, Version
42   apic_show_register_block( 0x80, 0x80);  // TaskPrio, Arb, ProcPrio, DFR
43   apic_show_register_block(0x100, 0x80);  // ISR 0-255
44   apic_show_register_block(0x180, 0x80);  // TMR 0-255
45   apic_show_register_block(0x200, 0x80);  // IRR 0-255
46   apic_show_register_block(0x300, 0x80);  // ICR
47   apic_show_register_block(0x380, 0x10);  // Initial Count Register
48 }
49
50 void
51 apic_timer_set_divisor(int newdiv)
52 {
53   int i;
54   int div = -1;
55   int divval = newdiv;
56   unsigned long tmp_value;
57     
58   static int divisor_tab[8] = 
59     {
60       APIC_TDR_DIV_1,  APIC_TDR_DIV_2,  APIC_TDR_DIV_4,  APIC_TDR_DIV_8,
61       APIC_TDR_DIV_16, APIC_TDR_DIV_32, APIC_TDR_DIV_64, APIC_TDR_DIV_128 
62     };
63
64   if (!apic_map_base)
65     return;
66     
67   for (i=0; i<8; i++)
68     {
69       if (divval & 1)
70         {
71           if (divval & ~1)
72             {
73               enter_kdebug("bad APIC divisor");
74             }
75           div = divisor_tab[i];
76           break;
77         }
78       divval >>= 1;
79     }
80     
81   if (div != -1)
82     {
83       apic_timer_divisor = newdiv;
84       tmp_value = apic_read(APIC_TDCR);
85       tmp_value &= ~0x1F;
86       tmp_value |= div;
87       apic_write(APIC_TDCR, tmp_value);
88     }
89 }
90
91
92 int
93 apic_check_working(void)
94 {
95 #define CLOCK_TICK_RATE 1193180  /* i8254 ticks per second */
96   unsigned long count;
97   unsigned long tt1, tt2;
98
99   unsigned int calibrate_latch = (CLOCK_TICK_RATE / 20); /* 50 ms */
100
101   if (!apic_map_base)
102     return 0;
103     
104   apic_timer_disable_irq();
105   apic_timer_set_divisor(1);
106   apic_timer_write(1000000000);
107
108   /* Set the Gate high, disable speaker */
109   l4util_out8((l4util_in8(0x61) & ~0x02) | 0x01, 0x61);
110   
111   l4util_out8(0xb0, 0x43);  /* binary, mode 0, LSB/MSB, Ch 2 */
112   l4util_out8(calibrate_latch & 0xff, 0x42); /* LSB of count */
113   l4util_out8(calibrate_latch >> 8,   0x42); /* MSB of count */
114
115   tt1=apic_timer_read();
116   count = 0;
117   do 
118     {
119       count++;
120     } while ((l4util_in8(0x61) & 0x20) == 0);
121     
122   tt2=apic_timer_read();
123   return (tt1-tt2) != 0;
124 }
125
126
127 /* activate APIC after activating by MSR was successful *
128  * see "Intel Architecture Software Developer's Manual, *
129  *      Volume 3: System Programming Guide, Appendix E" */
130 void
131 apic_activate_by_io(void)
132 {
133   char old_21, old_A1;
134   unsigned long tmp_val;
135   l4_uint32_t flags;
136
137   /* mask 8259 interrupts */
138   old_21 = l4util_in8(0x21); 
139   l4util_out8(0xff, 0x21);
140   old_A1 = l4util_in8(0xA1);
141   l4util_out8(0xff, 0xA1);
142
143   l4util_flags_save(&flags);
144   l4util_cli();
145
146   apic_soft_enable();
147
148   /* set LINT0 to ExtINT, edge triggered */
149   tmp_val = apic_read(APIC_LVT0);
150   tmp_val &= 0xfffe58ff;
151   tmp_val |= 0x00000700;
152   apic_write(APIC_LVT0, tmp_val);
153     
154   /* set LINT1 to NMI, edge triggered */
155   tmp_val = apic_read(APIC_LVT1);
156   tmp_val &= 0xfffe58ff;
157   tmp_val |= 0x00000400;
158   apic_write(APIC_LVT1, tmp_val);
159     
160   /* unmask 8259 interrupts */
161   l4util_flags_restore(&flags);
162   l4util_out8(old_A1, 0xA1);
163   l4util_out8(old_21, 0x21);
164 }
165
166 /*
167  * Return APIC clocks per ms
168  */
169 unsigned long
170 l4_calibrate_apic (void)
171 {
172   unsigned int calibrate_latch = (CLOCK_TICK_RATE / 20); /* 50 ms */
173   unsigned int calibrate_time  = 50;                     /* 50 ms */
174   
175   if (!apic_map_base)
176     return 0;
177   
178   apic_timer_disable_irq();
179   apic_timer_set_divisor(apic_timer_divisor);
180   apic_timer_write(1000000000);
181     
182   /* Set the Gate high, disable speaker */
183   l4util_out8((l4util_in8(0x61) & ~0x02) | 0x01, 0x61);
184
185   l4util_out8(0xb0, 0x43);  /* binary, mode 0, LSB/MSB, Ch 2 */
186   l4util_out8(calibrate_latch & 0xff, 0x42); /* LSB of count */
187   l4util_out8(calibrate_latch >> 8,   0x42); /* MSB of count */
188
189     {
190       unsigned long count;
191       unsigned long tt1, tt2;
192       unsigned long result;
193
194       tt1=apic_timer_read();
195       count = 0;
196       do 
197         {
198           count++;
199         } while ((l4util_in8(0x61) & 0x20) == 0);
200       tt2=apic_timer_read();
201         
202       result = (tt1-tt2)*apic_timer_divisor;
203
204       /* Error: ECTCNEVERSET */
205       if (count <= 1)
206         goto bad_ctc;
207         
208       /* Error: ECPUTOOSLOW */
209       if (result <= calibrate_time)
210         goto bad_ctc;
211         
212       __asm__ ("divl %1"
213               :"=a" (result)
214               :"r" (calibrate_time),
215                "0" (result),
216                "d" (0));
217
218       l4_scaler_apic_to_ms = result;
219
220       return result;
221     }
222
223 bad_ctc:
224     return 0;
225 }
226