···88 bindings, container_of, device,99 device::Bound,1010 device_id::{RawDeviceId, RawDeviceIdIndex},1111- devres::{self, Devres},1212- driver,1111+ devres, driver,1312 error::{from_result, to_result, Result},1414- io::{Io, IoRaw},1513 irq::{self, IrqRequest},1614 str::CStr,1715 sync::aref::ARef,···1820};1921use core::{2022 marker::PhantomData,2121- ops::{Deref, RangeInclusive},2323+ ops::RangeInclusive,2224 ptr::{addr_of_mut, NonNull},2325};2426use kernel::prelude::*;25272628mod id;2929+mod io;27302831pub use self::id::{Class, ClassMask, Vendor};3232+pub use self::io::Bar;29333034/// IRQ type flags for PCI interrupt allocation.3135#[derive(Debug, Clone, Copy)]···358358 PhantomData<Ctx>,359359);360360361361-/// A PCI BAR to perform I/O-Operations on.362362-///363363-/// # Invariants364364-///365365-/// `Bar` always holds an `IoRaw` inststance that holds a valid pointer to the start of the I/O366366-/// memory mapped PCI bar and its size.367367-pub struct Bar<const SIZE: usize = 0> {368368- pdev: ARef<Device>,369369- io: IoRaw<SIZE>,370370- num: i32,371371-}372372-373373-impl<const SIZE: usize> Bar<SIZE> {374374- fn new(pdev: &Device, num: u32, name: &CStr) -> Result<Self> {375375- let len = pdev.resource_len(num)?;376376- if len == 0 {377377- return Err(ENOMEM);378378- }379379-380380- // Convert to `i32`, since that's what all the C bindings use.381381- let num = i32::try_from(num)?;382382-383383- // SAFETY:384384- // `pdev` is valid by the invariants of `Device`.385385- // `num` is checked for validity by a previous call to `Device::resource_len`.386386- // `name` is always valid.387387- let ret = unsafe { bindings::pci_request_region(pdev.as_raw(), num, name.as_char_ptr()) };388388- if ret != 0 {389389- return Err(EBUSY);390390- }391391-392392- // SAFETY:393393- // `pdev` is valid by the invariants of `Device`.394394- // `num` is checked for validity by a previous call to `Device::resource_len`.395395- // `name` is always valid.396396- let ioptr: usize = unsafe { bindings::pci_iomap(pdev.as_raw(), num, 0) } as usize;397397- if ioptr == 0 {398398- // SAFETY:399399- // `pdev` valid by the invariants of `Device`.400400- // `num` is checked for validity by a previous call to `Device::resource_len`.401401- unsafe { bindings::pci_release_region(pdev.as_raw(), num) };402402- return Err(ENOMEM);403403- }404404-405405- let io = match IoRaw::new(ioptr, len as usize) {406406- Ok(io) => io,407407- Err(err) => {408408- // SAFETY:409409- // `pdev` is valid by the invariants of `Device`.410410- // `ioptr` is guaranteed to be the start of a valid I/O mapped memory region.411411- // `num` is checked for validity by a previous call to `Device::resource_len`.412412- unsafe { Self::do_release(pdev, ioptr, num) };413413- return Err(err);414414- }415415- };416416-417417- Ok(Bar {418418- pdev: pdev.into(),419419- io,420420- num,421421- })422422- }423423-424424- /// # Safety425425- ///426426- /// `ioptr` must be a valid pointer to the memory mapped PCI bar number `num`.427427- unsafe fn do_release(pdev: &Device, ioptr: usize, num: i32) {428428- // SAFETY:429429- // `pdev` is valid by the invariants of `Device`.430430- // `ioptr` is valid by the safety requirements.431431- // `num` is valid by the safety requirements.432432- unsafe {433433- bindings::pci_iounmap(pdev.as_raw(), ioptr as *mut c_void);434434- bindings::pci_release_region(pdev.as_raw(), num);435435- }436436- }437437-438438- fn release(&self) {439439- // SAFETY: The safety requirements are guaranteed by the type invariant of `self.pdev`.440440- unsafe { Self::do_release(&self.pdev, self.io.addr(), self.num) };441441- }442442-}443443-444444-impl Bar {445445- #[inline]446446- fn index_is_valid(index: u32) -> bool {447447- // A `struct pci_dev` owns an array of resources with at most `PCI_NUM_RESOURCES` entries.448448- index < bindings::PCI_NUM_RESOURCES449449- }450450-}451451-452452-impl<const SIZE: usize> Drop for Bar<SIZE> {453453- fn drop(&mut self) {454454- self.release();455455- }456456-}457457-458458-impl<const SIZE: usize> Deref for Bar<SIZE> {459459- type Target = Io<SIZE>;460460-461461- fn deref(&self) -> &Self::Target {462462- // SAFETY: By the type invariant of `Self`, the MMIO range in `self.io` is properly mapped.463463- unsafe { Io::from_raw(&self.io) }464464- }465465-}466466-467361impl<Ctx: device::DeviceContext> Device<Ctx> {468362 #[inline]469363 fn as_raw(&self) -> *mut bindings::pci_dev {···564670}565671566672impl Device<device::Bound> {567567- /// Mapps an entire PCI-BAR after performing a region-request on it. I/O operation bound checks568568- /// can be performed on compile time for offsets (plus the requested type size) < SIZE.569569- pub fn iomap_region_sized<'a, const SIZE: usize>(570570- &'a self,571571- bar: u32,572572- name: &'a CStr,573573- ) -> impl PinInit<Devres<Bar<SIZE>>, Error> + 'a {574574- Devres::new(self.as_ref(), Bar::<SIZE>::new(self, bar, name))575575- }576576-577577- /// Mapps an entire PCI-BAR after performing a region-request on it.578578- pub fn iomap_region<'a>(579579- &'a self,580580- bar: u32,581581- name: &'a CStr,582582- ) -> impl PinInit<Devres<Bar>, Error> + 'a {583583- self.iomap_region_sized::<0>(bar, name)584584- }585585-586673 /// Returns a [`kernel::irq::Registration`] for the given IRQ vector.587674 pub fn request_irq<'a, T: crate::irq::Handler + 'static>(588675 &'a self,
+141
rust/kernel/pci/io.rs
···11+// SPDX-License-Identifier: GPL-2.022+33+//! PCI memory-mapped I/O infrastructure.44+55+use super::Device;66+use crate::{77+ bindings, device,88+ devres::Devres,99+ io::{Io, IoRaw},1010+ str::CStr,1111+ sync::aref::ARef,1212+};1313+use core::ops::Deref;1414+use kernel::prelude::*;1515+1616+/// A PCI BAR to perform I/O-Operations on.1717+///1818+/// # Invariants1919+///2020+/// `Bar` always holds an `IoRaw` inststance that holds a valid pointer to the start of the I/O2121+/// memory mapped PCI bar and its size.2222+pub struct Bar<const SIZE: usize = 0> {2323+ pdev: ARef<Device>,2424+ io: IoRaw<SIZE>,2525+ num: i32,2626+}2727+2828+impl<const SIZE: usize> Bar<SIZE> {2929+ pub(super) fn new(pdev: &Device, num: u32, name: &CStr) -> Result<Self> {3030+ let len = pdev.resource_len(num)?;3131+ if len == 0 {3232+ return Err(ENOMEM);3333+ }3434+3535+ // Convert to `i32`, since that's what all the C bindings use.3636+ let num = i32::try_from(num)?;3737+3838+ // SAFETY:3939+ // `pdev` is valid by the invariants of `Device`.4040+ // `num` is checked for validity by a previous call to `Device::resource_len`.4141+ // `name` is always valid.4242+ let ret = unsafe { bindings::pci_request_region(pdev.as_raw(), num, name.as_char_ptr()) };4343+ if ret != 0 {4444+ return Err(EBUSY);4545+ }4646+4747+ // SAFETY:4848+ // `pdev` is valid by the invariants of `Device`.4949+ // `num` is checked for validity by a previous call to `Device::resource_len`.5050+ // `name` is always valid.5151+ let ioptr: usize = unsafe { bindings::pci_iomap(pdev.as_raw(), num, 0) } as usize;5252+ if ioptr == 0 {5353+ // SAFETY:5454+ // `pdev` valid by the invariants of `Device`.5555+ // `num` is checked for validity by a previous call to `Device::resource_len`.5656+ unsafe { bindings::pci_release_region(pdev.as_raw(), num) };5757+ return Err(ENOMEM);5858+ }5959+6060+ let io = match IoRaw::new(ioptr, len as usize) {6161+ Ok(io) => io,6262+ Err(err) => {6363+ // SAFETY:6464+ // `pdev` is valid by the invariants of `Device`.6565+ // `ioptr` is guaranteed to be the start of a valid I/O mapped memory region.6666+ // `num` is checked for validity by a previous call to `Device::resource_len`.6767+ unsafe { Self::do_release(pdev, ioptr, num) };6868+ return Err(err);6969+ }7070+ };7171+7272+ Ok(Bar {7373+ pdev: pdev.into(),7474+ io,7575+ num,7676+ })7777+ }7878+7979+ /// # Safety8080+ ///8181+ /// `ioptr` must be a valid pointer to the memory mapped PCI bar number `num`.8282+ unsafe fn do_release(pdev: &Device, ioptr: usize, num: i32) {8383+ // SAFETY:8484+ // `pdev` is valid by the invariants of `Device`.8585+ // `ioptr` is valid by the safety requirements.8686+ // `num` is valid by the safety requirements.8787+ unsafe {8888+ bindings::pci_iounmap(pdev.as_raw(), ioptr as *mut c_void);8989+ bindings::pci_release_region(pdev.as_raw(), num);9090+ }9191+ }9292+9393+ fn release(&self) {9494+ // SAFETY: The safety requirements are guaranteed by the type invariant of `self.pdev`.9595+ unsafe { Self::do_release(&self.pdev, self.io.addr(), self.num) };9696+ }9797+}9898+9999+impl Bar {100100+ #[inline]101101+ pub(super) fn index_is_valid(index: u32) -> bool {102102+ // A `struct pci_dev` owns an array of resources with at most `PCI_NUM_RESOURCES` entries.103103+ index < bindings::PCI_NUM_RESOURCES104104+ }105105+}106106+107107+impl<const SIZE: usize> Drop for Bar<SIZE> {108108+ fn drop(&mut self) {109109+ self.release();110110+ }111111+}112112+113113+impl<const SIZE: usize> Deref for Bar<SIZE> {114114+ type Target = Io<SIZE>;115115+116116+ fn deref(&self) -> &Self::Target {117117+ // SAFETY: By the type invariant of `Self`, the MMIO range in `self.io` is properly mapped.118118+ unsafe { Io::from_raw(&self.io) }119119+ }120120+}121121+122122+impl Device<device::Bound> {123123+ /// Mapps an entire PCI-BAR after performing a region-request on it. I/O operation bound checks124124+ /// can be performed on compile time for offsets (plus the requested type size) < SIZE.125125+ pub fn iomap_region_sized<'a, const SIZE: usize>(126126+ &'a self,127127+ bar: u32,128128+ name: &'a CStr,129129+ ) -> impl PinInit<Devres<Bar<SIZE>>, Error> + 'a {130130+ Devres::new(self.as_ref(), Bar::<SIZE>::new(self, bar, name))131131+ }132132+133133+ /// Mapps an entire PCI-BAR after performing a region-request on it.134134+ pub fn iomap_region<'a>(135135+ &'a self,136136+ bar: u32,137137+ name: &'a CStr,138138+ ) -> impl PinInit<Devres<Bar>, Error> + 'a {139139+ self.iomap_region_sized::<0>(bar, name)140140+ }141141+}