···6677use crate::{88 bindings, container_of, device,99- device::Bound,109 device_id::{RawDeviceId, RawDeviceIdIndex},1111- devres, driver,1010+ driver,1211 error::{from_result, to_result, Result},1313- irq::{self, IrqRequest},1412 str::CStr,1515- sync::aref::ARef,1613 types::Opaque,1714 ThisModule,1815};1916use core::{2017 marker::PhantomData,2121- ops::RangeInclusive,2218 ptr::{addr_of_mut, NonNull},2319};2420use kernel::prelude::*;25212622mod id;2723mod io;2424+mod irq;28252926pub use self::id::{Class, ClassMask, Vendor};3027pub use self::io::Bar;3131-3232-/// IRQ type flags for PCI interrupt allocation.3333-#[derive(Debug, Clone, Copy)]3434-pub enum IrqType {3535- /// INTx interrupts.3636- Intx,3737- /// Message Signaled Interrupts (MSI).3838- Msi,3939- /// Extended Message Signaled Interrupts (MSI-X).4040- MsiX,4141-}4242-4343-impl IrqType {4444- /// Convert to the corresponding kernel flags.4545- const fn as_raw(self) -> u32 {4646- match self {4747- IrqType::Intx => bindings::PCI_IRQ_INTX,4848- IrqType::Msi => bindings::PCI_IRQ_MSI,4949- IrqType::MsiX => bindings::PCI_IRQ_MSIX,5050- }5151- }5252-}5353-5454-/// Set of IRQ types that can be used for PCI interrupt allocation.5555-#[derive(Debug, Clone, Copy, Default)]5656-pub struct IrqTypes(u32);5757-5858-impl IrqTypes {5959- /// Create a set containing all IRQ types (MSI-X, MSI, and Legacy).6060- pub const fn all() -> Self {6161- Self(bindings::PCI_IRQ_ALL_TYPES)6262- }6363-6464- /// Build a set of IRQ types.6565- ///6666- /// # Examples6767- ///6868- /// ```ignore6969- /// // Create a set with only MSI and MSI-X (no legacy interrupts).7070- /// let msi_only = IrqTypes::default()7171- /// .with(IrqType::Msi)7272- /// .with(IrqType::MsiX);7373- /// ```7474- pub const fn with(self, irq_type: IrqType) -> Self {7575- Self(self.0 | irq_type.as_raw())7676- }7777-7878- /// Get the raw flags value.7979- const fn as_raw(self) -> u32 {8080- self.08181- }8282-}2828+pub use self::irq::{IrqType, IrqTypes, IrqVector};83298430/// An adapter for the registration of PCI drivers.8531pub struct Adapter<T: Driver>(T);···406460 pub fn pci_class(&self) -> Class {407461 // SAFETY: `self.as_raw` is a valid pointer to a `struct pci_dev`.408462 Class::from_raw(unsafe { (*self.as_raw()).class })409409- }410410-}411411-412412-/// Represents an allocated IRQ vector for a specific PCI device.413413-///414414-/// This type ties an IRQ vector to the device it was allocated for,415415-/// ensuring the vector is only used with the correct device.416416-#[derive(Clone, Copy)]417417-pub struct IrqVector<'a> {418418- dev: &'a Device<Bound>,419419- index: u32,420420-}421421-422422-impl<'a> IrqVector<'a> {423423- /// Creates a new [`IrqVector`] for the given device and index.424424- ///425425- /// # Safety426426- ///427427- /// - `index` must be a valid IRQ vector index for `dev`.428428- /// - `dev` must point to a [`Device`] that has successfully allocated IRQ vectors.429429- unsafe fn new(dev: &'a Device<Bound>, index: u32) -> Self {430430- Self { dev, index }431431- }432432-433433- /// Returns the raw vector index.434434- fn index(&self) -> u32 {435435- self.index436436- }437437-}438438-439439-impl<'a> TryInto<IrqRequest<'a>> for IrqVector<'a> {440440- type Error = Error;441441-442442- fn try_into(self) -> Result<IrqRequest<'a>> {443443- // SAFETY: `self.as_raw` returns a valid pointer to a `struct pci_dev`.444444- let irq = unsafe { bindings::pci_irq_vector(self.dev.as_raw(), self.index()) };445445- if irq < 0 {446446- return Err(crate::error::Error::from_errno(irq));447447- }448448- // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self`.449449- Ok(unsafe { IrqRequest::new(self.dev.as_ref(), irq as u32) })450450- }451451-}452452-453453-/// Represents an IRQ vector allocation for a PCI device.454454-///455455-/// This type ensures that IRQ vectors are properly allocated and freed by456456-/// tying the allocation to the lifetime of this registration object.457457-///458458-/// # Invariants459459-///460460-/// The [`Device`] has successfully allocated IRQ vectors.461461-struct IrqVectorRegistration {462462- dev: ARef<Device>,463463-}464464-465465-impl IrqVectorRegistration {466466- /// Allocate and register IRQ vectors for the given PCI device.467467- ///468468- /// Allocates IRQ vectors and registers them with devres for automatic cleanup.469469- /// Returns a range of valid IRQ vectors.470470- fn register<'a>(471471- dev: &'a Device<Bound>,472472- min_vecs: u32,473473- max_vecs: u32,474474- irq_types: IrqTypes,475475- ) -> Result<RangeInclusive<IrqVector<'a>>> {476476- // SAFETY:477477- // - `dev.as_raw()` is guaranteed to be a valid pointer to a `struct pci_dev`478478- // by the type invariant of `Device`.479479- // - `pci_alloc_irq_vectors` internally validates all other parameters480480- // and returns error codes.481481- let ret = unsafe {482482- bindings::pci_alloc_irq_vectors(dev.as_raw(), min_vecs, max_vecs, irq_types.as_raw())483483- };484484-485485- to_result(ret)?;486486- let count = ret as u32;487487-488488- // SAFETY:489489- // - `pci_alloc_irq_vectors` returns the number of allocated vectors on success.490490- // - Vectors are 0-based, so valid indices are [0, count-1].491491- // - `pci_alloc_irq_vectors` guarantees `count >= min_vecs > 0`, so both `0` and492492- // `count - 1` are valid IRQ vector indices for `dev`.493493- let range = unsafe { IrqVector::new(dev, 0)..=IrqVector::new(dev, count - 1) };494494-495495- // INVARIANT: The IRQ vector allocation for `dev` above was successful.496496- let irq_vecs = Self { dev: dev.into() };497497- devres::register(dev.as_ref(), irq_vecs, GFP_KERNEL)?;498498-499499- Ok(range)500500- }501501-}502502-503503-impl Drop for IrqVectorRegistration {504504- fn drop(&mut self) {505505- // SAFETY:506506- // - By the type invariant, `self.dev.as_raw()` is a valid pointer to a `struct pci_dev`.507507- // - `self.dev` has successfully allocated IRQ vectors.508508- unsafe { bindings::pci_free_irq_vectors(self.dev.as_raw()) };509509- }510510-}511511-512512-impl Device<device::Bound> {513513- /// Returns a [`kernel::irq::Registration`] for the given IRQ vector.514514- pub fn request_irq<'a, T: crate::irq::Handler + 'static>(515515- &'a self,516516- vector: IrqVector<'a>,517517- flags: irq::Flags,518518- name: &'static CStr,519519- handler: impl PinInit<T, Error> + 'a,520520- ) -> Result<impl PinInit<irq::Registration<T>, Error> + 'a> {521521- let request = vector.try_into()?;522522-523523- Ok(irq::Registration::<T>::new(request, flags, name, handler))524524- }525525-526526- /// Returns a [`kernel::irq::ThreadedRegistration`] for the given IRQ vector.527527- pub fn request_threaded_irq<'a, T: crate::irq::ThreadedHandler + 'static>(528528- &'a self,529529- vector: IrqVector<'a>,530530- flags: irq::Flags,531531- name: &'static CStr,532532- handler: impl PinInit<T, Error> + 'a,533533- ) -> Result<impl PinInit<irq::ThreadedRegistration<T>, Error> + 'a> {534534- let request = vector.try_into()?;535535-536536- Ok(irq::ThreadedRegistration::<T>::new(537537- request, flags, name, handler,538538- ))539539- }540540-541541- /// Allocate IRQ vectors for this PCI device with automatic cleanup.542542- ///543543- /// Allocates between `min_vecs` and `max_vecs` interrupt vectors for the device.544544- /// The allocation will use MSI-X, MSI, or legacy interrupts based on the `irq_types`545545- /// parameter and hardware capabilities. When multiple types are specified, the kernel546546- /// will try them in order of preference: MSI-X first, then MSI, then legacy interrupts.547547- ///548548- /// The allocated vectors are automatically freed when the device is unbound, using the549549- /// devres (device resource management) system.550550- ///551551- /// # Arguments552552- ///553553- /// * `min_vecs` - Minimum number of vectors required.554554- /// * `max_vecs` - Maximum number of vectors to allocate.555555- /// * `irq_types` - Types of interrupts that can be used.556556- ///557557- /// # Returns558558- ///559559- /// Returns a range of IRQ vectors that were successfully allocated, or an error if the560560- /// allocation fails or cannot meet the minimum requirement.561561- ///562562- /// # Examples563563- ///564564- /// ```565565- /// # use kernel::{ device::Bound, pci};566566- /// # fn no_run(dev: &pci::Device<Bound>) -> Result {567567- /// // Allocate using any available interrupt type in the order mentioned above.568568- /// let vectors = dev.alloc_irq_vectors(1, 32, pci::IrqTypes::all())?;569569- ///570570- /// // Allocate MSI or MSI-X only (no legacy interrupts).571571- /// let msi_only = pci::IrqTypes::default()572572- /// .with(pci::IrqType::Msi)573573- /// .with(pci::IrqType::MsiX);574574- /// let vectors = dev.alloc_irq_vectors(4, 16, msi_only)?;575575- /// # Ok(())576576- /// # }577577- /// ```578578- pub fn alloc_irq_vectors(579579- &self,580580- min_vecs: u32,581581- max_vecs: u32,582582- irq_types: IrqTypes,583583- ) -> Result<RangeInclusive<IrqVector<'_>>> {584584- IrqVectorRegistration::register(self, min_vecs, max_vecs, irq_types)585463 }586464}587465
+244
rust/kernel/pci/irq.rs
···11+// SPDX-License-Identifier: GPL-2.022+33+//! PCI interrupt infrastructure.44+55+use super::Device;66+use crate::{77+ bindings, device,88+ device::Bound,99+ devres,1010+ error::{to_result, Result},1111+ irq::{self, IrqRequest},1212+ str::CStr,1313+ sync::aref::ARef,1414+};1515+use core::ops::RangeInclusive;1616+use kernel::prelude::*;1717+1818+/// IRQ type flags for PCI interrupt allocation.1919+#[derive(Debug, Clone, Copy)]2020+pub enum IrqType {2121+ /// INTx interrupts.2222+ Intx,2323+ /// Message Signaled Interrupts (MSI).2424+ Msi,2525+ /// Extended Message Signaled Interrupts (MSI-X).2626+ MsiX,2727+}2828+2929+impl IrqType {3030+ /// Convert to the corresponding kernel flags.3131+ const fn as_raw(self) -> u32 {3232+ match self {3333+ IrqType::Intx => bindings::PCI_IRQ_INTX,3434+ IrqType::Msi => bindings::PCI_IRQ_MSI,3535+ IrqType::MsiX => bindings::PCI_IRQ_MSIX,3636+ }3737+ }3838+}3939+4040+/// Set of IRQ types that can be used for PCI interrupt allocation.4141+#[derive(Debug, Clone, Copy, Default)]4242+pub struct IrqTypes(u32);4343+4444+impl IrqTypes {4545+ /// Create a set containing all IRQ types (MSI-X, MSI, and Legacy).4646+ pub const fn all() -> Self {4747+ Self(bindings::PCI_IRQ_ALL_TYPES)4848+ }4949+5050+ /// Build a set of IRQ types.5151+ ///5252+ /// # Examples5353+ ///5454+ /// ```ignore5555+ /// // Create a set with only MSI and MSI-X (no legacy interrupts).5656+ /// let msi_only = IrqTypes::default()5757+ /// .with(IrqType::Msi)5858+ /// .with(IrqType::MsiX);5959+ /// ```6060+ pub const fn with(self, irq_type: IrqType) -> Self {6161+ Self(self.0 | irq_type.as_raw())6262+ }6363+6464+ /// Get the raw flags value.6565+ const fn as_raw(self) -> u32 {6666+ self.06767+ }6868+}6969+7070+/// Represents an allocated IRQ vector for a specific PCI device.7171+///7272+/// This type ties an IRQ vector to the device it was allocated for,7373+/// ensuring the vector is only used with the correct device.7474+#[derive(Clone, Copy)]7575+pub struct IrqVector<'a> {7676+ dev: &'a Device<Bound>,7777+ index: u32,7878+}7979+8080+impl<'a> IrqVector<'a> {8181+ /// Creates a new [`IrqVector`] for the given device and index.8282+ ///8383+ /// # Safety8484+ ///8585+ /// - `index` must be a valid IRQ vector index for `dev`.8686+ /// - `dev` must point to a [`Device`] that has successfully allocated IRQ vectors.8787+ unsafe fn new(dev: &'a Device<Bound>, index: u32) -> Self {8888+ Self { dev, index }8989+ }9090+9191+ /// Returns the raw vector index.9292+ fn index(&self) -> u32 {9393+ self.index9494+ }9595+}9696+9797+impl<'a> TryInto<IrqRequest<'a>> for IrqVector<'a> {9898+ type Error = Error;9999+100100+ fn try_into(self) -> Result<IrqRequest<'a>> {101101+ // SAFETY: `self.as_raw` returns a valid pointer to a `struct pci_dev`.102102+ let irq = unsafe { bindings::pci_irq_vector(self.dev.as_raw(), self.index()) };103103+ if irq < 0 {104104+ return Err(crate::error::Error::from_errno(irq));105105+ }106106+ // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self`.107107+ Ok(unsafe { IrqRequest::new(self.dev.as_ref(), irq as u32) })108108+ }109109+}110110+111111+/// Represents an IRQ vector allocation for a PCI device.112112+///113113+/// This type ensures that IRQ vectors are properly allocated and freed by114114+/// tying the allocation to the lifetime of this registration object.115115+///116116+/// # Invariants117117+///118118+/// The [`Device`] has successfully allocated IRQ vectors.119119+struct IrqVectorRegistration {120120+ dev: ARef<Device>,121121+}122122+123123+impl IrqVectorRegistration {124124+ /// Allocate and register IRQ vectors for the given PCI device.125125+ ///126126+ /// Allocates IRQ vectors and registers them with devres for automatic cleanup.127127+ /// Returns a range of valid IRQ vectors.128128+ fn register<'a>(129129+ dev: &'a Device<Bound>,130130+ min_vecs: u32,131131+ max_vecs: u32,132132+ irq_types: IrqTypes,133133+ ) -> Result<RangeInclusive<IrqVector<'a>>> {134134+ // SAFETY:135135+ // - `dev.as_raw()` is guaranteed to be a valid pointer to a `struct pci_dev`136136+ // by the type invariant of `Device`.137137+ // - `pci_alloc_irq_vectors` internally validates all other parameters138138+ // and returns error codes.139139+ let ret = unsafe {140140+ bindings::pci_alloc_irq_vectors(dev.as_raw(), min_vecs, max_vecs, irq_types.as_raw())141141+ };142142+143143+ to_result(ret)?;144144+ let count = ret as u32;145145+146146+ // SAFETY:147147+ // - `pci_alloc_irq_vectors` returns the number of allocated vectors on success.148148+ // - Vectors are 0-based, so valid indices are [0, count-1].149149+ // - `pci_alloc_irq_vectors` guarantees `count >= min_vecs > 0`, so both `0` and150150+ // `count - 1` are valid IRQ vector indices for `dev`.151151+ let range = unsafe { IrqVector::new(dev, 0)..=IrqVector::new(dev, count - 1) };152152+153153+ // INVARIANT: The IRQ vector allocation for `dev` above was successful.154154+ let irq_vecs = Self { dev: dev.into() };155155+ devres::register(dev.as_ref(), irq_vecs, GFP_KERNEL)?;156156+157157+ Ok(range)158158+ }159159+}160160+161161+impl Drop for IrqVectorRegistration {162162+ fn drop(&mut self) {163163+ // SAFETY:164164+ // - By the type invariant, `self.dev.as_raw()` is a valid pointer to a `struct pci_dev`.165165+ // - `self.dev` has successfully allocated IRQ vectors.166166+ unsafe { bindings::pci_free_irq_vectors(self.dev.as_raw()) };167167+ }168168+}169169+170170+impl Device<device::Bound> {171171+ /// Returns a [`kernel::irq::Registration`] for the given IRQ vector.172172+ pub fn request_irq<'a, T: crate::irq::Handler + 'static>(173173+ &'a self,174174+ vector: IrqVector<'a>,175175+ flags: irq::Flags,176176+ name: &'static CStr,177177+ handler: impl PinInit<T, Error> + 'a,178178+ ) -> Result<impl PinInit<irq::Registration<T>, Error> + 'a> {179179+ let request = vector.try_into()?;180180+181181+ Ok(irq::Registration::<T>::new(request, flags, name, handler))182182+ }183183+184184+ /// Returns a [`kernel::irq::ThreadedRegistration`] for the given IRQ vector.185185+ pub fn request_threaded_irq<'a, T: crate::irq::ThreadedHandler + 'static>(186186+ &'a self,187187+ vector: IrqVector<'a>,188188+ flags: irq::Flags,189189+ name: &'static CStr,190190+ handler: impl PinInit<T, Error> + 'a,191191+ ) -> Result<impl PinInit<irq::ThreadedRegistration<T>, Error> + 'a> {192192+ let request = vector.try_into()?;193193+194194+ Ok(irq::ThreadedRegistration::<T>::new(195195+ request, flags, name, handler,196196+ ))197197+ }198198+199199+ /// Allocate IRQ vectors for this PCI device with automatic cleanup.200200+ ///201201+ /// Allocates between `min_vecs` and `max_vecs` interrupt vectors for the device.202202+ /// The allocation will use MSI-X, MSI, or legacy interrupts based on the `irq_types`203203+ /// parameter and hardware capabilities. When multiple types are specified, the kernel204204+ /// will try them in order of preference: MSI-X first, then MSI, then legacy interrupts.205205+ ///206206+ /// The allocated vectors are automatically freed when the device is unbound, using the207207+ /// devres (device resource management) system.208208+ ///209209+ /// # Arguments210210+ ///211211+ /// * `min_vecs` - Minimum number of vectors required.212212+ /// * `max_vecs` - Maximum number of vectors to allocate.213213+ /// * `irq_types` - Types of interrupts that can be used.214214+ ///215215+ /// # Returns216216+ ///217217+ /// Returns a range of IRQ vectors that were successfully allocated, or an error if the218218+ /// allocation fails or cannot meet the minimum requirement.219219+ ///220220+ /// # Examples221221+ ///222222+ /// ```223223+ /// # use kernel::{ device::Bound, pci};224224+ /// # fn no_run(dev: &pci::Device<Bound>) -> Result {225225+ /// // Allocate using any available interrupt type in the order mentioned above.226226+ /// let vectors = dev.alloc_irq_vectors(1, 32, pci::IrqTypes::all())?;227227+ ///228228+ /// // Allocate MSI or MSI-X only (no legacy interrupts).229229+ /// let msi_only = pci::IrqTypes::default()230230+ /// .with(pci::IrqType::Msi)231231+ /// .with(pci::IrqType::MsiX);232232+ /// let vectors = dev.alloc_irq_vectors(4, 16, msi_only)?;233233+ /// # Ok(())234234+ /// # }235235+ /// ```236236+ pub fn alloc_irq_vectors(237237+ &self,238238+ min_vecs: u32,239239+ max_vecs: u32,240240+ irq_types: IrqTypes,241241+ ) -> Result<RangeInclusive<IrqVector<'_>>> {242242+ IrqVectorRegistration::register(self, min_vecs, max_vecs, irq_types)243243+ }244244+}