diff options
Diffstat (limited to 'rust/kernel/pci.rs')
-rw-r--r-- | rust/kernel/pci.rs | 55 |
1 files changed, 32 insertions, 23 deletions
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index c97d6d470b28..38fc8d5ffbf9 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -6,7 +6,7 @@ use crate::{ alloc::flags::*, - bindings, device, + bindings, container_of, device, device_id::RawDeviceId, devres::Devres, driver, @@ -360,11 +360,13 @@ impl<const SIZE: usize> Deref for Bar<SIZE> { } } -impl Device { +impl<Ctx: device::DeviceContext> Device<Ctx> { fn as_raw(&self) -> *mut bindings::pci_dev { self.0.get() } +} +impl Device { /// Returns the PCI vendor ID. pub fn vendor_id(&self) -> u16 { // SAFETY: `self.as_raw` is a valid pointer to a `struct pci_dev`. @@ -388,7 +390,9 @@ impl Device { // - by its type invariant `self.as_raw` is always a valid pointer to a `struct pci_dev`. Ok(unsafe { bindings::pci_resource_len(self.as_raw(), bar.try_into()?) }) } +} +impl Device<device::Bound> { /// Mapps an entire PCI-BAR after performing a region-request on it. I/O operation bound checks /// can be performed on compile time for offsets (plus the requested type size) < SIZE. pub fn iomap_region_sized<const SIZE: usize>( @@ -422,25 +426,10 @@ impl Device<device::Core> { } } -impl Deref for Device<device::Core> { - type Target = Device; - - fn deref(&self) -> &Self::Target { - let ptr: *const Self = self; - - // CAST: `Device<Ctx>` is a transparent wrapper of `Opaque<bindings::pci_dev>`. - let ptr = ptr.cast::<Device>(); - - // SAFETY: `ptr` was derived from `&self`. - unsafe { &*ptr } - } -} - -impl From<&Device<device::Core>> for ARef<Device> { - fn from(dev: &Device<device::Core>) -> Self { - (&**dev).into() - } -} +// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic +// argument. +kernel::impl_device_context_deref!(unsafe { Device }); +kernel::impl_device_context_into_aref!(Device); // SAFETY: Instances of `Device` are always reference-counted. unsafe impl crate::types::AlwaysRefCounted for Device { @@ -455,8 +444,8 @@ unsafe impl crate::types::AlwaysRefCounted for Device { } } -impl AsRef<device::Device> for Device { - fn as_ref(&self) -> &device::Device { +impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> { + fn as_ref(&self) -> &device::Device<Ctx> { // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid // `struct pci_dev`. let dev = unsafe { addr_of_mut!((*self.as_raw()).dev) }; @@ -466,6 +455,26 @@ impl AsRef<device::Device> for Device { } } +impl<Ctx: device::DeviceContext> TryFrom<&device::Device<Ctx>> for &Device<Ctx> { + type Error = kernel::error::Error; + + fn try_from(dev: &device::Device<Ctx>) -> Result<Self, Self::Error> { + // SAFETY: By the type invariant of `Device`, `dev.as_raw()` is a valid pointer to a + // `struct device`. + if !unsafe { bindings::dev_is_pci(dev.as_raw()) } { + return Err(EINVAL); + } + + // SAFETY: We've just verified that the bus type of `dev` equals `bindings::pci_bus_type`, + // hence `dev` must be embedded in a valid `struct pci_dev` as guaranteed by the + // corresponding C code. + let pdev = unsafe { container_of!(dev.as_raw(), bindings::pci_dev, dev) }; + + // SAFETY: `pdev` is a valid pointer to a `struct pci_dev`. + Ok(unsafe { &*pdev.cast() }) + } +} + // SAFETY: A `Device` is always reference-counted and can be released from any thread. unsafe impl Send for Device {} |