4 #include "lock_guard.h"
11 class Irq_chip_i8259 : public Irq_chip_icu, private Pm_object
13 friend class Jdb_kern_info_pic_state;
15 typedef typename IO::Port_addr Io_address;
16 unsigned nr_irqs() const override { return 16; }
17 int set_mode(Mword, Mode) override { return 0; }
18 bool is_edge_triggered(Mword) const override { return false; }
19 void set_cpu(Mword, Cpu_number) override {}
20 using Pm_object::register_pm;
106 // Standard PIC initialization values for PCs.
107 PICM_ICW1 = ICW_TEMPLATE | EDGE_TRIGGER | ADDR_INTRVL8
108 | CASCADE_MODE | ICW4__NEEDED,
109 PICM_ICW3 = SLAVE_ON_IR2,
110 PICM_ICW4 = SNF_MODE_DIS | NONBUFD_MODE | NRML_EOI_MOD
113 PICS_ICW1 = ICW_TEMPLATE | EDGE_TRIGGER | ADDR_INTRVL8
114 | CASCADE_MODE | ICW4__NEEDED,
115 PICS_ICW3 = I_AM_SLAVE_2,
116 PICS_ICW4 = SNF_MODE_DIS | NONBUFD_MODE | NRML_EOI_MOD
121 Unsigned8 read_ocw(Io_address base)
122 { return IO::in8(base + OFF_OCW); }
124 void write_ocw(Unsigned8 val, Io_address base)
125 { IO::out8(val, base + OFF_OCW); }
127 Unsigned8 read_icw(Io_address base)
128 { return IO::in8(base + OFF_ICW); }
130 void write_icw(Unsigned8 val, Io_address base)
131 { IO::out8(val, base + OFF_ICW); }
133 void iodelay() const { IO::iodelay(); }
135 // power-management hooks
136 void pm_on_suspend(Cpu_number) override
137 { _pm_saved_state = disable_all_save(); }
139 void pm_on_resume(Cpu_number) override
140 { restore_all(_pm_saved_state); }
142 Io_address _master, _slave;
146 // power-management state
147 Unsigned16 _pm_saved_state;
150 template<typename IO>
151 class Irq_chip_i8259_gen : public Irq_chip_i8259<IO>
154 typedef typename Irq_chip_i8259<IO>::Io_address Io_address;
155 Irq_chip_i8259_gen(Io_address master, Io_address slave)
156 : Irq_chip_i8259<IO>(master, slave)
162 Irq_base *irq(Mword pin) const override
170 bool alloc(Irq_base *irq, Mword pin) override
178 if (!mp_cas(&_irqs[pin], (Irq_base *)0, irq))
181 this->bind(irq, pin);
185 bool reserve(Mword pin) override
193 _irqs[pin] = (Irq_base*)1;
198 void unbind(Irq_base *irq) override
200 _irqs[irq->pin()] = 0;
201 Irq_chip_icu::unbind(irq);
209 // --------------------------------------------------------
210 IMPLEMENTATION [i8259]:
213 * Create a i8259 chip, does not do any hardware access.
214 * \note Hardware initalization is done in init().
216 PUBLIC template<typename IO>
217 Irq_chip_i8259<IO>::Irq_chip_i8259(Irq_chip_i8259::Io_address master,
218 Irq_chip_i8259::Io_address slave)
219 : _master(master), _slave(slave)
222 PUBLIC template<typename IO> inline
224 Irq_chip_i8259<IO>::disable_all_save()
226 Unsigned16 s = (Unsigned16)read_ocw(_master)
227 | (Unsigned16)read_ocw(_slave) << 8;
228 write_ocw(0xff, _master);
229 write_ocw(0xff, _slave);
233 PUBLIC template<typename IO> inline
235 Irq_chip_i8259<IO>::restore_all(Unsigned16 s)
237 write_ocw(s & 0x0ff, _master);
238 write_ocw((s >> 8) & 0x0ff, _slave);
242 * Initialize the i8259 hardware.
243 * \pre The IO access must be enabled in the constructor if needed,
244 * for example when using memory-mapped registers.
246 PUBLIC template<typename IO>
248 Irq_chip_i8259<IO>::init(Unsigned8 vect_base,
249 bool use_sfn = false,
250 bool high_prio_ir8 = false)
252 auto g = lock_guard(_lock);
256 write_ocw(0xff, _master);
257 write_ocw(0xff, _slave);
259 write_icw(PICM_ICW1, _master); iodelay();
260 write_ocw(vect_base, _master); iodelay();
261 write_ocw((1U << 2), _master); iodelay(); // cascade at IR2
262 Unsigned8 icw4 = PICM_ICW4;
264 icw4 |= SNF_MODE_ENA;
265 write_ocw(icw4, _master); iodelay();
267 write_icw(PICS_ICW1, _slave); iodelay();
268 write_ocw(vect_base + 8, _slave); iodelay();
269 write_ocw(PICS_ICW3, _slave); iodelay();
270 write_ocw(icw4, _slave); iodelay();
272 if (use_sfn && high_prio_ir8)
274 // setting specific rotation (specific priority)
275 // -- see Intel 8259A reference manual
276 // irq 1 on master hast lowest prio
277 // => irq 2 (cascade) = irqs 8..15 have highest prio
278 write_icw(SET_PRIORITY | 1, _master); iodelay();
279 // irq 7 on slave has lowest prio
280 // => irq 0 on slave (= irq 8) has highest prio
281 write_icw(SET_PRIORITY | 7, _slave); iodelay();
285 write_ocw(0xfb, _master); iodelay(); // unmask ir2
286 write_ocw(0xff, _slave); iodelay(); // mask everything
288 /* Ack any bogus intrs by setting the End Of Interrupt bit. */
289 write_icw(NON_SPEC_EOI, _master); iodelay();
290 write_icw(NON_SPEC_EOI, _slave); iodelay();
293 PRIVATE template<typename IO> inline
295 Irq_chip_i8259<IO>::_mask(Mword pin)
298 write_ocw(read_ocw(_master) | (1U << pin), _master);
300 write_ocw(read_ocw(_slave) | (1U << (pin - 8)), _slave);
303 PUBLIC template<typename IO>
305 Irq_chip_i8259<IO>::mask(Mword pin) override
307 auto g = lock_guard(_lock);
311 PUBLIC template<typename IO>
313 Irq_chip_i8259<IO>::unmask(Mword pin) override
315 auto g = lock_guard(_lock);
317 write_ocw(read_ocw(_master) & ~(1U << pin), _master);
319 write_ocw(read_ocw(_slave) & ~(1U << (pin - 8)), _slave);
322 PRIVATE template<typename IO> inline
324 Irq_chip_i8259<IO>::_ack(Mword pin)
328 write_icw(NON_SPEC_EOI, _slave);
331 write_icw(OCW_TEMPLATE | READ_NEXT_RD | READ_IS_ONRD, _slave);
332 if (read_icw(_slave))
333 return; // still active IRQs at the slave, don't EOI master
336 write_icw(NON_SPEC_EOI, _master);
339 PUBLIC template<typename IO>
341 Irq_chip_i8259<IO>::ack(Mword pin) override
343 auto g = lock_guard(_lock);
347 PUBLIC template<typename IO>
349 Irq_chip_i8259<IO>::mask_and_ack(Mword pin) override
351 auto g = lock_guard(_lock);
356 // -----------------------------------------------------------------
357 IMPLEMENTATION [i8259 && debug]:
359 PUBLIC template<typename IO>
361 Irq_chip_i8259<IO>::chip_type() const override