1 use core::ptr::NonNull;
2
3 use acpi::madt::Madt;
4 use alloc::sync::Arc;
5 use bit_field::BitField;
6 use bitflags::bitflags;
7 use log::{debug, info};
8 use system_error::SystemError;
9
10 use crate::{
11 driver::acpi::acpi_manager,
12 exception::{
13 handle::{edge_irq_handler, fast_eoi_irq_handler},
14 irqchip::{IrqChip, IrqChipData, IrqChipFlags, IrqChipSetMaskResult, IrqChipState},
15 irqdata::{IrqData, IrqLineStatus},
16 irqdesc::{irq_desc_manager, IrqDesc, IrqFlowHandler},
17 manage::irq_manager,
18 IrqNumber,
19 },
20 libs::{
21 cpumask::CpuMask,
22 once::Once,
23 spinlock::{SpinLock, SpinLockGuard},
24 volatile::{volwrite, Volatile},
25 },
26 mm::{
27 mmio_buddy::{mmio_pool, MMIOSpaceGuard},
28 PhysAddr,
29 },
30 };
31
32 use super::{CurrentApic, LocalAPIC};
33
34 static mut __IOAPIC: Option<SpinLock<IoApic>> = None;
35 static mut IOAPIC_IR_CHIP: Option<Arc<IoApicChip>> = None;
36
37 #[allow(non_snake_case)]
IOAPIC() -> &'static SpinLock<IoApic>38 fn IOAPIC() -> &'static SpinLock<IoApic> {
39 unsafe { __IOAPIC.as_ref().unwrap() }
40 }
41
42 #[inline(always)]
ioapic_ir_chip() -> Arc<dyn IrqChip>43 pub(super) fn ioapic_ir_chip() -> Arc<dyn IrqChip> {
44 unsafe { IOAPIC_IR_CHIP.as_ref().unwrap().clone() }
45 }
46
47 #[allow(dead_code)]
48 pub struct IoApic {
49 reg: *mut u32,
50 data: *mut u32,
51 virt_eoi: *mut u32,
52 phys_base: PhysAddr,
53 mmio_guard: MMIOSpaceGuard,
54 }
55
56 impl IoApic {
57 /// IO APIC的中断向量号从32开始
58 pub const VECTOR_BASE: u8 = 32;
59
60 /// Create a new IOAPIC.
61 ///
62 /// # Safety
63 ///
64 /// You must provide a valid address.
new() -> Self65 pub unsafe fn new() -> Self {
66 static INIT_STATE: Once = Once::new();
67 assert!(!INIT_STATE.is_completed());
68
69 let mut result: Option<IoApic> = None;
70 INIT_STATE.call_once(|| {
71 info!("Initializing ioapic...");
72
73 // get ioapic base from acpi
74
75 let madt = acpi_manager()
76 .tables()
77 .unwrap()
78 .find_table::<Madt>()
79 .expect("IoApic::new(): failed to find MADT");
80
81 let io_apic_paddr = madt
82 .entries()
83 .find(|x| {
84 if let acpi::madt::MadtEntry::IoApic(_x) = x {
85 return true;
86 }
87 return false;
88 })
89 .and_then(|x| {
90 if let acpi::madt::MadtEntry::IoApic(x) = x {
91 Some(x.io_apic_address)
92 } else {
93 None
94 }
95 })
96 .unwrap();
97
98 let phys_base = PhysAddr::new(io_apic_paddr as usize);
99
100 let mmio_guard = mmio_pool()
101 .create_mmio(0x1000)
102 .expect("IoApic::new(): failed to create mmio");
103 assert!(
104 mmio_guard.map_phys(phys_base, 0x1000).is_ok(),
105 "IoApic::new(): failed to map phys"
106 );
107 debug!("Ioapic map ok");
108 let reg = mmio_guard.vaddr();
109
110 result = Some(IoApic {
111 reg: reg.data() as *mut u32,
112 data: (reg + 0x10).data() as *mut u32,
113 virt_eoi: (reg + 0x40).data() as *mut u32,
114 phys_base,
115 mmio_guard,
116 });
117 debug!("IOAPIC: to mask all RTE");
118 // 屏蔽所有的RTE
119 let res_mut = result.as_mut().unwrap();
120 for i in 0..res_mut.supported_interrupts() {
121 res_mut.write_rte(i, 0x20 + i, RedirectionEntry::DISABLED, 0);
122 }
123 debug!("Ioapic init done");
124 });
125
126 assert!(
127 result.is_some(),
128 "Failed to init ioapic, maybe this is a double initialization bug?"
129 );
130 return result.unwrap();
131 }
132
133 /// Disable all interrupts.
134 #[allow(dead_code)]
disable_all(&mut self)135 pub fn disable_all(&mut self) {
136 // Mark all interrupts edge-triggered, active high, disabled,
137 // and not routed to any CPUs.
138 for i in 0..self.supported_interrupts() {
139 self.disable(i);
140 }
141 }
142
read(&mut self, reg: u8) -> u32143 unsafe fn read(&mut self, reg: u8) -> u32 {
144 assert!(!(0x3..REG_TABLE).contains(®));
145 self.reg.write_volatile(reg as u32);
146 self.data.read_volatile()
147 }
148
149 /// 直接写入REG_TABLE内的寄存器
150 ///
151 /// ## 参数
152 ///
153 /// * `reg` - 寄存器下标
154 /// * `data` - 寄存器数据
write(&mut self, reg: u8, data: u32)155 unsafe fn write(&mut self, reg: u8, data: u32) {
156 // 0x1 & 0x2 are read-only regs
157 assert!(!(0x1..REG_TABLE).contains(®));
158 self.reg.write_volatile(reg as u32);
159 self.data.write_volatile(data);
160 }
161
write_rte(&mut self, rte_index: u8, vector: u8, flags: RedirectionEntry, dest: u8)162 fn write_rte(&mut self, rte_index: u8, vector: u8, flags: RedirectionEntry, dest: u8) {
163 unsafe {
164 self.write(REG_TABLE + 2 * rte_index, vector as u32 | flags.bits());
165 self.write(REG_TABLE + 2 * rte_index + 1, (dest as u32) << 24);
166 }
167 }
168
169 /// 标记中断边沿触发、高电平有效、
170 /// 启用并路由到给定的 cpunum,即是是该 cpu 的 APIC ID(不是cpuid)
enable(&mut self, rte_index: u8)171 pub fn enable(&mut self, rte_index: u8) {
172 let mut val = unsafe { self.read(REG_TABLE + 2 * rte_index) };
173 val &= !RedirectionEntry::DISABLED.bits();
174 unsafe { self.write(REG_TABLE + 2 * rte_index, val) };
175 }
176
disable(&mut self, rte_index: u8)177 pub fn disable(&mut self, rte_index: u8) {
178 let reg = REG_TABLE + 2 * rte_index;
179 let mut val = unsafe { self.read(reg) };
180 val |= RedirectionEntry::DISABLED.bits();
181 unsafe { self.write(reg, val) };
182 }
183
184 /// 安装中断
185 ///
186 /// ## 参数
187 ///
188 /// * `rte_index` - RTE下标
189 /// * `vector` - 中断向量号
190 /// * `dest` - 目标CPU的APIC ID
191 /// * `level_triggered` - 是否为电平触发
192 /// * `active_high` - 是否为高电平有效
193 /// * `dest_logic` - 是否为逻辑模式
194 /// * `mask` - 是否屏蔽
195 #[allow(clippy::too_many_arguments)]
install( &mut self, rte_index: u8, vector: u8, dest: u8, level_triggered: bool, active_high: bool, dest_logic: bool, mut mask: bool, ) -> Result<(), SystemError>196 pub fn install(
197 &mut self,
198 rte_index: u8,
199 vector: u8,
200 dest: u8,
201 level_triggered: bool,
202 active_high: bool,
203 dest_logic: bool,
204 mut mask: bool,
205 ) -> Result<(), SystemError> {
206 // 重定向表从 REG_TABLE 开始,使用两个寄存器来配置每个中断。
207 // 一对中的第一个(低位)寄存器包含配置位。32bit
208 // 第二个(高)寄存器包含一个位掩码,告诉哪些 CPU 可以服务该中断。
209 // level_triggered:如果为真,表示中断触发方式为电平触发(level-triggered),则将RedirectionEntry::LEVEL标志位设置在flags中。
210 // active_high:如果为假,表示中断的极性为低电平有效(active-low),则将RedirectionEntry::ACTIVELOW标志位设置在flags中。
211 // dest_logic:如果为真,表示中断目标为逻辑模式(logical mode),则将RedirectionEntry::LOGICAL标志位设置在flags中。
212 // !(0x20..=0xef).contains(&vector):判断中断向量号(vector)是否在范围0x20到0xef之外,如果是,则表示中断无效,将mask标志位设置为真。
213 // mask:如果为真,表示中断被屏蔽(masked),将RedirectionEntry::DISABLED标志位设置在flags中。
214 let mut flags = RedirectionEntry::NONE;
215 if level_triggered {
216 flags |= RedirectionEntry::LEVEL;
217 }
218 if !active_high {
219 flags |= RedirectionEntry::ACTIVELOW;
220 }
221 if dest_logic {
222 flags |= RedirectionEntry::LOGICAL;
223 }
224 if !(0x20..=0xef).contains(&vector) {
225 mask = true;
226 }
227 if mask {
228 flags |= RedirectionEntry::DISABLED;
229 }
230 self.write_rte(rte_index, vector, flags, dest);
231 return Ok(());
232 }
233
234 /// Get the vector number for the given IRQ.
235 #[allow(dead_code)]
irq_vector(&mut self, irq: u8) -> u8236 pub fn irq_vector(&mut self, irq: u8) -> u8 {
237 unsafe { self.read(REG_TABLE + 2 * irq).get_bits(0..8) as u8 }
238 }
239
240 /// Set the vector number for the given IRQ.
241 #[allow(dead_code)]
set_irq_vector(&mut self, irq: u8, vector: u8)242 pub fn set_irq_vector(&mut self, irq: u8, vector: u8) {
243 let mut old = unsafe { self.read(REG_TABLE + 2 * irq) };
244 let old_vector = old.get_bits(0..8);
245 if !(0x20..=0xfe).contains(&old_vector) {
246 old |= RedirectionEntry::DISABLED.bits();
247 }
248 unsafe {
249 self.write(REG_TABLE + 2 * irq, *old.set_bits(0..8, vector as u32));
250 }
251 }
252
253 #[allow(dead_code)]
id(&mut self) -> u8254 pub fn id(&mut self) -> u8 {
255 unsafe { self.read(REG_ID).get_bits(24..28) as u8 }
256 }
257
258 /// IO APIC Version
259 #[allow(dead_code)]
version(&mut self) -> u8260 pub fn version(&mut self) -> u8 {
261 unsafe { self.read(REG_VER).get_bits(0..8) as u8 }
262 }
263
264 /// Number of supported interrupts by this IO APIC.
265 ///
266 /// Max Redirection Entry = "how many IRQs can this I/O APIC handle - 1"
267 /// The -1 is silly so we add one back to it.
supported_interrupts(&mut self) -> u8268 pub fn supported_interrupts(&mut self) -> u8 {
269 unsafe { (self.read(REG_VER).get_bits(16..24) + 1) as u8 }
270 }
271
pending(&mut self, irq: u8) -> bool272 pub fn pending(&mut self, irq: u8) -> bool {
273 let rte_index = Self::vector_rte_index(irq);
274 let data = unsafe { self.read(REG_TABLE + 2 * rte_index) };
275 data & (1 << 12) != 0
276 }
277
vector_rte_index(irq_num: u8) -> u8278 fn vector_rte_index(irq_num: u8) -> u8 {
279 assert!(irq_num >= Self::VECTOR_BASE);
280 irq_num - Self::VECTOR_BASE
281 }
282
283 /// 电平响应
284 #[allow(dead_code)]
level_ack(&mut self, irq_num: u8)285 fn level_ack(&mut self, irq_num: u8) {
286 #[repr(C)]
287 struct LevelAck {
288 virt_eoi: Volatile<u32>,
289 }
290
291 let p = NonNull::new(self.virt_eoi as *mut LevelAck).unwrap();
292
293 unsafe {
294 volwrite!(p, virt_eoi, irq_num as u32);
295 }
296 }
297 }
298
299 /// Register index: ID
300 const REG_ID: u8 = 0x00;
301 /// 获取IO APIC Version
302 const REG_VER: u8 = 0x01;
303 /// Redirection table base
304 const REG_TABLE: u8 = 0x10;
305
306 bitflags! {
307 /// The redirection table starts at REG_TABLE and uses
308 /// two registers to configure each interrupt.
309 /// The first (low) register in a pair contains configuration bits.
310 /// The second (high) register contains a bitmask telling which
311 /// CPUs can serve that interrupt.
312 struct RedirectionEntry: u32 {
313 /// Interrupt disabled
314 const DISABLED = 0x00010000;
315 /// Level-triggered (vs edge-)
316 const LEVEL = 0x00008000;
317 /// Active low (vs high)
318 const ACTIVELOW = 0x00002000;
319 /// Destination is CPU id (vs APIC ID)
320 const LOGICAL = 0x00000800;
321 /// None
322 const NONE = 0x00000000;
323 }
324 }
325
326 #[derive(Debug)]
327 struct IoApicChipData {
328 inner: SpinLock<InnerIoApicChipData>,
329 }
330
331 impl IrqChipData for IoApicChipData {
as_any_ref(&self) -> &dyn core::any::Any332 fn as_any_ref(&self) -> &dyn core::any::Any {
333 self
334 }
335 }
336
337 impl IoApicChipData {
default() -> Self338 const fn default() -> Self {
339 Self::new(0, 0, 0, false, false, false, true)
340 }
341
new( rte_index: u8, vector: u8, dest: u8, level_triggered: bool, active_high: bool, dest_logic: bool, mask: bool, ) -> Self342 const fn new(
343 rte_index: u8,
344 vector: u8,
345 dest: u8,
346 level_triggered: bool,
347 active_high: bool,
348 dest_logic: bool,
349 mask: bool,
350 ) -> Self {
351 IoApicChipData {
352 inner: SpinLock::new(InnerIoApicChipData {
353 rte_index,
354 vector,
355 dest,
356 level_triggered,
357 active_high,
358 dest_logic,
359 mask,
360 }),
361 }
362 }
363
inner(&self) -> SpinLockGuard<InnerIoApicChipData>364 fn inner(&self) -> SpinLockGuard<InnerIoApicChipData> {
365 self.inner.lock_irqsave()
366 }
367 }
368
369 #[derive(Debug)]
370 struct InnerIoApicChipData {
371 rte_index: u8,
372 vector: u8,
373 dest: u8,
374 level_triggered: bool,
375 active_high: bool,
376 dest_logic: bool,
377 mask: bool,
378 }
379
380 impl InnerIoApicChipData {
381 /// 把中断数据同步到芯片
sync_to_chip(&self) -> Result<(), SystemError>382 fn sync_to_chip(&self) -> Result<(), SystemError> {
383 ioapic_install(
384 self.vector,
385 self.dest,
386 self.level_triggered,
387 self.active_high,
388 self.dest_logic,
389 self.mask,
390 )
391 }
392 }
393
394 #[inline(never)]
ioapic_init(ignore: &'static [IrqNumber])395 pub fn ioapic_init(ignore: &'static [IrqNumber]) {
396 info!("Initializing ioapic...");
397 let ioapic = unsafe { IoApic::new() };
398 unsafe {
399 __IOAPIC = Some(SpinLock::new(ioapic));
400 }
401 unsafe {
402 IOAPIC_IR_CHIP = Some(Arc::new(IoApicChip));
403 }
404
405 // 绑定irqchip
406 for i in IoApic::VECTOR_BASE as u32..256 {
407 let irq = IrqNumber::new(i);
408
409 if ignore.contains(&irq) {
410 continue;
411 }
412
413 let desc = irq_desc_manager().lookup(irq).unwrap();
414 let irq_data = desc.irq_data();
415 let mut chip_info_guard = irq_data.chip_info_write_irqsave();
416 chip_info_guard.set_chip(Some(ioapic_ir_chip()));
417 let chip_data = IoApicChipData::default();
418 chip_data.inner().rte_index = IoApic::vector_rte_index(i as u8);
419 chip_data.inner().vector = i as u8;
420 chip_info_guard.set_chip_data(Some(Arc::new(chip_data)));
421 drop(chip_info_guard);
422 let level = irq_data.is_level_type();
423
424 register_handler(&desc, level);
425 }
426
427 info!("IO Apic initialized.");
428 }
429
register_handler(desc: &Arc<IrqDesc>, level_triggered: bool)430 fn register_handler(desc: &Arc<IrqDesc>, level_triggered: bool) {
431 let fasteoi: bool = if level_triggered {
432 desc.modify_status(IrqLineStatus::empty(), IrqLineStatus::IRQ_LEVEL);
433 true
434 } else {
435 desc.modify_status(IrqLineStatus::IRQ_LEVEL, IrqLineStatus::empty());
436 false
437 };
438
439 let handler: &dyn IrqFlowHandler = if fasteoi {
440 fast_eoi_irq_handler()
441 } else {
442 edge_irq_handler()
443 };
444 desc.set_handler(handler);
445 }
446
447 /// 安装中断
448 ///
449 /// ## 参数
450 ///
451 /// * `vector` - 中断向量号
452 /// * `dest` - 目标CPU的APIC ID
453 /// * `level_triggered` - 是否为电平触发
454 /// * `active_high` - 是否为高电平有效
455 /// * `dest_logic` - 是否为逻辑模式
456 /// * `mask` - 是否屏蔽
ioapic_install( vector: u8, dest: u8, level_triggered: bool, active_high: bool, dest_logic: bool, mask: bool, ) -> Result<(), SystemError>457 fn ioapic_install(
458 vector: u8,
459 dest: u8,
460 level_triggered: bool,
461 active_high: bool,
462 dest_logic: bool,
463 mask: bool,
464 ) -> Result<(), SystemError> {
465 let rte_index = IoApic::vector_rte_index(vector);
466 return IOAPIC().lock_irqsave().install(
467 rte_index,
468 vector,
469 dest,
470 level_triggered,
471 active_high,
472 dest_logic,
473 mask,
474 );
475 }
476
477 /// IoApic中断芯片
478 ///
479 /// https://code.dragonos.org.cn/xref/linux-6.1.9/arch/x86/kernel/apic/io_apic.c#1994
480 #[derive(Debug)]
481 struct IoApicChip;
482
483 impl IrqChip for IoApicChip {
name(&self) -> &'static str484 fn name(&self) -> &'static str {
485 "IR-IO-APIC"
486 }
487
irq_startup(&self, irq: &Arc<IrqData>) -> Result<(), SystemError>488 fn irq_startup(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
489 self.irq_unmask(irq)
490 }
491
irq_mask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError>492 fn irq_mask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
493 let binding = irq
494 .chip_info_read_irqsave()
495 .chip_data()
496 .ok_or(SystemError::EINVAL)?;
497 let chip_data = binding
498 .as_any_ref()
499 .downcast_ref::<IoApicChipData>()
500 .ok_or(SystemError::EINVAL)?;
501
502 let mut chip_data_inner = chip_data.inner();
503 chip_data_inner.mask = true;
504 chip_data_inner.sync_to_chip().ok();
505
506 drop(chip_data_inner);
507
508 return Ok(());
509 }
510
can_set_affinity(&self) -> bool511 fn can_set_affinity(&self) -> bool {
512 true
513 }
514
can_set_flow_type(&self) -> bool515 fn can_set_flow_type(&self) -> bool {
516 true
517 }
518
irq_set_type( &self, irq: &Arc<IrqData>, flow_type: IrqLineStatus, ) -> Result<IrqChipSetMaskResult, SystemError>519 fn irq_set_type(
520 &self,
521 irq: &Arc<IrqData>,
522 flow_type: IrqLineStatus,
523 ) -> Result<IrqChipSetMaskResult, SystemError> {
524 let binding = irq
525 .chip_info_read_irqsave()
526 .chip_data()
527 .ok_or(SystemError::EINVAL)?;
528 let chip_data = binding
529 .as_any_ref()
530 .downcast_ref::<IoApicChipData>()
531 .ok_or(SystemError::EINVAL)?;
532 let mut chip_data_inner = chip_data.inner();
533
534 let level_triggered = flow_type.is_level_type();
535 let active_high = flow_type.is_level_high().unwrap_or(false);
536 chip_data_inner.active_high = active_high;
537 chip_data_inner.level_triggered = level_triggered;
538 chip_data_inner.sync_to_chip()?;
539
540 return Ok(IrqChipSetMaskResult::Success);
541 }
542
irq_set_affinity( &self, irq: &Arc<IrqData>, cpu: &CpuMask, _force: bool, ) -> Result<IrqChipSetMaskResult, SystemError>543 fn irq_set_affinity(
544 &self,
545 irq: &Arc<IrqData>,
546 cpu: &CpuMask,
547 _force: bool,
548 ) -> Result<IrqChipSetMaskResult, SystemError> {
549 // 使用mask的第1个可用CPU
550 let dest = (cpu.first().ok_or(SystemError::EINVAL)?.data() & 0xff) as u8;
551
552 let binding = irq
553 .chip_info_read_irqsave()
554 .chip_data()
555 .ok_or(SystemError::EINVAL)?;
556 let chip_data = binding
557 .as_any_ref()
558 .downcast_ref::<IoApicChipData>()
559 .ok_or(SystemError::EINVAL)?;
560
561 let mut chip_data_inner = chip_data.inner();
562 let origin_dest = chip_data_inner.dest;
563 if origin_dest == dest {
564 return Ok(IrqChipSetMaskResult::Success);
565 }
566
567 chip_data_inner.dest = dest;
568
569 chip_data_inner.sync_to_chip()?;
570
571 return Ok(IrqChipSetMaskResult::Success);
572 }
573
irq_unmask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError>574 fn irq_unmask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
575 IOAPIC()
576 .lock_irqsave()
577 .enable(IoApic::vector_rte_index(irq.irq().data() as u8));
578 Ok(())
579 }
580
can_mask_ack(&self) -> bool581 fn can_mask_ack(&self) -> bool {
582 true
583 }
584
irq_mask_ack(&self, irq: &Arc<IrqData>)585 fn irq_mask_ack(&self, irq: &Arc<IrqData>) {
586 self.irq_mask(irq).ok();
587 self.irq_eoi(irq);
588 }
589
irq_eoi(&self, irq: &Arc<IrqData>)590 fn irq_eoi(&self, irq: &Arc<IrqData>) {
591 if irq.is_level_type() {
592 IOAPIC().lock_irqsave().level_ack(irq.irq().data() as u8);
593 } else {
594 CurrentApic.send_eoi();
595 }
596 }
597
retrigger(&self, irq_data: &Arc<IrqData>) -> Result<(), SystemError>598 fn retrigger(&self, irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
599 irq_manager().irq_chip_retrigger_hierarchy(irq_data)
600 }
601
irqchip_state(&self, irq: &Arc<IrqData>, which: IrqChipState) -> Result<bool, SystemError>602 fn irqchip_state(&self, irq: &Arc<IrqData>, which: IrqChipState) -> Result<bool, SystemError> {
603 let binding = irq
604 .chip_info_read_irqsave()
605 .chip_data()
606 .ok_or(SystemError::EINVAL)?;
607 let chip_data = binding
608 .as_any_ref()
609 .downcast_ref::<IoApicChipData>()
610 .ok_or(SystemError::EINVAL)?;
611
612 match which {
613 IrqChipState::Pending => {
614 return Ok(IOAPIC().lock_irqsave().pending(irq.irq().data() as u8));
615 }
616 IrqChipState::Active => {
617 let chip_data_inner = chip_data.inner();
618 return Ok(!chip_data_inner.mask);
619 }
620 IrqChipState::Masked => {
621 let chip_data_inner = chip_data.inner();
622 return Ok(chip_data_inner.mask);
623 }
624 IrqChipState::LineLevel => {
625 let chip_data_inner = chip_data.inner();
626 return Ok(chip_data_inner.active_high);
627 }
628 #[allow(unreachable_patterns)]
629 _ => {
630 return Err(SystemError::EINVAL);
631 }
632 }
633 }
634
irq_disable(&self, irq: &Arc<IrqData>)635 fn irq_disable(&self, irq: &Arc<IrqData>) {
636 let binding = irq
637 .chip_info_read_irqsave()
638 .chip_data()
639 .ok_or(SystemError::EINVAL)
640 .unwrap();
641 let chip_data = binding
642 .as_any_ref()
643 .downcast_ref::<IoApicChipData>()
644 .ok_or(SystemError::EINVAL)
645 .unwrap();
646 let mut chip_data_inner = chip_data.inner();
647 chip_data_inner.mask = true;
648 chip_data_inner.sync_to_chip().ok();
649 }
650
irq_ack(&self, irq_data: &Arc<IrqData>)651 fn irq_ack(&self, irq_data: &Arc<IrqData>) {
652 // irq_manager().irq_chip_ack_parent(irq_data);
653 self.irq_eoi(irq_data);
654 }
655
flags(&self) -> IrqChipFlags656 fn flags(&self) -> IrqChipFlags {
657 IrqChipFlags::IRQCHIP_SKIP_SET_WAKE | IrqChipFlags::IRQCHIP_AFFINITY_PRE_STARTUP
658 }
659 }
660