NetBSDのifを書くために調べています。
Comcerto 1000にはGIGAのMACが二つ付いています。PHYは外付けでターゲットにはAtherosのSwitchのAR8316が付いています。
AR8316はAtherosの最初のGIGAのSwitchです。MIPS SOCを作り始めた初期の頃はAtherosはSwitchのソリューションを持っていなかったのですが、どこかの会社を買収したのかSwitchやSwitch入りのSOCを作るようになりました。
AR8316は6ポート(MACx6,PHYx5)のSwitchで1ポートのPHYを切り離すことができます。
AtherosのSwitchは後発だが、けっこうセールスは上手かったのかもしれない。製品が良かったのが信頼につながったのかな。
AtherosはもともとはSwitchのソリューションを持っていなかったのだが、おそらくどこかの会社を買収して手に入れたのではないだろうか。
接続はこのようになっています。
グレーのMACは未使用で、PHYがWAN側として切り離されています。AtherosのSwitchはCPUポートが0なのでMACのPHYの番号がずれてややっこしいです。
FreeBSDのコードで16系としてAR8216,AR8316をまとめてるところあるのですが、AR8216は100MでAR8316はGigaで違ってるところのほうが多いのではないでしょうか。
AR8316はなぜかまったくデーターシートが落ちてません。
余談ですが、SOCのifが1本の場合はVLAN(.1q)でLAN,WANを切り分ける事もできます。
AR8316のコントロールはmdioでできて、GEMAC0のmdioに接続されていました。GEMAC1のmdioは何にも接続されてません。
SOCのMACとSWITCHの通信用の接続はGMII,RGMII,MIIなどがありますが、ifのattachでAR8316の設定を確認したところ、u-bootがrgmiiにして通信をおこなっているようなので、接続はrgmiiのようです。
u-bootがkernelを起動する時に設定を戻すことがありますが、AR8316はSOFT RESETしかないので、設定は残ったままになっている可能性が高いです。
Comcerto 1000には100にはなかった、ADMとSCHというレジスタがあるようです。
データーシートがないので、よく分からないのですが、おそらくADMは受信側の制御を調整する機能で、SCHは送信側を調整する機能のような気がします。Comcerto 100には無い機能です。
GPLなLinuxのコードを見るとLinuxのfast path(FreeBSDのnetmapのようなもの)の処理とも関連しているようです。
ディスクリプターは連続したタイプでかなり簡素化されたものです。RXは4x4でTXは4x2のようです。
NetBSDもbusdmaのKPIがありますが、FreeBSDとはちょっと違っているようです。
ただだいたいのドライバーの構成はFreeBSDとおなじで、RXはディスクリプタチェインをdma領域に作り、そこにmbufを貼り付けて待ち、じゅしんかんりょうわりこみでkernelに上げ、TXはkernelから落ちてきたmbufをディスクリプタに貼りdmaに乗っけて送信するようにします。送信完了の割り込みでmbufを開放して終わりです。
データーシートが手に入らないので、GPLなソースを参考にするのですが、以下の方法が考えられます。
- Fast Path相当で実装
- 通常のLinuxドライバと同じように実装
- u-bootレベルで実装
Fast Path相当は相当難易度が高いので却下です。通常のLinuxドライバも原始的なドライバーではなく、新しい仕組みのnapiで実装されているので、調べてはみたのですが結構難しくあきらめました。パフォーマンスは望めませんが、一番下にすることにしました。
受信と送信では、受信の方が処理は簡単だと思います。他のホストでいないローカルipにpingを打つとブロードキャストのarpが送信されるので、これを受けられるかテストするのが良いです。MACはブロードキャストと自分のMACアドレスのユニキャストしかhostに渡しません。
Comcertoにpingを打って返答が何故か壊れていて送られます。
09:06:01.838977 IP truncated-ip - 24 bytes missing! 10.0.1.101 > 10.0.1.38: ICMP echo reply, id 26067, seq 18, length 64
0x0000: 7085 c2c8 f06c d494 a197 0394 0800 4500
0x0010: 0054 f4c2 0000 ff01 b05b 0a00 0165 0a00
0x0020: 0126 0000 9c6c 65d3 0012 0000 1e19 3242
0x0030: c24f 0809 0a0b 0c0d 0e0f 1011 1213 1415
0x0040: 1617 1819 1a1b 1c1d 1e1f
二つに分かれてるデータを、一つのパケットにまとめて送る必要がありました。
このGEMACはかなり作りこまれていて、おそらくいろいろな使い方ができるのだと思われるが、データーシートが手に入らないのが残念。
だいたいできたのですがときどきethernet_inputで落ちます。デバッガーも固まって使えません。再現性がないので、ネットワークの問題を疑い隔離されて、ルーターのみのネットワークに移したところ、問題が起きなくなりました。何らかのパケットが原因と思われます。
他のifのコードを見たのですが、MACからのstatusでパケットが壊れている場合は捨てるような処理がありました。類似の処理が必要なのだと思われます。
受信は割り込みで上がってきたリングのmbufを上げればいいのですが、送信はいくつかのケースがあります。
pingのように1パケット毎の送信であればTXは送信と停止を繰り返すのですが、送信中にパケットが追加されるケースもあります。
DMAの処理のチェックはiperf3で試します。処理に問題があるとこけます。
NetBSDの送信はif_startに登録された関数で処理します。この関数がよばれた時にmbufを拾ってディスクリプタに貼り付けます。mbufは複数のセグメントに分かれていることもあり、その場合はそれぞれのセグメントをディスクリプタに貼ります。mbufのサイズがEthernetの最小パケットより小さい場合はパディングのバッファをディスクリプタに貼ります。
送信完了後の割り込みでは貼り付けてあってmbufを開放します。セグメントが二つ以上の場合は元のmbufだけ開放します。
先頭のディスクリプタにはGEMTX_RETBUFのフラグを付けておいて、割り込みでそこのmbufを開放するようにしました。GEMTX_RETBUFはおそらく機能はなくて、このような事に使える単なるフラグのような気がします。
NetBSDの送信は次のケースがあります。
- mbufがEthernetの最小パケットより大きくセグメントが一つ
- mbufがEthernetの最小パケットより大きくセグメントが二つ以上
- mbufがEthernetの最小パケットより小さい
最後のパターンはおそれくセグメントは一つのケースしかなくて、送信する時はパディングして送ります。MACによっては勝手にパディングされるものもあるのかもしれません。
Linuxの送信のskbは一つ一パケットのようなので、このような処理は必要ありません。
割り込みはTXDONEとRXDONEのみ上がるようにしているのですが、TXDONEのフラグが上手く拾えないことがあったのでRXDONEでない場合はTXDONEとして処理しています。割り込みは上がっているようなのですが、なにか設定が足りていないのかもしれません。
何故かPHY接続のGEMAC0は100でSWITCH接続のGEMAC1は1000でにしないと使えません。SWITCHの設定間違えてるのかもしれません。 両方とも1000にできました。
AR8316の全PHYをSwitchに入れることできました。この場合cge0は使えません。