第 1 部分针对 Oracle Solaris 平台设计设备驱动程序
9. 直接内存访问 (Direct Memory Access, DMA)
驱动程序框架和设备各自将要求置于中断处理程序上。所有中断处理程序均要求执行以下任务:
中断处理程序首先会检查设备,确定其是否发出了中断。如果设备未发出中断,则处理程序必须返回 DDI_INTR_UNCLAIMED。通过此步骤可实现设备轮询。在给定中断优先级别的任何设备都可能发出了中断。设备轮询将通知系统此设备是否已发出了中断。
通知设备正在对其进行服务。
通知设备服务是大多数设备所需的特定于设备的操作。例如,需要将 S 总线设备中断,直到驱动程序通知 S 总线设备停止。此方法可保证对在同一优先级别中断的所有 S 总线设备都进行服务。
执行任何与 I/O 请求有关的处理。
设备会由于不同原因而发生中断,如传送完成或传送错误。此步骤可涉及使用数据访问函数来读取设备的数据缓冲区,检查设备的错误寄存器,以及在数据结构中相应地设置状态字段。中断分发和处理相对比较耗时。
执行可以防止其他中断的任何附加处理。
例如,从设备中读取数据的下一项。
必须始终声明 MSI 中断。
对于 MSI-X 中断,声明中断是可选的。在任一情况下都无需检查中断的拥有权,因为 MSI 和 MSI-X 中断不是与其他设备共享的。
支持热插拔和多个 MSI 或 MSI-X 中断的驱动程序应针对热插拔事件保留单独的中断,并针对此中断注册单独的 ISR(interrupt service routine,中断服务例程)。
示例 8-9 中断示例
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); }
中断例程执行的大多数步骤都依赖于设备本身的特定信息。查询设备的硬件手册可确定中断原因,检测错误状态并访问设备数据寄存器。