]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/pic-i8259.cpp
update
[l4.git] / kernel / fiasco / src / kern / pic-i8259.cpp
1 INTERFACE[i8259]:
2
3 #include "initcalls.h"
4
5 EXTENSION class Pic
6 {
7 public:
8   enum
9   {
10     MASTER_PIC_BASE = 0x20,
11     SLAVES_PIC_BASE = 0xa0,
12     OFF_ICW         = 0x00,
13     OFF_OCW         = 0x01,
14
15     MASTER_ICW      = MASTER_PIC_BASE + OFF_ICW,
16     MASTER_OCW      = MASTER_PIC_BASE + OFF_OCW,
17     SLAVES_ICW      = SLAVES_PIC_BASE + OFF_ICW,
18     SLAVES_OCW      = SLAVES_PIC_BASE + OFF_OCW,
19
20
21     /*
22     **  ICW1                            
23     */
24
25     ICW_TEMPLATE    = 0x10,
26     
27     LEVL_TRIGGER    = 0x08,
28     EDGE_TRIGGER    = 0x00,
29     ADDR_INTRVL4    = 0x04,
30     ADDR_INTRVL8    = 0x00,
31     SINGLE__MODE    = 0x02,
32     CASCADE_MODE    = 0x00,
33     ICW4__NEEDED    = 0x01,
34     NO_ICW4_NEED    = 0x00,
35
36     /*
37     **  ICW3                            
38     */
39
40     SLAVE_ON_IR0    = 0x01,
41     SLAVE_ON_IR1    = 0x02,
42     SLAVE_ON_IR2    = 0x04,
43     SLAVE_ON_IR3    = 0x08,
44     SLAVE_ON_IR4    = 0x10,
45     SLAVE_ON_IR5    = 0x20,
46     SLAVE_ON_IR6    = 0x40,
47     SLAVE_ON_IR7    = 0x80,
48     
49     I_AM_SLAVE_0    = 0x00,
50     I_AM_SLAVE_1    = 0x01,
51     I_AM_SLAVE_2    = 0x02,
52     I_AM_SLAVE_3    = 0x03,
53     I_AM_SLAVE_4    = 0x04,
54     I_AM_SLAVE_5    = 0x05,
55     I_AM_SLAVE_6    = 0x06,
56     I_AM_SLAVE_7    = 0x07,
57
58     /*
59     **  ICW4                            
60     */
61     
62     SNF_MODE_ENA    = 0x10,
63     SNF_MODE_DIS    = 0x00,
64     BUFFERD_MODE    = 0x08,
65     NONBUFD_MODE    = 0x00,
66     AUTO_EOI_MOD    = 0x02,
67     NRML_EOI_MOD    = 0x00,
68     I8086_EMM_MOD   = 0x01,
69     SET_MCS_MODE    = 0x00,
70
71     /*
72     **  OCW1                            
73     */
74     
75     PICM_MASK       = 0xFF,
76     PICS_MASK       = 0xFF,
77     
78     /*
79     **  OCW2                            
80     */
81     
82     NON_SPEC_EOI    = 0x20,
83     SPECIFIC_EOI    = 0x60,
84     ROT_NON_SPEC    = 0xa0,
85     SET_ROT_AEOI    = 0x80,
86     RSET_ROTAEOI    = 0x00,
87     ROT_SPEC_EOI    = 0xe0,
88     SET_PRIORITY    = 0xc0,
89     NO_OPERATION    = 0x40,
90     
91     SND_EOI_IR0    = 0x00,
92     SND_EOI_IR1    = 0x01,
93     SND_EOI_IR2    = 0x02,
94     SND_EOI_IR3    = 0x03,
95     SND_EOI_IR4    = 0x04,
96     SND_EOI_IR5    = 0x05,
97     SND_EOI_IR6    = 0x06,
98     SND_EOI_IR7    = 0x07,
99  
100     /*
101     **  OCW3                            
102     */
103     
104     OCW_TEMPLATE    = 0x08,
105     SPECIAL_MASK    = 0x40,
106     MASK_MDE_SET    = 0x20,
107     MASK_MDE_RST    = 0x00,
108     POLL_COMMAND    = 0x04,
109     NO_POLL_CMND    = 0x00,
110     READ_NEXT_RD    = 0x02,
111     READ_IR_ONRD    = 0x00,
112     READ_IS_ONRD    = 0x01,
113     
114     /*
115     **  Standard PIC initialization values for PCs.
116     */
117     PICM_ICW1       = (ICW_TEMPLATE | EDGE_TRIGGER | ADDR_INTRVL8 
118                        | CASCADE_MODE | ICW4__NEEDED),
119     PICM_ICW3       = SLAVE_ON_IR2,
120     PICM_ICW4       = (SNF_MODE_DIS | NONBUFD_MODE | NRML_EOI_MOD 
121                        | I8086_EMM_MOD),
122
123     PICS_ICW1       = (ICW_TEMPLATE | EDGE_TRIGGER | ADDR_INTRVL8 
124                        | CASCADE_MODE | ICW4__NEEDED),
125     PICS_ICW3       = I_AM_SLAVE_2,
126     PICS_ICW4       = (SNF_MODE_DIS | NONBUFD_MODE | NRML_EOI_MOD
127                        | I8086_EMM_MOD),
128   };
129
130   static int special_fully_nested_mode;
131 };
132
133 IMPLEMENTATION[i8259]:
134
135 #include <cstring>
136 #include <cstdio>
137 #include <cassert>
138
139 #include "io.h"
140 #include "config.h"
141 #include "initcalls.h"
142 #include "koptions.h"
143 #include "mem_layout.h"
144
145 int Pic::special_fully_nested_mode = 1; // be compatible with Jochen's L4
146
147 IMPLEMENT FIASCO_INIT
148 void
149 Pic::init()
150 {
151   pic_init(0x20,0x28);
152 }
153
154 PUBLIC static inline
155 unsigned
156 Pic::nr_irqs()
157 { return 16; }
158
159
160 //
161 // this version of pic_init() overrides the OSKIT's.
162 //
163 // differences to standard AT initialization: 
164 // . we use the "special fully nested mode" to let irq sources on the
165 //   slave irq raise nested
166 // . we give irq 2 (= slave pic) the highest prio on the master pic; this
167 //   results in the following sequence of prios: 8-15,3-7,0,1
168 //   this way, the timer interrupt on irq 8 always gets thru (even if 
169 //   some user irq handler doesn't acknowledge its irq!)
170 //
171 static FIASCO_INIT
172 void
173 Pic::pic_init(unsigned char master_base, unsigned char slave_base)
174 {
175   // disallow all interrupts before we selectively enable them 
176   Pic::disable_all_save();
177   /*
178    * Set the LINTEN bit in the HyperTransport Transaction
179    * Control Register.
180    *
181    * This will cause EXTINT and NMI interrupts routed over the
182    * hypertransport bus to be fed into the LAPIC LINT0/LINT1.  If
183    * the bit isn't set, the interrupts will go to the general cpu
184    * INTR/NMI pins.  On a dual-core cpu the interrupt winds up
185    * going to BOTH cpus.  The first cpu that does the interrupt ack
186    * cycle will get the correct interrupt.  The second cpu that does
187    * it will get a spurious interrupt vector (typically IRQ 7).
188    */
189 #if 0
190   if ((cpu_id & 0xff0) == 0xf30) 
191 #endif
192     {
193 #if 0
194       Unsigned32 tcr;
195       Io::out32(0x0cf8,
196           (1 << 31) | /* enable */
197           (0 << 16) | /* bus */
198           (24 << 11) |        /* dev (cpu + 24) */
199           (0 << 8) |  /* func */
200           0x68                /* reg */
201           );
202       tcr = Io::in32(0xcfc);
203       if ((tcr & 0x00010000) == 0) {
204           Io::out32(0xcfc, tcr|0x00010000);
205           printf("AMD: Rerouting HyperTransport "
206               "EXTINT/NMI to APIC\n");
207       }
208       Io::out32(0x0cf8, 0);
209 #endif
210   }
211   // VMware isn't able to deal with the special fully nested mode
212   // correctly so we simply don't use it while running under
213   // VMware. Otherwise VMware will barf with 
214   // *** VMware Workstation internal monitor error ***
215   // BUG F(152):393 bugNr=4388
216
217   if (Koptions::o()->opt(Koptions::F_nosfn))
218     special_fully_nested_mode = 0;
219
220   if (special_fully_nested_mode)
221     {
222       puts ("Enabling special fully nested mode for PIC");
223       /* Initialize the master. */
224
225       Io::out8_p(PICM_ICW1, MASTER_ICW);
226       Io::out8_p(master_base, MASTER_OCW);
227       Io::out8_p(PICM_ICW3, MASTER_OCW);
228       Io::out8_p(SNF_MODE_ENA | PICM_ICW4, MASTER_OCW);
229
230       /* Initialize the slave. */
231       Io::out8_p(PICS_ICW1, SLAVES_ICW);
232       Io::out8_p(slave_base, SLAVES_OCW);
233       Io::out8_p(PICS_ICW3, SLAVES_OCW);
234       Io::out8_p(SNF_MODE_ENA | PICS_ICW4, SLAVES_OCW);
235
236       // the timer interrupt should have the highest priority so that it
237       // always gets through
238       if ( ! Config::profiling
239           && Config::pic_prio_modify
240           && Config::scheduler_mode == Config::SCHED_RTC)
241         {
242           // setting specific rotation (specific priority) 
243           // -- see Intel 8259A reference manual
244           // irq 1 on master hast lowest prio
245           // => irq 2 (cascade) = irqs 8..15 have highest prio
246           Io::out8_p(SET_PRIORITY | 1, MASTER_ICW);
247           // irq 7 on slave has lowest prio
248           // => irq 0 on slave (= irq 8) has highest prio
249           Io::out8_p(SET_PRIORITY | 7, SLAVES_ICW);
250         }
251     }
252   else
253     {
254       printf("%sUsing (normal) fully nested PIC mode\n",
255           Config::found_vmware ? "Found VMware: " : "");
256
257       /* Initialize the master. */
258       Io::out8_p(PICM_ICW1, MASTER_ICW);
259       Io::out8_p(master_base, MASTER_OCW);
260       Io::out8_p(PICM_ICW3, MASTER_OCW);
261       Io::out8_p(PICM_ICW4, MASTER_OCW);
262
263       /* Initialize the slave. */
264       Io::out8_p(PICS_ICW1, SLAVES_ICW);
265       Io::out8_p(slave_base, SLAVES_OCW);
266       Io::out8_p(PICS_ICW3, SLAVES_OCW);
267       Io::out8_p(PICS_ICW4, SLAVES_OCW);
268     }
269
270   // set initial masks
271   Io::out8_p(0xfb, MASTER_OCW); // unmask irq2
272   Io::out8_p(0xff, SLAVES_OCW); // mask everything
273
274   /* Ack any bogus intrs by setting the End Of Interrupt bit. */
275   Io::out8_p(NON_SPEC_EOI, MASTER_ICW);
276   Io::out8_p(NON_SPEC_EOI, SLAVES_ICW);
277
278   // disallow all interrupts before we selectively enable them 
279   Pic::disable_all_save();
280
281 }
282
283 IMPLEMENT inline NEEDS["io.h"]
284 void
285 Pic::disable_locked(unsigned irq)
286 {
287   if (irq < 8)
288     Io::out8(Io::in8(MASTER_OCW) | (1 << irq), MASTER_OCW);
289   else
290     Io::out8(Io::in8(SLAVES_OCW) | (1 << (irq-8)), SLAVES_OCW);
291 }
292
293 IMPLEMENT inline NEEDS["io.h"]
294 void
295 Pic::enable_locked(unsigned irq, unsigned /*prio*/)
296 {
297   if (irq < 8)
298     Io::out8(Io::in8(MASTER_OCW) & ~(1 << irq), MASTER_OCW);
299   else
300     {
301       Io::out8(Io::in8(MASTER_OCW) & ~(1 << 2), MASTER_OCW);
302       Io::out8(Io::in8(SLAVES_OCW) & ~(1 << (irq-8)), SLAVES_OCW);
303     }
304 }
305
306 IMPLEMENT inline NEEDS["io.h"]
307 void
308 Pic::acknowledge_locked(unsigned irq)
309 {
310   if (irq >= 8)
311     {
312       Io::out8(NON_SPEC_EOI, SLAVES_ICW); // EOI slave
313       if (special_fully_nested_mode)
314         {
315           Io::out8(OCW_TEMPLATE | READ_NEXT_RD | READ_IS_ONRD, SLAVES_ICW);
316           if (Io::in8(SLAVES_ICW))      // slave still active?
317             return;                 // -- don't EOI master
318         }
319     }
320   Io::out8(NON_SPEC_EOI, MASTER_ICW); // EOI master
321 }
322
323 IMPLEMENT inline
324 void
325 Pic::block_locked(unsigned)
326 {}
327
328 IMPLEMENT inline NEEDS["io.h"]
329 Pic::Status
330 Pic::disable_all_save()
331 {
332   Status s;
333   s  = Io::in8(MASTER_OCW);
334   s |= Io::in8(SLAVES_OCW) << 8;
335   Io::out8( 0xff, MASTER_OCW );
336   Io::out8( 0xff, SLAVES_OCW );
337   
338   return s;
339 }
340
341 IMPLEMENT inline NEEDS["io.h"]
342 void
343 Pic::restore_all( Status s )
344 {
345   Io::out8( s & 0x0ff, MASTER_OCW );
346   Io::out8( (s >> 8) & 0x0ff, SLAVES_OCW );
347 }
348
349
350 IMPLEMENT inline NEEDS[<cassert>]
351 void
352 Pic::set_cpu(unsigned, unsigned cpu)
353 {
354   (void)cpu;
355   assert(cpu == 0);
356 }