第 1 部分针对 Oracle Solaris 平台设计设备驱动程序
9. 直接内存访问 (Direct Memory Access, DMA)
14. 分层驱动程序接口 (Layered Driver Interface, LDI)
I/O 总线以两种常用方法来实现中断:向量化和轮询。这两种方法通常都会提供总线中断优先级别。向量化设备还会提供中断向量。轮询设备则不提供中断向量。
为了与不断发展的总线技术保持同步,Oracle Solaris OS 已经得到了增强,可适应更新类型的中断以及已经使用多年的较为传统的中断。具体来说,操作系统目前可识别三种类型的中断:
传统中断-传统或固定中断是指使用早期总线技术的中断。使用这些技术,可通过一个或多个“带外”(即,独立于总线的主线)连线的外部管脚来发送中断信号。较新的总线技术(如 PCI Express)通过带内机制模拟传统中断来维持软件兼容性。主机 OS 将这些模仿中断视为传统中断。
消息告知中断-消息告知中断 (message-signalled interrupt, MSI) 使用带内消息而不是使用管脚,可在主桥 (host bridge) 中确定中断的地址。(有关主桥 (host bridge) 的更多信息,请参见PCI 局部总线。)MSI 可以将数据与中断消息一起发送。每个 MSI 都不是共享的,这样可以保证指定给某一设备的 MSI 在系统中是唯一的。一个 PCI 函数最多可以请求 32 条 MSI 消息。
扩展消息告知中断-扩展消息告知中断 (Extended message-signalled interrupt, MSI-X) 是 MSI 的增强版本。MSI-X 中断具有以下新增的优点:
支持 2048 条而不是 32 条消息
针对每条消息支持独立的消息地址和消息数据
支持按消息屏蔽
软件分配的向量少于硬件请求的向量时可具有更大灵活性。软件可以在多个 MSI-X 插槽中重用相同的 MSI-X 地址和数据。
注 - 一些较新的总线技术(如 PCI Express)要求使用 MSI,但是可以使用 INTx 仿真来处理传统中断。INTx 仿真用于实现兼容性,但是这并不被认为是好的做法。
总线会在总线中断级别设置设备中断的优先级。然后,总线中断级别将映射到处理器中断级别。映射到高于调度程序优先级别的 CPU 中断优先级的总线中断级别称为高级别中断。高级别中断处理程序仅限于调用以下 DDI 接口:
使用与高级别中断关联的中断优先级初始化的互斥锁上的 mutex_enter(9F) 和 mutex_exit(9F)
以下 DDI get 和 put 例程:ddi_get8(9F)、ddi_put8(9F)、ddi_get16(9F)、ddi_put16(9F)、ddi_get32(9F)、ddi_put32(9F)、ddi_get64(9F) 和 ddi_put64(9F)。
总线中断级别本身无法确定设备是否会发生高级别中断。特定的总线中断级别可以在一个平台映射到高级别中断,而在其他平台上则映射到普通中断。
不要求驱动程序来支持具有高级别中断的设备。但是,要求驱动程序检查中断级别。如果中断优先级高于或等于系统最高优先级,中断处理程序会在高级别中断环境下运行。在这种情况下,驱动程序可能无法连接,或者驱动程序可能会使用双级别方案来处理中断。有关更多信息,请参见处理高级别中断 。
系统仅有的有关设备中断的信息为总线中断的优先级别和中断请求编号。例如,SPARC 计算机中 S 总线上的 IPL 即是总线中断的优先级别;x86 计算机中 ISA 总线上的 IRQ 即是中断请求编号。
注册中断处理程序之后,系统会将其添加到每个 IPL 或 IRQ 的潜在中断处理程序的列表中。出现中断时,系统必须确定与给定的 IPL 或 IRQ 关联的所有设备中实际导致此中断的设备。系统会针对指定的 IPL 或 IRQ 调用所有中断处理程序,直到一个处理程序声明中断为止。
以下总线可以支持轮询中断:
S 总线
ISA
PCI
标准 (MSI) 和扩展 (MSI-X) 消息告知中断均作为带内消息实现。消息告知中断可作为使用软件指定的地址和值的写操作进行发送。
常规 PCI 规范包括可选的消息信号中断 (Message Signaled Interrupt, MSI) 支持。MSI 是作为发送的写操作实现的带内消息。MSI 的地址和数据由软件指定,并特定于主桥 (host bridge)。由于消息是带内消息,因此消息的接收可用于“推送”与中断关联的数据。根据定义,MSI 中断是独享的。指定给设备的每条 MSI 消息保证在系统中均为唯一消息。PCI 函数可以请求 1、2、4、8、16 或 32 条 MSI 消息。请注意,系统软件为函数分配的 MSI 消息数可以少于函数所请求的数量。可限制主桥 (host bridge) 中为设备分配的唯一 MSI 消息的数量。
MSI-X 中断是 MSI 中断的增强版本,与 MSI 中断有相同功能,具有以下关键区别:
每个设备最多支持 2048 个 MSI-X 中断向量。
每个中断向量的地址和数据项都是唯一的。
MSI-X 支持按函数屏蔽和按向量屏蔽。
利用 MSI-X 中断,未分配的设备中断向量可以使用先前添加或初始化的 MSI-X 中断向量共享相同的向量地址、向量数据、中断处理程序和处理程序参数。使用 ddi_intr_dup_handler(9F) 函数可相对于关联设备上未分配的中断向量为 Oracle Solaris OS 提供的资源设置别名。例如,如果为驱动程序分配了 2 个 MSI-X 中断,并且设备支持 32 个中断,则驱动程序可以使用 ddi_intr_dup_handler() 相对于设备上其他 30 个中断为其收到的 2 个中断设置别名。
ddi_intr_dup_handler() 函数可以复制使用 ddi_intr_add_handler(9F) 添加或使用 ddi_intr_enable(9F) 初始化的中断。
复制的中断最初处于禁用状态。可使用 ddi_intr_enable() 启用复制的中断。您不能删除原始 MSI-X 中断处理程序,除非删除了与此原始中断处理程序相关联的所有复制的中断处理程序。要删除复制的中断处理程序,请首先调用 ddi_intr_disable(9F),然后调用 ddi_intr_free(9F)。当删除与该原始中断处理程序相关联的所有复制的中断处理程序后,就可以使用 ddi_intr_remove_handler(9F) 删除该原始 MSI-X 中断处理程序。有关示例,请参见 ddi_intr_dup_handler (9F) 手册页。
Oracle Solaris DDI/DKI 支持软件中断(也称为软中断)。软中断通过软件而不是硬件设备启动。另外,还必须在系统中添加和删除这些中断的处理程序。软中断处理程序在中断上下文中运行,因此可用于执行许多属于中断处理程序的任务。
硬件中断处理程序必须快速执行其任务,因为它们可能必须在执行这些任务的同时暂停其他系统活动。对于高级别中断处理程序,更需要满足此要求,这些处理程序在高于系统调度程序的优先级别上运行。高级别中断处理程序将屏蔽所有较低优先级中断的操作,包括系统时钟的中断操作。因此,该中断处理程序必须避免涉及到可能导致其休眠的活动,如获取互斥锁。
如果处理程序休眠,则系统可能会挂起,因为时钟会被屏蔽,从而无法调度休眠线程。因此,高级别中断处理程序通常在高优先级别执行最少量的工作,并将其他任务委托给运行优先级别低于高级别中断处理程序的软件中断。由于软件中断处理程序运行的优先级别低于系统调度程序,因此软件中断处理程序可以执行高级别中断处理程序无法执行的操作。