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 IRQ infrastructure to separate file

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

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

+247 -233
+3 -233
rust/kernel/pci.rs
··· 6 6 7 7 use crate::{ 8 8 bindings, container_of, device, 9 - device::Bound, 10 9 device_id::{RawDeviceId, RawDeviceIdIndex}, 11 - devres, driver, 10 + driver, 12 11 error::{from_result, to_result, Result}, 13 - irq::{self, IrqRequest}, 14 12 str::CStr, 15 - sync::aref::ARef, 16 13 types::Opaque, 17 14 ThisModule, 18 15 }; 19 16 use core::{ 20 17 marker::PhantomData, 21 - ops::RangeInclusive, 22 18 ptr::{addr_of_mut, NonNull}, 23 19 }; 24 20 use kernel::prelude::*; 25 21 26 22 mod id; 27 23 mod io; 24 + mod irq; 28 25 29 26 pub use self::id::{Class, ClassMask, Vendor}; 30 27 pub use self::io::Bar; 31 - 32 - /// IRQ type flags for PCI interrupt allocation. 33 - #[derive(Debug, Clone, Copy)] 34 - pub enum IrqType { 35 - /// INTx interrupts. 36 - Intx, 37 - /// Message Signaled Interrupts (MSI). 38 - Msi, 39 - /// Extended Message Signaled Interrupts (MSI-X). 40 - MsiX, 41 - } 42 - 43 - impl IrqType { 44 - /// Convert to the corresponding kernel flags. 45 - const fn as_raw(self) -> u32 { 46 - match self { 47 - IrqType::Intx => bindings::PCI_IRQ_INTX, 48 - IrqType::Msi => bindings::PCI_IRQ_MSI, 49 - IrqType::MsiX => bindings::PCI_IRQ_MSIX, 50 - } 51 - } 52 - } 53 - 54 - /// Set of IRQ types that can be used for PCI interrupt allocation. 55 - #[derive(Debug, Clone, Copy, Default)] 56 - pub struct IrqTypes(u32); 57 - 58 - impl IrqTypes { 59 - /// Create a set containing all IRQ types (MSI-X, MSI, and Legacy). 60 - pub const fn all() -> Self { 61 - Self(bindings::PCI_IRQ_ALL_TYPES) 62 - } 63 - 64 - /// Build a set of IRQ types. 65 - /// 66 - /// # Examples 67 - /// 68 - /// ```ignore 69 - /// // Create a set with only MSI and MSI-X (no legacy interrupts). 70 - /// let msi_only = IrqTypes::default() 71 - /// .with(IrqType::Msi) 72 - /// .with(IrqType::MsiX); 73 - /// ``` 74 - pub const fn with(self, irq_type: IrqType) -> Self { 75 - Self(self.0 | irq_type.as_raw()) 76 - } 77 - 78 - /// Get the raw flags value. 79 - const fn as_raw(self) -> u32 { 80 - self.0 81 - } 82 - } 28 + pub use self::irq::{IrqType, IrqTypes, IrqVector}; 83 29 84 30 /// An adapter for the registration of PCI drivers. 85 31 pub struct Adapter<T: Driver>(T); ··· 406 460 pub fn pci_class(&self) -> Class { 407 461 // SAFETY: `self.as_raw` is a valid pointer to a `struct pci_dev`. 408 462 Class::from_raw(unsafe { (*self.as_raw()).class }) 409 - } 410 - } 411 - 412 - /// Represents an allocated IRQ vector for a specific PCI device. 413 - /// 414 - /// This type ties an IRQ vector to the device it was allocated for, 415 - /// ensuring the vector is only used with the correct device. 416 - #[derive(Clone, Copy)] 417 - pub struct IrqVector<'a> { 418 - dev: &'a Device<Bound>, 419 - index: u32, 420 - } 421 - 422 - impl<'a> IrqVector<'a> { 423 - /// Creates a new [`IrqVector`] for the given device and index. 424 - /// 425 - /// # Safety 426 - /// 427 - /// - `index` must be a valid IRQ vector index for `dev`. 428 - /// - `dev` must point to a [`Device`] that has successfully allocated IRQ vectors. 429 - unsafe fn new(dev: &'a Device<Bound>, index: u32) -> Self { 430 - Self { dev, index } 431 - } 432 - 433 - /// Returns the raw vector index. 434 - fn index(&self) -> u32 { 435 - self.index 436 - } 437 - } 438 - 439 - impl<'a> TryInto<IrqRequest<'a>> for IrqVector<'a> { 440 - type Error = Error; 441 - 442 - fn try_into(self) -> Result<IrqRequest<'a>> { 443 - // SAFETY: `self.as_raw` returns a valid pointer to a `struct pci_dev`. 444 - let irq = unsafe { bindings::pci_irq_vector(self.dev.as_raw(), self.index()) }; 445 - if irq < 0 { 446 - return Err(crate::error::Error::from_errno(irq)); 447 - } 448 - // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self`. 449 - Ok(unsafe { IrqRequest::new(self.dev.as_ref(), irq as u32) }) 450 - } 451 - } 452 - 453 - /// Represents an IRQ vector allocation for a PCI device. 454 - /// 455 - /// This type ensures that IRQ vectors are properly allocated and freed by 456 - /// tying the allocation to the lifetime of this registration object. 457 - /// 458 - /// # Invariants 459 - /// 460 - /// The [`Device`] has successfully allocated IRQ vectors. 461 - struct IrqVectorRegistration { 462 - dev: ARef<Device>, 463 - } 464 - 465 - impl IrqVectorRegistration { 466 - /// Allocate and register IRQ vectors for the given PCI device. 467 - /// 468 - /// Allocates IRQ vectors and registers them with devres for automatic cleanup. 469 - /// Returns a range of valid IRQ vectors. 470 - fn register<'a>( 471 - dev: &'a Device<Bound>, 472 - min_vecs: u32, 473 - max_vecs: u32, 474 - irq_types: IrqTypes, 475 - ) -> Result<RangeInclusive<IrqVector<'a>>> { 476 - // SAFETY: 477 - // - `dev.as_raw()` is guaranteed to be a valid pointer to a `struct pci_dev` 478 - // by the type invariant of `Device`. 479 - // - `pci_alloc_irq_vectors` internally validates all other parameters 480 - // and returns error codes. 481 - let ret = unsafe { 482 - bindings::pci_alloc_irq_vectors(dev.as_raw(), min_vecs, max_vecs, irq_types.as_raw()) 483 - }; 484 - 485 - to_result(ret)?; 486 - let count = ret as u32; 487 - 488 - // SAFETY: 489 - // - `pci_alloc_irq_vectors` returns the number of allocated vectors on success. 490 - // - Vectors are 0-based, so valid indices are [0, count-1]. 491 - // - `pci_alloc_irq_vectors` guarantees `count >= min_vecs > 0`, so both `0` and 492 - // `count - 1` are valid IRQ vector indices for `dev`. 493 - let range = unsafe { IrqVector::new(dev, 0)..=IrqVector::new(dev, count - 1) }; 494 - 495 - // INVARIANT: The IRQ vector allocation for `dev` above was successful. 496 - let irq_vecs = Self { dev: dev.into() }; 497 - devres::register(dev.as_ref(), irq_vecs, GFP_KERNEL)?; 498 - 499 - Ok(range) 500 - } 501 - } 502 - 503 - impl Drop for IrqVectorRegistration { 504 - fn drop(&mut self) { 505 - // SAFETY: 506 - // - By the type invariant, `self.dev.as_raw()` is a valid pointer to a `struct pci_dev`. 507 - // - `self.dev` has successfully allocated IRQ vectors. 508 - unsafe { bindings::pci_free_irq_vectors(self.dev.as_raw()) }; 509 - } 510 - } 511 - 512 - impl Device<device::Bound> { 513 - /// Returns a [`kernel::irq::Registration`] for the given IRQ vector. 514 - pub fn request_irq<'a, T: crate::irq::Handler + 'static>( 515 - &'a self, 516 - vector: IrqVector<'a>, 517 - flags: irq::Flags, 518 - name: &'static CStr, 519 - handler: impl PinInit<T, Error> + 'a, 520 - ) -> Result<impl PinInit<irq::Registration<T>, Error> + 'a> { 521 - let request = vector.try_into()?; 522 - 523 - Ok(irq::Registration::<T>::new(request, flags, name, handler)) 524 - } 525 - 526 - /// Returns a [`kernel::irq::ThreadedRegistration`] for the given IRQ vector. 527 - pub fn request_threaded_irq<'a, T: crate::irq::ThreadedHandler + 'static>( 528 - &'a self, 529 - vector: IrqVector<'a>, 530 - flags: irq::Flags, 531 - name: &'static CStr, 532 - handler: impl PinInit<T, Error> + 'a, 533 - ) -> Result<impl PinInit<irq::ThreadedRegistration<T>, Error> + 'a> { 534 - let request = vector.try_into()?; 535 - 536 - Ok(irq::ThreadedRegistration::<T>::new( 537 - request, flags, name, handler, 538 - )) 539 - } 540 - 541 - /// Allocate IRQ vectors for this PCI device with automatic cleanup. 542 - /// 543 - /// Allocates between `min_vecs` and `max_vecs` interrupt vectors for the device. 544 - /// The allocation will use MSI-X, MSI, or legacy interrupts based on the `irq_types` 545 - /// parameter and hardware capabilities. When multiple types are specified, the kernel 546 - /// will try them in order of preference: MSI-X first, then MSI, then legacy interrupts. 547 - /// 548 - /// The allocated vectors are automatically freed when the device is unbound, using the 549 - /// devres (device resource management) system. 550 - /// 551 - /// # Arguments 552 - /// 553 - /// * `min_vecs` - Minimum number of vectors required. 554 - /// * `max_vecs` - Maximum number of vectors to allocate. 555 - /// * `irq_types` - Types of interrupts that can be used. 556 - /// 557 - /// # Returns 558 - /// 559 - /// Returns a range of IRQ vectors that were successfully allocated, or an error if the 560 - /// allocation fails or cannot meet the minimum requirement. 561 - /// 562 - /// # Examples 563 - /// 564 - /// ``` 565 - /// # use kernel::{ device::Bound, pci}; 566 - /// # fn no_run(dev: &pci::Device<Bound>) -> Result { 567 - /// // Allocate using any available interrupt type in the order mentioned above. 568 - /// let vectors = dev.alloc_irq_vectors(1, 32, pci::IrqTypes::all())?; 569 - /// 570 - /// // Allocate MSI or MSI-X only (no legacy interrupts). 571 - /// let msi_only = pci::IrqTypes::default() 572 - /// .with(pci::IrqType::Msi) 573 - /// .with(pci::IrqType::MsiX); 574 - /// let vectors = dev.alloc_irq_vectors(4, 16, msi_only)?; 575 - /// # Ok(()) 576 - /// # } 577 - /// ``` 578 - pub fn alloc_irq_vectors( 579 - &self, 580 - min_vecs: u32, 581 - max_vecs: u32, 582 - irq_types: IrqTypes, 583 - ) -> Result<RangeInclusive<IrqVector<'_>>> { 584 - IrqVectorRegistration::register(self, min_vecs, max_vecs, irq_types) 585 463 } 586 464 } 587 465
+244
rust/kernel/pci/irq.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! PCI interrupt infrastructure. 4 + 5 + use super::Device; 6 + use crate::{ 7 + bindings, device, 8 + device::Bound, 9 + devres, 10 + error::{to_result, Result}, 11 + irq::{self, IrqRequest}, 12 + str::CStr, 13 + sync::aref::ARef, 14 + }; 15 + use core::ops::RangeInclusive; 16 + use kernel::prelude::*; 17 + 18 + /// IRQ type flags for PCI interrupt allocation. 19 + #[derive(Debug, Clone, Copy)] 20 + pub enum IrqType { 21 + /// INTx interrupts. 22 + Intx, 23 + /// Message Signaled Interrupts (MSI). 24 + Msi, 25 + /// Extended Message Signaled Interrupts (MSI-X). 26 + MsiX, 27 + } 28 + 29 + impl IrqType { 30 + /// Convert to the corresponding kernel flags. 31 + const fn as_raw(self) -> u32 { 32 + match self { 33 + IrqType::Intx => bindings::PCI_IRQ_INTX, 34 + IrqType::Msi => bindings::PCI_IRQ_MSI, 35 + IrqType::MsiX => bindings::PCI_IRQ_MSIX, 36 + } 37 + } 38 + } 39 + 40 + /// Set of IRQ types that can be used for PCI interrupt allocation. 41 + #[derive(Debug, Clone, Copy, Default)] 42 + pub struct IrqTypes(u32); 43 + 44 + impl IrqTypes { 45 + /// Create a set containing all IRQ types (MSI-X, MSI, and Legacy). 46 + pub const fn all() -> Self { 47 + Self(bindings::PCI_IRQ_ALL_TYPES) 48 + } 49 + 50 + /// Build a set of IRQ types. 51 + /// 52 + /// # Examples 53 + /// 54 + /// ```ignore 55 + /// // Create a set with only MSI and MSI-X (no legacy interrupts). 56 + /// let msi_only = IrqTypes::default() 57 + /// .with(IrqType::Msi) 58 + /// .with(IrqType::MsiX); 59 + /// ``` 60 + pub const fn with(self, irq_type: IrqType) -> Self { 61 + Self(self.0 | irq_type.as_raw()) 62 + } 63 + 64 + /// Get the raw flags value. 65 + const fn as_raw(self) -> u32 { 66 + self.0 67 + } 68 + } 69 + 70 + /// Represents an allocated IRQ vector for a specific PCI device. 71 + /// 72 + /// This type ties an IRQ vector to the device it was allocated for, 73 + /// ensuring the vector is only used with the correct device. 74 + #[derive(Clone, Copy)] 75 + pub struct IrqVector<'a> { 76 + dev: &'a Device<Bound>, 77 + index: u32, 78 + } 79 + 80 + impl<'a> IrqVector<'a> { 81 + /// Creates a new [`IrqVector`] for the given device and index. 82 + /// 83 + /// # Safety 84 + /// 85 + /// - `index` must be a valid IRQ vector index for `dev`. 86 + /// - `dev` must point to a [`Device`] that has successfully allocated IRQ vectors. 87 + unsafe fn new(dev: &'a Device<Bound>, index: u32) -> Self { 88 + Self { dev, index } 89 + } 90 + 91 + /// Returns the raw vector index. 92 + fn index(&self) -> u32 { 93 + self.index 94 + } 95 + } 96 + 97 + impl<'a> TryInto<IrqRequest<'a>> for IrqVector<'a> { 98 + type Error = Error; 99 + 100 + fn try_into(self) -> Result<IrqRequest<'a>> { 101 + // SAFETY: `self.as_raw` returns a valid pointer to a `struct pci_dev`. 102 + let irq = unsafe { bindings::pci_irq_vector(self.dev.as_raw(), self.index()) }; 103 + if irq < 0 { 104 + return Err(crate::error::Error::from_errno(irq)); 105 + } 106 + // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self`. 107 + Ok(unsafe { IrqRequest::new(self.dev.as_ref(), irq as u32) }) 108 + } 109 + } 110 + 111 + /// Represents an IRQ vector allocation for a PCI device. 112 + /// 113 + /// This type ensures that IRQ vectors are properly allocated and freed by 114 + /// tying the allocation to the lifetime of this registration object. 115 + /// 116 + /// # Invariants 117 + /// 118 + /// The [`Device`] has successfully allocated IRQ vectors. 119 + struct IrqVectorRegistration { 120 + dev: ARef<Device>, 121 + } 122 + 123 + impl IrqVectorRegistration { 124 + /// Allocate and register IRQ vectors for the given PCI device. 125 + /// 126 + /// Allocates IRQ vectors and registers them with devres for automatic cleanup. 127 + /// Returns a range of valid IRQ vectors. 128 + fn register<'a>( 129 + dev: &'a Device<Bound>, 130 + min_vecs: u32, 131 + max_vecs: u32, 132 + irq_types: IrqTypes, 133 + ) -> Result<RangeInclusive<IrqVector<'a>>> { 134 + // SAFETY: 135 + // - `dev.as_raw()` is guaranteed to be a valid pointer to a `struct pci_dev` 136 + // by the type invariant of `Device`. 137 + // - `pci_alloc_irq_vectors` internally validates all other parameters 138 + // and returns error codes. 139 + let ret = unsafe { 140 + bindings::pci_alloc_irq_vectors(dev.as_raw(), min_vecs, max_vecs, irq_types.as_raw()) 141 + }; 142 + 143 + to_result(ret)?; 144 + let count = ret as u32; 145 + 146 + // SAFETY: 147 + // - `pci_alloc_irq_vectors` returns the number of allocated vectors on success. 148 + // - Vectors are 0-based, so valid indices are [0, count-1]. 149 + // - `pci_alloc_irq_vectors` guarantees `count >= min_vecs > 0`, so both `0` and 150 + // `count - 1` are valid IRQ vector indices for `dev`. 151 + let range = unsafe { IrqVector::new(dev, 0)..=IrqVector::new(dev, count - 1) }; 152 + 153 + // INVARIANT: The IRQ vector allocation for `dev` above was successful. 154 + let irq_vecs = Self { dev: dev.into() }; 155 + devres::register(dev.as_ref(), irq_vecs, GFP_KERNEL)?; 156 + 157 + Ok(range) 158 + } 159 + } 160 + 161 + impl Drop for IrqVectorRegistration { 162 + fn drop(&mut self) { 163 + // SAFETY: 164 + // - By the type invariant, `self.dev.as_raw()` is a valid pointer to a `struct pci_dev`. 165 + // - `self.dev` has successfully allocated IRQ vectors. 166 + unsafe { bindings::pci_free_irq_vectors(self.dev.as_raw()) }; 167 + } 168 + } 169 + 170 + impl Device<device::Bound> { 171 + /// Returns a [`kernel::irq::Registration`] for the given IRQ vector. 172 + pub fn request_irq<'a, T: crate::irq::Handler + 'static>( 173 + &'a self, 174 + vector: IrqVector<'a>, 175 + flags: irq::Flags, 176 + name: &'static CStr, 177 + handler: impl PinInit<T, Error> + 'a, 178 + ) -> Result<impl PinInit<irq::Registration<T>, Error> + 'a> { 179 + let request = vector.try_into()?; 180 + 181 + Ok(irq::Registration::<T>::new(request, flags, name, handler)) 182 + } 183 + 184 + /// Returns a [`kernel::irq::ThreadedRegistration`] for the given IRQ vector. 185 + pub fn request_threaded_irq<'a, T: crate::irq::ThreadedHandler + 'static>( 186 + &'a self, 187 + vector: IrqVector<'a>, 188 + flags: irq::Flags, 189 + name: &'static CStr, 190 + handler: impl PinInit<T, Error> + 'a, 191 + ) -> Result<impl PinInit<irq::ThreadedRegistration<T>, Error> + 'a> { 192 + let request = vector.try_into()?; 193 + 194 + Ok(irq::ThreadedRegistration::<T>::new( 195 + request, flags, name, handler, 196 + )) 197 + } 198 + 199 + /// Allocate IRQ vectors for this PCI device with automatic cleanup. 200 + /// 201 + /// Allocates between `min_vecs` and `max_vecs` interrupt vectors for the device. 202 + /// The allocation will use MSI-X, MSI, or legacy interrupts based on the `irq_types` 203 + /// parameter and hardware capabilities. When multiple types are specified, the kernel 204 + /// will try them in order of preference: MSI-X first, then MSI, then legacy interrupts. 205 + /// 206 + /// The allocated vectors are automatically freed when the device is unbound, using the 207 + /// devres (device resource management) system. 208 + /// 209 + /// # Arguments 210 + /// 211 + /// * `min_vecs` - Minimum number of vectors required. 212 + /// * `max_vecs` - Maximum number of vectors to allocate. 213 + /// * `irq_types` - Types of interrupts that can be used. 214 + /// 215 + /// # Returns 216 + /// 217 + /// Returns a range of IRQ vectors that were successfully allocated, or an error if the 218 + /// allocation fails or cannot meet the minimum requirement. 219 + /// 220 + /// # Examples 221 + /// 222 + /// ``` 223 + /// # use kernel::{ device::Bound, pci}; 224 + /// # fn no_run(dev: &pci::Device<Bound>) -> Result { 225 + /// // Allocate using any available interrupt type in the order mentioned above. 226 + /// let vectors = dev.alloc_irq_vectors(1, 32, pci::IrqTypes::all())?; 227 + /// 228 + /// // Allocate MSI or MSI-X only (no legacy interrupts). 229 + /// let msi_only = pci::IrqTypes::default() 230 + /// .with(pci::IrqType::Msi) 231 + /// .with(pci::IrqType::MsiX); 232 + /// let vectors = dev.alloc_irq_vectors(4, 16, msi_only)?; 233 + /// # Ok(()) 234 + /// # } 235 + /// ``` 236 + pub fn alloc_irq_vectors( 237 + &self, 238 + min_vecs: u32, 239 + max_vecs: u32, 240 + irq_types: IrqTypes, 241 + ) -> Result<RangeInclusive<IrqVector<'_>>> { 242 + IrqVectorRegistration::register(self, min_vecs, max_vecs, irq_types) 243 + } 244 + }