1use crate::{
4 config::{VirtDevice, mmio_of},
5 device::device_tree::FDT,
6 mm::address::{ConvertablePaddr, Paddr, UsizeConvert},
7 pr_info,
8};
9use core::ptr::{read_volatile, write_volatile};
10
11pub struct PciDevice {}
13
14pub struct PciDriver {}
16
17#[derive(Clone, Copy)]
19pub struct PcieHost {
20 ecam_paddr: usize,
22 ecam_vaddr: usize,
24 ecam_size: usize,
26 mmio_base: usize,
28 mmio_size: usize,
30 bus_start: u8,
32 bus_end: u8,
34}
35
36impl PcieHost {
37 pub fn from_fdt() -> Option<Self> {
39 let fdt = &*FDT;
40
41 let mut target = None;
43 for node in fdt.all_nodes() {
44 if let Some(prop) = node.property("compatible") {
45 let bytes = prop.value;
46 let mut start = 0;
47 while start < bytes.len() {
48 let mut end = start;
49 while end < bytes.len() && bytes[end] != 0 {
50 end += 1;
51 }
52 if end > start && &bytes[start..end] == b"pci-host-ecam-generic" {
53 target = Some(node);
54 break;
55 }
56 start = end + 1;
57 }
58 if target.is_some() {
59 break;
60 }
61 }
62 }
63 let node = target?;
64
65 let parent = node.interrupt_parent()?;
67
68 let child_addr_cells = node
69 .property("#address-cells")
70 .and_then(|p| {
71 if p.value.len() >= 4 {
72 Some(u32::from_be_bytes(p.value[0..4].try_into().unwrap()) as usize)
73 } else {
74 None
75 }
76 })
77 .unwrap_or(3); let child_size_cells = node
80 .property("#size-cells")
81 .and_then(|p| {
82 if p.value.len() >= 4 {
83 Some(u32::from_be_bytes(p.value[0..4].try_into().unwrap()) as usize)
84 } else {
85 None
86 }
87 })
88 .unwrap_or(2);
89
90 let parent_addr_cells = parent
91 .property("#address-cells")
92 .and_then(|p| {
93 if p.value.len() >= 4 {
94 Some(u32::from_be_bytes(p.value[0..4].try_into().unwrap()) as usize)
95 } else {
96 None
97 }
98 })
99 .unwrap_or(2);
100
101 let parent_size_cells = parent
102 .property("#size-cells")
103 .and_then(|p| {
104 if p.value.len() >= 4 {
105 Some(u32::from_be_bytes(p.value[0..4].try_into().unwrap()) as usize)
106 } else {
107 None
108 }
109 })
110 .unwrap_or(2);
111
112 let (bus_start, bus_end) = if let Some(prop) = node.property("bus-range") {
114 if prop.value.len() >= 8 {
115 let b0 = u32::from_be_bytes(prop.value[0..4].try_into().unwrap());
116 let b1 = u32::from_be_bytes(prop.value[4..8].try_into().unwrap());
117 (b0 as u8, b1 as u8)
118 } else {
119 (0, 255)
120 }
121 } else {
122 (0, 255)
123 };
124
125 let (ecam_base, ecam_size) = if let Some(prop) = node.property("reg") {
127 let cells = parent_addr_cells + parent_size_cells;
128 let need = cells * 4;
129 if prop.value.len() < need {
130 return None;
131 }
132 let mut idx = 0;
133 let mut addr = 0usize;
134 for _ in 0..parent_addr_cells {
135 addr = (addr << 32)
136 | u32::from_be_bytes(prop.value[idx..idx + 4].try_into().unwrap()) as usize;
137 idx += 4;
138 }
139 let mut size = 0usize;
140 for _ in 0..parent_size_cells {
141 size = (size << 32)
142 | u32::from_be_bytes(prop.value[idx..idx + 4].try_into().unwrap()) as usize;
143 idx += 4;
144 }
145 (addr, size)
146 } else {
147 return None;
148 };
149
150 let (mmio_base, mmio_size) = if let Some(prop) = node.property("ranges") {
152 let entry_cells = child_addr_cells + parent_addr_cells + parent_size_cells;
153 let entry_bytes = entry_cells * 4;
154 let mut mmio: Option<(usize, usize)> = None;
155 let mut off = 0;
156 while off + entry_bytes <= prop.value.len() {
157 let mut idx = off;
158
159 let mut child_cells_vals: [u32; 8] = [0; 8];
161 for c in 0..child_addr_cells {
162 child_cells_vals[c] =
163 u32::from_be_bytes(prop.value[idx..idx + 4].try_into().unwrap());
164 idx += 4;
165 }
166 let flags = child_cells_vals[0];
167
168 let space_code = flags & 0x0300_0000;
170 let is_mem = space_code == 0x0100_0000 || space_code == 0x0200_0000;
171 let mut child_addr = 0usize;
173 for c in 1..child_addr_cells {
174 child_addr = (child_addr << 32) | child_cells_vals[c] as usize;
175 }
176
177 let mut parent_addr = 0usize;
179 for _ in 0..parent_addr_cells {
180 parent_addr = (parent_addr << 32)
181 | u32::from_be_bytes(prop.value[idx..idx + 4].try_into().unwrap()) as usize;
182 idx += 4;
183 }
184
185 let mut size = 0usize;
187 for _ in 0..parent_size_cells {
188 size = (size << 32)
189 | u32::from_be_bytes(prop.value[idx..idx + 4].try_into().unwrap()) as usize;
190 idx += 4;
191 }
192
193 if is_mem && size != 0 && mmio.is_none() {
194 mmio = Some((parent_addr, size));
195 }
196
197 off += entry_bytes;
198 }
199
200 mmio.unwrap_or_else(|| mmio_of(VirtDevice::VirtPcieMmio).unwrap())
201 } else {
202 mmio_of(VirtDevice::VirtPcieMmio)?
203 };
204
205 let ecam_vaddr = Paddr::to_vaddr(&Paddr::from_usize(ecam_base)).as_usize();
206
207 Some(Self {
208 ecam_paddr: ecam_base,
209 ecam_vaddr,
210 ecam_size,
211 mmio_base,
212 mmio_size,
213 bus_start,
214 bus_end,
215 })
216 }
217
218 pub fn from_platform_defaults() -> Option<Self> {
220 let (ecam_base, ecam_size) = mmio_of(VirtDevice::VirtPcieEcam)?;
221 let (mmio_base, mmio_size) = mmio_of(VirtDevice::VirtPcieMmio)?;
222 let ecam_vaddr = Paddr::to_vaddr(&Paddr::from_usize(ecam_base)).as_usize();
223
224 Some(Self {
225 ecam_paddr: ecam_base,
226 ecam_vaddr,
227 ecam_size,
228 mmio_base,
229 mmio_size,
230 bus_start: 0,
231 bus_end: 255, })
233 }
234
235 #[inline]
237 fn cfg_addr(&self, bus: u8, dev: u8, func: u8, offset: u16) -> *mut u32 {
238 let off = ((bus as usize) << 20)
240 | ((dev as usize) << 15)
241 | ((func as usize) << 12)
242 | ((offset as usize) & 0xfff);
243 (self.ecam_vaddr + off) as *mut u32
244 }
245
246 pub unsafe fn cfg_read32(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32 {
248 unsafe { read_volatile(self.cfg_addr(bus, dev, func, offset)) }
249 }
250
251 pub unsafe fn cfg_write32(&self, bus: u8, dev: u8, func: u8, offset: u16, val: u32) {
253 unsafe {
254 write_volatile(self.cfg_addr(bus, dev, func, offset), val);
255 }
256 }
257
258 pub fn enumerate(&self) {
260 pr_info!(
261 "[PCIe] ECAM @ {:#x} (size {:#x}), MMIO @ {:#x} (size {:#x})",
262 self.ecam_paddr,
263 self.ecam_size,
264 self.mmio_base,
265 self.mmio_size
266 );
267
268 for bus in self.bus_start..=self.bus_end {
269 for dev in 0u8..32 {
270 let vend = unsafe { self.cfg_read32(bus, dev, 0, 0x00) } as u16;
272 if vend == 0xffff {
273 continue;
274 }
275 let did = (unsafe { self.cfg_read32(bus, dev, 0, 0x00) } >> 16) as u16;
277 let hdr = (unsafe { self.cfg_read32(bus, dev, 0, 0x0C) } >> 16) as u8; let multi_func = (hdr & 0x80) != 0;
279
280 pr_info!(
281 "[PCIe] bus {:02x} dev {:02x} fn 00: vendor={:04x} device={:04x} hdr={:02x}",
282 bus,
283 dev,
284 vend,
285 did,
286 hdr & 0x7f
287 );
288
289 if multi_func {
291 for func in 1u8..8 {
292 let vend = unsafe { self.cfg_read32(bus, dev, func, 0x00) } as u16;
293 if vend == 0xffff {
294 continue;
295 }
296 let did = (unsafe { self.cfg_read32(bus, dev, func, 0x00) } >> 16) as u16;
297 let hdr = (unsafe { self.cfg_read32(bus, dev, func, 0x0C) } >> 16) as u8;
298 pr_info!(
299 "[PCIe] bus {:02x} dev {:02x} fn {:02x}: vendor={:04x} device={:04x} hdr={:02x}",
300 bus,
301 dev,
302 func,
303 vend,
304 did,
305 hdr & 0x7f
306 );
307 }
308 }
309 }
310 }
311 }
312}
313
314pub fn init_and_enumerate() {
316 if let Some(host) = PcieHost::from_fdt().or_else(|| PcieHost::from_platform_defaults()) {
317 host.enumerate();
318 } else {
319 pr_info!("[PCIe] no host found from platform defaults");
320 }
321}