1 // Copyright 2016 The Fuchsia Authors 2 // Copyright (c) 2016, Google, Inc. All rights reserved 3 // 4 // Use of this source code is governed by a MIT-style 5 // license that can be found in the LICENSE file or at 6 // https://opensource.org/licenses/MIT 7 8 9 #pragma once 10 11 #include <assert.h> 12 #include <dev/interrupt.h> 13 #include <dev/pcie_platform.h> 14 #include <err.h> 15 #include <kernel/spinlock.h> 16 #include <fbl/intrusive_single_list.h> 17 #include <fbl/macros.h> 18 #include <fbl/ref_counted.h> 19 #include <fbl/ref_ptr.h> 20 #include <region-alloc/region-alloc.h> 21 #include <sys/types.h> 22 23 /* Fwd decls */ 24 class PcieDevice; 25 26 /** 27 * Enumeration which defines the IRQ modes a PCIe device may be operating in. 28 * IRQ modes are exclusive, a device may be operating in only one mode at any 29 * given point in time. Drivers may query the maximum number of IRQs supported 30 * by each mode using the pcie_query_irq_mode_capabilities function. Drivers 31 * may request a particular number of IRQs be allocated when selecting an IRQ 32 * mode with pcie_set_irq_mode. IRQ identifiers used in the system when 33 * registering, un-registering and dispatching IRQs are on the range [0, N-1] 34 * where N are the number of IRQs successfully allocated using a call to 35 * pcie_set_irq_mode. 36 * 37 * ++ PCIE_IRQ_MODE_DISABLED 38 * All IRQs are disabled. 0 total IRQs are supported in this mode. 39 * 40 * ++ PCIE_IRQ_MODE_LEGACY 41 * Devices may support up to 1 legacy IRQ in total. Exclusive IRQ access 42 * cannot be guaranteed (the IRQ may be shared with other devices) 43 * 44 * ++ PCIE_IRQ_MODE_MSI 45 * Devices may support up to 32 MSI IRQs in total. IRQs may be allocated 46 * exclusively, resources permitting. 47 * 48 * ++ PCIE_IRQ_MODE_MSI_X 49 * Devices may support up to 2048 MSI-X IRQs in total. IRQs may be allocated 50 * exclusively, resources permitting. 51 */ 52 typedef enum pcie_irq_mode { 53 PCIE_IRQ_MODE_DISABLED = 0, 54 PCIE_IRQ_MODE_LEGACY = 1, 55 PCIE_IRQ_MODE_MSI = 2, 56 PCIE_IRQ_MODE_MSI_X = 3, 57 PCIE_IRQ_MODE_COUNT = 4, 58 } pcie_irq_mode_t; 59 60 /** 61 * A structure used to hold output parameters when calling 62 * pcie_query_irq_mode_capabilities 63 */ 64 typedef struct pcie_irq_mode_caps { 65 uint max_irqs; /** The maximum number of IRQ supported by the selected mode */ 66 /** 67 * For MSI or MSI-X, indicates whether or not per-vector-masking has been 68 * implemented by the hardware. 69 */ 70 bool per_vector_masking_supported; 71 } pcie_irq_mode_caps_t; 72 73 /** 74 * An enumeration of the permitted return values from a PCIe IRQ handler. 75 * 76 * ++ PCIE_IRQRET_NO_ACTION 77 * Do not mask the IRQ. 78 * 79 * ++ PCIE_IRQRET_MASK 80 * Mask the IRQ if (and only if) per vector masking is supported. 81 */ 82 typedef enum pcie_irq_handler_retval { 83 PCIE_IRQRET_NO_ACTION = 0x0, 84 PCIE_IRQRET_MASK = 0x1, 85 } pcie_irq_handler_retval_t; 86 87 /** 88 * A structure used to hold the details about the currently configured IRQ mode 89 * of a device. Used in conjunction with pcie_get_irq_mode. 90 */ 91 typedef struct pcie_irq_mode_info { 92 pcie_irq_mode_t mode; /// The currently configured mode. 93 uint max_handlers; /// The max number of handlers for the mode. 94 uint registered_handlers; /// The current number of registered handlers. 95 } pcie_irq_mode_info_t; 96 97 /** 98 * Definition of the callback registered with pcie_register_irq_handler. This 99 * callback will be called by a bus central IRQ dispatcher any time a chosen 100 * device IRQ occurs. 101 * 102 * @note Masked/unmasked status of an IRQ MUST not be manipulated via the API 103 * during an IRQ handler dispatch. If an IRQ needs to be masked as part of a 104 * handler's behavior, the appropriate return value should be used instead of in 105 * the API. @see pcie_irq_handler_retval_t 106 * 107 * @param dev A pointer to the pci device for which this IRQ occurred. 108 * @param irq_id The 0-indexed ID of the IRQ which occurred. 109 * @param ctx The context pointer registered when registering the handler. 110 */ 111 typedef pcie_irq_handler_retval_t (*pcie_irq_handler_fn_t)( 112 const PcieDevice& dev, 113 uint irq_id, 114 void* ctx); 115 116 /** 117 * Structure used internally to hold the state of a registered handler. 118 */ 119 struct pcie_irq_handler_state_t { 120 SpinLock lock; 121 pcie_irq_handler_fn_t handler = nullptr; 122 void* ctx = nullptr; 123 PcieDevice* dev = nullptr; 124 uint pci_irq_id; 125 bool masked; 126 }; 127 128 /** 129 * Class for managing shared legacy IRQ handlers. 130 * TODO(johngro): Make this an inner class of PcieDevice 131 */ 132 class SharedLegacyIrqHandler 133 : public fbl::SinglyLinkedListable<fbl::RefPtr<SharedLegacyIrqHandler>>, 134 public fbl::RefCounted<SharedLegacyIrqHandler> { 135 public: 136 static fbl::RefPtr<SharedLegacyIrqHandler> Create(uint irq_id); 137 ~SharedLegacyIrqHandler(); 138 139 void AddDevice(PcieDevice& dev); 140 void RemoveDevice(PcieDevice& dev); 141 irq_id()142 uint irq_id() const { return irq_id_; } 143 144 // Disallow copying, assigning and moving. 145 DISALLOW_COPY_ASSIGN_AND_MOVE(SharedLegacyIrqHandler); 146 147 private: 148 explicit SharedLegacyIrqHandler(uint irq_id); 149 HandlerThunk(void * arg)150 static interrupt_eoi HandlerThunk(void *arg) { 151 DEBUG_ASSERT(arg); 152 reinterpret_cast<SharedLegacyIrqHandler*>(arg)->Handler(); 153 return IRQ_EOI_DEACTIVATE; 154 } 155 156 void Handler(); 157 158 struct list_node device_handler_list_; 159 SpinLock device_handler_list_lock_; 160 const uint irq_id_; 161 }; 162 163