xref: /linux/drivers/gpu/nova-core/irq/interrupt_tree.rs (revision 939b40877cb883de1fa335e950ff1a3f3bf113ed)
1 // SPDX-License-Identifier: GPL-2.0
2 // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3 
4 //! The GIN CPU interrupt tree for one PCIe function.
5 //!
6 //! A [`GinVector`] names an interrupt source, a [`LeafIndex`] the leaf register that latches it,
7 //! a [`LeafMask`] a set of vectors within one leaf, and a [`Subtree`] one `TOP` bit. The types
8 //! keep the four from being confused with one another.
9 //!
10 //! Servicing a leaf requires reading its pending bits before clearing them. Only
11 //! [`Tree::read_pending`] produces a [`LeafPending`], and only a [`LeafPending`] clears a leaf,
12 //! so that the wrong order does not compile. This module does not serialize access to the tree.
13 //!
14 //! See `Documentation/gpu/nova/core/interrupts.rst`.
15 
16 use kernel::{
17     device::Bound,
18     io::{
19         register::Array,
20         Io, //
21     },
22     irq,
23     num::Bounded,
24     pci::{
25         self,
26         IrqType, //
27     },
28     prelude::*, //
29 };
30 
31 use crate::{
32     driver::Bar0,
33     gpu::Chipset,
34     num, //
35 };
36 
37 use super::{
38     hal::{
39         cpu_interrupt_hal,
40         CpuInterruptHal, //
41     },
42     regs::*,
43     MsiType, //
44 };
45 
46 /// Number of vectors one leaf register carries, one per bit.
47 const VECTORS_PER_LEAF: u32 = u32::BITS;
48 
49 /// Number of leaves one subtree covers.
50 const LEAVES_PER_SUBTREE: u32 = 2;
51 
52 /// Number of subtrees the widest supported tree implements.
53 const MAX_NUM_SUBTREES: u32 = 8;
54 
55 /// Number of leaves the widest supported tree implements.
56 const MAX_NUM_LEAVES: u32 = MAX_NUM_SUBTREES * LEAVES_PER_SUBTREE;
57 
58 /// Number of bits needed to address every vector in the widest supported tree.
59 const VECTOR_BITS: u32 = (MAX_NUM_LEAVES * VECTORS_PER_LEAF).ilog2();
60 
61 /// Width of the vector field in the leaf trigger register.
62 const TRIGGER_VECTOR_BITS: u32 = {
63     let range = NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_TRIGGER::VECTOR_RANGE;
64     num::u8_as_u32(*range.end() - *range.start() + 1)
65 };
66 
67 /// Index of a leaf register within the widest supported tree. An 8-leaf tree implements only the
68 /// lower half of the range.
69 pub(super) type LeafIndex = Bounded<usize, { MAX_NUM_LEAVES.ilog2() }>;
70 
71 /// Number of leaves a tree implements.
72 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
73 #[repr(u32)]
74 pub(super) enum LeafCount {
75     /// Turing through Ada.
76     Eight = 8,
77 
78     /// Hopper and later.
79     Sixteen = 16,
80 }
81 
82 impl LeafCount {
83     pub(super) const fn into_u32(self) -> u32 {
84         // CAST: `LeafCount` is `repr(u32)`, so the cast is lossless.
85         self as u32
86     }
87 
88     pub(super) const fn into_raw(self) -> usize {
89         num::u32_as_usize(self.into_u32())
90     }
91 
92     /// Returns the number of subtrees a tree of this size implements.
93     pub(super) const fn subtree_count(self) -> u32 {
94         self.into_u32() / LEAVES_PER_SUBTREE
95     }
96 
97     /// Returns the set of every subtree a tree of this size implements.
98     pub(super) const fn subtree_set(self) -> SubtreeSet {
99         SubtreeSet((1u32 << self.subtree_count()) - 1)
100     }
101 
102     /// Returns the number of vectors a tree of this size carries.
103     pub(super) const fn vector_count(self) -> u32 {
104         self.into_u32() * VECTORS_PER_LEAF
105     }
106 
107     /// Returns every leaf a tree of this size implements.
108     pub(super) fn iter(self) -> impl Iterator<Item = LeafIndex> {
109         (0..self.into_raw()).filter_map(LeafIndex::try_new)
110     }
111 }
112 
113 // `VECTOR_BITS` and `LeafCount::Sixteen` are written separately. This assert keeps them in
114 // agreement about the widest supported tree.
115 static_assert!(1 << VECTOR_BITS == LeafCount::Sixteen.vector_count());
116 
117 /// Set of vectors within one leaf, one bit per vector.
118 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
119 pub(super) struct LeafMask(u32);
120 
121 impl LeafMask {
122     /// Returns the mask with every vector set.
123     pub(super) const fn all() -> Self {
124         Self(u32::MAX)
125     }
126 
127     pub(super) const fn from_raw(raw: u32) -> Self {
128         Self(raw)
129     }
130 
131     pub(super) const fn into_raw(self) -> u32 {
132         self.0
133     }
134 
135     pub(super) const fn is_empty(self) -> bool {
136         self.0 == 0
137     }
138 
139     /// Returns whether every vector in `other` is also in this mask.
140     pub(super) const fn contains(self, other: Self) -> bool {
141         self.0 & other.0 == other.0
142     }
143 }
144 
145 impl From<Bounded<u32, 32>> for LeafMask {
146     fn from(vectors: Bounded<u32, 32>) -> Self {
147         Self(vectors.get())
148     }
149 }
150 
151 impl From<LeafMask> for Bounded<u32, 32> {
152     fn from(vectors: LeafMask) -> Self {
153         vectors.0.into()
154     }
155 }
156 
157 /// One subtree, held as the `TOP` bit that covers it.
158 ///
159 /// # Invariants
160 ///
161 /// Exactly one bit is set.
162 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
163 pub(super) struct Subtree(u32);
164 
165 impl Subtree {
166     /// Returns the subtree at index `idx`.
167     const fn new(idx: u32) -> Self {
168         // INVARIANT: shifting `1` left leaves exactly one bit set.
169         Self(1 << idx)
170     }
171 
172     /// Returns this subtree's index within the tree.
173     pub(super) const fn index(self) -> u32 {
174         self.0.trailing_zeros()
175     }
176 
177     pub(super) const fn into_raw(self) -> u32 {
178         self.0
179     }
180 }
181 
182 /// Set of subtrees, one bit per subtree, in the layout of the `TOP` registers.
183 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
184 pub(crate) struct SubtreeSet(u32);
185 
186 impl SubtreeSet {
187     pub(super) const fn contains(self, subtree: Subtree) -> bool {
188         self.0 & subtree.into_raw() != 0
189     }
190 
191     pub(super) const fn is_empty(self) -> bool {
192         self.0 == 0
193     }
194 
195     pub(super) const fn intersection(self, other: Self) -> Self {
196         Self(self.0 & other.0)
197     }
198 
199     /// Returns one more than the highest index in this set, or `0` for an empty set. An MSI-X
200     /// allocation that covers the set needs this many entries.
201     pub(super) const fn span(self) -> u32 {
202         u32::BITS - self.0.leading_zeros()
203     }
204 
205     /// Returns the subtrees of this set, lowest index first.
206     pub(super) fn iter(self) -> impl Iterator<Item = Subtree> {
207         (0..u32::BITS)
208             .map(Subtree::new)
209             .filter(move |subtree| self.contains(*subtree))
210     }
211 }
212 
213 impl From<Subtree> for SubtreeSet {
214     fn from(subtree: Subtree) -> Self {
215         Self(subtree.into_raw())
216     }
217 }
218 
219 impl From<Bounded<u32, 32>> for SubtreeSet {
220     fn from(subtrees: Bounded<u32, 32>) -> Self {
221         Self(subtrees.get())
222     }
223 }
224 
225 impl From<SubtreeSet> for Bounded<u32, 32> {
226     fn from(subtrees: SubtreeSet) -> Self {
227         subtrees.0.into()
228     }
229 }
230 
231 /// A GIN interrupt vector, bounded to the widest tree that any supported chipset implements.
232 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
233 pub(super) struct GinVector(Bounded<u32, VECTOR_BITS>);
234 
235 impl GinVector {
236     /// Returns vector number `VECTOR`.
237     ///
238     /// Fails to compile if `VECTOR` is beyond the widest supported tree.
239     pub(super) const fn new<const VECTOR: u32>() -> Self {
240         Self(Bounded::<u32, VECTOR_BITS>::new::<VECTOR>())
241     }
242 
243     pub(super) const fn into_raw(self) -> u32 {
244         self.0.get()
245     }
246 
247     /// Returns this vector's leaf.
248     pub(super) fn leaf_index(self) -> LeafIndex {
249         // CALC: `self.0 / VECTORS_PER_LEAF`.
250         self.0.shr::<{ VECTORS_PER_LEAF.ilog2() }, _>().cast()
251     }
252 
253     /// Returns this vector's bit within its leaf.
254     pub(super) const fn leaf_mask(self) -> LeafMask {
255         LeafMask(1 << (self.0.get() % VECTORS_PER_LEAF))
256     }
257 
258     /// Returns this vector's subtree.
259     pub(super) const fn subtree(self) -> Subtree {
260         Subtree::new(self.0.get() / (VECTORS_PER_LEAF * LEAVES_PER_SUBTREE))
261     }
262 
263     /// Checks that a tree with `leaves` leaves implements this vector.
264     ///
265     /// # Errors
266     ///
267     /// `EINVAL` if it does not.
268     pub(super) const fn validate(self, leaves: LeafCount) -> Result {
269         if self.0.get() >= leaves.vector_count() {
270             Err(EINVAL)
271         } else {
272             Ok(())
273         }
274     }
275 }
276 
277 impl From<GinVector> for Bounded<u32, TRIGGER_VECTOR_BITS> {
278     fn from(vector: GinVector) -> Self {
279         vector.0.extend()
280     }
281 }
282 
283 /// Disables `vectors` in `leaf`.
284 fn clear_leaf_enables(bar: Bar0<'_>, leaf: LeafIndex, vectors: LeafMask) {
285     bar.write(
286         Array::at(*leaf),
287         NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_EN_CLEAR::zeroed().with_vectors(vectors),
288     );
289 }
290 
291 /// Disables the subtrees in `serviced` at `TOP`.
292 fn clear_top_enables(bar: Bar0<'_>, serviced: SubtreeSet) {
293     bar.write_reg(NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_CLEAR::zeroed().with_subtrees(serviced));
294 }
295 
296 /// The CPU tree of one PCIe function, the subtrees that nova-core services, and the PCI vectors
297 /// that deliver them.
298 ///
299 /// A subtree may be enabled at `TOP` only once a handler is registered on the PCI vector that
300 /// delivers it. See "The serviced-subtree invariant" in
301 /// `Documentation/gpu/nova/core/interrupts.rst`.
302 pub(crate) struct Tree<'a> {
303     bar: Bar0<'a>,
304     hal: &'static dyn CpuInterruptHal,
305     serviced: SubtreeSet,
306     /// The interrupt type that Linux granted for `vectors`.
307     pub(super) msi_type: MsiType,
308     vectors: pci::IrqVectorRegistration<'a>,
309 }
310 
311 impl<'a> Tree<'a> {
312     /// Creates the tree of `chipset` and allocates the PCI vectors for the subtrees in `serviced`.
313     ///
314     /// Requests MSI-X entries `0` through the highest subtree in `serviced`, since an allocation
315     /// cannot be sparse, and falls back to a single MSI message for the whole tree.
316     ///
317     /// # Errors
318     ///
319     /// `EINVAL` if `serviced` is empty or names a subtree that `chipset` does not implement.
320     /// Otherwise, when neither interrupt type could be allocated, the error from the MSI request.
321     pub(crate) fn new(
322         pdev: &'a pci::Device<Bound>,
323         bar: Bar0<'a>,
324         chipset: Chipset,
325         serviced: SubtreeSet,
326     ) -> Result<Self> {
327         let hal = cpu_interrupt_hal(chipset);
328         let num_leaves = hal.leaf_count();
329 
330         if serviced.is_empty() || serviced.intersection(num_leaves.subtree_set()) != serviced {
331             return Err(EINVAL);
332         }
333 
334         let entries = serviced.span();
335         let (vectors, msi_type) = pdev
336             .alloc_irq_vectors(entries, entries, IrqType::MsiX.into())
337             .map(|vectors| (vectors, MsiType::MsiX))
338             // Every subtree raises the one MSI message, so one MSI vector serves the whole tree.
339             // See "Delivery over PCI" in `Documentation/gpu/nova/core/interrupts.rst`.
340             .or_else(|_| {
341                 pdev.alloc_irq_vectors(1, 1, IrqType::Msi.into())
342                     .map(|vectors| (vectors, MsiType::Msi))
343             })?;
344 
345         Ok(Self {
346             bar,
347             hal,
348             serviced,
349             msi_type,
350             vectors,
351         })
352     }
353 
354     /// Returns the [`irq::IrqRequest`] for the PCI vector that delivers `subtree`.
355     ///
356     /// # Errors
357     ///
358     /// `EINVAL` if `subtree` is not one of the serviced subtrees.
359     pub(super) fn request_for(&self, subtree: Subtree) -> Result<irq::IrqRequest<'_>> {
360         if !self.serviced.contains(subtree) {
361             return Err(EINVAL);
362         }
363 
364         let entry = match self.msi_type {
365             MsiType::MsiX => num::u32_as_usize(subtree.index()),
366             MsiType::Msi => 0,
367         };
368 
369         self.vectors.index(entry).map(Into::into)
370     }
371 
372     /// Rearms PCI interrupt delivery to the CPU after servicing `subtree`, the one subtree that
373     /// the calling handler serves.
374     ///
375     /// A handler must call this before returning, or it receives no further interrupts.
376     pub(super) fn rearm_pci_irq(&self, subtree: Subtree) {
377         self.hal
378             .rearm_pci_irq(self.bar, self.msi_type, self.serviced, subtree);
379     }
380 
381     /// Enables the serviced subtrees at `TOP`.
382     ///
383     /// Each of them must have a handler registered on its PCI vector.
384     pub(super) fn enable_top(&self) {
385         self.bar.write_reg(
386             NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_TOP_EN_SET::zeroed().with_subtrees(self.serviced),
387         );
388     }
389 
390     /// Disables the serviced subtrees at `TOP`.
391     pub(super) fn disable_top(&self) {
392         clear_top_enables(self.bar, self.serviced);
393     }
394 
395     /// Enables the serviced subtrees at `TOP` until the returned guard drops.
396     pub(crate) fn enable_top_guarded(&self) -> TopEnableGuard<'a> {
397         self.enable_top();
398 
399         TopEnableGuard {
400             bar: self.bar,
401             serviced: self.serviced,
402         }
403     }
404 
405     /// Enables `vectors` in `leaf`.
406     pub(super) fn enable_leaf(&self, leaf: LeafIndex, vectors: LeafMask) {
407         self.bar.write(
408             Array::at(*leaf),
409             NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF_EN_SET::zeroed().with_vectors(vectors),
410         );
411     }
412 
413     /// Disables `vectors` in `leaf`.
414     pub(super) fn disable_leaf(&self, leaf: LeafIndex, vectors: LeafMask) {
415         clear_leaf_enables(self.bar, leaf, vectors);
416     }
417 
418     /// Enables `vectors` in `leaf` until the returned guard drops.
419     pub(super) fn enable_leaf_guarded(
420         &self,
421         leaf: LeafIndex,
422         vectors: LeafMask,
423     ) -> LeafEnableGuard<'a> {
424         self.enable_leaf(leaf, vectors);
425 
426         LeafEnableGuard {
427             bar: self.bar,
428             leaf,
429             vectors,
430         }
431     }
432 
433     /// Reads the pending bits of `leaf`, and returns the handle that clears them.
434     pub(super) fn read_pending(&self, leaf: LeafIndex) -> LeafPending<'a> {
435         let pending = self
436             .bar
437             .read(NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF::at(*leaf))
438             .vectors();
439 
440         LeafPending {
441             bar: self.bar,
442             leaf,
443             pending,
444         }
445     }
446 
447     /// Disables every vector in every implemented leaf, including the subtrees that nova-core does
448     /// not service. Call this only during probe.
449     pub(super) fn disable_all_leaves(&self) {
450         for leaf in self.hal.leaf_count().iter() {
451             self.disable_leaf(leaf, LeafMask::all());
452         }
453     }
454 
455     /// Clears every pending bit in every implemented leaf, including the subtrees that nova-core
456     /// does not service.
457     ///
458     /// The serviced subtrees are disabled at `TOP` on return. Call this only during probe, with no
459     /// interrupt handler registered.
460     pub(super) fn drain(&self) {
461         self.disable_top();
462 
463         // A vector that latched while disabled does not show in `TOP`, so read every leaf rather
464         // than descending from it.
465         for leaf in self.hal.leaf_count().iter() {
466             self.read_pending(leaf).clear();
467         }
468     }
469 
470     /// Disables every vector, clears every pending bit, and rearms PCI interrupt delivery.
471     ///
472     /// The serviced subtrees are disabled at `TOP` on return. Call this only during probe, with
473     /// no interrupt handler registered.
474     pub(super) fn reset(&self) {
475         self.disable_all_leaves();
476         self.drain();
477         for subtree in self.serviced.iter() {
478             self.rearm_pci_irq(subtree);
479         }
480 
481         // A `TOP`-enable rearm leaves the subtrees that it cycles enabled, and a subtree may be
482         // enabled only once a handler is registered on its vector.
483         self.disable_top();
484     }
485 }
486 
487 /// The pending bits of one leaf as they were read, and the handle that clears them.
488 pub(super) struct LeafPending<'a> {
489     bar: Bar0<'a>,
490     leaf: LeafIndex,
491     pending: LeafMask,
492 }
493 
494 impl LeafPending<'_> {
495     pub(super) fn vectors(&self) -> LeafMask {
496         self.pending
497     }
498 
499     /// Clears the vectors that were pending at the read. A vector that latched since stays pending.
500     pub(super) fn clear(&self) {
501         self.clear_vectors(self.pending);
502     }
503 
504     /// Clears `vectors` and no other bit.
505     pub(super) fn clear_vectors(&self, vectors: LeafMask) {
506         if !vectors.is_empty() {
507             self.bar.write(
508                 Array::at(*self.leaf),
509                 NV_VIRTUAL_FUNCTION_PRIV_CPU_INTR_LEAF::zeroed().with_vectors(vectors),
510             );
511         }
512     }
513 }
514 
515 /// Disables a set of vectors in one leaf when dropped.
516 pub(super) struct LeafEnableGuard<'a> {
517     bar: Bar0<'a>,
518     leaf: LeafIndex,
519     vectors: LeafMask,
520 }
521 
522 impl Drop for LeafEnableGuard<'_> {
523     fn drop(&mut self) {
524         clear_leaf_enables(self.bar, self.leaf, self.vectors);
525     }
526 }
527 
528 /// Disables the serviced subtrees at `TOP` when dropped.
529 pub(crate) struct TopEnableGuard<'a> {
530     bar: Bar0<'a>,
531     serviced: SubtreeSet,
532 }
533 
534 impl Drop for TopEnableGuard<'_> {
535     fn drop(&mut self) {
536         clear_top_enables(self.bar, self.serviced);
537     }
538 }
539