€•Œsphinx.addnodes”Œdocument”“”)�”}”(Œ rawsource”Œ”Œchildren”]”(Œ translations”Œ LanguagesNode”“”)�”}”(hhh]”(hŒ pending_xref”“”)�”}”(hhh]”Œdocutils.nodes”ŒText”“”ŒChinese (Simplified)”…”�”}”Œparent”hsbaŒ attributes”}”(Œids”]”Œclasses”]”Œnames”]”Œdupnames”]”Œbackrefs”]”Œ refdomain”Œstd”Œreftype”Œdoc”Œ reftarget”Œ,/translations/zh_CN/gpu/nova/core/interrupts”Œmodname”NŒ classname”NŒ refexplicit”ˆuŒtagname”hhh ubh)�”}”(hhh]”hŒChinese (Traditional)”…”�”}”hh2sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ,/translations/zh_TW/gpu/nova/core/interrupts”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒItalian”…”�”}”hhFsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ,/translations/it_IT/gpu/nova/core/interrupts”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒJapanese”…”�”}”hhZsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ,/translations/ja_JP/gpu/nova/core/interrupts”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒKorean”…”�”}”hhnsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ,/translations/ko_KR/gpu/nova/core/interrupts”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒPortuguese (Brazilian)”…”�”}”hh‚sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ,/translations/pt_BR/gpu/nova/core/interrupts”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒSpanish”…”�”}”hh–sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ,/translations/sp_SP/gpu/nova/core/interrupts”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒcomment”“”)�”}”(hŒ SPDX-License-Identifier: GPL-2.0”h]”hŒ SPDX-License-Identifier: GPL-2.0”…”�”}”hh·sbah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”uh1hµhhh²hh³ŒF/var/lib/git/docbuild/linux/Documentation/gpu/nova/core/interrupts.rst”h´Kubh¶)�”}”(hŒ`SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.”h]”hŒ`SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.”…”�”}”hhÈsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1hµhhh²hh³hÇh´KubhŒsection”“”)�”}”(hhh]”(hŒtitle”“”)�”}”(hŒ-GPU interrupt handling: GIN and the GSP event”h]”hŒ-GPU interrupt handling: GIN and the GSP event”…”�”}”(hhÝh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhhØh²hh³hÇh´KubhŒ paragraph”“”)�”}”(hXThis document describes how nova-core receives interrupts from the GPU on Turing and later chipsets. It covers the GPU Interrupt and Notification unit (GIN), which is the GPU's interrupt controller, and the GSP event, the interrupt that nova-core services in normal operation.”h]”hXThis document describes how nova-core receives interrupts from the GPU on Turing and later chipsets. It covers the GPU Interrupt and Notification unit (GIN), which is the GPU’s interrupt controller, and the GSP event, the interrupt that nova-core services in normal operation.”…”�”}”(hhíh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KhhØh²hubhì)�”}”(hŒØThroughout, *CPU* means the CPU and the nova-core driver running on it. The GPU also has on-chip processors that run their own firmware and receive their own interrupts. The GSP (GPU System Processor) is one of them.”h]”(hŒ Throughout, ”…”�”}”(hhûh²hh³Nh´NubhŒemphasis”“”)�”}”(hŒ*CPU*”h]”hŒCPU”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhhûubhŒÇ means the CPU and the nova-core driver running on it. The GPU also has on-chip processors that run their own firmware and receive their own interrupts. The GSP (GPU System Processor) is one of them.”…”�”}”(hhûh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´K hhØh²hubhì)�”}”(hX|Register names are the names from the GPU hardware reference headers. The pre-Hopper headers call the controller ``NV_CTRL`` and the Hopper-plus headers call it ``NV_GIN``. This document calls it GIN throughout, because the tree that nova-core services is the same on every supported chipset. OpenRM, NVIDIA's open-source GPU kernel driver, is cited wherever nova-core follows it.”h]”(hŒqRegister names are the names from the GPU hardware reference headers. The pre-Hopper headers call the controller ”…”�”}”(hjh²hh³Nh´NubhŒliteral”“”)�”}”(hŒ ``NV_CTRL``”h]”hŒNV_CTRL”…”�”}”(hj'h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjubhŒ% and the Hopper-plus headers call it ”…”�”}”(hjh²hh³Nh´Nubj&)�”}”(hŒ ``NV_GIN``”h]”hŒNV_GIN”…”�”}”(hj9h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjubhŒÓ. This document calls it GIN throughout, because the tree that nova-core services is the same on every supported chipset. OpenRM, NVIDIA’s open-source GPU kernel driver, is cited wherever nova-core follows it.”…”�”}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KhhØh²hubh×)�”}”(hhh]”(hÜ)�”}”(hŒ Terminology”h]”hŒ Terminology”…”�”}”(hjTh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjQh²hh³hÇh´Kubhì)�”}”(hŒ4The three levels of the controller, innermost first:”h]”hŒ4The three levels of the controller, innermost first:”…”�”}”(hjbh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KhjQh²hubhŒdefinition_list”“”)�”}”(hhh]”(hŒdefinition_list_item”“”)�”}”(hŒ«leaf One ``LEAF`` register. Each of its 32 bits is the pending bit of one interrupt source. A Turing, Ampere, or Ada tree has 8 leaves. A Hopper or Blackwell tree has 16. ”h]”(hŒterm”“”)�”}”(hŒleaf”h]”hŒleaf”…”�”}”(hj}h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j{h³hÇh´KhjwubhŒ definition”“”)�”}”(hhh]”hì)�”}”(hŒ¥One ``LEAF`` register. Each of its 32 bits is the pending bit of one interrupt source. A Turing, Ampere, or Ada tree has 8 leaves. A Hopper or Blackwell tree has 16.”h]”(hŒOne ”…”�”}”(hj�h²hh³Nh´Nubj&)�”}”(hŒ``LEAF``”h]”hŒLEAF”…”�”}”(hj˜h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj�ubhŒ™ register. Each of its 32 bits is the pending bit of one interrupt source. A Turing, Ampere, or Ada tree has 8 leaves. A Hopper or Blackwell tree has 16.”…”�”}”(hj�h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´Khj�ubah}”(h]”h ]”h"]”h$]”h&]”uh1j‹hjwubeh}”(h]”h ]”h"]”h$]”h&]”uh1juh³hÇh´Khjrubjv)�”}”(hŒÙsubtree Two consecutive leaves, summarized by one bit of ``TOP``. A subtree is the unit of enabling at ``TOP``, and under MSI-X it is the unit of delivery: every interrupt from one subtree arrives on one MSI-X entry. ”h]”(j|)�”}”(hŒsubtree”h]”hŒsubtree”…”�”}”(hjÀh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j{h³hÇh´K$hj¼ubjŒ)�”}”(hhh]”hì)�”}”(hŒÐTwo consecutive leaves, summarized by one bit of ``TOP``. A subtree is the unit of enabling at ``TOP``, and under MSI-X it is the unit of delivery: every interrupt from one subtree arrives on one MSI-X entry.”h]”(hŒ1Two consecutive leaves, summarized by one bit of ”…”�”}”(hjÑh²hh³Nh´Nubj&)�”}”(hŒ``TOP``”h]”hŒTOP”…”�”}”(hjÙh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjÑubhŒ'. A subtree is the unit of enabling at ”…”�”}”(hjÑh²hh³Nh´Nubj&)�”}”(hŒ``TOP``”h]”hŒTOP”…”�”}”(hjëh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjÑubhŒj, and under MSI-X it is the unit of delivery: every interrupt from one subtree arrives on one MSI-X entry.”…”�”}”(hjÑh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´K"hjÎubah}”(h]”h ]”h"]”h$]”h&]”uh1j‹hj¼ubeh}”(h]”h ]”h"]”h$]”h&]”uh1juh³hÇh´K$hjrh²hubjv)�”}”(hŒŽtree One ``TOP`` register and the leaves under it. Every PCIe function has its own tree, and nova-core services the CPU tree of one function. ”h]”(j|)�”}”(hŒtree”h]”hŒtree”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j{h³hÇh´K(hjubjŒ)�”}”(hhh]”hì)�”}”(hŒˆOne ``TOP`` register and the leaves under it. Every PCIe function has its own tree, and nova-core services the CPU tree of one function.”h]”(hŒOne ”…”�”}”(hj$h²hh³Nh´Nubj&)�”}”(hŒ``TOP``”h]”hŒTOP”…”�”}”(hj,h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj$ubhŒ} register and the leaves under it. Every PCIe function has its own tree, and nova-core services the CPU tree of one function.”…”�”}”(hj$h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´K'hj!ubah}”(h]”h ]”h"]”h$]”h&]”uh1j‹hjubeh}”(h]”h ]”h"]”h$]”h&]”uh1juh³hÇh´K(hjrh²hubeh}”(h]”h ]”h"]”h$]”h&]”uh1jphjQh²hh³hÇh´Nubhì)�”}”(hŒÅThe hardware headers, OpenRM, and the Linux PCI API all use the word "vector", each for a different number. This document gives each one its own name, and a bare "vector" always means a GIN vector.”h]”hŒÍThe hardware headers, OpenRM, and the Linux PCI API all use the word “vectorâ€�, each for a different number. This document gives each one its own name, and a bare “vectorâ€� always means a GIN vector.”…”�”}”(hjVh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´K*hjQh²hubjq)�”}”(hhh]”(jv)�”}”(hŒëGIN vector The GPU-internal interrupt source number. It addresses one bit of one leaf. A 16-leaf tree holds vectors 0 through 511, and an 8-leaf tree holds 0 through 255. The CPU doorbell is vector 129 and the GSP event is vector 155. ”h]”(j|)�”}”(hŒ GIN vector”h]”hŒ GIN vector”…”�”}”(hjkh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j{h³hÇh´K2hjgubjŒ)�”}”(hhh]”hì)�”}”(hŒßThe GPU-internal interrupt source number. It addresses one bit of one leaf. A 16-leaf tree holds vectors 0 through 511, and an 8-leaf tree holds 0 through 255. The CPU doorbell is vector 129 and the GSP event is vector 155.”h]”hŒßThe GPU-internal interrupt source number. It addresses one bit of one leaf. A 16-leaf tree holds vectors 0 through 511, and an 8-leaf tree holds 0 through 255. The CPU doorbell is vector 129 and the GSP event is vector 155.”…”�”}”(hj|h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´K/hjyubah}”(h]”h ]”h"]”h$]”h&]”uh1j‹hjgubeh}”(h]”h ]”h"]”h$]”h&]”uh1juh³hÇh´K2hjdubjv)�”}”(hŒRMSI-X entry An index into the device's MSI-X table. One entry serves one subtree. ”h]”(j|)�”}”(hŒ MSI-X entry”h]”hŒ MSI-X entry”…”�”}”(hjšh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j{h³hÇh´K5hj–ubjŒ)�”}”(hhh]”hì)�”}”(hŒEAn index into the device's MSI-X table. One entry serves one subtree.”h]”hŒGAn index into the device’s MSI-X table. One entry serves one subtree.”…”�”}”(hj«h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´K5hj¨ubah}”(h]”h ]”h"]”h$]”h&]”uh1j‹hj–ubeh}”(h]”h ]”h"]”h$]”h&]”uh1juh³hÇh´K5hjdh²hubjv)�”}”(hŒxPCI vector One of the interrupts that ``pci_alloc_irq_vectors()`` allocates: an MSI-X entry, or the single MSI message. ”h]”(j|)�”}”(hŒ PCI vector”h]”hŒ PCI vector”…”�”}”(hjÉh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j{h³hÇh´K9hjÅubjŒ)�”}”(hhh]”hì)�”}”(hŒlOne of the interrupts that ``pci_alloc_irq_vectors()`` allocates: an MSI-X entry, or the single MSI message.”h]”(hŒOne of the interrupts that ”…”�”}”(hjÚh²hh³Nh´Nubj&)�”}”(hŒ``pci_alloc_irq_vectors()``”h]”hŒpci_alloc_irq_vectors()”…”�”}”(hjâh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjÚubhŒ6 allocates: an MSI-X entry, or the single MSI message.”…”�”}”(hjÚh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´K8hj×ubah}”(h]”h ]”h"]”h$]”h&]”uh1j‹hjÅubeh}”(h]”h ]”h"]”h$]”h&]”uh1juh³hÇh´K9hjdh²hubjv)�”}”(hŒ©Linux IRQ number What ``request_irq()`` takes, obtained from ``pci_irq_vector()`` for a PCI vector. Linux's ``struct msix_entry`` calls this number ``.vector`` as well. ”h]”(j|)�”}”(hŒLinux IRQ number”h]”hŒLinux IRQ number”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j{h³hÇh´K>hjubjŒ)�”}”(hhh]”hì)�”}”(hŒ—What ``request_irq()`` takes, obtained from ``pci_irq_vector()`` for a PCI vector. Linux's ``struct msix_entry`` calls this number ``.vector`` as well.”h]”(hŒWhat ”…”�”}”(hjh²hh³Nh´Nubj&)�”}”(hŒ``request_irq()``”h]”hŒ request_irq()”…”�”}”(hj#h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjubhŒ takes, obtained from ”…”�”}”(hjh²hh³Nh´Nubj&)�”}”(hŒ``pci_irq_vector()``”h]”hŒpci_irq_vector()”…”�”}”(hj5h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjubhŒ for a PCI vector. Linux’s ”…”�”}”(hjh²hh³Nh´Nubj&)�”}”(hŒ``struct msix_entry``”h]”hŒstruct msix_entry”…”�”}”(hjGh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjubhŒ calls this number ”…”�”}”(hjh²hh³Nh´Nubj&)�”}”(hŒ ``.vector``”h]”hŒ.vector”…”�”}”(hjYh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjubhŒ as well.”…”�”}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´Khjdh²hubeh}”(h]”h ]”h"]”h$]”h&]”uh1jphjQh²hh³hÇh´Nubhì)�”}”(hŒVThe remaining terms, each named for the register or the specification that defines it:”h]”hŒVThe remaining terms, each named for the register or the specification that defines it:”…”�”}”(hjƒh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´K@hjQh²hubjq)�”}”(hhh]”(jv)�”}”(hŒJenable, disable a vector Writes to ``LEAF_EN_SET`` and ``LEAF_EN_CLEAR``. ”h]”(j|)�”}”(hŒenable, disable a vector”h]”hŒenable, disable a vector”…”�”}”(hj˜h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j{h³hÇh´KDhj”ubjŒ)�”}”(hhh]”hì)�”}”(hŒ0Writes to ``LEAF_EN_SET`` and ``LEAF_EN_CLEAR``.”h]”(hŒ Writes to ”…”�”}”(hj©h²hh³Nh´Nubj&)�”}”(hŒ``LEAF_EN_SET``”h]”hŒ LEAF_EN_SET”…”�”}”(hj±h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj©ubhŒ and ”…”�”}”(hj©h²hh³Nh´Nubj&)�”}”(hŒ``LEAF_EN_CLEAR``”h]”hŒ LEAF_EN_CLEAR”…”�”}”(hjÃh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj©ubhŒ.”…”�”}”(hj©h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KDhj¦ubah}”(h]”h ]”h"]”h$]”h&]”uh1j‹hj”ubeh}”(h]”h ]”h"]”h$]”h&]”uh1juh³hÇh´KDhj‘ubjv)�”}”(hŒIenable, disable a subtree Writes to ``TOP_EN_SET`` and ``TOP_EN_CLEAR``. ”h]”(j|)�”}”(hŒenable, disable a subtree”h]”hŒenable, disable a subtree”…”�”}”(hjëh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j{h³hÇh´KGhjçubjŒ)�”}”(hhh]”hì)�”}”(hŒ.Writes to ``TOP_EN_SET`` and ``TOP_EN_CLEAR``.”h]”(hŒ Writes to ”…”�”}”(hjüh²hh³Nh´Nubj&)�”}”(hŒ``TOP_EN_SET``”h]”hŒ TOP_EN_SET”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjüubhŒ and ”…”�”}”(hjüh²hh³Nh´Nubj&)�”}”(hŒ``TOP_EN_CLEAR``”h]”hŒ TOP_EN_CLEAR”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjüubhŒ.”…”�”}”(hjüh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KGhjùubah}”(h]”h ]”h"]”h$]”h&]”uh1j‹hjçubeh}”(h]”h ]”h"]”h$]”h&]”uh1juh³hÇh´KGhj‘h²hubjv)�”}”(hŒIserviced subtree A subtree that nova-core enables and has a handler for. ”h]”(j|)�”}”(hŒserviced subtree”h]”hŒserviced subtree”…”�”}”(hj>h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j{h³hÇh´KJhj:ubjŒ)�”}”(hhh]”hì)�”}”(hŒ7A subtree that nova-core enables and has a handler for.”h]”hŒ7A subtree that nova-core enables and has a handler for.”…”�”}”(hjOh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KJhjLubah}”(h]”h ]”h"]”h$]”h&]”uh1j‹hj:ubeh}”(h]”h ]”h"]”h$]”h&]”uh1juh³hÇh´KJhj‘h²hubjv)�”}”(hŒlrearm Restoring PCI interrupt delivery after servicing an interrupt. See "Rearming PCI interrupt delivery". ”h]”(j|)�”}”(hŒrearm”h]”hŒrearm”…”�”}”(hjmh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j{h³hÇh´KNhjiubjŒ)�”}”(hhh]”hì)�”}”(hŒeRestoring PCI interrupt delivery after servicing an interrupt. See "Rearming PCI interrupt delivery".”h]”hŒiRestoring PCI interrupt delivery after servicing an interrupt. See “Rearming PCI interrupt deliveryâ€�.”…”�”}”(hj~h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KMhj{ubah}”(h]”h ]”h"]”h$]”h&]”uh1j‹hjiubeh}”(h]”h ]”h"]”h$]”h&]”uh1juh³hÇh´KNhj‘h²hubjv)�”}”(hŒØmask Reserved for the two places where hardware and the PCI specification use the word: the MSI-X per-entry Vector Control mask bit, which Linux controls, and the falcon interrupt masks. It never names a GIN enable. ”h]”(j|)�”}”(hŒmask”h]”hŒmask”…”�”}”(hjœh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j{h³hÇh´KShj˜ubjŒ)�”}”(hhh]”hì)�”}”(hŒÒReserved for the two places where hardware and the PCI specification use the word: the MSI-X per-entry Vector Control mask bit, which Linux controls, and the falcon interrupt masks. It never names a GIN enable.”h]”hŒÒReserved for the two places where hardware and the PCI specification use the word: the MSI-X per-entry Vector Control mask bit, which Linux controls, and the falcon interrupt masks. It never names a GIN enable.”…”�”}”(hj­h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KQhjªubah}”(h]”h ]”h"]”h$]”h&]”uh1j‹hj˜ubeh}”(h]”h ]”h"]”h$]”h&]”uh1juh³hÇh´KShj‘h²hubjv)�”}”(hŒ…latched, pending Two names for one state, a set ``LEAF`` bit. The vector's source sets the bit whether or not the vector is enabled. ”h]”(j|)�”}”(hŒlatched, pending”h]”hŒlatched, pending”…”�”}”(hjËh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j{h³hÇh´KWhjÇubjŒ)�”}”(hhh]”hì)�”}”(hŒsTwo names for one state, a set ``LEAF`` bit. The vector's source sets the bit whether or not the vector is enabled.”h]”(hŒTwo names for one state, a set ”…”�”}”(hjÜh²hh³Nh´Nubj&)�”}”(hŒ``LEAF``”h]”hŒLEAF”…”�”}”(hjäh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjÜubhŒN bit. The vector’s source sets the bit whether or not the vector is enabled.”…”�”}”(hjÜh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KVhjÙubah}”(h]”h ]”h"]”h$]”h&]”uh1j‹hjÇubeh}”(h]”h ]”h"]”h$]”h&]”uh1juh³hÇh´KWhj‘h²hubjv)�”}”(hŒwclear a vector Write a 1 to the vector's bit in ``LEAF``. OpenRM calls the same operation ``intrClearLeafVector_HAL``. ”h]”(j|)�”}”(hŒclear a vector”h]”hŒclear a vector”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j{h³hÇh´K[hjubjŒ)�”}”(hhh]”hì)�”}”(hŒgWrite a 1 to the vector's bit in ``LEAF``. OpenRM calls the same operation ``intrClearLeafVector_HAL``.”h]”(hŒ#Write a 1 to the vector’s bit in ”…”�”}”(hjh²hh³Nh´Nubj&)�”}”(hŒ``LEAF``”h]”hŒLEAF”…”�”}”(hj%h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjubhŒ". OpenRM calls the same operation ”…”�”}”(hjh²hh³Nh´Nubj&)�”}”(hŒ``intrClearLeafVector_HAL``”h]”hŒintrClearLeafVector_HAL”…”�”}”(hj7h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjubhŒ.”…”�”}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KZhjubah}”(h]”h ]”h"]”h$]”h&]”uh1j‹hjubeh}”(h]”h ]”h"]”h$]”h&]”uh1juh³hÇh´K[hj‘h²hubjv)�”}”(hŒCpending bits The plain 32-bit value read from a ``LEAF`` register. ”h]”(j|)�”}”(hŒ pending bits”h]”hŒ pending bits”…”�”}”(hj_h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j{h³hÇh´K^hj[ubjŒ)�”}”(hhh]”hì)�”}”(hŒ5The plain 32-bit value read from a ``LEAF`` register.”h]”(hŒ#The plain 32-bit value read from a ”…”�”}”(hjph²hh³Nh´Nubj&)�”}”(hŒ``LEAF``”h]”hŒLEAF”…”�”}”(hjxh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjpubhŒ register.”…”�”}”(hjph²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´K^hjmubah}”(h]”h ]”h"]”h$]”h&]”uh1j‹hj[ubeh}”(h]”h ]”h"]”h$]”h&]”uh1juh³hÇh´K^hj‘h²hubjv)�”}”(hŒßnotification An interrupt whose only content is that something happened, such as a posted message. Servicing a notification means reading what it announces. The unit that raised it needs no attention. The GSP event is one. ”h]”(j|)�”}”(hŒ notification”h]”hŒ notification”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j{h³hÇh´KchjœubjŒ)�”}”(hhh]”hì)�”}”(hŒÑAn interrupt whose only content is that something happened, such as a posted message. Servicing a notification means reading what it announces. The unit that raised it needs no attention. The GSP event is one.”h]”hŒÑAn interrupt whose only content is that something happened, such as a posted message. Servicing a notification means reading what it announces. The unit that raised it needs no attention. The GSP event is one.”…”�”}”(hj±h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´Kahj®ubah}”(h]”h ]”h"]”h$]”h&]”uh1j‹hjœubeh}”(h]”h ]”h"]”h$]”h&]”uh1juh³hÇh´Kchj‘h²hubjv)�”}”(hŒ}unit Any block that raises an interrupt. "Engine" is reserved for the blocks that do user work: GR, CE, NVDEC, and the like. ”h]”(j|)�”}”(hŒunit”h]”hŒunit”…”�”}”(hjÏh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j{h³hÇh´KghjËubjŒ)�”}”(hhh]”hì)�”}”(hŒwAny block that raises an interrupt. "Engine" is reserved for the blocks that do user work: GR, CE, NVDEC, and the like.”h]”hŒ{Any block that raises an interrupt. “Engineâ€� is reserved for the blocks that do user work: GR, CE, NVDEC, and the like.”…”�”}”(hjàh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KfhjÝubah}”(h]”h ]”h"]”h$]”h&]”uh1j‹hjËubeh}”(h]”h ]”h"]”h$]”h&]”uh1juh³hÇh´Kghj‘h²hubjv)�”}”(hŒÿfalcon One of the GPU's microcontrollers (see Documentation/gpu/nova/core/falcon.rst). The GSP runs on the RISC-V core inside its falcon. A falcon latches each of its interrupt causes and routes it either to the host, meaning the CPU, or to its own core. ”h]”(j|)�”}”(hŒfalcon”h]”hŒfalcon”…”�”}”(hjþh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j{h³hÇh´KmhjúubjŒ)�”}”(hhh]”hì)�”}”(hŒ÷One of the GPU's microcontrollers (see Documentation/gpu/nova/core/falcon.rst). The GSP runs on the RISC-V core inside its falcon. A falcon latches each of its interrupt causes and routes it either to the host, meaning the CPU, or to its own core.”h]”hŒùOne of the GPU’s microcontrollers (see Documentation/gpu/nova/core/falcon.rst). The GSP runs on the RISC-V core inside its falcon. A falcon latches each of its interrupt causes and routes it either to the host, meaning the CPU, or to its own core.”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´Kjhj ubah}”(h]”h ]”h"]”h$]”h&]”uh1j‹hjúubeh}”(h]”h ]”h"]”h$]”h&]”uh1juh³hÇh´Kmhj‘h²hubeh}”(h]”h ]”h"]”h$]”h&]”uh1jphjQh²hh³hÇh´Nubeh}”(h]”Œ terminology”ah ]”h"]”Œ terminology”ah$]”h&]”uh1hÖhhØh²hh³hÇh´Kubh×)�”}”(hhh]”(hÜ)�”}”(hŒThe GIN controller”h]”hŒThe GIN controller”…”�”}”(hj:h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhj7h²hh³hÇh´Kpubhì)�”}”(hŒáA GPU has many interrupt sources: the GSP, the copy engines, the graphics engine, video decode and encode, the MMU fault path, timers, and others. GIN records which of them are pending and raises the PCI interrupt to the CPU.”h]”hŒáA GPU has many interrupt sources: the GSP, the copy engines, the graphics engine, video decode and encode, the MMU fault path, timers, and others. GIN records which of them are pending and raises the PCI interrupt to the CPU.”…”�”}”(hjHh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´Krhj7h²hubh×)�”}”(hhh]”(hÜ)�”}”(hŒTrees”h]”hŒTrees”…”�”}”(hjYh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjVh²hh³hÇh´Kwubhì)�”}”(hX€GIN keeps one tree for each destination it can deliver an interrupt to. The CPU has one tree per PCIe function, so the physical function and each virtual function have their own. The GSP has a tree, and so do the other on-chip processors that receive interrupts. Every tree has the same two-level layout, and a function reaches its own tree through the per-function register aperture.”h]”hX€GIN keeps one tree for each destination it can deliver an interrupt to. The CPU has one tree per PCIe function, so the physical function and each virtual function have their own. The GSP has a tree, and so do the other on-chip processors that receive interrupts. Every tree has the same two-level layout, and a function reaches its own tree through the per-function register aperture.”…”�”}”(hjgh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KyhjVh²hubhì)�”}”(hŒ·nova-core services the CPU tree of one function. A virtual function's tree belongs to that function's driver, and a processor's tree belongs to the firmware running on that processor.”h]”hŒ½nova-core services the CPU tree of one function. A virtual function’s tree belongs to that function’s driver, and a processor’s tree belongs to the firmware running on that processor.”…”�”}”(hjuh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KhjVh²hubeh}”(h]”Œtrees”ah ]”h"]”Œtrees”ah$]”h&]”uh1hÖhj7h²hh³hÇh´Kwubh×)�”}”(hhh]”(hÜ)�”}”(hŒThe two-level tree”h]”hŒThe two-level tree”…”�”}”(hjŽh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhj‹h²hh³hÇh´K„ubhì)�”}”(hŒ?A tree is a set of ``LEAF`` registers and one ``TOP`` register.”h]”(hŒA tree is a set of ”…”�”}”(hjœh²hh³Nh´Nubj&)�”}”(hŒ``LEAF``”h]”hŒLEAF”…”�”}”(hj¤h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjœubhŒ registers and one ”…”�”}”(hjœh²hh³Nh´Nubj&)�”}”(hŒ``TOP``”h]”hŒTOP”…”�”}”(hj¶h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjœubhŒ register.”…”�”}”(hjœh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´K†hj‹h²hubhŒ bullet_list”“”)�”}”(hhh]”(hŒ list_item”“”)�”}”(hŒ„``LEAF(i)`` is a 32-bit register that holds the pending bits of vectors ``32i`` through ``32i + 31``. A set bit is a pending vector.”h]”hì)�”}”(hŒ„``LEAF(i)`` is a 32-bit register that holds the pending bits of vectors ``32i`` through ``32i + 31``. A set bit is a pending vector.”h]”(j&)�”}”(hŒ ``LEAF(i)``”h]”hŒLEAF(i)”…”�”}”(hjÝh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjÙubhŒ= is a 32-bit register that holds the pending bits of vectors ”…”�”}”(hjÙh²hh³Nh´Nubj&)�”}”(hŒ``32i``”h]”hŒ32i”…”�”}”(hjïh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjÙubhŒ through ”…”�”}”(hjÙh²hh³Nh´Nubj&)�”}”(hŒ ``32i + 31``”h]”hŒ32i + 31”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjÙubhŒ . A set bit is a pending vector.”…”�”}”(hjÙh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KˆhjÕubah}”(h]”h ]”h"]”h$]”h&]”uh1jÓhjÐh²hh³hÇh´NubjÔ)�”}”(hŒ¹``TOP`` is a 32-bit read-only register. Bit ``N`` summarizes subtree ``N``, which is ``LEAF(2N)`` and ``LEAF(2N + 1)``. The bit is set when an enabled vector is pending in either leaf. ”h]”hì)�”}”(hŒ¸``TOP`` is a 32-bit read-only register. Bit ``N`` summarizes subtree ``N``, which is ``LEAF(2N)`` and ``LEAF(2N + 1)``. The bit is set when an enabled vector is pending in either leaf.”h]”(j&)�”}”(hŒ``TOP``”h]”hŒTOP”…”�”}”(hj'h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj#ubhŒ% is a 32-bit read-only register. Bit ”…”�”}”(hj#h²hh³Nh´Nubj&)�”}”(hŒ``N``”h]”hŒN”…”�”}”(hj9h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj#ubhŒ summarizes subtree ”…”�”}”(hj#h²hh³Nh´Nubj&)�”}”(hŒ``N``”h]”hŒN”…”�”}”(hjKh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj#ubhŒ , which is ”…”�”}”(hj#h²hh³Nh´Nubj&)�”}”(hŒ ``LEAF(2N)``”h]”hŒLEAF(2N)”…”�”}”(hj]h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj#ubhŒ and ”…”�”}”(hj#h²hh³Nh´Nubj&)�”}”(hŒ``LEAF(2N + 1)``”h]”hŒ LEAF(2N + 1)”…”�”}”(hjoh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj#ubhŒB. The bit is set when an enabled vector is pending in either leaf.”…”�”}”(hj#h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KŠhjubah}”(h]”h ]”h"]”h$]”h&]”uh1jÓhjÐh²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”Œbullet”Œ*”uh1jÎh³hÇh´Kˆhj‹h²hubhì)�”}”(hXA tree with L leaves has L / 2 subtrees and uses TOP bits 0 through L / 2 - 1. The other TOP bits read 0. The leaves and subtrees that a chipset has are its implemented leaves and subtrees, and "Per-architecture differences" gives the counts. For an 8-leaf tree::”h]”hX A tree with L leaves has L / 2 subtrees and uses TOP bits 0 through L / 2 - 1. The other TOP bits read 0. The leaves and subtrees that a chipset has are its implemented leaves and subtrees, and “Per-architecture differencesâ€� gives the counts. For an 8-leaf tree:”…”�”}”(hj•h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KŽhj‹h²hubhŒ literal_block”“”)�”}”(hX†TOP bit 0 -> subtree 0 -> LEAF(0), LEAF(1) vectors 0..63 TOP bit 1 -> subtree 1 -> LEAF(2), LEAF(3) vectors 64..127 TOP bit 2 -> subtree 2 -> LEAF(4), LEAF(5) vectors 128..191 TOP bit 3 -> subtree 3 -> LEAF(6), LEAF(7) vectors 192..255 LEAF(4), one bit per vector, holds vectors 128..159: bit 1 = vector 129 (CPU doorbell) bit 27 = vector 155 (GSP event)”h]”hX†TOP bit 0 -> subtree 0 -> LEAF(0), LEAF(1) vectors 0..63 TOP bit 1 -> subtree 1 -> LEAF(2), LEAF(3) vectors 64..127 TOP bit 2 -> subtree 2 -> LEAF(4), LEAF(5) vectors 128..191 TOP bit 3 -> subtree 3 -> LEAF(6), LEAF(7) vectors 192..255 LEAF(4), one bit per vector, holds vectors 128..159: bit 1 = vector 129 (CPU doorbell) bit 27 = vector 155 (GSP event)”…”�”}”hj¥sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j£h³hÇh´K“hj‹h²hubhì)�”}”(hŒ/A vector's number fixes its place in the tree::”h]”hŒ0A vector’s number fixes its place in the tree:”…”�”}”(hj³h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´K�hj‹h²hubj¤)�”}”(hŒ>leaf = vector / 32 bit = vector % 32 subtree = leaf / 2”h]”hŒ>leaf = vector / 32 bit = vector % 32 subtree = leaf / 2”…”�”}”hjÁsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j£h³hÇh´KŸhj‹h²hubeh}”(h]”Œthe-two-level-tree”ah ]”h"]”Œthe two-level tree”ah$]”h&]”uh1hÖhj7h²hh³hÇh´K„ubh×)�”}”(hhh]”(hÜ)�”}”(hŒ Registers”h]”hŒ Registers”…”�”}”(hjÚh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhj×h²hh³hÇh´K¤ubhì)�”}”(hŒ�nova-core defines the tree's registers in the ``irq`` module's ``regs.rs``. The leaf registers are arrays indexed by leaf number.”h]”(hŒ0nova-core defines the tree’s registers in the ”…”�”}”(hjèh²hh³Nh´Nubj&)�”}”(hŒ``irq``”h]”hŒirq”…”�”}”(hjðh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjèubhŒ module’s ”…”�”}”(hjèh²hh³Nh´Nubj&)�”}”(hŒ ``regs.rs``”h]”hŒregs.rs”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjèubhŒ7. The leaf registers are arrays indexed by leaf number.”…”�”}”(hjèh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´K¦hj×h²hubjÏ)�”}”(hhh]”(jÔ)�”}”(hŒ``LEAF(i)`` reads as the pending bits of leaf ``i``. Writing a 1 to a bit clears that vector, and a 0 leaves the bit as it was.”h]”hì)�”}”(hŒ``LEAF(i)`` reads as the pending bits of leaf ``i``. Writing a 1 to a bit clears that vector, and a 0 leaves the bit as it was.”h]”(j&)�”}”(hŒ ``LEAF(i)``”h]”hŒLEAF(i)”…”�”}”(hj%h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj!ubhŒ# reads as the pending bits of leaf ”…”�”}”(hj!h²hh³Nh´Nubj&)�”}”(hŒ``i``”h]”hŒi”…”�”}”(hj7h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj!ubhŒL. Writing a 1 to a bit clears that vector, and a 0 leaves the bit as it was.”…”�”}”(hj!h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´K©hjubah}”(h]”h ]”h"]”h$]”h&]”uh1jÓhjh²hh³hÇh´NubjÔ)�”}”(hŒm``LEAF_EN_SET(i)`` and ``LEAF_EN_CLEAR(i)`` enable and disable the vectors of leaf ``i``, one bit per vector.”h]”hì)�”}”(hŒm``LEAF_EN_SET(i)`` and ``LEAF_EN_CLEAR(i)`` enable and disable the vectors of leaf ``i``, one bit per vector.”h]”(j&)�”}”(hŒ``LEAF_EN_SET(i)``”h]”hŒLEAF_EN_SET(i)”…”�”}”(hj]h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjYubhŒ and ”…”�”}”(hjYh²hh³Nh´Nubj&)�”}”(hŒ``LEAF_EN_CLEAR(i)``”h]”hŒLEAF_EN_CLEAR(i)”…”�”}”(hjoh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjYubhŒ( enable and disable the vectors of leaf ”…”�”}”(hjYh²hh³Nh´Nubj&)�”}”(hŒ``i``”h]”hŒi”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjYubhŒ, one bit per vector.”…”�”}”(hjYh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´K«hjUubah}”(h]”h ]”h"]”h$]”h&]”uh1jÓhjh²hh³hÇh´NubjÔ)�”}”(hŒU``TOP_EN_SET`` and ``TOP_EN_CLEAR`` enable and disable subtrees, one bit per subtree.”h]”hì)�”}”(hŒU``TOP_EN_SET`` and ``TOP_EN_CLEAR`` enable and disable subtrees, one bit per subtree.”h]”(j&)�”}”(hŒ``TOP_EN_SET``”h]”hŒ TOP_EN_SET”…”�”}”(hj§h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj£ubhŒ and ”…”�”}”(hj£h²hh³Nh´Nubj&)�”}”(hŒ``TOP_EN_CLEAR``”h]”hŒ TOP_EN_CLEAR”…”�”}”(hj¹h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj£ubhŒ2 enable and disable subtrees, one bit per subtree.”…”�”}”(hj£h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´K­hjŸubah}”(h]”h ]”h"]”h$]”h&]”uh1jÓhjh²hh³hÇh´NubjÔ)�”}”(hŒ“``LEAF_TRIGGER`` takes a vector number and latches that vector, exactly as the vector's own source would. It is write-only. The self-test uses it. ”h]”hì)�”}”(hŒ’``LEAF_TRIGGER`` takes a vector number and latches that vector, exactly as the vector's own source would. It is write-only. The self-test uses it.”h]”(j&)�”}”(hŒ``LEAF_TRIGGER``”h]”hŒ LEAF_TRIGGER”…”�”}”(hjßh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjÛubhŒ„ takes a vector number and latches that vector, exactly as the vector’s own source would. It is write-only. The self-test uses it.”…”�”}”(hjÛh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´K¯hj×ubah}”(h]”h ]”h"]”h$]”h&]”uh1jÓhjh²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”j“j”uh1jÎh³hÇh´K©hj×h²hubhì)�”}”(hŒ?nova-core does not read ``TOP``. "Servicing the tree" says why.”h]”(hŒnova-core does not read ”…”�”}”(hj h²hh³Nh´Nubj&)�”}”(hŒ``TOP``”h]”hŒTOP”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj ubhŒ$. “Servicing the treeâ€� says why.”…”�”}”(hj h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´K²hj×h²hubhì)�”}”(hŒ•Every set and clear register acts per bit: a 1 performs the action for that bit, and a 0 leaves the bit alone. No register needs a read-modify-write.”h]”hŒ•Every set and clear register acts per bit: a 1 performs the action for that bit, and a 0 leaves the bit alone. No register needs a read-modify-write.”…”�”}”(hj# h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´K´hj×h²hubhì)�”}”(hXGIN delivers a vector to the CPU only when its leaf enable bit and its subtree's TOP enable bit are both set. The enables do not affect the latch. The source of a disabled vector still sets its ``LEAF`` bit. ``TOP`` does not show that bit, so reading the leaf is the only way to see it.”h]”(hŒÄGIN delivers a vector to the CPU only when its leaf enable bit and its subtree’s TOP enable bit are both set. The enables do not affect the latch. The source of a disabled vector still sets its ”…”�”}”(hj1 h²hh³Nh´Nubj&)�”}”(hŒ``LEAF``”h]”hŒLEAF”…”�”}”(hj9 h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj1 ubhŒ bit. ”…”�”}”(hj1 h²hh³Nh´Nubj&)�”}”(hŒ``TOP``”h]”hŒTOP”…”�”}”(hjK h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj1 ubhŒG does not show that bit, so reading the leaf is the only way to see it.”…”�”}”(hj1 h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´K·hj×h²hubeh}”(h]”Œ registers”ah ]”h"]”Œ registers”ah$]”h&]”uh1hÖhj7h²hh³hÇh´K¤ubh×)�”}”(hhh]”(hÜ)�”}”(hŒ$How a unit interrupt reaches the CPU”h]”hŒ$How a unit interrupt reaches the CPU”…”�”}”(hjn h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjk h²hh³hÇh´K½ubhì)�”}”(hXcA unit does not write a ``LEAF`` register. Each unit has an interrupt control register that GSP firmware programs. The control register holds the unit's vector, the GFID that identifies the PCIe function whose tree receives the interrupt, and one enable bit per destination: the CPU, the GSP, and the other on-chip processors. When the unit has an event::”h]”(hŒA unit does not write a ”…”�”}”(hj| h²hh³Nh´Nubj&)�”}”(hŒ``LEAF``”h]”hŒLEAF”…”�”}”(hj„ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj| ubhXD register. Each unit has an interrupt control register that GSP firmware programs. The control register holds the unit’s vector, the GFID that identifies the PCIe function whose tree receives the interrupt, and one enable bit per destination: the CPU, the GSP, and the other on-chip processors. When the unit has an event:”…”�”}”(hj| h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´K¿hjk h²hubj¤)�”}”(hXS1. The unit sends GIN an interrupt message carrying the vector, the GFID, and the destination enables from its control register. 2. In the tree of each destination that the message selects, GIN sets bit (vector % 32) of LEAF(vector / 32). 3. If the vector and its subtree are enabled in the CPU tree, GIN raises the PCI interrupt.”h]”hXS1. The unit sends GIN an interrupt message carrying the vector, the GFID, and the destination enables from its control register. 2. In the tree of each destination that the message selects, GIN sets bit (vector % 32) of LEAF(vector / 32). 3. If the vector and its subtree are enabled in the CPU tree, GIN raises the PCI interrupt.”…”�”}”hjœ sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j£h³hÇh´KÅhjk h²hubhì)�”}”(hX5Because firmware assigns the vectors, nova-core does not hardcode which vector belongs to which unit, with two exceptions. The hardware headers of every supported chipset define the GSP event as vector 155, and GSP firmware's own interrupt table uses that definition. The CPU doorbell is vector 129. Pre-Hopper hardware fixes that number, and GSP firmware keeps it on Hopper and later. nova-core names both by number. A driver can fetch the full unit-to-vector table from the GSP by RPC, and nouveau does. nova-core does not, because a fixed vector needs no lookup.”h]”hX7Because firmware assigns the vectors, nova-core does not hardcode which vector belongs to which unit, with two exceptions. The hardware headers of every supported chipset define the GSP event as vector 155, and GSP firmware’s own interrupt table uses that definition. The CPU doorbell is vector 129. Pre-Hopper hardware fixes that number, and GSP firmware keeps it on Hopper and later. nova-core names both by number. A driver can fetch the full unit-to-vector table from the GSP by RPC, and nouveau does. nova-core does not, because a fixed vector needs no lookup.”…”�”}”(hjª h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KÌhjk h²hubeh}”(h]”Œ$how-a-unit-interrupt-reaches-the-cpu”ah ]”h"]”Œ$how a unit interrupt reaches the cpu”ah$]”h&]”uh1hÖhj7h²hh³hÇh´K½ubh×)�”}”(hhh]”(hÜ)�”}”(hŒEdge-triggered delivery”h]”hŒEdge-triggered delivery”…”�”}”(hjà h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjÀ h²hh³hÇh´KÖubhì)�”}”(hŒžA ``LEAF`` bit is a latch. Its source sets it on a rising edge, and it stays set until the CPU clears it. A source that stays high does not set the bit again.”h]”(hŒA ”…”�”}”(hjÑ h²hh³Nh´Nubj&)�”}”(hŒ``LEAF``”h]”hŒLEAF”…”�”}”(hjÙ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjÑ ubhŒ” bit is a latch. Its source sets it on a rising edge, and it stays set until the CPU clears it. A source that stays high does not set the bit again.”…”�”}”(hjÑ h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KØhjÀ h²hubhì)�”}”(hŒkGIN raises the PCI interrupt for a subtree when the subtree's enabled pending state goes from low to high::”h]”hŒlGIN raises the PCI interrupt for a subtree when the subtree’s enabled pending state goes from low to high:”…”�”}”(hjñ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KÛhjÀ h²hubj¤)�”}”(hŒóPer vector, in leaf i at bit b: LEAF(i)[b] AND LEAF_EN(i)[b] Per subtree N, across leaves 2N and 2N + 1: OR of every enabled pending bit -> TOP[N] Delivery for subtree N: TOP[N] AND TOP_EN[N] -> rising edge -> PCI interrupt”h]”hŒóPer vector, in leaf i at bit b: LEAF(i)[b] AND LEAF_EN(i)[b] Per subtree N, across leaves 2N and 2N + 1: OR of every enabled pending bit -> TOP[N] Delivery for subtree N: TOP[N] AND TOP_EN[N] -> rising edge -> PCI interrupt”…”�”}”hjÿ sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j£h³hÇh´KÞhjÀ h²hubhì)�”}”(hŒr``TOP_EN`` applies after the summary, so disabling a subtree stops delivery without changing what ``TOP`` reports.”h]”(j&)�”}”(hŒ ``TOP_EN``”h]”hŒTOP_EN”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj ubhŒX applies after the summary, so disabling a subtree stops delivery without changing what ”…”�”}”(hj h²hh³Nh´Nubj&)�”}”(hŒ``TOP``”h]”hŒTOP”…”�”}”(hj# h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj ubhŒ reports.”…”�”}”(hj h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KçhjÀ h²hubhì)�”}”(hŒThree consequences:”h]”hŒThree consequences:”…”�”}”(hj; h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KêhjÀ h²hubjÏ)�”}”(hhh]”(jÔ)�”}”(hŒrCode that must find every pending vector reads the leaves. A vector that latched while disabled is not in ``TOP``.”h]”hì)�”}”(hŒrCode that must find every pending vector reads the leaves. A vector that latched while disabled is not in ``TOP``.”h]”(hŒjCode that must find every pending vector reads the leaves. A vector that latched while disabled is not in ”…”�”}”(hjP h²hh³Nh´Nubj&)�”}”(hŒ``TOP``”h]”hŒTOP”…”�”}”(hjX h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjP ubhŒ.”…”�”}”(hjP h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´KìhjL ubah}”(h]”h ]”h"]”h$]”h&]”uh1jÓhjI h²hh³hÇh´NubjÔ)�”}”(hŒ¹Writing ``TOP_EN_SET`` for a subtree with an enabled pending bit produces a new edge. GIN delivers an interrupt for a pending bit left uncleared as soon as its subtree is enabled again.”h]”hì)�”}”(hŒ¹Writing ``TOP_EN_SET`` for a subtree with an enabled pending bit produces a new edge. GIN delivers an interrupt for a pending bit left uncleared as soon as its subtree is enabled again.”h]”(hŒWriting ”…”�”}”(hjz h²hh³Nh´Nubj&)�”}”(hŒ``TOP_EN_SET``”h]”hŒ TOP_EN_SET”…”�”}”(hj‚ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjz ubhŒ£ for a subtree with an enabled pending bit produces a new edge. GIN delivers an interrupt for a pending bit left uncleared as soon as its subtree is enabled again.”…”�”}”(hjz h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´Kîhjv ubah}”(h]”h ]”h"]”h$]”h&]”uh1jÓhjI h²hh³hÇh´NubjÔ)�”}”(hŒÖA source that holds its signal high produces no new edge after the CPU clears the leaf bit. Such a source has to re-emit its interrupt. The falcons do that through ``INTR_RETRIGGER`` (see "Retriggering a falcon"). ”h]”hì)�”}”(hŒÕA source that holds its signal high produces no new edge after the CPU clears the leaf bit. Such a source has to re-emit its interrupt. The falcons do that through ``INTR_RETRIGGER`` (see "Retriggering a falcon").”h]”(hŒ¤A source that holds its signal high produces no new edge after the CPU clears the leaf bit. Such a source has to re-emit its interrupt. The falcons do that through ”…”�”}”(hj¤ h²hh³Nh´Nubj&)�”}”(hŒ``INTR_RETRIGGER``”h]”hŒINTR_RETRIGGER”…”�”}”(hj¬ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj¤ ubhŒ# (see “Retriggering a falconâ€�).”…”�”}”(hj¤ h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´Kñhj  ubah}”(h]”h ]”h"]”h$]”h&]”uh1jÓhjI h²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”j“j”uh1jÎh³hÇh´KìhjÀ h²hubeh}”(h]”Œedge-triggered-delivery”ah ]”h"]”Œedge-triggered delivery”ah$]”h&]”uh1hÖhj7h²hh³hÇh´KÖubeh}”(h]”Œthe-gin-controller”ah ]”h"]”Œthe gin controller”ah$]”h&]”uh1hÖhhØh²hh³hÇh´Kpubh×)�”}”(hhh]”(hÜ)�”}”(hŒDelivery over PCI”h]”hŒDelivery over PCI”…”�”}”(hjã h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjà h²hh³hÇh´Köubhì)�”}”(hŒ¡GIN delivers the tree's interrupts to the CPU as MSI or MSI-X, whichever Linux grants. nova-core requests MSI-X first and falls back to MSI, and never uses INTx.”h]”hŒ£GIN delivers the tree’s interrupts to the CPU as MSI or MSI-X, whichever Linux grants. nova-core requests MSI-X first and falls back to MSI, and never uses INTx.”…”�”}”(hjñ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´Køhjà h²hubhì)�”}”(hŒlMSI has a single message, and every subtree raises that one message, so one Linux IRQ serves the whole tree.”h]”hŒlMSI has a single message, and every subtree raises that one message, so one Linux IRQ serves the whole tree.”…”�”}”(hjÿ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´Kühjà h²hubhì)�”}”(hXGMSI-X gives each subtree its own table entry, at the index equal to the subtree number. Linux masks every entry until a driver requests its Linux IRQ number, and a masked entry sends no message: the GPU records the interrupt in the MSI-X pending bit array, where it stays until Linux unmasks the entry. An entry that the driver never requests is never unmasked. A driver that enables a subtree without requesting that subtree's entry loses every interrupt from that subtree, with nothing reported: the leaf and TOP registers show the vector pending and enabled while no handler runs.”h]”hXIMSI-X gives each subtree its own table entry, at the index equal to the subtree number. Linux masks every entry until a driver requests its Linux IRQ number, and a masked entry sends no message: the GPU records the interrupt in the MSI-X pending bit array, where it stays until Linux unmasks the entry. An entry that the driver never requests is never unmasked. A driver that enables a subtree without requesting that subtree’s entry loses every interrupt from that subtree, with nothing reported: the leaf and TOP registers show the vector pending and enabled while no handler runs.”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´Kÿhjà h²hubh×)�”}”(hhh]”(hÜ)�”}”(hŒThe serviced-subtree invariant”h]”hŒThe serviced-subtree invariant”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhj h²hh³hÇh´M ubhì)�”}”(hŒWEvery subtree enabled at ``TOP`` has an allocated PCI vector with a registered handler.”h]”(hŒEvery subtree enabled at ”…”�”}”(hj, h²hh³Nh´Nubj&)�”}”(hŒ``TOP``”h]”hŒTOP”…”�”}”(hj4 h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj, ubhŒ7 has an allocated PCI vector with a registered handler.”…”�”}”(hj, h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M hj h²hubhì)�”}”(hŒÏMSI satisfies this with its single message. MSI-X needs one allocated entry per serviced subtree, and a PCI allocation cannot be sparse, so nova-core requests entries 0 through the highest serviced subtree::”h]”hŒÎMSI satisfies this with its single message. MSI-X needs one allocated entry per serviced subtree, and a PCI allocation cannot be sparse, so nova-core requests entries 0 through the highest serviced subtree:”…”�”}”(hjL h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´Mhj h²hubj¤)�”}”(hX’MSI-X, with subtree 2 serviced: subtree 0 -> entry 0 allocated, no handler, stays masked subtree 1 -> entry 1 allocated, no handler, stays masked subtree 2 -> entry 2 handler here, and its rearm covers subtree 2 MSI, with any serviced set: every serviced subtree -> the one allocated PCI vector, whose handler's rearm covers the whole serviced set”h]”hX’MSI-X, with subtree 2 serviced: subtree 0 -> entry 0 allocated, no handler, stays masked subtree 1 -> entry 1 allocated, no handler, stays masked subtree 2 -> entry 2 handler here, and its rearm covers subtree 2 MSI, with any serviced set: every serviced subtree -> the one allocated PCI vector, whose handler's rearm covers the whole serviced set”…”�”}”hjZ sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j£h³hÇh´Mhj h²hubhì)�”}”(hŒŽAn allocated entry whose subtree nova-core does not service costs nothing. The entry stays masked, and a disabled subtree raises no interrupt.”h]”hŒŽAn allocated entry whose subtree nova-core does not service costs nothing. The entry stays masked, and a disabled subtree raises no interrupt.”…”�”}”(hjh h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´Mhj h²hubhì)�”}”(hX7nova-core services one subtree. The GSP event, vector 155, is in leaf 4, which is in subtree 2. OpenRM's headers place its UVM_SHARED interrupt category in subtree 2 on every chipset that nova-core supports. The self-test doorbell, vector 129, is in the same leaf, and the test allocates its own vectors for it.”h]”hX9nova-core services one subtree. The GSP event, vector 155, is in leaf 4, which is in subtree 2. OpenRM’s headers place its UVM_SHARED interrupt category in subtree 2 on every chipset that nova-core supports. The self-test doorbell, vector 129, is in the same leaf, and the test allocates its own vectors for it.”…”�”}”(hjv h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M hj h²hubeh}”(h]”Œthe-serviced-subtree-invariant”ah ]”h"]”Œthe serviced-subtree invariant”ah$]”h&]”uh1hÖhjà h²hh³hÇh´M ubh×)�”}”(hhh]”(hÜ)�”}”(hŒRearming PCI interrupt delivery”h]”hŒRearming PCI interrupt delivery”…”�”}”(hj� h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjŒ h²hh³hÇh´M&ubhì)�”}”(hŒÜA message-signaled interrupt is delivered once per edge, and the PCI side delivers no further interrupt until the CPU rearms it. The rearm operation depends on the GPU family and on the interrupt type that Linux granted:”h]”hŒÜA message-signaled interrupt is delivered once per edge, and the PCI side delivers no further interrupt until the CPU rearms it. The rearm operation depends on the GPU family and on the interrupt type that Linux granted:”…”�”}”(hj� h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M(hjŒ h²hubhŒtable”“”)�”}”(hhh]”hŒtgroup”“”)�”}”(hhh]”(hŒcolspec”“”)�”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”Kuh1jµ hj² ubj¶ )�”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”Kuh1jµ hj² ubj¶ )�”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”K+uh1jµ hj² ubhŒthead”“”)�”}”(hhh]”hŒrow”“”)�”}”(hhh]”(hŒentry”“”)�”}”(hhh]”hì)�”}”(hŒ Architecture”h]”hŒ Architecture”…”�”}”(hjä h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M-hjá ubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hjÜ ubjà )�”}”(hhh]”hì)�”}”(hŒType”h]”hŒType”…”�”}”(hjû h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M-hjø ubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hjÜ ubjà )�”}”(hhh]”hì)�”}”(hŒRearm operation”h]”hŒRearm operation”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M-hj ubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hjÜ ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jÚ hj× ubah}”(h]”h ]”h"]”h$]”h&]”uh1jÕ hj² ubhŒtbody”“”)�”}”(hhh]”(jÛ )�”}”(hhh]”(jà )�”}”(hhh]”hì)�”}”(hŒTuring through Ada”h]”hŒTuring through Ada”…”�”}”(hj= h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M/hj: ubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hj7 ubjà )�”}”(hhh]”hì)�”}”(hŒMSI”h]”hŒMSI”…”�”}”(hjT h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M/hjQ ubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hj7 ubjà )�”}”(hhh]”hì)�”}”(hŒ+write the configuration-mirror EOI register”h]”hŒ+write the configuration-mirror EOI register”…”�”}”(hjk h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M/hjh ubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hj7 ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jÚ hj4 ubjÛ )�”}”(hhh]”(jà )�”}”(hhh]”hì)�”}”(hŒHopper and later”h]”hŒHopper and later”…”�”}”(hj‹ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M0hjˆ ubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hj… ubjà )�”}”(hhh]”hì)�”}”(hŒMSI”h]”hŒMSI”…”�”}”(hj¢ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M0hjŸ ubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hj… ubjà )�”}”(hhh]”hì)�”}”(hŒ'clear then set the serviced TOP enables”h]”hŒ'clear then set the serviced TOP enables”…”�”}”(hj¹ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M0hj¶ ubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hj… ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jÚ hj4 ubjÛ )�”}”(hhh]”(jà )�”}”(hhh]”hì)�”}”(hŒAny”h]”hŒAny”…”�”}”(hjÙ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M1hjÖ ubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hjÓ ubjà )�”}”(hhh]”hì)�”}”(hŒMSI-X”h]”hŒMSI-X”…”�”}”(hjð h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M1hjí ubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hjÓ ubjà )�”}”(hhh]”hì)�”}”(hŒ+clear then set the handler's own TOP enable”h]”hŒ-clear then set the handler’s own TOP enable”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M1hj ubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hjÓ ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jÚ hj4 ubeh}”(h]”h ]”h"]”h$]”h&]”uh1j2 hj² ubeh}”(h]”h ]”h"]”h$]”h&]”Œcols”Kuh1j° hj­ ubah}”(h]”h ]”h"]”h$]”h&]”uh1j« hjŒ h²hh³hÇh´Nubhì)�”}”(hXvThe end-of-interrupt register is ``NV_XVE_CYA_2`` in the BAR0 mirror of PCI configuration space, and the value written does not matter. The ``TOP_EN`` cycle produces a new delivery edge. The MSI forms cover every serviced subtree, because one message serves all of them. The MSI-X form covers one subtree, because each serviced subtree has its own entry and its own handler.”h]”(hŒ!The end-of-interrupt register is ”…”�”}”(hj4 h²hh³Nh´Nubj&)�”}”(hŒ``NV_XVE_CYA_2``”h]”hŒ NV_XVE_CYA_2”…”�”}”(hj< h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj4 ubhŒ[ in the BAR0 mirror of PCI configuration space, and the value written does not matter. The ”…”�”}”(hj4 h²hh³Nh´Nubj&)�”}”(hŒ ``TOP_EN``”h]”hŒTOP_EN”…”�”}”(hjN h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj4 ubhŒà cycle produces a new delivery edge. The MSI forms cover every serviced subtree, because one message serves all of them. The MSI-X form covers one subtree, because each serviced subtree has its own entry and its own handler.”…”�”}”(hj4 h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M4hjŒ h²hubhì)�”}”(hŒ¶A handler rearms once per delivered interrupt, on every path, including the path where it finds its vector not pending. A handler that skips the rearm receives no further interrupts.”h]”hŒ¶A handler rearms once per delivered interrupt, on every path, including the path where it finds its vector not pending. A handler that skips the rearm receives no further interrupts.”…”�”}”(hjf h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M:hjŒ h²hubhì)�”}”(hŒÁOpenRM makes the same split. It writes the configuration-space EOI for MSI on pre-Hopper chipsets, and cycles the TOP enables of the subtrees that it services for Hopper-plus MSI and for MSI-X.”h]”hŒÁOpenRM makes the same split. It writes the configuration-space EOI for MSI on pre-Hopper chipsets, and cycles the TOP enables of the subtrees that it services for Hopper-plus MSI and for MSI-X.”…”�”}”(hjt h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M>hjŒ h²hubeh}”(h]”Œrearming-pci-interrupt-delivery”ah ]”h"]”Œrearming pci interrupt delivery”ah$]”h&]”uh1hÖhjà h²hh³hÇh´M&ubeh}”(h]”Œdelivery-over-pci”ah ]”h"]”Œdelivery over pci”ah$]”h&]”uh1hÖhhØh²hh³hÇh´Köubh×)�”}”(hhh]”(hÜ)�”}”(hŒServicing the tree”h]”hŒServicing the tree”…”�”}”(hj• h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhj’ h²hh³hÇh´MCubhì)�”}”(hXŠServicing a leaf has a required order: read its pending bits, then clear them. Clearing a leaf before reading it discards every vector latched in it, and no register reports the loss. In nova-core, reading a leaf produces the handle that clears it, so that the wrong order does not compile. The handle clears exactly the bits that it read, so a vector that latched after the read stays pending.”h]”hXŠServicing a leaf has a required order: read its pending bits, then clear them. Clearing a leaf before reading it discards every vector latched in it, and no register reports the loss. In nova-core, reading a leaf produces the handle that clears it, so that the wrong order does not compile. The handle clears exactly the bits that it read, so a vector that latched after the read stays pending.”…”�”}”(hj£ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MEhj’ h²hubhì)�”}”(hŒ”A handler clears its bit before it services the vector. Clearing afterwards would discard an interrupt that the source raised while the handler ran.”h]”hŒ”A handler clears its bit before it services the vector. Clearing afterwards would discard an interrupt that the source raised while the handler ran.”…”�”}”(hj± h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MKhj’ h²hubhì)�”}”(hŒ(nova-core services the tree in two ways.”h]”hŒ(nova-core services the tree in two ways.”…”�”}”(hj¿ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MNhj’ h²hubhì)�”}”(hX?The notification path services one vector. It reads the vector's leaf, clears only the vector's bit, and rearms. The subtree stays enabled, and a vector pending beside it in the same leaf keeps its bit set for the code that services that vector. The GSP event handler takes this path, and so does the self-test handler.”h]”hXCThe notification path services one vector. It reads the vector’s leaf, clears only the vector’s bit, and rearms. The subtree stays enabled, and a vector pending beside it in the same leaf keeps its bit set for the code that services that vector. The GSP event handler takes this path, and so does the self-test handler.”…”�”}”(hjÍ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MPhj’ h²hubhì)�”}”(hX.The startup drain walks the whole tree, because it must clear whatever is pending across every subtree rather than one known vector. It disables the serviced subtrees at ``TOP``, reads and clears every implemented leaf, and leaves the subtrees disabled for its caller to enable once the caller is ready for deliveries. The drain reads every leaf rather than descending from ``TOP``, because sources latch vectors during boot while those vectors are disabled, and ``TOP`` does not show them. OpenRM's stall-interrupt path reads every leaf for the same reason.”h]”(hŒªThe startup drain walks the whole tree, because it must clear whatever is pending across every subtree rather than one known vector. It disables the serviced subtrees at ”…”�”}”(hjÛ h²hh³Nh´Nubj&)�”}”(hŒ``TOP``”h]”hŒTOP”…”�”}”(hjã h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjÛ ubhŒÅ, reads and clears every implemented leaf, and leaves the subtrees disabled for its caller to enable once the caller is ready for deliveries. The drain reads every leaf rather than descending from ”…”�”}”(hjÛ h²hh³Nh´Nubj&)�”}”(hŒ``TOP``”h]”hŒTOP”…”�”}”(hjõ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjÛ ubhŒR, because sources latch vectors during boot while those vectors are disabled, and ”…”�”}”(hjÛ h²hh³Nh´Nubj&)�”}”(hŒ``TOP``”h]”hŒTOP”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjÛ ubhŒZ does not show them. OpenRM’s stall-interrupt path reads every leaf for the same reason.”…”�”}”(hjÛ h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MVhj’ h²hubhì)�”}”(hŒ&The two paths as register operations::”h]”hŒ%The two paths as register operations:”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M_hj’ h²hubj¤)�”}”(hXÏStartup drain, run once during probe: write TOP_EN_CLEAR = serviced stop new deliveries for each implemented leaf i: pending = read LEAF(i) write LEAF(i) = pending clear what was read (returns with TOP_EN still clear) Notification, the subtree stays enabled: pending = read LEAF(leaf) is the handler's bit set? write LEAF(leaf) = bit clear that one bit rearm PCI interrupt delivery”h]”hXÏStartup drain, run once during probe: write TOP_EN_CLEAR = serviced stop new deliveries for each implemented leaf i: pending = read LEAF(i) write LEAF(i) = pending clear what was read (returns with TOP_EN still clear) Notification, the subtree stays enabled: pending = read LEAF(leaf) is the handler's bit set? write LEAF(leaf) = bit clear that one bit rearm PCI interrupt delivery”…”�”}”hj-sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j£h³hÇh´Mahj’ h²hubhì)�”}”(hŒìThe drain clears every pending bit, including bits that nova-core never services. An uncleared bit holds its subtree in the pending state, and enabling that subtree again would deliver an interrupt for a vector that no handler services.”h]”hŒìThe drain clears every pending bit, including bits that nova-core never services. An uncleared bit holds its subtree in the pending state, and enabling that subtree again would deliver an interrupt for a vector that no handler services.”…”�”}”(hj;h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´Mmhj’ h²hubhì)�”}”(hX[The drain's ``TOP_EN_CLEAR`` is not a rearm, and pre-Hopper MSI rearms through the configuration mirror, which the drain never writes. An interrupt delivered before probe had no handler to rearm it, so the tree reset rearms explicitly after the drain. A TOP-enable rearm leaves the serviced subtrees enabled, so the reset then disables them again.”h]”(hŒThe drain’s ”…”�”}”(hjIh²hh³Nh´Nubj&)�”}”(hŒ``TOP_EN_CLEAR``”h]”hŒ TOP_EN_CLEAR”…”�”}”(hjQh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjIubhX? is not a rearm, and pre-Hopper MSI rearms through the configuration mirror, which the drain never writes. An interrupt delivered before probe had no handler to rearm it, so the tree reset rearms explicitly after the drain. A TOP-enable rearm leaves the serviced subtrees enabled, so the reset then disables them again.”…”�”}”(hjIh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´Mrhj’ h²hubhì)�”}”(hŒ¥nova-core does not serialize access to the tree. The GSP event handler touches only its own leaf, and the drain runs during probe, before that handler is registered.”h]”hŒ¥nova-core does not serialize access to the tree. The GSP event handler touches only its own leaf, and the drain runs during probe, before that handler is registered.”…”�”}”(hjih²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´Mxhj’ h²hubeh}”(h]”Œservicing-the-tree”ah ]”h"]”Œservicing the tree”ah$]”h&]”uh1hÖhhØh²hh³hÇh´MCubh×)�”}”(hhh]”(hÜ)�”}”(hŒPer-architecture differences”h]”hŒPer-architecture differences”…”�”}”(hj‚h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjh²hh³hÇh´M}ubhì)�”}”(hŒYThe tree is the same on every supported GPU except for its size, which changes at Hopper:”h]”hŒYThe tree is the same on every supported GPU except for its size, which changes at Hopper:”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´Mhjh²hubj¬ )�”}”(hhh]”j± )�”}”(hhh]”(j¶ )�”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”Kuh1jµ hj¡ubj¶ )�”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”Kuh1jµ hj¡ubj¶ )�”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”Kuh1jµ hj¡ubj¶ )�”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”Kuh1jµ hj¡ubjÖ )�”}”(hhh]”jÛ )�”}”(hhh]”(jà )�”}”(hhh]”hì)�”}”(hŒGPUs”h]”hŒGPUs”…”�”}”(hjÕh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MƒhjÒubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hjÏubjà )�”}”(hhh]”hì)�”}”(hŒLeaves”h]”hŒLeaves”…”�”}”(hjìh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´Mƒhjéubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hjÏubjà )�”}”(hhh]”hì)�”}”(hŒSubtrees”h]”hŒSubtrees”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´Mƒhjubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hjÏubjà )�”}”(hhh]”hì)�”}”(hŒImplemented subtrees”h]”hŒImplemented subtrees”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´Mƒhjubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hjÏubeh}”(h]”h ]”h"]”h$]”h&]”uh1jÚ hjÌubah}”(h]”h ]”h"]”h$]”h&]”uh1jÕ hj¡ubj3 )�”}”(hhh]”(jÛ )�”}”(hhh]”(jà )�”}”(hhh]”hì)�”}”(hŒTuring, Ampere, Ada”h]”hŒTuring, Ampere, Ada”…”�”}”(hjCh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M…hj@ubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hj=ubjà )�”}”(hhh]”hì)�”}”(hŒ8”h]”hŒ8”…”�”}”(hjZh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M…hjWubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hj=ubjà )�”}”(hhh]”hì)�”}”(hŒ4”h]”hŒ4”…”�”}”(hjqh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M…hjnubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hj=ubjà )�”}”(hhh]”hì)�”}”(hŒ``0x0f``”h]”j&)�”}”(hjŠh]”hŒ0x0f”…”�”}”(hjŒh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjˆubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M…hj…ubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hj=ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jÚ hj:ubjÛ )�”}”(hhh]”(jà )�”}”(hhh]”hì)�”}”(hŒHopper, Blackwell”h]”hŒHopper, Blackwell”…”�”}”(hj±h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M†hj®ubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hj«ubjà )�”}”(hhh]”hì)�”}”(hŒ16”h]”hŒ16”…”�”}”(hjÈh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M†hjÅubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hj«ubjà )�”}”(hhh]”hì)�”}”(hj\h]”hŒ8”…”�”}”(hjßh²hh³Nh´Nubah}”(h]”h ]”•«‰h"]”h$]”h&]”uh1hëh³hÇh´M†hjÜubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hj«ubjà )�”}”(hhh]”hì)�”}”(hŒ``0xff``”h]”j&)�”}”(hj÷h]”hŒ0xff”…”�”}”(hjùh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjõubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M†hjòubah}”(h]”h ]”h"]”h$]”h&]”uh1jß hj«ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jÚ hj:ubeh}”(h]”h ]”h"]”h$]”h&]”uh1j2 hj¡ubeh}”(h]”h ]”h"]”h$]”h&]”Œcols”Kuh1j° hjžubah}”(h]”h ]”h"]”h$]”h&]”uh1j« hjh²hh³hÇh´Nubhì)�”}”(hX;The interrupt HAL provides the leaf count, and the subtree count and the implemented-subtree set derive from it. A subtree that the chipset does not implement has no TOP bit, so building a tree that services one fails with ``EINVAL``. Vectors 129 and 155 are in the 8-leaf tree, so every supported chipset has them.”h]”(hŒßThe interrupt HAL provides the leaf count, and the subtree count and the implemented-subtree set derive from it. A subtree that the chipset does not implement has no TOP bit, so building a tree that services one fails with ”…”�”}”(hj+h²hh³Nh´Nubj&)�”}”(hŒ ``EINVAL``”h]”hŒEINVAL”…”�”}”(hj3h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj+ubhŒR. Vectors 129 and 155 are in the 8-leaf tree, so every supported chipset has them.”…”�”}”(hj+h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M‰hjh²hubhì)�”}”(hŒ«OpenRM's headers assign every interrupt category of a 16-leaf tree to leaves 0 through 11. The drain reads all 16, because a vector can be latched in any implemented leaf.”h]”hŒ­OpenRM’s headers assign every interrupt category of a 16-leaf tree to leaves 0 through 11. The drain reads all 16, because a vector can be latched in any implemented leaf.”…”�”}”(hjKh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M�hjh²hubhì)�”}”(hXThe HAL performs the rearm as well (see "Rearming PCI interrupt delivery"). Two falcon properties also differ by family, and the falcon HAL carries them: Turing falcons have no ``INTR_RETRIGGER``, and the RISC-V routing registers moved at GA102 (see "Retriggering a falcon").”h]”(hŒµThe HAL performs the rearm as well (see “Rearming PCI interrupt deliveryâ€�). Two falcon properties also differ by family, and the falcon HAL carries them: Turing falcons have no ”…”�”}”(hjYh²hh³Nh´Nubj&)�”}”(hŒ``INTR_RETRIGGER``”h]”hŒINTR_RETRIGGER”…”�”}”(hjah²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjYubhŒT, and the RISC-V routing registers moved at GA102 (see “Retriggering a falconâ€�).”…”�”}”(hjYh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M“hjh²hubeh}”(h]”Œper-architecture-differences”ah ]”h"]”Œper-architecture differences”ah$]”h&]”uh1hÖhhØh²hh³hÇh´M}ubh×)�”}”(hhh]”(hÜ)�”}”(hŒ The GSP event”h]”hŒ The GSP event”…”�”}”(hj„h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhj�h²hh³hÇh´M™ubhì)�”}”(hXWhen the GSP has output for the CPU, it writes messages into the GSP-to-CPU queue in shared memory and raises SWGEN0, one of the software-generated interrupt causes of the GSP falcon. SWGEN0 is routed to the host, at vector 155, leaf 4 bit 27, in subtree 2.”h]”hXWhen the GSP has output for the CPU, it writes messages into the GSP-to-CPU queue in shared memory and raises SWGEN0, one of the software-generated interrupt causes of the GSP falcon. SWGEN0 is routed to the host, at vector 155, leaf 4 bit 27, in subtree 2.”…”�”}”(hj’h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M›hj�h²hubhì)�”}”(hŒ÷The queue carries notifications (log records, error records, lifecycle events) and command replies. A thread waiting for a reply reads the queue itself, so the interrupt is only the trigger to drain the queue (see "Draining the GSP-to-CPU queue").”h]”hŒûThe queue carries notifications (log records, error records, lifecycle events) and command replies. A thread waiting for a reply reads the queue itself, so the interrupt is only the trigger to drain the queue (see “Draining the GSP-to-CPU queueâ€�).”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M hj�h²hubhì)�”}”(hX7The falcon latches every cause that it raises, SWGEN0 among them, in its ``IRQSTAT`` register. The handler services the host-routed causes and clears their latches, and then it writes ``INTR_RETRIGGER`` so that the falcon re-emits any cause that latched in the meantime. "Retriggering a falcon" has the details.”h]”(hŒIThe falcon latches every cause that it raises, SWGEN0 among them, in its ”…”�”}”(hj®h²hh³Nh´Nubj&)�”}”(hŒ ``IRQSTAT``”h]”hŒIRQSTAT”…”�”}”(hj¶h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj®ubhŒd register. The handler services the host-routed causes and clears their latches, and then it writes ”…”�”}”(hj®h²hh³Nh´Nubj&)�”}”(hŒ``INTR_RETRIGGER``”h]”hŒINTR_RETRIGGER”…”�”}”(hjÈh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj®ubhŒq so that the falcon re-emits any cause that latched in the meantime. “Retriggering a falconâ€� has the details.”…”�”}”(hj®h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M¥hj�h²hubhì)�”}”(hXUDraining the queue takes the command-queue mutex and walks shared memory, so it cannot run in hard interrupt context. nova-core registers a threaded handler, under the name ``nova-core`` in ``/proc/interrupts``. The top half runs in hard interrupt context and reads and writes only registers, and it wakes the IRQ thread to drain the queue::”h]”(hŒ­Draining the queue takes the command-queue mutex and walks shared memory, so it cannot run in hard interrupt context. nova-core registers a threaded handler, under the name ”…”�”}”(hjàh²hh³Nh´Nubj&)�”}”(hŒ ``nova-core``”h]”hŒ nova-core”…”�”}”(hjèh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjàubhŒ in ”…”�”}”(hjàh²hh³Nh´Nubj&)�”}”(hŒ``/proc/interrupts``”h]”hŒ/proc/interrupts”…”�”}”(hjúh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjàubhŒ‚. The top half runs in hard interrupt context and reads and writes only registers, and it wakes the IRQ thread to drain the queue:”…”�”}”(hjàh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´Mªhj�h²hubj¤)�”}”(hXïGSP writes messages into the GSP-to-CPU queue GSP raises SWGEN0 GIN sets bit 27 of LEAF(4), and subtree 2 becomes pending PCI interrupt -> Linux IRQ -> top half, in hard interrupt context: read LEAF(4), and if bit 27 is clear, rearm and return clear bit 27 (the subtree stays enabled) read the falcon causes routed to the host, clearing SWGEN0 if set for every other host cause: log it, clear its latch, and read the host causes back if the clear ended all of them: retrigger the falcon otherwise: disable vector 155 at its leaf and skip the retrigger rearm PCI interrupt delivery wake the IRQ thread if SWGEN0 was set IRQ thread, which may sleep: take the command-queue mutex and drain the GSP-to-CPU queue”h]”hXïGSP writes messages into the GSP-to-CPU queue GSP raises SWGEN0 GIN sets bit 27 of LEAF(4), and subtree 2 becomes pending PCI interrupt -> Linux IRQ -> top half, in hard interrupt context: read LEAF(4), and if bit 27 is clear, rearm and return clear bit 27 (the subtree stays enabled) read the falcon causes routed to the host, clearing SWGEN0 if set for every other host cause: log it, clear its latch, and read the host causes back if the clear ended all of them: retrigger the falcon otherwise: disable vector 155 at its leaf and skip the retrigger rearm PCI interrupt delivery wake the IRQ thread if SWGEN0 was set IRQ thread, which may sleep: take the command-queue mutex and drain the GSP-to-CPU queue”…”�”}”hjsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j£h³hÇh´M°hj�h²hubhì)�”}”(hŒrA halt and a posted message can be pending together, so the top half services every cause that the status reports.”h]”hŒrA halt and a posted message can be pending together, so the top half services every cause that the status reports.”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MÀhj�h²hubhì)�”}”(hX-A drain fails when a message's framing or checksum is bad (see "Draining the GSP-to-CPU queue"). The message stays at the queue head, so every later drain would fail the same way, and the IRQ thread disables vector 155 and logs the failure, which leaves the queue unserviced until the device is reset.”h]”hX3A drain fails when a message’s framing or checksum is bad (see “Draining the GSP-to-CPU queueâ€�). The message stays at the queue head, so every later drain would fail the same way, and the IRQ thread disables vector 155 and logs the failure, which leaves the queue unserviced until the device is reset.”…”�”}”(hj.h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MÃhj�h²hubhì)�”}”(hŒÑThe handler, the self-test, and the rest of the driver read BAR0 through one shared mapping. nova-core unregisters an interrupt handler when the device unbinds, so a handler runs only while the mapping exists.”h]”hŒÑThe handler, the self-test, and the rest of the driver read BAR0 through one shared mapping. nova-core unregisters an interrupt handler when the device unbinds, so a handler runs only while the mapping exists.”…”�”}”(hj<h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MÈhj�h²hubh×)�”}”(hhh]”(hÜ)�”}”(hŒRetriggering a falcon”h]”hŒRetriggering a falcon”…”�”}”(hjMh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjJh²hh³hÇh´MÍubhì)�”}”(hXCA falcon signals the tree when its set of host-routed causes goes from empty to non-empty. A cause left latched keeps the set non-empty, so no later cause signals the tree, and the vector is lost. For a cause that stays latched, the handler can clear the tree leaf first or the falcon latch first, and the loss is the same.”h]”hXCA falcon signals the tree when its set of host-routed causes goes from empty to non-empty. A cause left latched keeps the set non-empty, so no later cause signals the tree, and the vector is lost. For a cause that stays latched, the handler can clear the tree leaf first or the falcon latch first, and the loss is the same.”…”�”}”(hj[h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MÏhjJh²hubhì)�”}”(hX½``IRQSTAT`` latches every cause in the falcon, including the causes routed to the falcon's own RISC-V core and owned by the firmware running on it. A host handler owns only the causes that ``PRISCV_RISCV_IRQMASK`` and ``PRISCV_RISCV_IRQDEST`` both select, so it intersects ``IRQSTAT`` with both before it reads or clears a cause. OpenRM computes the same intersection in ``kflcnRiscvReadIntrStatus``. GA100 keeps the Turing offsets of the two routing registers and GA102 moves them, so the offsets change at GA102 rather than at the Ampere boundary. The handler masks no cause: ``PRISCV_RISCV_IRQMASK`` is read-only to the host, and ``FALCON_IRQMASK`` has no effect on host routing on a RISC-V falcon.”h]”(j&)�”}”(hŒ ``IRQSTAT``”h]”hŒIRQSTAT”…”�”}”(hjmh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjiubhŒ´ latches every cause in the falcon, including the causes routed to the falcon’s own RISC-V core and owned by the firmware running on it. A host handler owns only the causes that ”…”�”}”(hjih²hh³Nh´Nubj&)�”}”(hŒ``PRISCV_RISCV_IRQMASK``”h]”hŒPRISCV_RISCV_IRQMASK”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjiubhŒ and ”…”�”}”(hjih²hh³Nh´Nubj&)�”}”(hŒ``PRISCV_RISCV_IRQDEST``”h]”hŒPRISCV_RISCV_IRQDEST”…”�”}”(hj‘h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjiubhŒ both select, so it intersects ”…”�”}”(hjih²hh³Nh´Nubj&)�”}”(hŒ ``IRQSTAT``”h]”hŒIRQSTAT”…”�”}”(hj£h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjiubhŒW with both before it reads or clears a cause. OpenRM computes the same intersection in ”…”�”}”(hjih²hh³Nh´Nubj&)�”}”(hŒ``kflcnRiscvReadIntrStatus``”h]”hŒkflcnRiscvReadIntrStatus”…”�”}”(hjµh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjiubhŒ³. GA100 keeps the Turing offsets of the two routing registers and GA102 moves them, so the offsets change at GA102 rather than at the Ampere boundary. The handler masks no cause: ”…”�”}”(hjih²hh³Nh´Nubj&)�”}”(hŒ``PRISCV_RISCV_IRQMASK``”h]”hŒPRISCV_RISCV_IRQMASK”…”�”}”(hjÇh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjiubhŒ is read-only to the host, and ”…”�”}”(hjih²hh³Nh´Nubj&)�”}”(hŒ``FALCON_IRQMASK``”h]”hŒFALCON_IRQMASK”…”�”}”(hjÙh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjiubhŒ2 has no effect on host routing on a RISC-V falcon.”…”�”}”(hjih²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MÕhjJh²hubhì)�”}”(hXH``INTR_RETRIGGER`` makes the falcon re-emit its host-routed causes into the tree, which supplies the transition that clearing the leaf lost. The handler writes ``INTR_RETRIGGER`` only on a path where it ended every cause that it read, because a re-emitted cause that stays set arrives again at once and on every pass after that.”h]”(j&)�”}”(hŒ``INTR_RETRIGGER``”h]”hŒINTR_RETRIGGER”…”�”}”(hjõh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjñubhŒŽ makes the falcon re-emit its host-routed causes into the tree, which supplies the transition that clearing the leaf lost. The handler writes ”…”�”}”(hjñh²hh³Nh´Nubj&)�”}”(hŒ``INTR_RETRIGGER``”h]”hŒINTR_RETRIGGER”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjñubhŒ– only on a path where it ended every cause that it read, because a re-emitted cause that stays set arrives again at once and on every pass after that.”…”�”}”(hjñh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MàhjJh²hubhì)�”}”(hXt``IRQSCLR`` ends a latch and does not end the source behind it, so a cause driven from outside the falcon stays set after the write. On Blackwell the fault-containment and ECC causes are driven that way: they appear in ``IRQSTAT`` but come from ``PRISCV_RISCV_FAULT_CONTAINMENT_SRCSTAT`` and ``PGSP_ECC_INTR_STATUS``, and only a device reset ends them. So the handler clears the latch of every host cause other than SWGEN0, reads the host causes back, and retriggers only when the read-back is empty. When a cause is still set, the handler disables vector 155 instead and reports that the device needs a reset. Disabling loses no notification: the cause that is still set holds the host-routed set non-empty, so the falcon would signal nothing further either way. OpenRM makes the same choice, and ``kgspService_TU102`` skips ``kflcnIntrRetrigger`` once it has recorded a fatal error.”h]”(j&)�”}”(hŒ ``IRQSCLR``”h]”hŒIRQSCLR”…”�”}”(hj#h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjubhŒÐ ends a latch and does not end the source behind it, so a cause driven from outside the falcon stays set after the write. On Blackwell the fault-containment and ECC causes are driven that way: they appear in ”…”�”}”(hjh²hh³Nh´Nubj&)�”}”(hŒ ``IRQSTAT``”h]”hŒIRQSTAT”…”�”}”(hj5h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjubhŒ but come from ”…”�”}”(hjh²hh³Nh´Nubj&)�”}”(hŒ*``PRISCV_RISCV_FAULT_CONTAINMENT_SRCSTAT``”h]”hŒ&PRISCV_RISCV_FAULT_CONTAINMENT_SRCSTAT”…”�”}”(hjGh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjubhŒ and ”…”�”}”(hjh²hh³Nh´Nubj&)�”}”(hŒ``PGSP_ECC_INTR_STATUS``”h]”hŒPGSP_ECC_INTR_STATUS”…”�”}”(hjYh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjubhXâ, and only a device reset ends them. So the handler clears the latch of every host cause other than SWGEN0, reads the host causes back, and retriggers only when the read-back is empty. When a cause is still set, the handler disables vector 155 instead and reports that the device needs a reset. Disabling loses no notification: the cause that is still set holds the host-routed set non-empty, so the falcon would signal nothing further either way. OpenRM makes the same choice, and ”…”�”}”(hjh²hh³Nh´Nubj&)�”}”(hŒ``kgspService_TU102``”h]”hŒkgspService_TU102”…”�”}”(hjkh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjubhŒ skips ”…”�”}”(hjh²hh³Nh´Nubj&)�”}”(hŒ``kflcnIntrRetrigger``”h]”hŒkflcnIntrRetrigger”…”�”}”(hj}h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjubhŒ$ once it has recorded a fatal error.”…”�”}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MæhjJh²hubhì)�”}”(hŒÀThe handler cannot distinguish a fault cause that arrives after the clear from one that the clear failed to end, so it disables the vector in that case too. Both mean that the GSP has faulted.”h]”hŒÀThe handler cannot distinguish a fault cause that arrives after the clear from one that the clear failed to end, so it disables the vector in that case too. Both mean that the GSP has faulted.”…”�”}”(hj•h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MóhjJh²hubhì)�”}”(hX\Turing falcons have no ``INTR_RETRIGGER``, so a Turing handler cannot re-create a transition that it has lost. It must leave no host cause latched: it reads the host-routed status once and takes every cause that the status reports, rather than stopping at the first one that it recognizes. One window stays open. A cause that arrives after the handler has read the status is not in the value that the handler clears, so it stays latched after the leaf has been cleared, and no later cause from that falcon signals the tree. OpenRM has the same window on Turing, where ``kflcnIntrRetrigger`` does nothing.”h]”(hŒTuring falcons have no ”…”�”}”(hj£h²hh³Nh´Nubj&)�”}”(hŒ``INTR_RETRIGGER``”h]”hŒINTR_RETRIGGER”…”�”}”(hj«h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj£ubhX, so a Turing handler cannot re-create a transition that it has lost. It must leave no host cause latched: it reads the host-routed status once and takes every cause that the status reports, rather than stopping at the first one that it recognizes. One window stays open. A cause that arrives after the handler has read the status is not in the value that the handler clears, so it stays latched after the leaf has been cleared, and no later cause from that falcon signals the tree. OpenRM has the same window on Turing, where ”…”�”}”(hj£h²hh³Nh´Nubj&)�”}”(hŒ``kflcnIntrRetrigger``”h]”hŒkflcnIntrRetrigger”…”�”}”(hj½h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj£ubhŒ does nothing.”…”�”}”(hj£h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M÷hjJh²hubeh}”(h]”Œretriggering-a-falcon”ah ]”h"]”Œretriggering a falcon”ah$]”h&]”uh1hÖhj�h²hh³hÇh´MÍubh×)�”}”(hhh]”(hÜ)�”}”(hŒEnabling the GSP event”h]”hŒEnabling the GSP event”…”�”}”(hjàh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjÝh²hh³hÇh´Mubhì)�”}”(hX"SWGEN0 is a latch, and the GSP drives no new edge into the tree while it stays set. nova-core's GSP boot code consumes the GSP's notifications by polling the queue, which leaves the latch set and leaves pending bits in the tree. The handoff from polling to interrupts has a required order::”h]”hX%SWGEN0 is a latch, and the GSP drives no new edge into the tree while it stays set. nova-core’s GSP boot code consumes the GSP’s notifications by polling the queue, which leaves the latch set and leaves pending bits in the tree. The handoff from polling to interrupts has a required order:”…”�”}”(hjîh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MhjÝh²hubj¤)�”}”(hXãdisable every implemented vector drop enables left by boot, or by a driver that ran before this one drain the tree clear stale pending bits rearm PCI interrupt delivery required under pre-Hopper MSI, which no later step rearms disable subtree 2 at TOP a TOP-enable rearm enabled it again clear the SWGEN0 latch so the next message makes an edge register the threaded handler no delivery can reach it yet enable vector 155 at LEAF(4) the subtree is still disabled enable subtree 2 at TOP deliveries become possible here drain the GSP-to-CPU queue messages posted before the clear”h]”hXãdisable every implemented vector drop enables left by boot, or by a driver that ran before this one drain the tree clear stale pending bits rearm PCI interrupt delivery required under pre-Hopper MSI, which no later step rearms disable subtree 2 at TOP a TOP-enable rearm enabled it again clear the SWGEN0 latch so the next message makes an edge register the threaded handler no delivery can reach it yet enable vector 155 at LEAF(4) the subtree is still disabled enable subtree 2 at TOP deliveries become possible here drain the GSP-to-CPU queue messages posted before the clear”…”�”}”hjüsbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1j£h³hÇh´MhjÝh²hubhì)�”}”(hXhThe first four steps are the tree reset. nova-core runs them, and clears the latch, before it registers the handler. Registering unmasks the PCI interrupt, and GIN would then deliver a vector that boot left enabled to a handler that services one vector and has no way to service any other. OpenRM clears every leaf enable at the same point for the same reason.”h]”hXhThe first four steps are the tree reset. nova-core runs them, and clears the latch, before it registers the handler. Registering unmasks the PCI interrupt, and GIN would then deliver a vector that boot left enabled to a handler that services one vector and has no way to service any other. OpenRM clears every leaf enable at the same point for the same reason.”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MhjÝh²hubhì)�”}”(hXAnova-core clears the latch after the drain. If nova-core cleared the latch first, a message posted before the drain could set it again, along with bit 27 of LEAF(4). The drain would then clear the leaf bit while the latch stays set, and no later message would signal the tree. Clearing after the drain can instead leave the leaf bit pending with the latch already clear. Enabling the subtree then delivers one interrupt whose ``IRQSTAT`` reads zero. The top half clears the leaf bit, rearms, and does not wake the IRQ thread, and the queue drain that follows reads the message.”h]”(hXªnova-core clears the latch after the drain. If nova-core cleared the latch first, a message posted before the drain could set it again, along with bit 27 of LEAF(4). The drain would then clear the leaf bit while the latch stays set, and no later message would signal the tree. Clearing after the drain can instead leave the leaf bit pending with the latch already clear. Enabling the subtree then delivers one interrupt whose ”…”�”}”(hjh²hh³Nh´Nubj&)�”}”(hŒ ``IRQSTAT``”h]”hŒIRQSTAT”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjubhŒŒ reads zero. The top half clears the leaf bit, rearms, and does not wake the IRQ thread, and the queue drain that follows reads the message.”…”�”}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MhjÝh²hubhì)�”}”(hŒ©Clearing the latch makes the first interrupt possible. A message that the GSP posted before that clear produces no interrupt, so the sequence ends by draining the queue.”h]”hŒ©Clearing the latch makes the first interrupt possible. A message that the GSP posted before that clear produces no interrupt, so the sequence ends by draining the queue.”…”�”}”(hj8h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M#hjÝh²hubhì)�”}”(hXThe subtree is enabled at ``TOP`` only once the handler is registered. A TOP-enable rearm sets the enables that it cycles, so the reset disables the serviced subtrees again after its rearm, and the tree reaches the registration with subtree 2 disabled under every rearm method. On teardown nova-core disables the vector at its leaf, so that no vector in the subtree can be delivered, then calls ``free_irq()``, and disables the subtree last. Disabling the subtree earlier would let a handler still in flight enable it again through the ``TOP_EN`` cycle of its rearm, which would leave the subtree enabled with no handler registered. The driver's ``Gpu`` object, which owns the tree, holds the subtree enable, and a handler's registration holds only the enable of its own vector, so that tearing down one handler does not disable a subtree that another handler shares. nova-core tears down the registration before it frees the queue that the handler drains and the falcon that the handler reads, and before it unloads the GSP.”h]”(hŒThe subtree is enabled at ”…”�”}”(hjFh²hh³Nh´Nubj&)�”}”(hŒ``TOP``”h]”hŒTOP”…”�”}”(hjNh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjFubhXj only once the handler is registered. A TOP-enable rearm sets the enables that it cycles, so the reset disables the serviced subtrees again after its rearm, and the tree reaches the registration with subtree 2 disabled under every rearm method. On teardown nova-core disables the vector at its leaf, so that no vector in the subtree can be delivered, then calls ”…”�”}”(hjFh²hh³Nh´Nubj&)�”}”(hŒ``free_irq()``”h]”hŒ free_irq()”…”�”}”(hj`h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjFubhŒ, and disables the subtree last. Disabling the subtree earlier would let a handler still in flight enable it again through the ”…”�”}”(hjFh²hh³Nh´Nubj&)�”}”(hŒ ``TOP_EN``”h]”hŒTOP_EN”…”�”}”(hjrh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjFubhŒf cycle of its rearm, which would leave the subtree enabled with no handler registered. The driver’s ”…”�”}”(hjFh²hh³Nh´Nubj&)�”}”(hŒ``Gpu``”h]”hŒGpu”…”�”}”(hj„h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjFubhXv object, which owns the tree, holds the subtree enable, and a handler’s registration holds only the enable of its own vector, so that tearing down one handler does not disable a subtree that another handler shares. nova-core tears down the registration before it frees the queue that the handler drains and the falcon that the handler reads, and before it unloads the GSP.”…”�”}”(hjFh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M'hjÝh²hubeh}”(h]”Œenabling-the-gsp-event”ah ]”h"]”Œenabling the gsp event”ah$]”h&]”uh1hÖhj�h²hh³hÇh´Mubh×)�”}”(hhh]”(hÜ)�”}”(hŒDraining the GSP-to-CPU queue”h]”hŒDraining the GSP-to-CPU queue”…”�”}”(hj§h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhj¤h²hh³hÇh´M7ubhì)�”}”(hŒiThe queue carries command replies and unsolicited events, and a message's function code says which it is.”h]”hŒkThe queue carries command replies and unsolicited events, and a message’s function code says which it is.”…”�”}”(hjµh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M9hj¤h²hubjÏ)�”}”(hhh]”(jÔ)�”}”(hŒxA function code that matches the awaited reply: the message is decoded and returned to the caller that sent the command.”h]”hì)�”}”(hŒxA function code that matches the awaited reply: the message is decoded and returned to the caller that sent the command.”h]”hŒxA function code that matches the awaited reply: the message is decoded and returned to the caller that sent the command.”…”�”}”(hjÊh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M<hjÆubah}”(h]”h ]”h"]”h$]”h&]”uh1jÓhjÃh²hh³hÇh´NubjÔ)�”}”(hX¢Anything else is an event. An OS error record and a robust-channel record are logged at error level, and an unrecognized function code at warning level. The other known events (GSP logs, libos prints, assertion records, lifecycle notices) need no action and get no line of their own, because the receive trace at debug level already records every message's arrival with its sequence number, function code, and length. ”h]”hì)�”}”(hX¡Anything else is an event. An OS error record and a robust-channel record are logged at error level, and an unrecognized function code at warning level. The other known events (GSP logs, libos prints, assertion records, lifecycle notices) need no action and get no line of their own, because the receive trace at debug level already records every message's arrival with its sequence number, function code, and length.”h]”hX£Anything else is an event. An OS error record and a robust-channel record are logged at error level, and an unrecognized function code at warning level. The other known events (GSP logs, libos prints, assertion records, lifecycle notices) need no action and get no line of their own, because the receive trace at debug level already records every message’s arrival with its sequence number, function code, and length.”…”�”}”(hjâh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´M>hjÞubah}”(h]”h ]”h"]”h$]”h&]”uh1jÓhjÃh²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”j“j”uh1jÎh³hÇh´M<hj¤h²hubhì)�”}”(hŒ½The sequence number takes no part in the match, because the GSP does not echo the command's sequence number on every reply. On r570 the reply to ``UnloadingGuestDriver`` carries sequence 0.”h]”(hŒ“The sequence number takes no part in the match, because the GSP does not echo the command’s sequence number on every reply. On r570 the reply to ”…”�”}”(hjüh²hh³Nh´Nubj&)�”}”(hŒ``UnloadingGuestDriver``”h]”hŒUnloadingGuestDriver”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjüubhŒ carries sequence 0.”…”�”}”(hjüh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MEhj¤h²hubhì)�”}”(hŒÝThe read pointer advances past every message that passes framing and checksum validation, whether it matched or was an event. A matched message that is too short to decode is the exception, and it stays at the queue head.”h]”hŒÝThe read pointer advances past every message that passes framing and checksum validation, whether it matched or was an event. A matched message that is too short to decode is the exception, and it stays at the queue head.”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MIhj¤h²hubhì)�”}”(hX#A message's length is inside the region that the checksum covers, so once the framing or the checksum fails there is no trustworthy length with which to skip the message. Such a message also stays at the queue head, and every later receive fails on it with ``EIO`` until the device is reset.”h]”(hXA message’s length is inside the region that the checksum covers, so once the framing or the checksum fails there is no trustworthy length with which to skip the message. Such a message also stays at the queue head, and every later receive fails on it with ”…”�”}”(hj*h²hh³Nh´Nubj&)�”}”(hŒ``EIO``”h]”hŒEIO”…”�”}”(hj2h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj*ubhŒ until the device is reset.”…”�”}”(hj*h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MMhj¤h²hubhì)�”}”(hXñThe polling path and the IRQ thread both read the queue under the command-queue mutex. Replies and events share one queue and one read pointer, so one lock is held across the whole drain. A thread waiting for a reply logs each event that arrives before the reply and keeps waiting. One deadline of 5 seconds applies to the whole wait, rather than a fresh timeout after each message, and the thread holds the mutex for the whole wait, so that no other caller consumes the message that it waits for.”h]”hXñThe polling path and the IRQ thread both read the queue under the command-queue mutex. Replies and events share one queue and one read pointer, so one lock is held across the whole drain. A thread waiting for a reply logs each event that arrives before the reply and keeps waiting. One deadline of 5 seconds applies to the whole wait, rather than a fresh timeout after each message, and the thread holds the mutex for the whole wait, so that no other caller consumes the message that it waits for.”…”�”}”(hjJh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MRhj¤h²hubhì)�”}”(hŒŒWith one lock, a drain waits for an in-flight command's receive to finish or time out. For log and error records that delay does not matter.”h]”hŒŽWith one lock, a drain waits for an in-flight command’s receive to finish or time out. For log and error records that delay does not matter.”…”�”}”(hjXh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hëh³hÇh´MZhj¤h²hubeh}”(h]”Œdraining-the-gsp-to-cpu-queue”ah ]”h"]”Œdraining the gsp-to-cpu queue”ah$]”h&]”uh1hÖhj�h²hh³hÇh´M7ubeh}”(h]”Œ the-gsp-event”ah ]”h"]”Œ the gsp event”ah$]”h&]”uh1hÖhhØh²hh³hÇh´M™ubeh}”(h]”Œ,gpu-interrupt-handling-gin-and-the-gsp-event”ah ]”h"]”Œ-gpu interrupt handling: gin and the gsp event”ah$]”h&]”uh1hÖhhh²hh³hÇh´Kubeh}”(h]”h ]”h"]”h$]”h&]”Œsource”hÇuh1hŒcurrent_source”NŒ current_line”NŒsettings”Œdocutils.frontend”ŒValues”“”)�”}”(hÛNŒ generator”NŒ datestamp”NŒ source_link”NŒ source_url”NŒ toc_backlinks”jß Œfootnote_backlinks”KŒ sectnum_xform”KŒstrip_comments”NŒstrip_elements_with_classes”NŒ strip_classes”NŒ report_level”KŒ halt_level”KŒexit_status_level”KŒdebug”NŒwarning_stream”NŒ traceback”ˆŒinput_encoding”Œ utf-8-sig”Œinput_encoding_error_handler”Œstrict”Œoutput_encoding”Œutf-8”Œoutput_encoding_error_handler”j Œerror_encoding”Œutf-8”Œerror_encoding_error_handler”Œbackslashreplace”Œ language_code”Œen”Œrecord_dependencies”NŒconfig”NŒ id_prefix”hŒauto_id_prefix”Œid”Œ dump_settings”NŒdump_internals”NŒdump_transforms”NŒdump_pseudo_xml”NŒexpose_internals”NŒstrict_visitor”NŒ_disable_config”NŒ_source”hÇŒ _destination”NŒ _config_files”]”Œ7/var/lib/git/docbuild/linux/Documentation/docutils.conf”aŒfile_insertion_enabled”ˆŒ raw_enabled”KŒline_length_limit”M'Œpep_references”NŒ pep_base_url”Œhttps://peps.python.org/”Œpep_file_url_template”Œpep-%04d”Œrfc_references”NŒ rfc_base_url”Œ&https://datatracker.ietf.org/doc/html/”Œ tab_width”KŒtrim_footnote_reference_space”‰Œsyntax_highlight”Œlong”Œ smart_quotes”ˆŒsmartquotes_locales”]”Œcharacter_level_inline_markup”‰Œdoctitle_xform”‰Œ docinfo_xform”KŒsectsubtitle_xform”‰Œ image_loading”Œlink”Œembed_stylesheet”‰Œcloak_email_addresses”ˆŒsection_self_link”‰Œenv”NubŒreporter”NŒindirect_targets”]”Œsubstitution_defs”}”Œsubstitution_names”}”Œrefnames”}”Œrefids”}”Œnameids”}”(j{jxj4j1jÝ jÚ jˆj…jÔjÑjh je j½ jº jÕ jÒ j� jŒ j‰ j† j‡ j„ j|jyj~j{jsjpjÚj×j¡jžjkjhuŒ nametypes”}”(j{‰j4‰jÝ ‰jˆ‰jÔ‰jh ‰j½ ‰jÕ ‰j� ‰j‰ ‰j‡ ‰j|‰j~‰js‰jÚ‰j¡‰jk‰uh}”(jxhØj1jQjÚ j7j…jVjÑj‹je j×jº jk jÒ jÀ jŒ jà j† j j„ jŒ jyj’ j{jjpj�j×jJjžjÝjhj¤uŒ footnote_refs”}”Œ citation_refs”}”Œ autofootnotes”]”Œautofootnote_refs”]”Œsymbol_footnotes”]”Œsymbol_footnote_refs”]”Œ footnotes”]”Œ citations”]”Œautofootnote_start”KŒsymbol_footnote_start”KŒ id_counter”Œ collections”ŒCounter”“”}”…”R”Œparse_messages”]”Œtransform_messages”]”Œ transformer”NŒ include_log”]”Œ decoration”Nh²hub.