要注册驱动程序的中断处理程序,驱动程序通常会在其 attach(9E) 入口点执行以下步骤。
使用 ddi_intr_get_supported_types(9F) 确定支持的中断类型。
使用 ddi_intr_get_nintrs(9F) 确定支持的 MSI 中断类型的数量。
使用 ddi_intr_alloc(9F) 为 MSI 中断分配内存。
对于分配的每个中断类型,执行以下步骤:
使用 ddi_intr_get_pri(9F) 获取中断的优先级。
如果需要为中断设置新的优先级,请使用 ddi_intr_set_pri(9F)。
使用 mutex_init(9F) 将锁初始化。
使用 ddi_intr_add_handler(9F) 注册中断的处理程序。
使用以下函数之一启用所有中断:
使用 ddi_intr_block_enable(9F) 启用某个块中的所有中断。
在循环中使用 ddi_intr_enable(9F) 单独启用每个中断。
以下示例说明如何为名为 mydev 的设备注册 MSI 中断。
/* Get supported interrupt types */
if (ddi_intr_get_supported_types(devinfo, &intr_types) != DDI_SUCCESS) {
cmn_err(CE_WARN, "ddi_intr_get_supported_types failed");
goto attach_fail;
}
if (intr_types & DDI_INTR_TYPE_MSI)
mydev_add_msi_intrs(mydevp);
/* Check count, available and actual interrupts */
static int
mydev_add_msi_intrs(mydev_t *mydevp)
{
dev_info_t *devinfo = mydevp->devinfo;
int count, avail, actual;
int x, y, rc, inum = 0;
/* Get number of interrupts */
rc = ddi_intr_get_nintrs(devinfo, DDI_INTR_TYPE_MSI, &count);
if ((rc != DDI_SUCCESS) || (count == 0)) {
cmn_err(CE_WARN, "ddi_intr_get_nintrs() failure, rc: %d, "
"count: %d", rc, count);
return (DDI_FAILURE);
}
/* Get number of available interrupts */
rc = ddi_intr_get_navail(devinfo, DDI_INTR_TYPE_MSI, &avail);
if ((rc != DDI_SUCCESS) || (avail == 0)) {
cmn_err(CE_WARN, "ddi_intr_get_navail() failure, "
"rc: %d, avail: %d\n", rc, avail);
return (DDI_FAILURE);
}
if (avail < count) {
cmn_err(CE_NOTE, "nitrs() returned %d, navail returned %d",
count, avail);
}
/* Allocate memory for MSI interrupts */
mydevp->intr_size = count * sizeof (ddi_intr_handle_t);
mydevp->htable = kmem_alloc(mydevp->intr_size, KM_SLEEP);
rc = ddi_intr_alloc(devinfo, mydevp->htable, DDI_INTR_TYPE_MSI, inum,
count, &actual, DDI_INTR_ALLOC_NORMAL);
if ((rc != DDI_SUCCESS) || (actual == 0)) {
cmn_err(CE_WARN, "ddi_intr_alloc() failed: %d", rc);
kmem_free(mydevp->htable, mydevp->intr_size);
return (DDI_FAILURE);
}
if (actual < count) {
cmn_err(CE_NOTE, "Requested: %d, Received: %d", count, actual);
}
mydevp->intr_cnt = actual;
/*
* Get priority for first msi, assume remaining are all the same
*/
if (ddi_intr_get_pri(mydevp->htable[0], &mydev->intr_pri) !=
DDI_SUCCESS) {
cmn_err(CE_WARN, "ddi_intr_get_pri() failed");
/* Free already allocated intr */
for (y = 0; y < actual; y++) {
(void) ddi_intr_free(mydevp->htable[y]);
}
kmem_free(mydevp->htable, mydevp->intr_size);
return (DDI_FAILURE);
}
/* Call ddi_intr_add_handler() */
for (x = 0; x < actual; x++) {
if (ddi_intr_add_handler(mydevp->htable[x], mydev_intr,
(caddr_t)mydevp, NULL) != DDI_SUCCESS) {
cmn_err(CE_WARN, "ddi_intr_add_handler() failed");
/* Free already allocated intr */
for (y = 0; y < actual; y++) {
(void) ddi_intr_free(mydevp->htable[y]);
}
kmem_free(mydevp->htable, mydevp->intr_size);
return (DDI_FAILURE);
}
}
(void) ddi_intr_get_cap(mydevp->htable[0], &mydevp->intr_cap);
if (mydev->m_intr_cap & DDI_INTR_FLAG_BLOCK) {
/* Call ddi_intr_block_enable() for MSI */
(void) ddi_intr_block_enable(mydev->m_htable, mydev->m_intr_cnt);
} else {
/* Call ddi_intr_enable() for MSI non block enable */
for (x = 0; x < mydev->m_intr_cnt; x++) {
(void) ddi_intr_enable(mydev->m_htable[x]);
}
}
return (DDI_SUCCESS);
}
示例 8-8 删除 MSI 中断 以下示例说明如何删除 MSI 中断。
static void
mydev_rem_intrs(mydev_t *mydev)
{
int x;
/* Disable all interrupts */
if (mydev->m_intr_cap & DDI_INTR_FLAG_BLOCK) {
/* Call ddi_intr_block_disable() */
(void) ddi_intr_block_disable(mydev->m_htable, mydev->m_intr_cnt);
} else {
for (x = 0; x < mydev->m_intr_cnt; x++) {
(void) ddi_intr_disable(mydev->m_htable[x]);
}
}
/* Call ddi_intr_remove_handler() */
for (x = 0; x < mydev->m_intr_cnt; x++) {
(void) ddi_intr_remove_handler(mydev->m_htable[x]);
(void) ddi_intr_free(mydev->m_htable[x]);
}
kmem_free(mydev->m_htable, mydev->m_intr_size);
}