Skip to content

Commit 0eb73f2

Browse files
author
Danilo Krummrich
committed
rust: pci: add basic PCI device / driver abstractions
Implement the basic PCI abstractions required to write a basic PCI driver. This includes the following data structures: The `pci::Driver` trait represents the interface to the driver and provides `pci::Driver::probe` for the driver to implement. The `pci::Device` abstraction represents a `struct pci_dev` and provides abstractions for common functions, such as `pci::Device::set_master`. In order to provide the PCI specific parts to a generic `driver::Registration` the `driver::RegistrationOps` trait is implemented by `pci::Adapter`. `pci::DeviceId` implements PCI device IDs based on the generic `device_id::RawDevceId` abstraction. Co-developed-by: FUJITA Tomonori <[email protected]> Signed-off-by: FUJITA Tomonori <[email protected]> Signed-off-by: Danilo Krummrich <[email protected]>
1 parent 5abe57e commit 0eb73f2

File tree

5 files changed

+287
-0
lines changed

5 files changed

+287
-0
lines changed

rust/bindings/bindings_helper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/firmware.h>
1616
#include <linux/jiffies.h>
1717
#include <linux/mdio.h>
18+
#include <linux/pci.h>
1819
#include <linux/phy.h>
1920
#include <linux/refcount.h>
2021
#include <linux/sched.h>

rust/helpers/helpers.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "kunit.c"
1818
#include "mutex.c"
1919
#include "page.c"
20+
#include "pci.c"
2021
#include "rbtree.c"
2122
#include "rcu.c"
2223
#include "refcount.c"

rust/helpers/pci.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/pci.h>
4+
5+
void rust_helper_pci_set_drvdata(struct pci_dev *pdev, void *data)
6+
{
7+
pci_set_drvdata(pdev, data);
8+
}
9+
10+
void *rust_helper_pci_get_drvdata(struct pci_dev *pdev)
11+
{
12+
return pci_get_drvdata(pdev);
13+
}
14+
15+
u64 rust_helper_pci_resource_len(struct pci_dev *pdev, int bar)
16+
{
17+
return pci_resource_len(pdev, bar);
18+
}

rust/kernel/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ pub mod workqueue;
7373
pub use bindings;
7474
pub mod io;
7575
pub use macros;
76+
#[cfg(all(CONFIG_PCI, CONFIG_PCI_MSI))]
77+
pub mod pci;
7678
pub use uapi;
7779

7880
#[doc(hidden)]

rust/kernel/pci.rs

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Wrappers for the PCI subsystem
4+
//!
5+
//! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h)
6+
7+
use crate::{
8+
bindings, container_of, device,
9+
device_id::RawDeviceId,
10+
driver,
11+
error::{to_result, Result},
12+
str::CStr,
13+
types::{ARef, ForeignOwnable},
14+
ThisModule,
15+
};
16+
use kernel::prelude::*;
17+
18+
/// An adapter for the registration of PCI drivers.
19+
pub struct Adapter<T: Driver>(T);
20+
21+
impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
22+
type RegType = bindings::pci_driver;
23+
24+
fn register(
25+
pdrv: &mut Self::RegType,
26+
name: &'static CStr,
27+
module: &'static ThisModule,
28+
) -> Result {
29+
pdrv.name = name.as_char_ptr();
30+
pdrv.probe = Some(Self::probe_callback);
31+
pdrv.remove = Some(Self::remove_callback);
32+
pdrv.id_table = T::ID_TABLE.as_ptr();
33+
34+
// SAFETY: `pdrv` is guaranteed to be a valid `RegType`.
35+
to_result(unsafe {
36+
bindings::__pci_register_driver(pdrv as _, module.0, name.as_char_ptr())
37+
})
38+
}
39+
40+
fn unregister(pdrv: &mut Self::RegType) {
41+
// SAFETY: `pdrv` is guaranteed to be a valid `RegType`.
42+
unsafe { bindings::pci_unregister_driver(pdrv) }
43+
}
44+
}
45+
46+
impl<T: Driver + 'static> Adapter<T> {
47+
extern "C" fn probe_callback(
48+
pdev: *mut bindings::pci_dev,
49+
id: *const bindings::pci_device_id,
50+
) -> core::ffi::c_int {
51+
// SAFETY: The PCI core only ever calls the probe callback with a valid `pdev`.
52+
let dev = unsafe { device::Device::from_raw(&mut (*pdev).dev) };
53+
// SAFETY: `dev` is guaranteed to be embedded in a valid `struct pci_dev` by the call
54+
// above.
55+
let mut pdev = unsafe { Device::from_dev(dev) };
56+
57+
// SAFETY: The PCI core only ever calls the probe callback with a valid `id`.
58+
let index = unsafe { (*id).driver_data };
59+
let raw_id = T::ID_TABLE.id(index as _);
60+
61+
// SAFETY: `DeviceId` is a `#[repr(transparent)` wrapper of `DeviceId::RawType` and does not
62+
// add additional invariants, so it's safe to transmute to `DeviceId`.
63+
let id = unsafe {
64+
core::mem::transmute::<&<DeviceId as RawDeviceId>::RawType, &DeviceId>(raw_id)
65+
};
66+
let info = T::ID_TABLE.info(index as _);
67+
68+
match T::probe(&mut pdev, id, info) {
69+
Ok(data) => {
70+
// Let the `struct pci_dev` own a reference of the driver's private data.
71+
// SAFETY: By the type invariant `pdev.as_raw` returns a valid pointer to a
72+
// `struct pci_dev`.
73+
unsafe { bindings::pci_set_drvdata(pdev.as_raw(), data.into_foreign() as _) };
74+
}
75+
Err(err) => return Error::to_errno(err),
76+
}
77+
78+
0
79+
}
80+
81+
extern "C" fn remove_callback(pdev: *mut bindings::pci_dev) {
82+
// SAFETY: The PCI core only ever calls the remove callback with a valid `pdev`. `ptr`
83+
// points to a valid reference of the driver's private data; it was set by
84+
// `Adapter::probe_callback`.
85+
let _ = unsafe {
86+
let ptr = bindings::pci_get_drvdata(pdev);
87+
88+
KBox::<T>::from_foreign(ptr)
89+
};
90+
}
91+
}
92+
93+
/// Declares a kernel module that exposes a single PCI driver.
94+
///
95+
/// # Example
96+
///
97+
///```ignore
98+
/// kernel::module_pci_driver! {
99+
/// type: MyDriver,
100+
/// name: "Module name",
101+
/// author: "Author name",
102+
/// description: "Description",
103+
/// license: "GPL v2",
104+
/// }
105+
///```
106+
#[macro_export]
107+
macro_rules! module_pci_driver {
108+
($($f:tt)*) => {
109+
$crate::module_driver!(<T>, $crate::pci::Adapter<T>, { $($f)* });
110+
};
111+
}
112+
113+
/// Abstraction for bindings::pci_device_id.
114+
#[repr(transparent)]
115+
#[derive(Clone, Copy)]
116+
pub struct DeviceId(bindings::pci_device_id);
117+
118+
impl DeviceId {
119+
const PCI_ANY_ID: u32 = !0;
120+
121+
/// PCI_DEVICE macro.
122+
pub const fn new(vendor: u32, device: u32) -> Self {
123+
Self(bindings::pci_device_id {
124+
vendor,
125+
device,
126+
subvendor: DeviceId::PCI_ANY_ID,
127+
subdevice: DeviceId::PCI_ANY_ID,
128+
class: 0,
129+
class_mask: 0,
130+
driver_data: 0,
131+
override_only: 0,
132+
})
133+
}
134+
135+
/// PCI_DEVICE_CLASS macro.
136+
pub const fn with_class(class: u32, class_mask: u32) -> Self {
137+
Self(bindings::pci_device_id {
138+
vendor: DeviceId::PCI_ANY_ID,
139+
device: DeviceId::PCI_ANY_ID,
140+
subvendor: DeviceId::PCI_ANY_ID,
141+
subdevice: DeviceId::PCI_ANY_ID,
142+
class,
143+
class_mask,
144+
driver_data: 0,
145+
override_only: 0,
146+
})
147+
}
148+
}
149+
150+
// Allow drivers R/O access to the fields of `pci_device_id`; should we prefer accessor functions
151+
// to void exposing C structure fields?
152+
impl Deref for DeviceId {
153+
type Target = bindings::pci_device_id;
154+
155+
fn deref(&self) -> &Self::Target {
156+
&self.0
157+
}
158+
}
159+
160+
// SAFETY:
161+
// * `DeviceId` is a `#[repr(transparent)` wrapper of `pci_device_id` and does not add
162+
// additional invariants, so it's safe to transmute to `RawType`.
163+
// * `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field.
164+
unsafe impl RawDeviceId for DeviceId {
165+
type RawType = bindings::pci_device_id;
166+
167+
const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::pci_device_id, driver_data);
168+
}
169+
170+
/// IdTable type for PCI
171+
pub type IdTable<T> = &'static dyn kernel::device_id::IdTable<DeviceId, T>;
172+
173+
/// The PCI driver trait.
174+
///
175+
/// # Example
176+
///
177+
///```
178+
/// # use kernel::{bindings, device_id::IdArray, pci, sync::Arc};
179+
///
180+
/// struct MyDriver;
181+
/// struct MyDeviceData;
182+
///
183+
/// impl pci::Driver for MyDriver {
184+
/// type IdInfo = ();
185+
///
186+
/// const ID_TABLE: pci::IdTable<Self::IdInfo> = &IdArray::new([
187+
/// (pci::DeviceId::new(bindings::PCI_VENDOR_ID_REDHAT, bindings::PCI_ANY_ID as u32), ())
188+
/// ]);
189+
///
190+
/// fn probe(
191+
/// _pdev: &mut pci::Device,
192+
/// _id: &pci::DeviceId,
193+
/// _id_info: &Self::IdInfo,
194+
/// ) -> Result<Pin<KBox<Self>>> {
195+
/// Err(ENODEV)
196+
/// }
197+
/// }
198+
///```
199+
/// Drivers must implement this trait in order to get a PCI driver registered. Please refer to the
200+
/// `Adapter` documentation for an example.
201+
pub trait Driver {
202+
/// The type holding information about each device id supported by the driver.
203+
///
204+
/// TODO: Use associated_type_defaults once stabilized:
205+
///
206+
/// type IdInfo: 'static = ();
207+
type IdInfo: 'static;
208+
209+
/// The table of device ids supported by the driver.
210+
const ID_TABLE: IdTable<Self::IdInfo>;
211+
212+
/// PCI driver probe.
213+
///
214+
/// Called when a new platform device is added or discovered.
215+
/// Implementers should attempt to initialize the device here.
216+
fn probe(dev: &mut Device, id: &DeviceId, id_info: &Self::IdInfo) -> Result<Pin<KBox<Self>>>;
217+
}
218+
219+
/// The PCI device representation.
220+
///
221+
/// A PCI device is based on an always reference counted `device:Device` instance. Cloning a PCI
222+
/// device, hence, also increments the base device' reference count.
223+
#[derive(Clone)]
224+
pub struct Device(ARef<device::Device>);
225+
226+
impl Device {
227+
/// Create a PCI Device instance from an existing `device::Device`.
228+
///
229+
/// # Safety
230+
///
231+
/// `dev` must be an `ARef<device::Device>` whose underlying `bindings::device` is a member of
232+
/// a `bindings::pci_dev`.
233+
pub unsafe fn from_dev(dev: ARef<device::Device>) -> Self {
234+
Self(dev)
235+
}
236+
237+
fn as_raw(&self) -> *mut bindings::pci_dev {
238+
// SAFETY: By the type invariant `self.0.as_raw` is a pointer to the `struct device`
239+
// embedded in `struct pci_dev`.
240+
unsafe { container_of!(self.0.as_raw(), bindings::pci_dev, dev) as _ }
241+
}
242+
243+
/// Enable memory resources for this device.
244+
pub fn enable_device_mem(&self) -> Result {
245+
// SAFETY: `self.as_raw` is guaranteed to be a pointer to a valid `struct pci_dev`.
246+
let ret = unsafe { bindings::pci_enable_device_mem(self.as_raw()) };
247+
if ret != 0 {
248+
Err(Error::from_errno(ret))
249+
} else {
250+
Ok(())
251+
}
252+
}
253+
254+
/// Enable bus-mastering for this device.
255+
pub fn set_master(&self) {
256+
// SAFETY: `self.as_raw` is guaranteed to be a pointer to a valid `struct pci_dev`.
257+
unsafe { bindings::pci_set_master(self.as_raw()) };
258+
}
259+
}
260+
261+
impl AsRef<device::Device> for Device {
262+
fn as_ref(&self) -> &device::Device {
263+
&self.0
264+
}
265+
}

0 commit comments

Comments
 (0)