Skip to content

Commit a50ed67

Browse files
committed
rust: pci: add IRQ and misc methods
Based on wedsonaf@02541e6
1 parent ee21500 commit a50ed67

File tree

1 file changed

+130
-4
lines changed

1 file changed

+130
-4
lines changed

rust/kernel/pci.rs

Lines changed: 130 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88

99
use crate::{
1010
bindings, device, driver,
11-
error::{from_result, to_result, Result},
11+
error::{from_result, to_result, Error, Result},
12+
io_mem::Resource,
13+
irq,
1214
str::CStr,
1315
types::ForeignOwnable,
1416
ThisModule,
1517
};
18+
use core::fmt;
1619

1720
/// An adapter for the registration of PCI drivers.
1821
pub struct Adapter<T: Driver>(T);
@@ -177,6 +180,7 @@ macro_rules! define_pci_id_table {
177180
};
178181
};
179182
}
183+
pub use define_pci_id_table;
180184

181185
/// A PCI driver
182186
pub trait Driver {
@@ -187,7 +191,9 @@ pub trait Driver {
187191
///
188192
/// Require that `Data` implements `ForeignOwnable`. We guarantee to
189193
/// never move the underlying wrapped data structure. This allows
190-
type Data: ForeignOwnable + Send + Sync + driver::DeviceRemoval = ();
194+
// TODO: Data Send + Sync ?
195+
//type Data: ForeignOwnable + Send + Sync + driver::DeviceRemoval = ();
196+
type Data: ForeignOwnable + driver::DeviceRemoval = ();
191197

192198
/// The type holding information about each device id supported by the driver.
193199
type IdInfo: 'static = ();
@@ -215,11 +221,131 @@ pub trait Driver {
215221
/// The field `ptr` is non-null and valid for the lifetime of the object.
216222
pub struct Device {
217223
ptr: *mut bindings::pci_dev,
224+
res_taken: u64,
218225
}
219226

220227
impl Device {
221-
unsafe fn from_ptr(ptr: *mut bindings::pci_dev) -> Self {
222-
Self { ptr }
228+
pub unsafe fn from_ptr(ptr: *mut bindings::pci_dev) -> Self {
229+
Self { ptr, res_taken: 0 }
230+
}
231+
232+
pub unsafe fn as_ptr(&self) -> *mut bindings::pci_dev {
233+
self.ptr
234+
}
235+
236+
pub fn enable_device_mem(&self) -> Result {
237+
let ret = unsafe { bindings::pci_enable_device_mem(self.ptr) };
238+
if ret != 0 {
239+
Err(Error::from_errno(ret))
240+
} else {
241+
Ok(())
242+
}
243+
}
244+
245+
pub fn set_master(&self) {
246+
unsafe { bindings::pci_set_master(self.ptr) };
247+
}
248+
249+
pub fn select_bars(&self, flags: core::ffi::c_ulong) -> i32 {
250+
unsafe { bindings::pci_select_bars(self.ptr, flags) }
251+
}
252+
253+
pub fn request_selected_regions(&self, bars: i32, name: &'static CStr) -> Result {
254+
let ret =
255+
unsafe { bindings::pci_request_selected_regions(self.ptr, bars, name.as_char_ptr()) };
256+
if ret != 0 {
257+
Err(Error::from_errno(ret))
258+
} else {
259+
Ok(())
260+
}
261+
}
262+
263+
pub fn take_resource(&mut self, index: usize) -> Option<Resource> {
264+
let pdev = unsafe { &*self.ptr };
265+
266+
// Fail if the index is beyond the end or if it has already been taken.
267+
if index >= pdev.resource.len() || self.res_taken & (1 << index) != 0 {
268+
return None;
269+
}
270+
271+
self.res_taken |= 1 << index;
272+
Resource::new(pdev.resource[index].start, pdev.resource[index].end)
273+
}
274+
275+
pub fn irq(&self) -> Option<u32> {
276+
let pdev = unsafe { &*self.ptr };
277+
278+
if pdev.irq == 0 {
279+
None
280+
} else {
281+
Some(pdev.irq)
282+
}
283+
}
284+
285+
pub fn alloc_irq_vectors(&mut self, min_vecs: u32, max_vecs: u32, flags: u32) -> Result<u32> {
286+
let ret = unsafe {
287+
bindings::pci_alloc_irq_vectors_affinity(
288+
self.ptr,
289+
min_vecs,
290+
max_vecs,
291+
flags,
292+
core::ptr::null_mut(),
293+
)
294+
};
295+
if ret < 0 {
296+
Err(Error::from_errno(ret))
297+
} else {
298+
Ok(ret as _)
299+
}
300+
}
301+
302+
pub fn alloc_irq_vectors_affinity(
303+
&mut self,
304+
min_vecs: u32,
305+
max_vecs: u32,
306+
pre: u32,
307+
post: u32,
308+
flags: u32,
309+
) -> Result<u32> {
310+
let mut affd = bindings::irq_affinity {
311+
pre_vectors: pre,
312+
post_vectors: post,
313+
..bindings::irq_affinity::default()
314+
};
315+
316+
let ret = unsafe {
317+
bindings::pci_alloc_irq_vectors_affinity(
318+
self.ptr,
319+
min_vecs,
320+
max_vecs,
321+
flags | bindings::PCI_IRQ_AFFINITY,
322+
&mut affd,
323+
)
324+
};
325+
if ret < 0 {
326+
Err(Error::from_errno(ret))
327+
} else {
328+
Ok(ret as _)
329+
}
330+
}
331+
332+
pub fn free_irq_vectors(&mut self) {
333+
unsafe { bindings::pci_free_irq_vectors(self.ptr) };
334+
}
335+
336+
pub fn request_irq<T: irq::Handler>(
337+
&self,
338+
index: u32,
339+
data: T::Data,
340+
name_args: fmt::Arguments<'_>,
341+
) -> Result<irq::Registration<T>> {
342+
let ret = unsafe { bindings::pci_irq_vector(self.ptr, index) };
343+
if ret < 0 {
344+
return Err(Error::from_errno(ret));
345+
}
346+
crate::pr_info!("Setting up IRQ: {}\n", ret);
347+
348+
irq::Registration::try_new(ret as _, data, irq::flags::SHARED, name_args)
223349
}
224350
}
225351

0 commit comments

Comments
 (0)