]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/apic-ia32-mp.cpp
update
[l4.git] / kernel / fiasco / src / kern / ia32 / apic-ia32-mp.cpp
1 INTERFACE [mp]:
2
3 EXTENSION class Apic
4 {
5 public:
6   typedef enum
7     {
8       APIC_IPI_NOSHRT = 0x00000000,
9       APIC_IPI_SELF   = 0x00040000,
10       APIC_IPI_ALL    = 0x00080000,
11       APIC_IPI_OTHERS = 0x000c0000,
12       APIC_IPI_DSTMSK = 0x000c0000
13     } Apic_ipi_dest;
14
15   typedef enum
16     {
17       APIC_IPI_FIXED  = 0x00000000,
18       APIC_IPI_NMI    = 0x00000400,
19       APIC_IPI_INIT   = 0x00000500,
20       APIC_IPI_STRTUP = 0x00000600
21     } Apic_ipi_mode;
22
23 private:
24   enum
25     {
26       APIC_ID   = 0x20,
27       APIC_ICR  = 0x300,
28       APIC_ICR2 = 0x310,
29     };
30 };
31
32
33 IMPLEMENTATION[mp]:
34
35 #include <cassert>
36 #include "cpu.h"
37 #include "processor.h"
38
39 PUBLIC static inline
40 void
41 Apic::disable_external_ints()
42 {
43   reg_write(APIC_lvt0, 0x0001003f);
44   reg_write(APIC_lvt1, 0x0001003f);
45 }
46
47 PUBLIC static inline
48 bool
49 Apic::mp_ipi_idle()
50 {
51   return ((reg_read(APIC_ICR) & 0x00001000) == 0);
52 }
53
54 PRIVATE static inline
55 bool
56 Apic::mp_ipi_idle_timeout(Cpu const *c, Unsigned32 wait)
57 {
58   Unsigned64 wait_till = c->time_us() + wait;
59   while (!mp_ipi_idle() && c->time_us() < wait_till)
60     Proc::pause();
61   return mp_ipi_idle();
62 }
63
64 PRIVATE static inline
65 void
66 Apic::delay(Cpu const *c, Unsigned32 wait)
67 {
68   Unsigned64 wait_till = c->time_us() + wait;
69   while (c->time_us() < wait_till)
70     Proc::pause();
71 }
72
73 PUBLIC static inline NEEDS [<cassert>]
74 void
75 Apic::mp_send_ipi(Unsigned32 dest, Unsigned32 vect,
76                   Unsigned32 mode = APIC_IPI_FIXED)
77 {
78   Unsigned32 tmp_val;
79
80   assert((dest & 0x00f3ffff) == 0);
81   assert(vect <= 0xff);
82
83   while (!mp_ipi_idle())
84     Proc::pause();
85
86   // Set destination for no-shorthand destination type
87   if ((dest & APIC_IPI_DSTMSK) == APIC_IPI_NOSHRT)
88     {
89       tmp_val  = reg_read(APIC_ICR2);
90       tmp_val &= 0x00ffffff;
91       tmp_val |= dest & 0xff000000;
92       reg_write(APIC_ICR2, tmp_val);
93     }
94
95   // send the interrupt vector to the destination...
96   tmp_val  = reg_read(APIC_ICR);
97   tmp_val &= 0xfff32000;
98   tmp_val |= (dest & 0x000c0000) |
99              (       0x00004000) | // phys proc num, edge triggered, assert
100              (mode & 0x00000700) |
101              (vect & 0x000000ff);
102   reg_write(APIC_ICR, tmp_val);
103 }
104
105 PUBLIC static inline
106 void
107 Apic::mp_ipi_ack()
108 {
109   reg_write(APIC_eoi, 0);
110 }
111
112
113 PUBLIC static
114 void
115 Apic::init_ap()
116 {
117   dump_info();
118   // set some interrupt vectors to appropriate values
119   init_lvt();
120
121   // initialize APIC_spiv register
122   init_spiv();
123
124   // initialize task-priority register
125   init_tpr();
126
127   disable_external_ints();
128
129   // get timer going on this CPU
130   timer_set_divisor(1);
131   enable_errors();
132 }
133
134 PUBLIC static
135 void
136 Apic::mp_startup(Cpu const *current_cpu, Unsigned32 dest, Address tramp_page)
137 {
138   assert((tramp_page & 0xfff00fff) == 0);
139
140   // XXX: should check for the apic version what to do exactly
141   // XXX: should check for some errors after sending ipi
142
143   // Send INIT IPI
144   mp_send_ipi(dest, 0, APIC_IPI_INIT);
145
146   delay(current_cpu, 200);
147
148   // delay for 10ms (=10,000us)
149   if (!mp_ipi_idle_timeout(current_cpu, 10000))
150     return;
151
152   // Send STARTUP IPI
153   mp_send_ipi(dest, tramp_page >> 12, APIC_IPI_STRTUP);
154
155   // delay for 200us
156   if (!mp_ipi_idle_timeout(current_cpu, 200))
157     return;
158
159   // Send STARTUP IPI
160   mp_send_ipi(dest, tramp_page >> 12, APIC_IPI_STRTUP);
161
162   // delay for 200us
163   if (!mp_ipi_idle_timeout(current_cpu, 200))
164     return;
165 }