1 // SPDX-License-Identifier: GPL-2.0 2 3 //! PCI interrupt infrastructure. 4 5 use super::Device; 6 use crate::{ 7 bindings, 8 device, 9 device::Bound, 10 error::to_result, 11 irq::IrqRequest, 12 prelude::*, // 13 }; 14 use core::num::NonZero; 15 16 /// IRQ type flags for PCI interrupt allocation. 17 #[derive(Debug, Clone, Copy)] 18 pub enum IrqType { 19 /// INTx interrupts. 20 Intx, 21 /// Message Signaled Interrupts (MSI). 22 Msi, 23 /// Extended Message Signaled Interrupts (MSI-X). 24 MsiX, 25 } 26 27 impl IrqType { 28 /// Convert to the corresponding kernel flags. 29 const fn as_raw(self) -> u32 { 30 match self { 31 IrqType::Intx => bindings::PCI_IRQ_INTX, 32 IrqType::Msi => bindings::PCI_IRQ_MSI, 33 IrqType::MsiX => bindings::PCI_IRQ_MSIX, 34 } 35 } 36 37 /// Construct from raw value. 38 #[inline] 39 const fn from_raw(raw: u32) -> Self { 40 match raw { 41 bindings::PCI_IRQ_MSIX => IrqType::MsiX, 42 bindings::PCI_IRQ_MSI => IrqType::Msi, 43 _ => IrqType::Intx, 44 } 45 } 46 } 47 48 /// Set of IRQ types that can be used for PCI interrupt allocation. 49 #[derive(Debug, Clone, Copy, Default)] 50 pub struct IrqTypes(u32); 51 52 impl IrqTypes { 53 /// Create a set containing all IRQ types (MSI-X, MSI, and INTx). 54 pub const fn all() -> Self { 55 Self(bindings::PCI_IRQ_ALL_TYPES) 56 } 57 58 /// Build a set of IRQ types. 59 /// 60 /// # Examples 61 /// 62 /// ```ignore 63 /// // Create a set with only MSI and MSI-X (no INTx interrupts). 64 /// let msi_only = IrqTypes::default() 65 /// .with(IrqType::Msi) 66 /// .with(IrqType::MsiX); 67 /// ``` 68 pub const fn with(self, irq_type: IrqType) -> Self { 69 Self(self.0 | irq_type.as_raw()) 70 } 71 72 /// Get the raw flags value. 73 const fn as_raw(self) -> u32 { 74 self.0 75 } 76 } 77 78 /// A resolved IRQ vector from a PCI interrupt vector allocation. 79 /// 80 /// Created by [`IrqVectorRegistration::index`]. Convert to [`IrqRequest`] via [`From`] to register 81 /// a handler with [`irq::Registration::new`](crate::irq::Registration::new). 82 pub struct IrqVector<'a> { 83 request: IrqRequest<'a>, 84 reg: &'a IrqVectorRegistration<'a>, 85 } 86 87 impl<'a> IrqVector<'a> { 88 /// Creates a new [`IrqVector`] with an already resolved [`IrqRequest`]. 89 /// 90 /// # Safety 91 /// 92 /// `request` must have been resolved from `reg`. 93 #[inline] 94 unsafe fn new(request: IrqRequest<'a>, reg: &'a IrqVectorRegistration<'a>) -> Self { 95 Self { request, reg } 96 } 97 98 /// Returns the [`IrqVectorRegistration`] this vector was derived from. 99 #[inline] 100 pub fn vectors(&self) -> &'a IrqVectorRegistration<'a> { 101 self.reg 102 } 103 104 /// Returns the interrupt type the PCI core selected for this vector's allocation. 105 #[inline] 106 pub fn irq_type(&self) -> IrqType { 107 self.reg.irq_type() 108 } 109 } 110 111 impl<'a> From<IrqVector<'a>> for IrqRequest<'a> { 112 #[inline] 113 fn from(vector: IrqVector<'a>) -> Self { 114 vector.request 115 } 116 } 117 118 /// An allocation of PCI interrupt vectors for a device. 119 /// 120 /// This type owns the vector allocation; dropping it frees the vectors. IRQ handlers borrow from 121 /// this registration and must be dropped before it is. 122 /// 123 /// # Invariants 124 /// 125 /// `dev` has an allocation of `len` interrupt vectors. 126 pub struct IrqVectorRegistration<'a> { 127 dev: &'a Device<Bound>, 128 len: NonZero<usize>, 129 } 130 131 impl<'a> IrqVectorRegistration<'a> { 132 /// Returns the number of allocated vectors. 133 /// 134 /// This is at least the `min_vecs` that [`Device::alloc_irq_vectors`] was asked for. 135 #[inline] 136 #[allow(clippy::len_without_is_empty)] 137 pub fn len(&self) -> usize { 138 self.len.get() 139 } 140 141 /// Returns the interrupt type the PCI core selected for this allocation. 142 #[inline] 143 pub fn irq_type(&self) -> IrqType { 144 // SAFETY: `self.dev.as_raw()` is a valid pointer to a `struct pci_dev`. 145 IrqType::from_raw(unsafe { bindings::pci_irq_type(self.dev.as_raw()) }) 146 } 147 148 /// Returns the [`IrqVector`] at `index`. 149 /// 150 /// Returns [`EINVAL`] if the `index` is out of bounds for the length reported by 151 /// [`Self::len()`]. 152 #[inline] 153 pub fn index(&self, index: usize) -> Result<IrqVector<'_>> { 154 // SAFETY: `self.dev.as_raw()` is a valid pointer to a `struct pci_dev`. 155 let irq = unsafe { bindings::pci_irq_vector(self.dev.as_raw(), index as u32) }; 156 if irq < 0 { 157 return Err(Error::from_errno(irq)); 158 } 159 160 // SAFETY: `irq` is a valid IRQ number for `self.dev`, resolved from this registration. 161 Ok(unsafe { IrqVector::new(IrqRequest::new(self.dev.as_ref(), irq as u32), self) }) 162 } 163 } 164 165 impl Drop for IrqVectorRegistration<'_> { 166 #[inline] 167 fn drop(&mut self) { 168 // SAFETY: By the type invariant, `self.dev.as_raw()` is a valid pointer to a 169 // `struct pci_dev` that has successfully allocated IRQ vectors. 170 unsafe { bindings::pci_free_irq_vectors(self.dev.as_raw()) }; 171 } 172 } 173 174 impl Device<device::Bound> { 175 /// Allocate IRQ vectors for this PCI device. 176 /// 177 /// Allocates between `min_vecs` and `max_vecs` interrupt vectors for the device. 178 /// The allocation will use MSI-X, MSI, or INTx interrupts based on the `irq_types` 179 /// parameter and hardware capabilities. When multiple types are specified, the kernel 180 /// will try them in order of preference: MSI-X first, then MSI, then INTx interrupts. 181 /// 182 /// The allocated vectors are freed when the returned [`IrqVectorRegistration`] is dropped. 183 /// Use [`IrqVectorRegistration::index`] to obtain an [`IrqVector`] for a given vector 184 /// index. 185 /// 186 /// # Arguments 187 /// 188 /// * `min_vecs` - Minimum number of vectors required. 189 /// * `max_vecs` - Maximum number of vectors to allocate. 190 /// * `irq_types` - Types of interrupts that can be used. 191 /// 192 /// # Returns 193 /// 194 /// Returns the IRQ vector registration, or an error if `min_vecs` vectors cannot be 195 /// allocated. 196 /// 197 /// # Examples 198 /// 199 /// ``` 200 /// # use kernel::{ device::Bound, pci}; 201 /// # fn no_run(dev: &pci::Device<Bound>) -> Result { 202 /// // Allocate using any available interrupt type in the order mentioned above. 203 /// let vectors = dev.alloc_irq_vectors(1, 32, pci::IrqTypes::all())?; 204 /// 205 /// // Allocate MSI or MSI-X only (no INTx interrupts). 206 /// let msi_only = pci::IrqTypes::default() 207 /// .with(pci::IrqType::Msi) 208 /// .with(pci::IrqType::MsiX); 209 /// let vectors = dev.alloc_irq_vectors(4, 16, msi_only)?; 210 /// # Ok(()) 211 /// # } 212 /// ``` 213 pub fn alloc_irq_vectors( 214 &self, 215 min_vecs: u32, 216 max_vecs: u32, 217 irq_types: IrqTypes, 218 ) -> Result<IrqVectorRegistration<'_>> { 219 // SAFETY: 220 // - `self.as_raw()` is guaranteed to be a valid pointer to a `struct pci_dev` 221 // by the type invariant of `Device`. 222 // - `pci_alloc_irq_vectors` internally validates all other parameters 223 // and returns error codes. 224 let ret = unsafe { 225 bindings::pci_alloc_irq_vectors(self.as_raw(), min_vecs, max_vecs, irq_types.as_raw()) 226 }; 227 to_result(ret)?; 228 229 let len = NonZero::new(ret as usize).ok_or(EINVAL)?; 230 231 // INVARIANT: `pci_alloc_irq_vectors()` allocated `len` vectors for `self`. 232 Ok(IrqVectorRegistration { dev: self, len }) 233 } 234 } 235