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カーネルメモ