Skip to content

Commit 78ded37

Browse files
fujitametaspace
authored andcommitted
rust: add pci_device_id abstraction
Signed-off-by: FUJITA Tomonori <[email protected]> Modified slightly to rebase by Andreas Hindborg.
1 parent bf06051 commit 78ded37

File tree

1 file changed

+128
-5
lines changed

1 file changed

+128
-5
lines changed

rust/kernel/pci.rs

Lines changed: 128 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
//!
55
//! C header: [`include/linux/pci.h`](../../../../include/linux/pci.h)
66
7+
#![allow(dead_code)]
8+
79
use crate::{
810
bindings, device, driver,
911
error::{from_result, to_result, Result},
@@ -28,7 +30,7 @@ impl<T: Driver> driver::DriverOps for Adapter<T> {
2830
pdrv.name = name.as_char_ptr();
2931
pdrv.probe = Some(Self::probe_callback);
3032
pdrv.remove = Some(Self::remove_callback);
31-
pdrv.id_table = T::PCI_ID_TABLE.as_ptr();
33+
pdrv.id_table = T::ID_TABLE.as_ref();
3234
to_result(unsafe { bindings::__pci_register_driver(reg, module.0, name.as_char_ptr()) })
3335
}
3436

@@ -40,11 +42,24 @@ impl<T: Driver> driver::DriverOps for Adapter<T> {
4042
impl<T: Driver> Adapter<T> {
4143
extern "C" fn probe_callback(
4244
pdev: *mut bindings::pci_dev,
43-
_id: *const bindings::pci_device_id,
45+
id: *const bindings::pci_device_id,
4446
) -> core::ffi::c_int {
4547
from_result(|| {
4648
let mut dev = unsafe { Device::from_ptr(pdev) };
47-
let data = T::probe(&mut dev)?;
49+
50+
// SAFETY: `id` is a pointer within the static table, so it's always valid.
51+
let offset = unsafe { (*id).driver_data };
52+
// SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`, which
53+
// guarantees that the resulting pointer is within the table.
54+
let info = {
55+
let ptr = unsafe {
56+
id.cast::<u8>()
57+
.offset(offset as _)
58+
.cast::<Option<T::IdInfo>>()
59+
};
60+
unsafe { (&*ptr).as_ref() }
61+
};
62+
let data = T::probe(&mut dev, info)?;
4863
unsafe { bindings::pci_set_drvdata(pdev, data.into_foreign() as _) };
4964
Ok(0)
5065
})
@@ -58,6 +73,111 @@ impl<T: Driver> Adapter<T> {
5873
}
5974
}
6075

76+
/// Abstraction for bindings::pci_device_id.
77+
#[derive(Clone, Copy)]
78+
pub struct DeviceId {
79+
/// Vendor ID
80+
pub vendor: u32,
81+
/// Device ID
82+
pub device: u32,
83+
/// Subsystem vendor ID
84+
pub subvendor: u32,
85+
/// Subsystem device ID
86+
pub subdevice: u32,
87+
/// Device class and subclass
88+
pub class: u32,
89+
/// Limit which sub-fields of the class
90+
pub class_mask: u32,
91+
}
92+
93+
impl DeviceId {
94+
const PCI_ANY_ID: u32 = !0;
95+
96+
/// PCI_DEVICE macro.
97+
pub const fn new(vendor: u32, device: u32) -> Self {
98+
Self {
99+
vendor,
100+
device,
101+
subvendor: DeviceId::PCI_ANY_ID,
102+
subdevice: DeviceId::PCI_ANY_ID,
103+
class: 0,
104+
class_mask: 0,
105+
}
106+
}
107+
108+
/// PCI_DEVICE_CLASS macro.
109+
pub const fn with_class(class: u32, class_mask: u32) -> Self {
110+
Self {
111+
vendor: DeviceId::PCI_ANY_ID,
112+
device: DeviceId::PCI_ANY_ID,
113+
subvendor: DeviceId::PCI_ANY_ID,
114+
subdevice: DeviceId::PCI_ANY_ID,
115+
class,
116+
class_mask,
117+
}
118+
}
119+
120+
pub const fn to_rawid(&self, offset: isize) -> bindings::pci_device_id {
121+
bindings::pci_device_id {
122+
vendor: self.vendor,
123+
device: self.device,
124+
subvendor: self.subvendor,
125+
subdevice: self.subdevice,
126+
class: self.class,
127+
class_mask: self.class_mask,
128+
driver_data: offset as _,
129+
override_only: 0,
130+
}
131+
}
132+
}
133+
134+
// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `pci_device_id::driver_data`.
135+
unsafe impl driver::RawDeviceId for DeviceId {
136+
type RawType = bindings::pci_device_id;
137+
138+
const ZERO: Self::RawType = bindings::pci_device_id {
139+
vendor: 0,
140+
device: 0,
141+
subvendor: 0,
142+
subdevice: 0,
143+
class: 0,
144+
class_mask: 0,
145+
driver_data: 0,
146+
override_only: 0,
147+
};
148+
149+
}
150+
151+
/// Define a const pci device id table
152+
///
153+
/// # Examples
154+
///
155+
/// ```ignore
156+
/// # use kernel::{pci, define_pci_id_table};
157+
/// #
158+
/// struct MyDriver;
159+
/// impl pci::Driver for MyDriver {
160+
/// // [...]
161+
/// # fn probe(_dev: &mut pci::Device, _id_info: Option<&Self::IdInfo>) -> Result {
162+
/// # Ok(())
163+
/// # }
164+
/// # define_pci_id_table! {u32, [
165+
/// # (pci::DeviceId::new(0x010800, 0xffffff), None),
166+
/// # (pci::DeviceId::with_class(0x010802, 0xfffff), Some(0x10)),
167+
/// # ]}
168+
/// }
169+
/// ```
170+
#[macro_export]
171+
macro_rules! define_pci_id_table {
172+
($data_type:ty, $($t:tt)*) => {
173+
type IdInfo = $data_type;
174+
const ID_TABLE: $crate::driver::IdTable<'static, $crate::pci::DeviceId, $data_type> = {
175+
$crate::define_id_array!(ARRAY, $crate::pci::DeviceId, $data_type, $($t)* );
176+
ARRAY.as_table()
177+
};
178+
};
179+
}
180+
61181
/// A PCI driver
62182
pub trait Driver {
63183
/// Data stored on device by driver.
@@ -69,14 +189,17 @@ pub trait Driver {
69189
/// never move the underlying wrapped data structure. This allows
70190
type Data: ForeignOwnable + Send + Sync + driver::DeviceRemoval = ();
71191

192+
/// The type holding information about each device id supported by the driver.
193+
type IdInfo: 'static = ();
194+
72195
/// The table of device ids supported by the driver.
73-
const PCI_ID_TABLE: &'static [bindings::pci_device_id];
196+
const ID_TABLE: driver::IdTable<'static, DeviceId, Self::IdInfo>;
74197

75198
/// PCI driver probe.
76199
///
77200
/// Called when a new platform device is added or discovered.
78201
/// Implementers should attempt to initialize the device here.
79-
fn probe(dev: &mut Device) -> Result<Self::Data>;
202+
fn probe(dev: &mut Device, id: Option<&Self::IdInfo>) -> Result<Self::Data>;
80203

81204
/// PCI driver remove.
82205
///

0 commit comments

Comments
 (0)