The interrupt handler has a set of responsibilities to perform. Some are required by the framework, and some are required by the device. All interrupt handlers are required to do the following:
Determine if the device is interrupting and possibly reject the interrupt.
The interrupt handler must first examine the device and determine if it has issued the interrupt. If it has not, the handler must return DDI_INTR_UNCLAIMED. This step allows the implementation of device polling: it tells the system whether this device, among a number of devices at the given interrupt priority level, has issued the interrupt.
Inform the device that it is being serviced.
This is a device-specific operation, but it is required for the majority of devices. For example, SBus devices are required to interrupt until the driver tells them to stop. This guarantees that all SBus devices interrupting at the same priority level will be serviced.
Perform any I/O request-related processing.
Devices interrupt for different reasons, such as transfer done or transfer error. This step may involve using data access functions to read the device's data buffer, examine the device's error register, and set the status field in a data structure accordingly. Interrupt dispatching and processing are relatively time consuming.
Do any additional processing that could save another interrupt, for example, read the next data from the device.
Return DDI_INTR_CLAIMED.
Example 7-2 shows an interrupt routine.
static uint_t xxintr(caddr_t arg) { struct xxstate *xsp = (struct xxstate *)arg; uint8_t status; volatile uint8_t temp; /* * Claim or reject the interrupt.This example assumes * that the device's CSR includes this information. */ mutex_enter(&xsp->high_mu); /* use data access routines to read status */ status = ddi_get8(xsp->data_access_handle, &xsp->regp->csr); if (!(status & INTERRUPTING)) { mutex_exit(&xsp->high_mu); return (DDI_INTR_UNCLAIMED); /* dev not interrupting */ } /* * Inform the device that it is being serviced, and re-enable * interrupts. The example assumes that writing to the * CSR accomplishes this. The driver must ensure that this data * access operation makes it to the device before the interrupt * service routine returns. For example, using the data access * functions to read the CSR, if it does not result in unwanted * effects, can ensure this. */ ddi_put8(xsp->data_access_handle, &xsp->regp->csr, CLEAR_INTERRUPT | ENABLE_INTERRUPTS); /* flush store buffers */ temp = ddi_get8(xsp->data_access_handle, &xsp->regp->csr); mutex_exit(&xsp->mu); return (DDI_INTR_CLAIMED); }
Most of the steps performed by the interrupt routine depend on the specifics of the device itself. Consult the hardware manual for the device to determine the cause of the interrupt, detect error conditions, and access the device data registers.