]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/apic-ia32-mp.cpp
67519263726c1c8d368e405dc9685e979679f68f
[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 Signed32
41 Apic::apic_id()
42 {
43   return ((reg_read(APIC_ID) >> 24) & 0xff);
44 }
45
46 PUBLIC static inline
47 void
48 Apic::disable_external_ints()
49 {
50   reg_write(APIC_lvt0, 0x0001003f);
51   reg_write(APIC_lvt1, 0x0001003f);
52 }
53
54 PUBLIC static inline
55 bool
56 Apic::mp_ipi_idle()
57 {
58   return ((reg_read(APIC_ICR) & 0x00001000) == 0);
59 }
60
61 PRIVATE static inline
62 bool
63 Apic::mp_ipi_idle_timeout(Cpu const *c, Unsigned32 wait)
64 {
65   Unsigned64 wait_till = c->time_us() + wait;
66   while (!mp_ipi_idle() && c->time_us() < wait_till)
67     Proc::pause();
68   return mp_ipi_idle();
69 }
70
71 PUBLIC static inline NEEDS [<cassert>]
72 void
73 Apic::mp_send_ipi(Unsigned32 dest, Unsigned32 vect,
74                   Unsigned32 mode = APIC_IPI_FIXED)
75 {
76   Unsigned32 tmp_val;
77
78   assert((dest & 0x00f3ffff) == 0);
79   assert(vect <= 0xff);
80
81   while (!mp_ipi_idle())
82     Proc::pause();
83
84   // Set destination for no-shorthand destination type
85   if ((dest & APIC_IPI_DSTMSK) == APIC_IPI_NOSHRT)
86     {
87       tmp_val  = reg_read(APIC_ICR2);
88       tmp_val &= 0x00ffffff;
89       tmp_val |= dest & 0xff000000;
90       reg_write(APIC_ICR2, tmp_val);
91     }
92
93   // send the interrupt vector to the destination...
94   tmp_val  = reg_read(APIC_ICR);
95   tmp_val &= 0xfff32000;
96   tmp_val |= (dest & 0x000c0000) |
97              (       0x00004000) | // phys proc num, edge triggered, assert
98              (mode & 0x00000700) |
99              (vect & 0x000000ff);
100   reg_write(APIC_ICR, tmp_val);
101 }
102
103 PUBLIC static inline
104 void
105 Apic::mp_ipi_ack()
106 {
107   reg_write(APIC_eoi, 0);
108 }
109
110
111 PUBLIC static
112 void
113 Apic::init_ap()
114 {
115   dump_info();
116   // set some interrupt vectors to appropriate values
117   init_lvt();
118
119   // initialize APIC_spiv register
120   init_spiv();
121
122   // initialize task-priority register
123   init_tpr();
124
125   disable_external_ints();
126
127   // get timer going on this CPU
128   init_timer();
129 }
130
131 PUBLIC static
132 void
133 Apic::mp_startup(Cpu const *current_cpu, Unsigned32 dest, Address tramp_page)
134 {
135   assert((tramp_page & 0xfff00fff) == 0);
136
137   // XXX: should check for the apic version what to do exactly
138   // XXX: should check for some errors after sending ipi
139
140   // Send INIT IPI
141   mp_send_ipi(dest, 0, APIC_IPI_INIT);
142
143   // delay for 10ms (=10,000us)
144   if (!mp_ipi_idle_timeout(current_cpu, 10000))
145     return;
146
147   // Send STARTUP IPI
148   mp_send_ipi(dest, tramp_page >> 12, APIC_IPI_STRTUP);
149
150   // delay for 200us
151   if (!mp_ipi_idle_timeout(current_cpu, 200))
152     return;
153
154   // Send STARTUP IPI
155   mp_send_ipi(dest, tramp_page >> 12, APIC_IPI_STRTUP);
156
157   // delay for 200us
158   if (!mp_ipi_idle_timeout(current_cpu, 200))
159     return;
160 }