Interrupt Synchronization for GPIO Controller Drivers

GPIO controller drivers can call the GPIO_CLX_AcquireInterruptLock and GPIO_CLX_ReleaseInterruptLock methods to acquire and release interrupt locks that are implemented internally by the GPIO framework extension (GpioClx). Driver code that runs at IRQL = PASSIVE_LEVEL can call these methods to synchronize to the interrupt service routine (ISR) in GpioClx. GpioClx dedicates a separate interrupt lock to each bank of pins in the GPIO controller.

If the hardware registers of the GPIO controller are memory-mapped, the ISR in GpioClx calls certain driver-implemented event callback functions at DIRQL; GpioClx calls the rest of the callback functions at PASSIVE_LEVEL. A passive-level callback function that accesses a bank of registers might need to use an interrupt lock to synchronize to callback functions that run at DIRQL and that access the same registers.

For example, the passive-level CLIENT_EnableInterrupt and CLIENT_DisableInterrupt callback functions modify hardware settings that affect the operation of other interrupt-related callback routines that run at DIRQL. The CLIENT_EnableInterrupt and CLIENT_DisableInterrupt functions typically use the bank interrupt locks to synchronize their register accesses.

GpioClx automatically serializes interrupt-related and I/O-related callbacks that occur at DIRQL. GpioClx acquires the interrupt lock for the target bank before calling a callback function at DIRQL, and releases the lock after the function returns. It is an error for a callback function that is called at DIRQL to try to re-acquire the bank interrupt lock by calling GPIO_CLX_AcquireInterruptLock.

Similarly, GpioClx automatically serializes callbacks that occur at PASSIVE_LEVEL. GpioClx internally implements a wait lock per bank. GpioClx acquires the wait lock for the target bank before calling a callback function at PASSIVE_LEVEL, and releases the lock when the function returns. For a memory-mapped GPIO controller, GpioClx manages the bank wait locks on behalf of the driver but does not enable the driver to explicitly acquire and release the locks.

However, for a non-memory-mapped GPIO controller, GPIO_CLX_AcquireInterruptLock and GPIO_CLX_ReleaseInterruptLock acquire and release a wait lock instead of an interrupt lock. GpioClx implements a separate wait lock for each bank of pins in the GPIO controller. Because the registers are not memory-mapped, all interrupt-related and I/O-related callback functions are called at PASSIVE_LEVEL so that they can use I/O requests to access the registers through a serial bus, such as I²C. GpioClx acquires the wait lock for the target bank before calling one of these callback functions, and releases the lock after the function returns.

It is an error for a callback function for a non-memory-mapped controller to try to re-acquire the bank wait lock by calling GPIO_CLX_AcquireInterruptLock. However, passive-level driver code outside of the callback functions can call the GPIO_CLX_XxxInterruptLock methods to synchronize to the callback functions. Because GpioClx calls all interrupt-related and I/O-related callback functions at PASSIVE_LEVEL, the bank wait locks effectively take the place of the bank interrupt locks for non-memory-mapped controllers.

Another option for a non-memory-mapped controller is for the controller driver to implement a set of wait locks. These wait locks might enable the callback routines to do more fine-grained locking and unlocking of shared resources than is possible with the wait locks implemented by GpioClx.

During the call to the CLIENT_QueryControllerBasicInformation callback routine, a GPIO controller driver reports to GpioClx whether the controller registers are memory-mapped. For more information, see the description of the MemoryMappedController flag in CLIENT_CONTROLLER_BASIC_INFORMATION.

For more information about interrupt locks and wait locks, see Using Framework Locks.

The following tables provide more detailed information about which callback functions are called at DIRQL instead of at PASSIVE_LEVEL if the registers are memory-mapped. The notes that follow the tables explain when passive-level callback functions should use interrupt locks.

To support GPIO pins that are configured as interrupt inputs, a GPIO controller driver implements a set of event callback functions to manage interrupt requests through these pins. In the following table, the middle column indicates the IRQL at which the functions are called if the hardware registers of the GPIO controller are memory-mapped. The rightmost column indicates the IRQL at which the functions are called if the registers are not memory-mapped and must be accessed through a serial bus.

Callback function IRQL if memory-mapped (MemoryMappedController = 1) IRQL if serially accessed (MemoryMappedController = 0)

CLIENT_EnableInterrupt

CLIENT_DisableInterrupt

PASSIVE_LEVEL

(See note 1.)

PASSIVE_LEVEL

(See note 2.)

CLIENT_ClearActiveInterrupts

CLIENT_MaskInterrupts

CLIENT_QueryActiveInterrupts

CLIENT_QueryEnabledInterrupts

CLIENT_ReconfigureInterrupt

CLIENT_UnmaskInterrupt

DIRQL

(See note 3.)

PASSIVE_LEVEL

(See note 4.)

CLIENT_PreProcessControllerInterrupt

DIRQL

(See note 5.)

DIRQL

(See note 6.)

Notes

  1. GpioClx does not acquire the bank interrupt lock before calling this callback function. The callback function can acquire the bank interrupt lock, if necessary, to synchronize accesses of registers that are shared with callback functions that run at DIRQL.

  2. GpioClx serializes the call to this callback function with other interrupt-related and I/O-related callback functions that are called at PASSIVE_LEVEL. Thus, the callback function should not try to acquire the bank wait lock.

  3. GpioClx acquires the bank interrupt lock before calling this callback function, and releases the lock after the function returns. Thus, the callback function should not try to acquire the bank interrupt lock.

  4. GpioClx serializes the call to this callback function with other interrupt-related and I/O-related callback functions that are called at PASSIVE_LEVEL. Thus, the callback function should not try to acquire the bank wait lock.

  5. GpioClx acquires the bank interrupt lock before calling this callback function, and releases the lock after the function returns. Thus, the callback function should not try to acquire the bank interrupt lock.

  6. GpioClx does not acquire the bank interrupt lock before calling this callback function. The GPIO controller driver is responsible for providing any synchronization that might be required.

To support GPIO pins that are configured as data I/O pins, a GPIO controller driver implements a set of event callback functions to manage I/O operations through these pins. In the following table, the middle column indicates the IRQL at which the functions are called if the hardware registers of the GPIO controller are memory-mapped. The rightmost column indicates the IRQL at which the functions are called if the registers are not memory-mapped and must be accessed through a serial bus.

Callback function IRQL if memory-mapped (MemoryMappedController = 1) IRQL if serially accessed (MemoryMappedController = 0)

CLIENT_ConnectIoPins

CLIENT_DisconnectIoPins

PASSIVE_LEVEL

(See note 1.)

PASSIVE_LEVEL

(See note 2.)

CLIENT_ReadGpioPins

CLIENT_ReadGpioPinsUsingMask

CLIENT_WriteGpioPins

CLIENT_WriteGpioPinsUsingMask

DIRQL

(See note 3.)

PASSIVE_LEVEL

(See note 4.)

Notes

  1. GpioClx does not acquire the bank interrupt lock before calling this callback function. The callback function can acquire the interrupt lock, if necessary, to synchronize accesses of registers that are shared with callback functions that run at DIRQL.

  2. GpioClx serializes the call to this callback function with other interrupt-related and I/O-related callback functions that are called at PASSIVE_LEVEL. Thus, the callback function should not try to acquire the bank wait lock.

  3. GpioClx acquires the bank interrupt lock before calling this callback function, and releases the lock after the function returns. Thus, the callback function should not try to acquire the bank interrupt lock.

  4. GpioClx serializes the call to this callback function with other interrupt-related and I/O-related callback functions that are called at PASSIVE_LEVEL. Thus, the callback function should not try to acquire the bank wait lock.

To set up a GPIO controller to perform I/O and interrupt operations, a GPIO controller driver implements a set of event callback functions to initialize the controller. In the following table, the middle column indicates the IRQL at which the functions are called if the hardware registers of the GPIO controller are memory-mapped. The rightmost column indicates the IRQL at which the functions are called if the registers are not memory-mapped and must be accessed through a serial bus.

Callback function IRQL if memory-mapped (MemoryMappedController = 1) IRQL if serially accessed (MemoryMappedController = 0)

CLIENT_PrepareController

CLIENT_ReleaseController

CLIENT_StartController

CLIENT_StopController

CLIENT_QueryControllerBasicInformation

CLIENT_QuerySetControllerInformation

PASSIVE_LEVEL

(See note 1.)

PASSIVE_LEVEL

(See note 2.)

Notes

  1. When GpioClx calls any of these callback functions, bank interrupt locks are not available. Thus, these callback functions should not try to acquire the bank interrupt lock.

  2. The GpioClx bank wait locks are not available when these callback functions are called. Thus, the driver should not try to acquire a bank wait lock to synchronize to these callback functions.

To enable a GPIO controller to change device power states, a GPIO controller driver implements a set of event callback functions to save and restore the hardware settings during these changes. In the following table, the middle column indicates the IRQL at which the functions are called if the hardware registers of the GPIO controller are memory-mapped. The rightmost column indicates the IRQL at which the functions are called if the registers are not memory-mapped and must be accessed through a serial bus.

Callback function IRQL if memory-mapped (MemoryMappedController = 1) IRQL if serially accessed (MemoryMappedController = 0)

CLIENT_RestoreBankHardwareContext

CLIENT_SaveBankHardwareContext

DIRQL or HIGH_LEVEL

(See Notes.)

Not supported.

Notes

  • For regular F-state transitions: The save/restore callback functions are called with the bank interrupt lock held by GpioClx at DIRQL. Thus, neither callback function should try to acquire the bank interrupt lock.
  • For critical F-state transitions: The save/restore callbacks are called when the power engine plug-in (PEP) is invoked to save and restore the GPIO state. The save/restore callback functions are called at HIGH_LEVEL in the context of the last processor to go idle, which occurs late in the platform deep-idle transition sequence. Thus, neither callback function should try to acquire the bank interrupt lock.

For more information about F-states, see Component-Level Power Management. For more information about the PEP, see PoFxPowerControl.

Other callback functions

To enable a GPIO controller to support controller-specific operations, a GPIO controller driver implements a CLIENT_ControllerSpecificFunction event callback function. In the following table, the middle column indicates the IRQL at which the function is called if the hardware registers of the GPIO controller are memory-mapped. The rightmost column indicates the IRQL at which the function is called if the registers are not memory-mapped and must be accessed through a serial bus.

Callback function IRQL if memory-mapped (MemoryMappedController = 1) IRQL if serially accessed (MemoryMappedController = 0)

CLIENT_ControllerSpecificFunction

PASSIVE_LEVEL

(See note 1.)

PASSIVE_LEVEL

(See note 2.)

Notes

  1. GpioClx does not acquire the bank interrupt lock before calling this callback function. The callback function can acquire the bank interrupt lock, if necessary, to synchronize accesses of registers that are shared with callback functions that run at DIRQL.

  2. GpioClx serializes the call to this callback function with other interrupt-related and I/O-related callback functions that are called at PASSIVE_LEVEL. Thus, the callback function should not try to acquire the bank wait lock.