Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

rust: pci: move I/O infrastructure to separate file

Move the PCI I/O infrastructure to a separate sub-module in order to
keep things organized.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>

+145 -129
+4 -129
rust/kernel/pci.rs
··· 8 8 bindings, container_of, device, 9 9 device::Bound, 10 10 device_id::{RawDeviceId, RawDeviceIdIndex}, 11 - devres::{self, Devres}, 12 - driver, 11 + devres, driver, 13 12 error::{from_result, to_result, Result}, 14 - io::{Io, IoRaw}, 15 13 irq::{self, IrqRequest}, 16 14 str::CStr, 17 15 sync::aref::ARef, ··· 18 20 }; 19 21 use core::{ 20 22 marker::PhantomData, 21 - ops::{Deref, RangeInclusive}, 23 + ops::RangeInclusive, 22 24 ptr::{addr_of_mut, NonNull}, 23 25 }; 24 26 use kernel::prelude::*; 25 27 26 28 mod id; 29 + mod io; 27 30 28 31 pub use self::id::{Class, ClassMask, Vendor}; 32 + pub use self::io::Bar; 29 33 30 34 /// IRQ type flags for PCI interrupt allocation. 31 35 #[derive(Debug, Clone, Copy)] ··· 358 358 PhantomData<Ctx>, 359 359 ); 360 360 361 - /// A PCI BAR to perform I/O-Operations on. 362 - /// 363 - /// # Invariants 364 - /// 365 - /// `Bar` always holds an `IoRaw` inststance that holds a valid pointer to the start of the I/O 366 - /// memory mapped PCI bar and its size. 367 - pub struct Bar<const SIZE: usize = 0> { 368 - pdev: ARef<Device>, 369 - io: IoRaw<SIZE>, 370 - num: i32, 371 - } 372 - 373 - impl<const SIZE: usize> Bar<SIZE> { 374 - fn new(pdev: &Device, num: u32, name: &CStr) -> Result<Self> { 375 - let len = pdev.resource_len(num)?; 376 - if len == 0 { 377 - return Err(ENOMEM); 378 - } 379 - 380 - // Convert to `i32`, since that's what all the C bindings use. 381 - let num = i32::try_from(num)?; 382 - 383 - // SAFETY: 384 - // `pdev` is valid by the invariants of `Device`. 385 - // `num` is checked for validity by a previous call to `Device::resource_len`. 386 - // `name` is always valid. 387 - let ret = unsafe { bindings::pci_request_region(pdev.as_raw(), num, name.as_char_ptr()) }; 388 - if ret != 0 { 389 - return Err(EBUSY); 390 - } 391 - 392 - // SAFETY: 393 - // `pdev` is valid by the invariants of `Device`. 394 - // `num` is checked for validity by a previous call to `Device::resource_len`. 395 - // `name` is always valid. 396 - let ioptr: usize = unsafe { bindings::pci_iomap(pdev.as_raw(), num, 0) } as usize; 397 - if ioptr == 0 { 398 - // SAFETY: 399 - // `pdev` valid by the invariants of `Device`. 400 - // `num` is checked for validity by a previous call to `Device::resource_len`. 401 - unsafe { bindings::pci_release_region(pdev.as_raw(), num) }; 402 - return Err(ENOMEM); 403 - } 404 - 405 - let io = match IoRaw::new(ioptr, len as usize) { 406 - Ok(io) => io, 407 - Err(err) => { 408 - // SAFETY: 409 - // `pdev` is valid by the invariants of `Device`. 410 - // `ioptr` is guaranteed to be the start of a valid I/O mapped memory region. 411 - // `num` is checked for validity by a previous call to `Device::resource_len`. 412 - unsafe { Self::do_release(pdev, ioptr, num) }; 413 - return Err(err); 414 - } 415 - }; 416 - 417 - Ok(Bar { 418 - pdev: pdev.into(), 419 - io, 420 - num, 421 - }) 422 - } 423 - 424 - /// # Safety 425 - /// 426 - /// `ioptr` must be a valid pointer to the memory mapped PCI bar number `num`. 427 - unsafe fn do_release(pdev: &Device, ioptr: usize, num: i32) { 428 - // SAFETY: 429 - // `pdev` is valid by the invariants of `Device`. 430 - // `ioptr` is valid by the safety requirements. 431 - // `num` is valid by the safety requirements. 432 - unsafe { 433 - bindings::pci_iounmap(pdev.as_raw(), ioptr as *mut c_void); 434 - bindings::pci_release_region(pdev.as_raw(), num); 435 - } 436 - } 437 - 438 - fn release(&self) { 439 - // SAFETY: The safety requirements are guaranteed by the type invariant of `self.pdev`. 440 - unsafe { Self::do_release(&self.pdev, self.io.addr(), self.num) }; 441 - } 442 - } 443 - 444 - impl Bar { 445 - #[inline] 446 - fn index_is_valid(index: u32) -> bool { 447 - // A `struct pci_dev` owns an array of resources with at most `PCI_NUM_RESOURCES` entries. 448 - index < bindings::PCI_NUM_RESOURCES 449 - } 450 - } 451 - 452 - impl<const SIZE: usize> Drop for Bar<SIZE> { 453 - fn drop(&mut self) { 454 - self.release(); 455 - } 456 - } 457 - 458 - impl<const SIZE: usize> Deref for Bar<SIZE> { 459 - type Target = Io<SIZE>; 460 - 461 - fn deref(&self) -> &Self::Target { 462 - // SAFETY: By the type invariant of `Self`, the MMIO range in `self.io` is properly mapped. 463 - unsafe { Io::from_raw(&self.io) } 464 - } 465 - } 466 - 467 361 impl<Ctx: device::DeviceContext> Device<Ctx> { 468 362 #[inline] 469 363 fn as_raw(&self) -> *mut bindings::pci_dev { ··· 564 670 } 565 671 566 672 impl Device<device::Bound> { 567 - /// Mapps an entire PCI-BAR after performing a region-request on it. I/O operation bound checks 568 - /// can be performed on compile time for offsets (plus the requested type size) < SIZE. 569 - pub fn iomap_region_sized<'a, const SIZE: usize>( 570 - &'a self, 571 - bar: u32, 572 - name: &'a CStr, 573 - ) -> impl PinInit<Devres<Bar<SIZE>>, Error> + 'a { 574 - Devres::new(self.as_ref(), Bar::<SIZE>::new(self, bar, name)) 575 - } 576 - 577 - /// Mapps an entire PCI-BAR after performing a region-request on it. 578 - pub fn iomap_region<'a>( 579 - &'a self, 580 - bar: u32, 581 - name: &'a CStr, 582 - ) -> impl PinInit<Devres<Bar>, Error> + 'a { 583 - self.iomap_region_sized::<0>(bar, name) 584 - } 585 - 586 673 /// Returns a [`kernel::irq::Registration`] for the given IRQ vector. 587 674 pub fn request_irq<'a, T: crate::irq::Handler + 'static>( 588 675 &'a self,
+141
rust/kernel/pci/io.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! PCI memory-mapped I/O infrastructure. 4 + 5 + use super::Device; 6 + use crate::{ 7 + bindings, device, 8 + devres::Devres, 9 + io::{Io, IoRaw}, 10 + str::CStr, 11 + sync::aref::ARef, 12 + }; 13 + use core::ops::Deref; 14 + use kernel::prelude::*; 15 + 16 + /// A PCI BAR to perform I/O-Operations on. 17 + /// 18 + /// # Invariants 19 + /// 20 + /// `Bar` always holds an `IoRaw` inststance that holds a valid pointer to the start of the I/O 21 + /// memory mapped PCI bar and its size. 22 + pub struct Bar<const SIZE: usize = 0> { 23 + pdev: ARef<Device>, 24 + io: IoRaw<SIZE>, 25 + num: i32, 26 + } 27 + 28 + impl<const SIZE: usize> Bar<SIZE> { 29 + pub(super) fn new(pdev: &Device, num: u32, name: &CStr) -> Result<Self> { 30 + let len = pdev.resource_len(num)?; 31 + if len == 0 { 32 + return Err(ENOMEM); 33 + } 34 + 35 + // Convert to `i32`, since that's what all the C bindings use. 36 + let num = i32::try_from(num)?; 37 + 38 + // SAFETY: 39 + // `pdev` is valid by the invariants of `Device`. 40 + // `num` is checked for validity by a previous call to `Device::resource_len`. 41 + // `name` is always valid. 42 + let ret = unsafe { bindings::pci_request_region(pdev.as_raw(), num, name.as_char_ptr()) }; 43 + if ret != 0 { 44 + return Err(EBUSY); 45 + } 46 + 47 + // SAFETY: 48 + // `pdev` is valid by the invariants of `Device`. 49 + // `num` is checked for validity by a previous call to `Device::resource_len`. 50 + // `name` is always valid. 51 + let ioptr: usize = unsafe { bindings::pci_iomap(pdev.as_raw(), num, 0) } as usize; 52 + if ioptr == 0 { 53 + // SAFETY: 54 + // `pdev` valid by the invariants of `Device`. 55 + // `num` is checked for validity by a previous call to `Device::resource_len`. 56 + unsafe { bindings::pci_release_region(pdev.as_raw(), num) }; 57 + return Err(ENOMEM); 58 + } 59 + 60 + let io = match IoRaw::new(ioptr, len as usize) { 61 + Ok(io) => io, 62 + Err(err) => { 63 + // SAFETY: 64 + // `pdev` is valid by the invariants of `Device`. 65 + // `ioptr` is guaranteed to be the start of a valid I/O mapped memory region. 66 + // `num` is checked for validity by a previous call to `Device::resource_len`. 67 + unsafe { Self::do_release(pdev, ioptr, num) }; 68 + return Err(err); 69 + } 70 + }; 71 + 72 + Ok(Bar { 73 + pdev: pdev.into(), 74 + io, 75 + num, 76 + }) 77 + } 78 + 79 + /// # Safety 80 + /// 81 + /// `ioptr` must be a valid pointer to the memory mapped PCI bar number `num`. 82 + unsafe fn do_release(pdev: &Device, ioptr: usize, num: i32) { 83 + // SAFETY: 84 + // `pdev` is valid by the invariants of `Device`. 85 + // `ioptr` is valid by the safety requirements. 86 + // `num` is valid by the safety requirements. 87 + unsafe { 88 + bindings::pci_iounmap(pdev.as_raw(), ioptr as *mut c_void); 89 + bindings::pci_release_region(pdev.as_raw(), num); 90 + } 91 + } 92 + 93 + fn release(&self) { 94 + // SAFETY: The safety requirements are guaranteed by the type invariant of `self.pdev`. 95 + unsafe { Self::do_release(&self.pdev, self.io.addr(), self.num) }; 96 + } 97 + } 98 + 99 + impl Bar { 100 + #[inline] 101 + pub(super) fn index_is_valid(index: u32) -> bool { 102 + // A `struct pci_dev` owns an array of resources with at most `PCI_NUM_RESOURCES` entries. 103 + index < bindings::PCI_NUM_RESOURCES 104 + } 105 + } 106 + 107 + impl<const SIZE: usize> Drop for Bar<SIZE> { 108 + fn drop(&mut self) { 109 + self.release(); 110 + } 111 + } 112 + 113 + impl<const SIZE: usize> Deref for Bar<SIZE> { 114 + type Target = Io<SIZE>; 115 + 116 + fn deref(&self) -> &Self::Target { 117 + // SAFETY: By the type invariant of `Self`, the MMIO range in `self.io` is properly mapped. 118 + unsafe { Io::from_raw(&self.io) } 119 + } 120 + } 121 + 122 + impl Device<device::Bound> { 123 + /// Mapps an entire PCI-BAR after performing a region-request on it. I/O operation bound checks 124 + /// can be performed on compile time for offsets (plus the requested type size) < SIZE. 125 + pub fn iomap_region_sized<'a, const SIZE: usize>( 126 + &'a self, 127 + bar: u32, 128 + name: &'a CStr, 129 + ) -> impl PinInit<Devres<Bar<SIZE>>, Error> + 'a { 130 + Devres::new(self.as_ref(), Bar::<SIZE>::new(self, bar, name)) 131 + } 132 + 133 + /// Mapps an entire PCI-BAR after performing a region-request on it. 134 + pub fn iomap_region<'a>( 135 + &'a self, 136 + bar: u32, 137 + name: &'a CStr, 138 + ) -> impl PinInit<Devres<Bar>, Error> + 'a { 139 + self.iomap_region_sized::<0>(bar, name) 140 + } 141 + }