JavaScript is required to for searching.
ナビゲーションリンクをスキップ
印刷ビューの終了
デバイスドライバの記述     Oracle Solaris 10 8/11 Information Library (日本語)
search filter icon
search icon

ドキュメントの情報

はじめに

パート I Solaris プラットフォーム用デバイスドライバの設計

1.  Solaris デバイスドライバの概要

2.  Solaris カーネルとデバイスツリー

3.  マルチスレッド

4.  プロパティー

5.  イベントの管理とタスクのキュー

6.  ドライバの自動設定

7.  デバイスアクセス: プログラム式入出力

8.  割り込みハンドラ

割り込みハンドラの概要

デバイス割り込み

高レベルの割り込み

レガシー割り込み

標準メッセージシグナル割り込みと拡張メッセージシグナル割り込み

MSI 割り込み

MSI-X 割り込み

ソフトウェア割り込み

DDI 割り込み関数

割り込み許可フラグ関数

割り込み初期化関数と割り込み破棄関数

優先順位管理関数

ソフト割り込み関数

割り込み関数の例

割り込みの登録

レガシー割り込みの登録

MSI 割り込みの登録

割り込みリソース管理

割り込みリソース管理機能

コールバックのインタフェース

コールバックハンドラ関数の登録

コールバックハンドラ関数の登録解除

コールバックハンドラ関数

割り込み要求のインタフェース

割り込みの割り当て

要求する割り込みベクターの数の変更

割り込みの使用率と柔軟性

割り込みリソース管理の実装例

割り込みハンドラの機能

高レベルの割り込みの処理

高レベルの mutex

高レベルの割り込み処理の例

9.  ダイレクトメモリーアクセス (DMA)

10.  デバイスメモリーおよびカーネルメモリーのマッピング

11.  デバイスコンテキスト管理

12.  電源管理

13.  Solaris ドライバの強化

14.  階層化ドライバインタフェース (LDI)

パート II 特定の種類のデバイスドライバの設計

15.  文字デバイスのドライバ

16.  ブロックデバイスのドライバ

17.  SCSI ターゲットドライバ

18.  SCSI ホストバスアダプタドライバ

19.  ネットワークデバイスのドライバ

20.  USB ドライバ

パート III デバイスドライバの構築

21.  ドライバのコンパイル、ロード、パッケージ化、およびテスト

22.  デバイスドライバのデバッグ、テスト、およびチューニング

23.  推奨されるコーティング方法

パート IV 付録

A.  ハードウェアの概要

B.  Solaris DDI/DKI サービスの概要

C.  64 ビットデバイスドライバの準備

D.  コンソールフレームバッファードライバ

索引

割り込みの登録

デバイスドライバが割り込みを受信および保守するには、ドライバが ddi_intr_add_handler(9F) を呼び出して割り込みハンドラをシステムに登録する必要があります。割り込みハンドラを登録すると、システムは割り込みハンドラを割り込み仕様に関連付けることができます。割り込みハンドラは、デバイスがその割り込みを担当している可能性のあるときに呼び出されます。ハンドラは、割り込みを処理するかどうかの判定、および処理する場合にはその割り込みの取り込みを担当します。


ヒント - サポートされている SPARC または x86 システムでデバイスの登録済み割り込み情報を取得するときは、mdb または kmdb デバッガの ::interrupts コマンドを使用します。


レガシー割り込みの登録

ドライバの割り込みハンドラを登録する場合、ドライバは通常、その attach(9E) エントリポイントで次の手順を実行します。

  1. ddi_intr_get_supported_types(9F) を使用して、サポートされている割り込みのタイプを判定します。

  2. ddi_intr_get_nintrs(9F) を使用して、サポートされている割り込みタイプの数を判定します。

  3. kmem_zalloc(9F) を使用して、DDI 割り込みハンドルにメモリーを割り当てます。

  4. 割り当てる割り込みタイプごとに、次の手順を実行します。

    1. ddi_intr_get_pri(9F) を使用して、割り込みの優先順位を取得します。

    2. 割り込みに新しい優先順位を設定する必要がある場合は、ddi_intr_set_pri(9F) を使用します。

    3. mutex_init(9F) を使用して、ロックを初期化します。

    4. ddi_intr_add_handler(9F) を使用して、割り込みのハンドラを登録します。

    5. ddi_intr_enable(9F) を使用して、割り込みを有効にします。

  5. 次の手順を実行して、各割り込みを解放します。

    1. ddi_intr_disable(9F) を使用して、各割り込みを無効にします。

    2. ddi_intr_remove_handler(9F) を使用して、割り込みハンドラを削除します。

    3. mutex_destroy(9F) を使用して、ロックを削除します。

    4. ddi_intr_free(9F) および kmem_free(9F) を使用して DDI 割り込みハンドルに割り当てられたメモリーを解放し、割り込みを解放します。

例 8-5 レガシー割り込みの登録

次の例は、mydev というデバイスの割り込みハンドラをインストールする方法を示しています。この例では、mydev が 1 つの割り込みだけをサポートしていることを前提としています。

/* Determine which types of interrupts supported */
ret = ddi_intr_get_supported_types(mydevp->mydev_dip, &type);

if ((ret != DDI_SUCCESS) || (!(type & DDI_INTR_TYPE_FIXED))) {
    cmn_err(CE_WARN, "Fixed type interrupt is not supported");
    return (DDI_FAILURE);
}

/* Determine number of supported interrupts */
ret = ddi_intr_get_nintrs(mydevp->mydev_dip, DDI_INTR_TYPE_FIXED, 
    &count);

/*
 * Fixed interrupts can only have one interrupt. Check to make
 * sure that number of supported interrupts and number of
 * available interrupts are both equal to 1.
 */
if ((ret != DDI_SUCCESS) || (count != 1)) {
    cmn_err(CE_WARN, "No fixed interrupts");
    return (DDI_FAILURE);
}

/* Allocate memory for DDI interrupt handles */
mydevp->mydev_htable = kmem_zalloc(sizeof (ddi_intr_handle_t), 
    KM_SLEEP);
ret = ddi_intr_alloc(mydevp->mydev_dip, mydevp->mydev_htable,
    DDI_INTR_TYPE_FIXED, 0, count, &actual, 0);

if ((ret != DDI_SUCCESS) || (actual != 1)) {
    cmn_err(CE_WARN, "ddi_intr_alloc() failed 0x%x", ret);
    kmem_free(mydevp->mydev_htable, sizeof (ddi_intr_handle_t));

    return (DDI_FAILURE);
}

/* Sanity check that count and available are the same. */
ASSERT(count == actual);

/* Get the priority of the interrupt */
if (ddi_intr_get_pri(mydevp->mydev_htable[0], &mydevp->mydev_intr_pri)) {
    cmn_err(CE_WARN, "ddi_intr_alloc() failed 0x%x", ret);

    (void) ddi_intr_free(mydevp->mydev_htable[0]);
    kmem_free(mydevp->mydev_htable, sizeof (ddi_intr_handle_t));

    return (DDI_FAILURE);
}

cmn_err(CE_NOTE, "Supported Interrupt pri = 0x%x", mydevp->mydev_intr_pri);

/* Test for high level mutex */
if (mydevp->mydev_intr_pri >= ddi_intr_get_hilevel_pri()) {
    cmn_err(CE_WARN, "Hi level interrupt not supported");

    (void) ddi_intr_free(mydevp->mydev_htable[0]);
    kmem_free(mydevp->mydev_htable, sizeof (ddi_intr_handle_t));

    return (DDI_FAILURE);
}

/* Initialize the mutex */
mutex_init(&mydevp->mydev_int_mutex, NULL, MUTEX_DRIVER,
    DDI_INTR_PRI(mydevp->mydev_intr_pri));

/* Register the interrupt handler */
if (ddi_intr_add_handler(mydevp->mydev_htable[0], mydev_intr, 
   (caddr_t)mydevp, NULL) !=DDI_SUCCESS) {
    cmn_err(CE_WARN, "ddi_intr_add_handler() failed");

    mutex_destroy(&mydevp->mydev_int_mutex);
    (void) ddi_intr_free(mydevp->mydev_htable[0]);
    kmem_free(mydevp->mydev_htable, sizeof (ddi_intr_handle_t));

    return (DDI_FAILURE);
}

/* Enable the interrupt */
if (ddi_intr_enable(mydevp->mydev_htable[0]) != DDI_SUCCESS) {
    cmn_err(CE_WARN, "ddi_intr_enable() failed");

    (void) ddi_intr_remove_handler(mydevp->mydev_htable[0]);
    mutex_destroy(&mydevp->mydev_int_mutex);
    (void) ddi_intr_free(mydevp->mydev_htable[0]);
    kmem_free(mydevp->mydev_htable, sizeof (ddi_intr_handle_t));

    return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}

例 8-6 レガシー割り込みの削除

次の例は、レガシー割り込みを削除する方法を示しています。

/* disable interrupt */
(void) ddi_intr_disable(mydevp->mydev_htable[0]);

/* Remove interrupt handler */
(void) ddi_intr_remove_handler(mydevp->mydev_htable[0]);

/* free interrupt handle */
(void) ddi_intr_free(mydevp->mydev_htable[0]);

/* free memory */
kmem_free(mydevp->mydev_htable, sizeof (ddi_intr_handle_t));

MSI 割り込みの登録

ドライバの割り込みハンドラを登録する場合、ドライバは通常、その attach(9E) エントリポイントで次の手順を実行します。

  1. ddi_intr_get_supported_types(9F) を使用して、サポートされている割り込みのタイプを判定します。

  2. ddi_intr_get_nintrs(9F) を使用して、サポートされている MSI 割り込みタイプの数を判定します。

  3. ddi_intr_alloc(9F) を使用して、MSI 割り込みにメモリーを割り当てます。

  4. 割り当てる割り込みタイプごとに、次の手順を実行します。

    1. ddi_intr_get_pri(9F) を使用して、割り込みの優先順位を取得します。

    2. 割り込みに新しい優先順位を設定する必要がある場合は、ddi_intr_set_pri(9F) を使用します。

    3. mutex_init(9F) を使用して、ロックを初期化します。

    4. ddi_intr_add_handler(9F) を使用して、割り込みのハンドラを登録します。

  5. 次の関数のいずれかを使用して、すべての割り込みを有効にします。

    • ブロック内のすべての割り込みを有効にするときは、ddi_intr_block_enable(9F) を使用します。

    • 各割り込みを個別に有効にするときは、ループで ddi_intr_enable(9F) を使用します。

例 8-7 一連の MSI 割り込みの登録

次の例は、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);
}