OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (c) 2009 NVIDIA Corporation. |
| 3 * All rights reserved. |
| 4 * |
| 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions are met: |
| 7 * |
| 8 * Redistributions of source code must retain the above copyright notice, |
| 9 * this list of conditions and the following disclaimer. |
| 10 * |
| 11 * Redistributions in binary form must reproduce the above copyright notice, |
| 12 * this list of conditions and the following disclaimer in the documentation |
| 13 * and/or other materials provided with the distribution. |
| 14 * |
| 15 * Neither the name of the NVIDIA Corporation nor the names of its contributors |
| 16 * may be used to endorse or promote products derived from this software |
| 17 * without specific prior written permission. |
| 18 * |
| 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| 20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| 23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 29 * POSSIBILITY OF SUCH DAMAGE. |
| 30 * |
| 31 */ |
| 32 |
| 33 #ifndef INCLUDED_nvrm_interrupt_H |
| 34 #define INCLUDED_nvrm_interrupt_H |
| 35 |
| 36 |
| 37 #if defined(__cplusplus) |
| 38 extern "C" |
| 39 { |
| 40 #endif |
| 41 |
| 42 #include "nvrm_module.h" |
| 43 #include "nvrm_init.h" |
| 44 |
| 45 #include "nvos.h" |
| 46 |
| 47 /** @file |
| 48 * @brief <b>NVIDIA Driver Development Kit: |
| 49 * Resource Manager %Interrupt API</b> |
| 50 * |
| 51 * @b Description: Declares the interrupt API for use by NvDDK modules. |
| 52 */ |
| 53 |
| 54 /** |
| 55 * @defgroup nvrm_interrupt RM Interrupt Management Services |
| 56 * |
| 57 * @ingroup nvddk_rm |
| 58 * @{ |
| 59 * |
| 60 * IRQ Numbers |
| 61 * ----------- |
| 62 * In most cases, we are using the CPU's legacy interrupt support, rather than |
| 63 * the new MPCore interrupt controller. This means that we only have one ISR |
| 64 * shared between all of the devices in our chip. To determine which device is |
| 65 * interrupting us, we have to read some registers. We assign each interrupt |
| 66 * source an "IRQ number". IRQ numbers are OS-independent and HW-dependent (a |
| 67 * given device may have a different IRQ number from chip to chip). |
| 68 * |
| 69 * It is arbitrary how far we decode interrupts as part of determining the IRQ |
| 70 * number. Normally we might assign one IRQ number to each interrupt line that |
| 71 * feeds into the main interrupt controller (typically one per device in the |
| 72 * chip), but we can decode further if we want. For example, there are several |
| 73 * GPIO controllers, each of which controls 32 GPIO lines. The GPIO controller |
| 74 * interrupt line is constructed by OR'ing together the interrupt lines for each |
| 75 * of the 32 GPIO pins. If we want, we can assign each GPIO controller 32 |
| 76 * separate IRQ numbers, one per GPIO line; this simply means we have to sub- |
| 77 * decode the interrupts a little further inside the ISR. |
| 78 * |
| 79 * The main advantage of doing this sub-decoding is that only a single driver is |
| 80 * allowed to hook each interrupt source -- if multiple drivers both want to |
| 81 * register interrupt handlers for the same interrupt source, the drivers will |
| 82 * fight with one another trying to handle the same interrupt, so this is an |
| 83 * error. At the same time, it's entirely plausible that out of a group of 32 |
| 84 * GPIO pins, multiple different drivers care about different groups of those |
| 85 * pins. In the absence of sub-decoding, we would have to implement a "GPIO |
| 86 * driver" whose sole purpose was to allow those other drivers to register for |
| 87 * GPIO notifications, and then use driver-to-driver signaling to indicate when |
| 88 * a pin has transitioned state. This is an extra level of overhead compared |
| 89 * to if drivers are allowed to directly hook the interrupts for the pins they |
| 90 * care about. |
| 91 * |
| 92 * Because IRQ numbers change from chip to chip, you must ask the RM for the IRQ |
| 93 * number of the device when you want to hook its interrupt. This can be |
| 94 * accomplished using the NvRmGetIrqForLogicalInterrupt() API. You pass it an |
| 95 * [NvRmModuleID, Index] pair telling it what device you are interested in, and |
| 96 * which sub-interrupt within that device. Often Index is just zero (many |
| 97 * devices only have one IRQ number). For GPIO it might by the pin number |
| 98 * within the GPIO controller. For UART, you might (entirely hypothetically -- |
| 99 * there is no requirement that you do this) have Index=0 for the receive |
| 100 * interrupt and Index=1 for the send interrupt. |
| 101 * |
| 102 * Hooking an Interrupt |
| 103 * -------------------- |
| 104 * Once you have the IRQ number(s), you can hook the interrupt(s) by calling |
| 105 * NvRmInterruptRegister(). At driver shutdown, you can unhook the interrupt(s) |
| 106 * by calling NvRmInterruptUnregister(). |
| 107 * |
| 108 * NvRmInterruptRegister takes a list of IRQs and a list of callback functions t
o be |
| 109 * called when the corresponding interrupt has fired. The callback functions |
| 110 * will be passed an extra "void *context" parameter, typically a pointer to |
| 111 * your private driver structure that keeps track of the state of your device. |
| 112 * For example, the NAND driver might pass the NvDdkNandHandle as the context |
| 113 * param. |
| 114 * |
| 115 * Drivers that care about more than one IRQ should call NvRmInterruptRegister o
nly |
| 116 * once. Calling NvRmInterruptRegister twice (each time with a single IRQ numbe
r) |
| 117 * may consume more system resources than calling NvRmInterruptRegister once wit
h |
| 118 * a list of 2 IRQ numbers and 2 callbacks. |
| 119 * |
| 120 * Rules for Interrupt Handlers |
| 121 * ---------------------------- |
| 122 * We assume that all interrupt handlers (i.e. the callbacks passed to |
| 123 * NvRmInterruptRegister) are "fast": that is, any complex processing that canno
t |
| 124 * complete in a tightly bounded amount of time, such as polling registers to |
| 125 * wait for the HW to complete some processing, is not done in the ISR proper. |
| 126 * Instead, the ISR would signal a semaphore, clear the interrupt, and pass off |
| 127 * the rest of the work to another thread. |
| 128 * |
| 129 * To be more precise about this, we expect all interrupt handlers to follow |
| 130 * these rules: |
| 131 * - They may only call a subset of NvOs functions. The exact subset is |
| 132 * documented in nvos.h. |
| 133 * - No floating-point. (We don't want to have to save and restore the |
| 134 * floating point registers on an interrupt.) |
| 135 * - They should use as little stack space as possible. They certainly should |
| 136 * not use any recursive algorithms, for example. (For example, if they need |
| 137 * to look up a node in a red-black tree, they must use an iterative version |
| 138 * of the tree search rather than recursion.) Straw man: 256B maximum? |
| 139 * - Any control flow structure that involves looping (like a "for" or "while" |
| 140 * statement) must be guaranteed to terminate within a clearly understood |
| 141 * time limit. We don't have a strict upper bound, but if it takes |
| 142 * milliseconds, it's out of the question. |
| 143 * - The callback function _must_ clear the cause of the interrupt. Upon |
| 144 * returning from the callback the interrupt will be automatically re-enabled. |
| 145 * If the cause is not cleared the system will be stuck in an infinite loop |
| 146 * taking interrupts. |
| 147 */ |
| 148 |
| 149 /** |
| 150 * A Logical Interrupt is a tuple that includes the class of interrupts |
| 151 * (i.e., a module), an instance of that module, and the specific interrupt |
| 152 * within that instance (an index). This is an abstraction for the |
| 153 * actual interrupt bits implemented on the SOC. |
| 154 */ |
| 155 |
| 156 typedef struct NvRmLogicalIntrRec |
| 157 { |
| 158 |
| 159 /** |
| 160 * Interrupt index within the current instance of specified Module. |
| 161 * This identifies a specific interrupt. This is an enumerated index |
| 162 * and not a bit-mask. |
| 163 */ |
| 164 NvU8 Index; |
| 165 |
| 166 /** |
| 167 * The SOC hardware controller class identifier |
| 168 */ |
| 169 NvRmModuleID ModuleID; |
| 170 } NvRmLogicalIntr; |
| 171 |
| 172 /** |
| 173 * Translate a given logical interrupt to its corresponding IRQ number. |
| 174 * |
| 175 * @param hRmDevice The RM device handle |
| 176 * @param ModuleID The module of interest |
| 177 * @param Index Zero-based interrupt index within the module |
| 178 * |
| 179 * @return The IRQ number. |
| 180 */ |
| 181 |
| 182 NvU32 NvRmGetIrqForLogicalInterrupt( |
| 183 NvRmDeviceHandle hRmDevice, |
| 184 NvRmModuleID ModuleID, |
| 185 NvU32 Index ); |
| 186 |
| 187 /** |
| 188 * Retrieve the number of IRQs associated with a particular module instance. |
| 189 * |
| 190 * @param hRmDevice The RM device handle |
| 191 * @param ModuleID The module of interest |
| 192 * |
| 193 * @return The number of IRQs. |
| 194 */ |
| 195 |
| 196 NvU32 NvRmGetIrqCountForLogicalInterrupt( |
| 197 NvRmDeviceHandle hRmDevice, |
| 198 NvRmModuleID ModuleID ); |
| 199 |
| 200 /* |
| 201 * Register the interrupt with the given interrupt handler. |
| 202 * |
| 203 * Assert encountered in debug mode if irq number is not valid. |
| 204 * |
| 205 * @see NvRmInterruptEnable() |
| 206 * |
| 207 * @param hRmDevice The RM device handle. |
| 208 * @param IrqListSize size of the IrqList passed in for registering the irq |
| 209 * handlers for each irq number. |
| 210 * @param pIrqList Array of IRQ numbers for which interupt handlers to be |
| 211 * registerd. |
| 212 * @param pIrqHandlerList array intrupt routine to be called when interrupt |
| 213 * occures. |
| 214 * @param context pointer to the registrer's context handle |
| 215 * @param handle handle to the registered interrupts. This handle is used by for |
| 216 * unregistering the interrupt. |
| 217 * @param InterruptEnable If true, immediately enable interrupt. Otherwise |
| 218 * enable interrupt only after calling NvRmInterruptEnable(). |
| 219 * |
| 220 * @retval "NvError_IrqRegistrationFailed" if interupt is already registred. |
| 221 * @retval "NvSuccess" if registration is successfull. |
| 222 */ |
| 223 NvError |
| 224 NvRmInterruptRegister( |
| 225 NvRmDeviceHandle hRmDevice, |
| 226 NvU32 IrqListSize, |
| 227 const NvU32 *pIrqList, |
| 228 const NvOsInterruptHandler *pIrqHandlerList, |
| 229 void *context, |
| 230 NvOsInterruptHandle *handle, |
| 231 NvBool InterruptEnable); |
| 232 |
| 233 /** |
| 234 * Un-registers the interrupt handler from the associated interrupt handle which |
| 235 * is returned by the NvRmInterruptRegister API. |
| 236 * |
| 237 * @param handle Handle returned when the interrupt is registered. |
| 238 */ |
| 239 void |
| 240 NvRmInterruptUnregister( |
| 241 NvRmDeviceHandle hRmDevice, |
| 242 NvOsInterruptHandle handle); |
| 243 |
| 244 /** |
| 245 * Enable the interrupt handler from the associated interrupt handle which |
| 246 * is returned by the NvRmInterruptRegister API. |
| 247 * |
| 248 * @param handle Handle returned when the interrupt is registered. |
| 249 * |
| 250 * @retval "NvError_BadParameter" if handle is not valid |
| 251 * @retval "NvError_InsufficientMemory" if interupt enable failed. |
| 252 * @retval "NvSuccess" if registration is successfull. |
| 253 */ |
| 254 NvError |
| 255 NvRmInterruptEnable( |
| 256 NvRmDeviceHandle hRmDevice, |
| 257 NvOsInterruptHandle handle); |
| 258 |
| 259 /** |
| 260 * Called by the interrupt callaback to re-enable the interrupt. |
| 261 */ |
| 262 |
| 263 void |
| 264 NvRmInterruptDone( NvOsInterruptHandle handle ); |
| 265 |
| 266 |
| 267 #if defined(__cplusplus) |
| 268 } |
| 269 #endif |
| 270 |
| 271 #endif |
OLD | NEW |