Go to main content
Oracle® Solaris 11.3 デバイスドライバの記述

印刷ビューの終了

更新: 2016 年 11 月
 
 

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

高レベルの割り込みとは、スケジューラおよびそれより上のレベルで行われる割り込みのことです。このレベルでは、スケジューラは実行できません。したがって、スケジューラであらかじめ高レベルの割り込みハンドラを無効にすることはできません。スケジューラが原因となって、高レベルの割り込みをブロックできません。高レベルの割り込みで可能なのは、相互排他ロックを使ってロックすることのみです。

ドライバは、デバイスが高レベルの割り込みを使用しているかどうかを判定する必要があります。このテストは、割り込みの登録時にドライバの attach(9E) エントリポイントで行います。高レベルの割り込み処理の例を参照してください。

  • ddi_intr_get_pri(9F) から返される割り込み優先順位が ddi_intr_get_hilevel_pri(9F) から返される優先順位以上である場合、ドライバは接続に失敗することがあります。または、ドライバは高レベルの割り込みハンドラを実装する可能性があります。高レベルの割り込みハンドラは、優先順位の低いソフトウェア割り込みを使用してデバイスを扱います。許可する並行処理の程度を上げるには、別個の mutex を使ってデータを高レベルのハンドラから保護します。

  • ddi_intr_get_pri(9F) から返される割り込み優先順位が ddi_intr_get_hilevel_pri(9F) から返される優先順位より低い場合、attach (9E) エントリポイントは通常の割り込み登録になります。この場合、ソフト割り込みは必要ありません。

高レベルの mutex

高レベルの割り込みを表す割り込み優先順位で初期化された mutex は、高レベルの mutex と呼ばれます。ドライバは、高レベルの mutex を保持している間、高レベルの割り込みハンドラと同じ制限に従います。

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

次の例では、高レベルの mutex (xsp->high_mu) は、高レベルの割り込みハンドラとソフト割り込みハンドラの間で共有されるデータを保護するためにのみ使用されます。保護されるデータには、高レベルの割り込みハンドラと低レベルのハンドラの両方で使用されるキューと、低レベルのハンドラが実行されていることを示すフラグが含まれています。別個の低レベルの mutex (xsp->low_mu) は、ドライバの残りの部分をソフト割り込みハンドラから保護します。

使用例 26  attach() を使用した高レベルの割り込みの処理
static int
mydevattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
    struct mydevstate *xsp;
    /* ... */

    ret = ddi_intr_get_supported_types(dip, &type);
    if ((ret != DDI_SUCCESS) || (!(type & DDI_INTR_TYPE_FIXED))) {
        cmn_err(CE_WARN, "ddi_intr_get_supported_types() failed");
        return (DDI_FAILURE);
    }

    ret = ddi_intr_get_nintrs(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 found");
            return (DDI_FAILURE);
    }

    xsp->xs_htable = kmem_zalloc(count * sizeof (ddi_intr_handle_t),
        KM_SLEEP);

    ret = ddi_intr_alloc(dip, xsp->xs_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(xsp->xs_htable, sizeof (ddi_intr_handle_t));
        return (DDI_FAILURE);
    }

    ret = ddi_intr_get_pri(xsp->xs_htable[0], &intr_pri);
    if (ret != DDI_SUCCESS) {
        cmn_err(CE_WARN, "ddi_intr_get_pri failed 0x%x", ret");
        (void) ddi_intr_free(xsp->xs_htable[0]);
        kmem_free(xsp->xs_htable, sizeof (ddi_intr_handle_t));
        return (DDI_FAILURE);
    }

    if (intr_pri >= ddi_intr_get_hilevel_pri()) {

        mutex_init(&xsp->high_mu, NULL, MUTEX_DRIVER,
            DDI_INTR_PRI(intr_pri));

        ret = ddi_intr_add_handler(xsp->xs_htable[0],
            mydevhigh_intr, (caddr_t)xsp, NULL);

        if (ret != DDI_SUCCESS) {
            cmn_err(CE_WARN, "ddi_intr_add_handler failed 0x%x", ret");
            mutex_destroy(&xsp>xs_int_mutex);
                (void) ddi_intr_free(xsp->xs_htable[0]);
                kmem_free(xsp->xs_htable, sizeof (ddi_intr_handle_t));
            return (DDI_FAILURE);
        }

        /* add soft interrupt */
        if (ddi_intr_add_softint(xsp->xs_dip, &xsp->xs_softint_hdl,
            DDI_INTR_SOFTPRI_MAX, xs_soft_intr, (caddr_t)xsp) !=
            DDI_SUCCESS) {
            cmn_err(CE_WARN, "add soft interrupt failed");
            mutex_destroy(&xsp->high_mu);
            (void) ddi_intr_remove_handler(xsp->xs_htable[0]);
            (void) ddi_intr_free(xsp->xs_htable[0]);
            kmem_free(xsp->xs_htable, sizeof (ddi_intr_handle_t));
            return (DDI_FAILURE);
        }

        xsp->low_soft_pri = DDI_INTR_SOFTPRI_MAX;

        mutex_init(&xsp->low_mu, NULL, MUTEX_DRIVER,
            DDI_INTR_PRI(xsp->low_soft_pri));

    } else {
    /*
     * regular interrupt registration continues from here
     * do not use a soft interrupt
     */
    }

    return (DDI_SUCCESS);
}

高レベルの割り込みルーチンは、デバイスを保守し、データをキューに入れます。低レベルのルーチンが実行されていない場合、高レベルのルーチンはソフトウェア割り込みをトリガーします。次に例を示します。

使用例 27  高レベルの割り込みルーチン
static uint_t
mydevhigh_intr(caddr_t arg1, caddr_t arg2)
{
    struct mydevstate    *xsp = (struct mydevstate *)arg1;
    uint8_t    status;
    volatile  uint8_t  temp;
    int    need_softint;

    mutex_enter(&xsp->high_mu);
    /* 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 */
    }

    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);

    /* read data from device, queue data for low-level interrupt handler */
    if (xsp->softint_running)
        need_softint = 0;
    else {
        xsp->softint_count++;
        need_softint = 1;
    }
    mutex_exit(&xsp->high_mu);

    /* read-only access to xsp->id, no mutex needed */
    if (need_softint) {
        ret = ddi_intr_trigger_softint(xsp->xs_softint_hdl, NULL);
        if (ret == DDI_EPENDING) {
            cmn_err(CE_WARN, "ddi_intr_trigger_softint() soft interrupt "
                "already pending for this handler");
        } else if (ret != DDI_SUCCESS) {
            cmn_err(CE_WARN, "ddi_intr_trigger_softint() failed");
        }           
    }

    return (DDI_INTR_CLAIMED);
}

低レベルの割り込みルーチンは、ソフトウェア割り込みをトリガーする高レベルの割り込みルーチンによって開始されます。低レベルの割り込みルーチンは、処理するものがなくなるまで実行されます。次に例を示します。

使用例 28  低レベルのソフト割り込みルーチン
static uint_t
mydev_soft_intr(caddr_t arg1, caddr_t arg2)
{
    struct mydevstate *mydevp = (struct mydevstate *)arg1;
    /* ... */
    mutex_enter(&mydevp->low_mu);
    mutex_enter(&mydevp->high_mu);
    if (mydevp->softint_count > 1) {
        mydevp->softint_count--;
        mutex_exit(&mydevp->high_mu);
        mutex_exit(&mydevp->low_mu);
        return (DDI_INTR_CLAIMED);
    }

    if ( /* queue empty */ ) {
        mutex_exit(&mydevp->high_mu);
        mutex_exit(&mydevp->low_mu);
        return (DDI_INTR_UNCLAIMED);
    }

    mydevp->softint_running = 1;
    while (EMBEDDED COMMENT:data on queue) {
        ASSERT(mutex_owned(&mydevp->high_mu);
        /* Dequeue data from high-level queue. */
        mutex_exit(&mydevp->high_mu);
        /* normal interrupt processing */
        mutex_enter(&mydevp->high_mu);
    }

    mydevp->softint_running = 0;
    mydevp->softint_count = 0;
    mutex_exit(&mydevp->high_mu);
    mutex_exit(&mydevp->low_mu);
    return (DDI_INTR_CLAIMED);
}