Linuxドライバ_LDD3メモ_割り込み処理

來源:互聯網
上載者:User

割り込み処理        (※マルチコア対応関連)
割り込みハンドラは別のコードと同時に実行されます。
つまり、並行処理と、データ構造體とハードウェアの競爭の問題が必ず起こることになります。
多くの場合、モジュールは別のドライバと割り込み訊號線を共有することになります。
1)、割り込みハンドラのインストール                            
    ①、関連関數
        割り込みハンドラのインストールは、ドライバの初期化時、あるいはデバイスが始めてオープンされたときに行います。
        ・割り込み登録のIFとして、  (<linux/interrupt.h>)                                                        
            int request_irq( // 割り込み番號    // 割り込みハンドラ
                                unsigned int irq,
                                irqreturn_t (*handler)(int, void *, struct pt_regs *),    
                                // オプション
                                unsigned long flags,
                                // 割り込み所有者
                                const char *dev_name,
                                // 割り込み回線を共有する場合使われる。共有しない場合はNULL。
                                void *dev_id);
            void free_irq(unsigned int irq, void *dev_id);                
            int can_request_irq(unsigned int irq, unsigned long flags);

            ※1 「request_irq」を呼び出す正しい位置は、デバイスが初めてオープンされたときで、
                   ハードウェアに「割り込みを產生しなさい」という指示を出す「前」です。
            ※2 「free_irq」を呼び出す位置は、デバイスが最後にクローズされたときで、
                   ハードウェアに「以後CPUに割り込みをかけないように」と指示を出した「後」です。
            ※3 「can_request_irq」を行ってから「request_irq」を呼び出す間に、様子が変わってしまう可能性があります。
    ②、/procインタフェース        
        ・「/proc/interrupts」    
            割り込みを処理した回數が「/proc/interrupts」に示されます。
            ハードウェア割り込みがCPUに通知されるたびに1増える內部カウンタ用意されています。
            「/proc/interrupts」には、ハンドラがインストールされているものだけ記載します。
        ・「/proc/stat」    
            システムアクティビティに関する低レベルな統計を示します。起動以降に受信した割り込みの數も含まれています。
            ドライバがオープン/クローズのたびに割り込み訊號線を獲得/解放する場合には、「/proc/interrupts」よりも便利です。
    ③、IRQ番號の自動推定        
        ドライバの初期化時には、デバイスが使うIRQ訊號線の決定方法が問題となります。    
        ・カーネルが手伝う自動検出    
            unsigned long probe_irq_on(void);
            int probe_irq_off(unsigned long);

            ※1 「probe_irq_off」を呼び出す前に、「udelay」が必要、CPUの処理速度に応じて、
                   実際に割り込みが発生して処理されるのを、短時間待つ必要があります。
            ※2 自動検出には、かなり時間かかるかもしれません。
        ・自前の自動検出    
            自動検出の仕組みは、すべての未使用の割り込みを有効にした後、何かが起きるのをじっと待つというものです。
            関連関數は: request_irq と free_irq です。
            事前に「ありえる」IRQが知っている場合、それらをテストして、何が起こるかをじっと待って、自動検出を行います。
            事前に「ありえる」IRQが知らない場合は、IRQ0~IRQ NR_IRQS-1までを調べます。
    ④、高速ハンドラと低速ハンドラ        
        最新のカーネルは、高速割り込みと低速割り込みの違いはほとんどなくなっています。    
        ただ、高速割り込み(SA_INTERRUPT)が、カレントプロセッサ上で、
        他の全ての割り込みを無効にして実行されるという點あるため、強力な理由がない限り、使うべきではありません。    
2)、ハンドラを実裝する            
    ①、通常ルーチンとの違い        
        実は、割り込みハンドラといっても何も特別なことはありません、通常のCのコードです。    
        唯一の違いは、ハンドラーはプロセスのコンテキスト中で実行されていないため、    
        ・ユーザ空間とのデータ転送ができません    
        ・スリープができません    
        ・GFP_ATOMIC以外を使ったメモリ割り當てが行えません    
        ・セマフォのロックが行えません    
        ・scheduleを呼び出すことができません    
    ②、ハンドラ作成の注意點        
        ・実行にかかる時間を最小限にする    
        ・長時間にわたる計算を実行するなら、最もよい方法はタスクレットかタスク待ち列を用いてスケジュールし、
          より安全な時間に計算を行うようにすることです。
    ③、ハンドラの引數と戻り値                            
        /* 【引數】
           irq: 割り込み番號
           dev_id: クライアントデータの一種で、request_irqに渡されたものと同じポインタが、        
                     割り込みが発生したときにハンドラーに戻されます。                                
                     通常は、dev_idにデバイスデータ構造體(ユーザデータ)を指すポインタを渡します。    
           regs: 通常のデバイスドライバの処理で必要になることはありません。

          【戻り値】                                                                                
           デバイスに割り込みがあったことをハンドラが見つけた場合は、「IRQ_HANDLED」を、
           それ以外の場合は、「IRQ_NONE」を返します。                                    
           戻り値は、マクロ「IRQ_RETVAL(handled)」で產生できます。                        
        */
        irqreturn_t sample_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        {
            xxx xxx

            wake_up_interruptible(&sample_queue);     /* 処理プロセスを目覚めさせる */

            return XXX;
        }
    ④、割り込みの有効化と無効化
        要因例:
        ・システムのデッドロックを防ぐために、スピンロックを保持している間は、割り込みをブロックする必要がある。
        ・処理速度の問題で割り込みをブロックする必要がある。
         (例えば、受信側のIFが1バイト受信するたびに2つの割り込みを処理することになる場合。)
        ※ ドライバであっても、割り込みを無効化するのは比較的珍しい操作であることを指摘しておきます。

        ・単一の割り込みを無効にする
            void disable_irq(int irq);              // ①指定した割り込みを無効にする。
                                                       // ②実行中の割り込みハンドラがあればその完了を待つことになる。        
            void disable_irq_nosync(int irq);    // no sync        
            void enable_irq(int irq);            
            ※1 このAPIをドライバにおける相互排他の仕組みとして使ってはいけません。
            ※2 ほとんどのドライバではこの使用をお勧めしません。とりわけ、共有されている割り込み訊號線を無効にしてはいけません。
            ※3 全てのCPUが対象。                                                    
        ・全ての割り込みを無効にする                                                        
            void local_irq_save(unsigned long flags);    // ①割り込み狀態をflagsに儲存。
                                                                 // ②割り込みの配付を無効。
            void local_irq_disable(void);                   // 割り込みの配付を無効にするのみ。

            void local_irq_restore(unsigned long flags);
            void local_irq_enable(void);
            ※1 カレントCPUにおける割り込みの配布を無効にします。
3)、前半部と後半部
    割り込み処理における最大の問題は、ハンドラー內で時間のかかる処理をどう実行するかということです。        
    Linuxはこの問題を、割り込みハンドラーを2つの部分に分割して「半分」にすることで解決しています。            
    ・「前半部(Top half)」は実際に割り込みに応答するルーチンであり、これをrequest_irqを使って登録します。        ※ 割り込みが無効
    ・「後半部(Bottom half)」は前半部によってスケジュールされるもので、後のもっと安全な時間に実行されます        ※ 割り込みが有効

    後半部の実裝に使用するメカニズムが2つあります。
    ①タスクレット                                    
        タスクレットは                                
        ・大変速く処理されますが、コードはアトミックでないといけない。
        ・割り込みコンテキスト中で実行される特殊な関數である。        
        ・何回も実行するようにスケジュールできますが、タスクレットのスケジュールは累積されない。
          従って、タスクレット自身が並行して実行されることがない。

        下記原因でタスクレット間にロック機能を求められます。
        ・SMPシステムでは、あるタスクレットと並行して別のタスクレットが実行されることがあります。
        ・タスクレットの実行中に、別の割り込みが発生することがありえます。
          このため、タスクレットと割り込みハンドラーの間のロック機能がやはり必要になります。
    ②作業待ち列    
        作業待ち列は
        ・タスクレットよりも長時間待つことになりますが、スリープできる方法です。
        ・將來のある時點に、特殊なワーカプロセスのコンテキストの中で実行されます。
        ・ユーザ空間とのデータのやり取りをするのにDMA処理が必要です。
        ・ドライバに遅延が要求される場合、或いは作業関數內で長時間スリープする場合、作業待ち列が適當です。
4)、割り込みの共有        
    例: PCIデバイスは割り込み共有をサポートする。少ない例として、ISAデバイスは共有しない。    
    ①、共有ハンドラーのインストール    
        割り込みを共有しないものと同様に「request_irq」で行うのですが、相違點は2つあります。
        ・引數flagsの中で「SA_SHIRQ」ビットを指定する
        ・引數dev_idは、ユニークでないといけない。 (カーネルはハンドラーの識別にdev_idを使います)
        ・共有ハンドラーのために利用できる自動検出機能はないです。
          幸い、割り込みを共有できるハードウェアは、どの割り込み訊號線を使っているかをCPUに通知できます。
        ・「enable_irq」、「disable_irq」は使えないです。
    ②、ハンドラの実行    
        カーネルが割り込み要求を受け取ると、登録された全てのハンドラーを起動します。
        このため、共有ハンドラは自分が処理すべき割り込みと、他のデバイスが產生した割り込みを區別する必要があります。
        ・「dev_id」より區別
        ・割り込み保留ビットより區別
    ③、/procインタフェースと共有割り込み    
        共有ハンドラーは「/proc/interrupts」にの同じ割り込み番號に表示されます。「/proc/stat」には表示しません。

5)、割り込み駆動I/O        
    管理しているハードウェアとの間のデータ転送が何らかの理由で遅延されそうなときは、必ずバッファリングを実裝しましょう。    
    ・write & readシステムコールからデータの送受信処理を切り離すのを助ける。    
    ・システム全體の処理能力を高めます。    

    時としてデバイスからの割り込みを失うことがあります。    
    このため、データをデバイスに出力するたびにカーネルタイムを設定します。タイマが満了したら、割り込みを失ったと見なすのです。    

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.