Skip to content
oraccha edited this page Jan 14, 2013 · 1 revision

NICLinux/デバイスドライバ/NICから分家.


対象は Digital 21140.通称 Tulip.

コンフィグレーションレジスタ: PCIデバイスで共通の 256 バイトの空間.先頭の 64 バイト(ベンダID,デバイスID,クラスなどのレジスタ部分)は共通化されている.

  • /proc/pci で調べることができる. {{{ Bus 0, device 9, function 0: Ethernet controller: Digital Equipment Corporation DECchip 21140 [FasterNet] PCI (rev 32). IRQ 11. Master Capable. Latency=32. Min Gnt=20.Max Lat=40. I/O at 0x6000 [0x607f]. Non-prefetchable 32 bit memory at 0xe4000000 [0xe4000007f] }}}
  • コンフィグレーションレジスタの読書きは pci_[read|write]config[byte|word|dword] で行なう.

CSR(Command and Status Register): 12個

  • I/O 空間またはメモリ空間にマップして利用する.arbitration はデバイス側でやってくれるので,通常はドライバ側で特にリマップしたりする必要はない.
  • /proc/pci の出力では 0x6000-7f が I/O 空間,0xe4000000-7f がメモリ空間を意味しており,この範囲に CSR がマップされる.I/O 空間かメモリ空間かはアドレスの最下位ビットで区別する.

ディスクリプタ: 送受信に使う.OS側でメインメモリ上に用意してやる.

  • 受信用は CSR3,送信用は CSR4 に先頭ディスクリプタのアドレスを設定する.
  • ディスクリプタは配列(ring mode),またはリンクリスト(chain mode)として連結することができる(リングバッファになる).ドライバでは tx_ring,rx_ring と呼ばれている.
    • 例えば,tx_ring ディスクリプタは次のように定義されている.このドライバでは ring mode で動作しているが,chain mode でしか動作しないチップもあるため buffer2 をリンクリストの次エントリを指すために初期化されている(バッファサイズを 0 に設定しておけばそのバッファは無視される). {{{ struct tulip_tx_desc { s32 status; s32 length; u32 buffer1; u32 buffer2; /* We use only buffer 1. */ } }}}
    • ディスクリプタを送信する場合は,status の ownership bit をセットして,CSR1 に何か書き込む.これがトリガになって送信要求される.送信が完了したら割込みが起こる.
    • 送信完了割込みは IC(Interrupt on Completion) ビットがセットされたディスクリプタの送信が完了した場合に発生する.
  • ディスクリプタに格納されているバッファ(buffer1)領域のマッピングには pci_map_single を使っている.HIGHMEM 領域でのバウンスバッファを避けるために pci_map_page を使えとあるが...
    • 具体的には, {{{ mapping = pci_map_single(tp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); tp->tx_buffers[entry].mapping = mapping; /* skfree に使用する */ tp->tx_ring[entry].buffer1 = cpu_to_le32(mapping); }}}
    • pci_map_single は virt_to_bus(x86の場合 virt_to_phys と同じ.つまり __pa と同じで,アドレスから PAGE_OFFSET(3GB)引いた値) を使うがこれは HIGHMEM に対応していない.
  • scatter/gather 版インタフェースである pci_map_sg ってのもある.

PCI デバイスドライバは struct pci_driver を持つ. {{{ static struct pci_driver tulip_driver = { name: DRV_NAME, id_table: tulip_pci_tbl, probe: tulip_init_one, remove: __devexit_p(tulip_remove_one), #ifdef CONFIG_PM suspend: tulip_suspend, resume: tulip_resume, #endif /* CONFIG_PM */ }; }}}

デバイスを認識し,ドライバがインストールされる(pci_register_driver)と最初に probe ハンドラが呼ばれる.

struct pci_dev

struct net_device

  • open(ifconfig up),close(ifconfig down),hard_start_xmit などが定義されている.
  • 送信処理(dev->hard_start_xmit),受信処理(割込みハンドラ)のエントリは Linux/プロトコルスタックへ.
Clone this wiki locally