Skip Navigation Links | |
Exit Print View | |
Writing Device Drivers Oracle Solaris 11.1 Information Library |
Part I Designing Device Drivers for the Oracle Solaris Platform
1. Overview of Oracle Solaris Device Drivers
2. Oracle Solaris Kernel and Device Tree
5. Managing Events and Queueing Tasks
7. Device Access: Programmed I/O
Standard and Extended Message-Signaled Interrupts
Interrupt Capability Functions
Interrupt Initialization and Destruction Functions
The Interrupt Resource Management Feature
Register a Callback Handler Function
Unregister a Callback Handler Function
Modify Number of Interrupt Vectors Requested
Interrupt Usage and Flexibility
Example Implementation of Interrupt Resource Management
Handling High-Level Interrupts
High-Level Interrupt Handling Example
10. Mapping Device and Kernel Memory
13. Hardening Oracle Solaris Drivers
14. Layered Driver Interface (LDI)
Part II Designing Specific Kinds of Device Drivers
15. Drivers for Character Devices
18. SCSI Host Bus Adapter Drivers
19. Drivers for Network Devices
Part III Building a Device Driver
22. Compiling, Loading, Packaging, and Testing Drivers
23. Debugging, Testing, and Tuning Device Drivers
24. Recommended Coding Practices
B. Summary of Oracle Solaris DDI/DKI Services
C. Making a Device Driver 64-Bit Ready
The driver framework and the device each place demands on the interrupt handler. All interrupt handlers are required to do the following tasks:
Determine whether the device is interrupting and possibly reject the interrupt.
The interrupt handler first examines the device to determine whether this device issued the interrupt. If this device did not issue the interrupt, the handler must return DDI_INTR_UNCLAIMED. This step enables the implementation of device polling. Any device at the given interrupt priority level might have issued the interrupt. Device polling tells the system whether this device issued the interrupt.
Inform the device that the device is being serviced.
Informing a device about servicing is a device-specific operation that is required for the majority of devices. For example, SBus devices are required to interrupt until the driver tells the SBus devices to stop. This approach guarantees that all SBus devices that interrupt at the same priority level are serviced.
Perform any I/O request-related processing.
Devices interrupt for different reasons, such as transfer done or transfer error. This step can 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 prevent another interrupt.
For example, read the next item of data from the device.
MSI interrupts must always be claimed.
Claiming an interrupt is optional for MSI-X interrupts. In either case, the ownership of the interrupt need not be checked, because MSI and MSI-X interrupts are not shared with other devices.
Drivers that support hotplugging and multiple MSI or MSI-X interrupts should retain a separate interrupt for hotplug events and register a separate ISR (interrupt service routine) for that interrupt.
The following example shows an interrupt routine for a device called mydev.
Example 8-9 Interrupt Example
static uint_t mydev_intr(caddr_t arg1, caddr_t arg2) { struct mydevstate *xsp = (struct mydevstate *)arg1; 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.