qshinoの日記

Powershell関係と徒然なこと

pci bus tree

pci bus scan

pci bus をscanする方法。

Config Access Type

pciのbus scanには2種類のConfig accessが使われる。

  1. Type0 / T0: Bridgeが透過不可のアクセス
  2. Type 1 / T2 : Bridgeが透過可のアクセス

Type 0

31-11 10-8 7-2 1 0
Devsel func reg 0 0

Type 1

31-24 23-16 15-11 10-8 7-2 1 0
reserved Bus Dev func reg 0 1

BridgeのConfig Access処理

Bridgeは、a) ホスト側のPrimary Bus番号PBN、b)ホストから遠い側のSecondary Bus番号SBN、c) Bridge配下の最大のBus番号Subordinate Bus番号/OBNの3つを使いConfig accessの透過を判断する。

Bridgeが2.透過可能アクセスを受けた時、アクセスのBus番号/ABNがa) PBN以下の場合、あるいはOBNを超える場合、破棄する。b) SBNの場合、アクセスを1.透過不可アクセスに変更してSBN側に透過する。c) SBNを超え、OBN以下の場合、2.透過可能アクセスのまま透過する。まとめると、

  1. ABN=SBN, T0に変更し透過。
  2. SBN<ABN<=OBN: T1のまま透過。
  3. 上記以外: 破棄

Bus scan 方法

上記Config Access TypeとBridge挙動から下記の方法にてBus scanする。

Step 1. 最もcpuに近いホストブリッジ(bus=0,dev=0)が、T0アクセスによりDev=0からMAXDEVまでデバイスを探索する。

Step 2. ブリッジが見つかったら、PBN/SBN/OBN=0xffを設定し、ブリッジ配下を探索する。

Step 3. ブリッジ配下のデバイス探索結果、最大のバス番号をOBNに設定し、SBNをOBN+1とし、中断していたStep 1のバス探索を再開する。

上記は再帰深さ優先探索になっているが、仮のOBNを付けた幅優先探索の方が良い?

Bus scanをコードにする

int scan_bridge(int pbn){
  sbn = pbn + 1
  obn = sbn
  for (dev = 0 ;dev < MAXDEV;dev++){
    id = t0(dev)
    if( id == 0xffffffff ) return obn
    if( id.class == bridge ){
      set((pbn,dev), pbn, sbn, 0xff)
      obn = scan_bridge( sbn )
      sbn = obn + 1
      setobn((pbn, dev), obn)
    }
    return obn
}

do_main(){
  config( hostbridge )
  scan_bridge(1)
}

ref

http://archive.linux.or.jp/JF/JFdocs/The-Linux-Kernel-7.html