Linuxのポーリング処理のコードを読んでみよう 〜割り込み編〜

Linuxのポーリング処理のコードを読んでみよう 〜初期化編〜 - かーねる・う゛いえむにっきの続き。

まず、割り込みがかかるとe1000_intrが呼ばれる。

 3370 static irqreturn_t e1000_intr(int irq, void *data)
 3371 {
 3372         struct net_device *netdev = data;
 3373         struct e1000_adapter *adapter = netdev_priv(netdev);
 3374         struct e1000_hw *hw = &adapter->hw;
 3375         u32 icr = er32(ICR);
 3376 
 3377         if (unlikely((!icr) || test_bit(__E1000_DOWN, &adapter->flags)))
 3378                 return IRQ_NONE;  /* Not our interrupt */
 3379 
 3380         if (unlikely(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC))) {
 3381                 hw->get_link_status = 1;
 3382                 /* guard against interrupt when we're going down */
 3383                 if (!test_bit(__E1000_DOWN, &adapter->flags))
 3384                         mod_timer(&adapter->watchdog_timer, jiffies + 1);
 3385         }
 3386 
 3387         /* disable interrupts, without the synchronize_irq bit */
 3388         ew32(IMC, ~0);
 3389         E1000_WRITE_FLUSH();
 3390 
 3391         if (likely(napi_schedule_prep(&adapter->napi))) {
 3392                 adapter->total_tx_bytes = 0;
 3393                 adapter->total_tx_packets = 0;
 3394                 adapter->total_rx_bytes = 0;
 3395                 adapter->total_rx_packets = 0;
 3396                 __napi_schedule(&adapter->napi);
 3397         } else {
 3398                 /* this really should not happen! if it does it is basically a
 3399                  * bug, but not a hard error, so enable ints and continue */
 3400                 if (!test_bit(__E1000_DOWN, &adapter->flags))
 3401                         e1000_irq_enable(adapter);
 3402         }
 3403 
 3404         return IRQ_HANDLED;
 3405 }

3388行目で割り込みを止める。
3391行目のnapi_schedule_prep()でnapiが動作可能かチェックし、3396行目の__napi_schedule()でポーリングをスケジュールしている。
e1000に対する割り込みは無効なまま、割り込みコンテキストを抜ける(普通の割り込みハンドラなら有り得ない事で、ここがミソ)。

void __napi_schedule(struct napi_struct *n)
{
	unsigned long flags;

	local_irq_save(flags);
	____napi_schedule(&__get_cpu_var(softnet_data), n);
	local_irq_restore(flags);
}
EXPORT_SYMBOL(__napi_schedule);

__napi_schedule()はpercpuなsoftnet_dataとnapiを___napi_schedule()に渡す。

 2254 /* Called with irq disabled */
 2255 static inline void ____napi_schedule(struct softnet_data *sd,
 2256                                      struct napi_struct *napi)
 2257 {
 2258         list_add_tail(&napi->poll_list, &sd->poll_list);
 2259         __raise_softirq_irqoff(NET_RX_SOFTIRQ);
 2260 }

___napi_schedule()では、ポーリング対象のリストにnapiを追加し、__raise_softirq_irqoff(NET_RX_SOFTIRQ)を呼んでソフトウェア割り込みをスケジュールしている。
__get_cpu_var()と__raise_softirq_irqoff()は現在のCPUをターゲットにしているので、結果として必ずポーリングは割り込みがかかったCPUで行われるはず。

※ソフトウェア割り込みの資料:ソフト割り込み - Linuxカーネルメモ