1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#![allow(missing_docs)]
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct PciIrqSwizzleLut(
[[[u32; PCI_MAX_LEGACY_IRQ_PINS]; PCI_MAX_FUNCTIONS_PER_DEVICE]; PCI_MAX_DEVICES_PER_BUS],
);
#[repr(C)]
pub struct PciInitArgsIrqs {
pub global_irq: u32,
pub level_triggered: bool,
pub active_high: bool,
pub padding1: [u8; 2],
}
#[repr(C)]
pub struct PciInitArgsHeader {
pub dev_pin_to_global_irq: PciIrqSwizzleLut,
pub num_irqs: u32,
pub irqs: [PciInitArgsIrqs; PCI_MAX_IRQS],
pub addr_window_count: u32,
}
#[repr(C)]
#[derive(Debug)]
pub struct PciInitArgsAddrWindows {
pub base: u64,
pub size: usize,
pub bus_start: u8,
pub bus_end: u8,
pub cfg_space_type: u8,
pub has_ecam: bool,
pub padding1: [u8; 4],
}
pub const PCI_INIT_ARG_MAX_ECAM_WINDOWS: usize = 2;
pub const PCI_INIT_ARG_MAX_SIZE: usize = core::mem::size_of::<PciInitArgsAddrWindows>()
* PCI_INIT_ARG_MAX_ECAM_WINDOWS
+ core::mem::size_of::<PciInitArgsHeader>();
use super::*;
use kernel_hal::InterruptManager;
impl PciInitArgsHeader {
pub fn configure_interrupt(&mut self) -> ZxResult {
for i in 0..self.num_irqs as usize {
let irq = &mut self.irqs[i];
let global_irq = irq.global_irq;
if !is_valid_interrupt(global_irq) {
irq.global_irq = PCI_NO_IRQ_MAPPING;
self.dev_pin_to_global_irq.remove_irq(global_irq);
} else {
irq_configure(
global_irq,
irq.level_triggered,
irq.active_high,
)?;
}
}
Ok(())
}
}
fn is_valid_interrupt(irq: u32) -> bool {
InterruptManager::is_valid(irq)
}
fn irq_configure(irq: u32, level_trigger: bool, active_high: bool) -> ZxResult {
let dest = kernel_hal::apic_local_id();
if InterruptManager::configure(
irq,
0,
dest,
level_trigger,
active_high,
) {
Ok(())
} else {
Err(ZxError::INVALID_ARGS)
}
}
impl PciIrqSwizzleLut {
pub(super) fn swizzle(&self, dev_id: usize, func_id: usize, pin: usize) -> ZxResult<usize> {
if dev_id >= PCI_MAX_DEVICES_PER_BUS
|| func_id >= PCI_MAX_FUNCTIONS_PER_DEVICE
|| pin >= PCI_MAX_LEGACY_IRQ_PINS
{
return Err(ZxError::INVALID_ARGS);
}
let irq = self.0[dev_id][func_id][pin];
if irq == PCI_NO_IRQ_MAPPING {
Err(ZxError::NOT_FOUND)
} else {
Ok(irq as usize)
}
}
fn remove_irq(&mut self, irq: u32) {
for dev in self.0.iter_mut() {
for func in dev.iter_mut() {
for pin in func.iter_mut() {
if *pin == irq {
*pin = PCI_NO_IRQ_MAPPING;
}
}
}
}
}
}