10 MASTER_PIC_BASE = 0x20,
11 SLAVES_PIC_BASE = 0xa0,
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,
115 ** Standard PIC initialization values for PCs.
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
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
130 static int special_fully_nested_mode;
133 IMPLEMENTATION[i8259]:
141 #include "initcalls.h"
142 #include "koptions.h"
143 #include "mem_layout.h"
145 int Pic::special_fully_nested_mode = 1; // be compatible with Jochen's L4
147 IMPLEMENT FIASCO_INIT
161 // this version of pic_init() overrides the OSKIT's.
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!)
173 Pic::pic_init(unsigned char master_base, unsigned char slave_base)
175 // disallow all interrupts before we selectively enable them
176 Pic::disable_all_save();
178 * Set the LINTEN bit in the HyperTransport Transaction
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).
190 if ((cpu_id & 0xff0) == 0xf30)
196 (1 << 31) | /* enable */
197 (0 << 16) | /* bus */
198 (24 << 11) | /* dev (cpu + 24) */
199 (0 << 8) | /* func */
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");
208 Io::out32(0x0cf8, 0);
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
217 if (Koptions::o()->opt(Koptions::F_nosfn))
218 special_fully_nested_mode = 0;
220 if (special_fully_nested_mode)
222 puts ("Enabling special fully nested mode for PIC");
223 /* Initialize the master. */
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);
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);
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)
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);
254 printf("%sUsing (normal) fully nested PIC mode\n",
255 Config::found_vmware ? "Found VMware: " : "");
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);
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);
271 Io::out8_p(0xfb, MASTER_OCW); // unmask irq2
272 Io::out8_p(0xff, SLAVES_OCW); // mask everything
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);
278 // disallow all interrupts before we selectively enable them
279 Pic::disable_all_save();
283 IMPLEMENT inline NEEDS["io.h"]
285 Pic::disable_locked(unsigned irq)
288 Io::out8(Io::in8(MASTER_OCW) | (1 << irq), MASTER_OCW);
290 Io::out8(Io::in8(SLAVES_OCW) | (1 << (irq-8)), SLAVES_OCW);
293 IMPLEMENT inline NEEDS["io.h"]
295 Pic::enable_locked(unsigned irq, unsigned /*prio*/)
298 Io::out8(Io::in8(MASTER_OCW) & ~(1 << irq), MASTER_OCW);
301 Io::out8(Io::in8(MASTER_OCW) & ~(1 << 2), MASTER_OCW);
302 Io::out8(Io::in8(SLAVES_OCW) & ~(1 << (irq-8)), SLAVES_OCW);
306 IMPLEMENT inline NEEDS["io.h"]
308 Pic::acknowledge_locked(unsigned irq)
312 Io::out8(NON_SPEC_EOI, SLAVES_ICW); // EOI slave
313 if (special_fully_nested_mode)
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
320 Io::out8(NON_SPEC_EOI, MASTER_ICW); // EOI master
325 Pic::block_locked(unsigned)
328 IMPLEMENT inline NEEDS["io.h"]
330 Pic::disable_all_save()
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 );
341 IMPLEMENT inline NEEDS["io.h"]
343 Pic::restore_all( Status s )
345 Io::out8( s & 0x0ff, MASTER_OCW );
346 Io::out8( (s >> 8) & 0x0ff, SLAVES_OCW );
350 IMPLEMENT inline NEEDS[<cassert>]
352 Pic::set_cpu(unsigned, unsigned cpu)