| ナビゲーションリンクをスキップ | |
| 印刷ビューの終了 | |
|
デバイスドライバの記述 Oracle Solaris 11.1 Information Library (日本語) |
パート I Oracle Solaris プラットフォーム用デバイスドライバの設計
2. Oracle Solaris カーネルとデバイスツリー
標準メッセージシグナル割り込みと拡張メッセージシグナル割り込み
22. ドライバのコンパイル、ロード、パッケージ化、およびテスト
23. デバイスドライバのデバッグ、テスト、およびチューニング
高レベルの割り込みとは、スケジューラおよびそれより上のレベルで行われる割り込みのことです。このレベルでは、スケジューラは実行できません。したがって、スケジューラであらかじめ高レベルの割り込みハンドラを無効にすることはできません。スケジューラが原因となって、高レベルの割り込みをブロックできません。高レベルの割り込みで可能なのは、相互排他ロックを使ってロックすることのみです。
ドライバは、デバイスが高レベルの割り込みを使用しているかどうかを判定する必要があります。このテストは、割り込みの登録時にドライバの 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 (xsp->high_mu) は、高レベルの割り込みハンドラとソフト割り込みハンドラの間で共有されるデータを保護するためにのみ使用されます。保護されるデータには、高レベルの割り込みハンドラと低レベルのハンドラの両方で使用されるキューと、低レベルのハンドラが実行されていることを示すフラグが含まれています。別個の低レベルの mutex (xsp->low_mu) は、ドライバの残りの部分をソフト割り込みハンドラから保護します。
例 8-10 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);
}
高レベルの割り込みルーチンは、デバイスを保守し、データをキューに入れます。低レベルのルーチンが実行されていない場合、高レベルのルーチンはソフトウェア割り込みをトリガーします。次に例を示します。
例 8-11 高レベルの割り込みルーチン
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);
}
低レベルの割り込みルーチンは、ソフトウェア割り込みをトリガーする高レベルの割り込みルーチンによって開始されます。低レベルの割り込みルーチンは、処理するものがなくなるまで実行されます。次に例を示します。
例 8-12 低レベルのソフト割り込みルーチン
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);
}