ドライバの割り込みハンドラを登録する場合、ドライバは通常、その 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);
}