蟹さん(RTL8196C)のPCIeを調べてみました。
PICeはPCIと同じようにコンフィグレーションレジスタ、IO領域、メモリ領域が用意されています。
PCIeのバスはシリアルでPCIはパラレルになりますが、制御は同じようにできます。
余談ですが、昔はパレレルの方が通信速度を上げられると思われていましたが、極端に処理速度が上がってしまい、信号間の同期のコストがかかりすぎるため、シリアルの方が有効になったようです。
それぞれの物理アドレスはPCIコントローラーによって決められていて、蟹さんの場合は以下になります。
# define BSP_PCIE0_H_CFG 0xB8B00000
# define BSP_PCIE0_D_CFG0 0xB8B10000
# define BSP_PCIE0_D_IO 0xB8C00000
# define BSP_PCIE0_D_MEM 0xB9000000
コンフィグレーションレジスタはホスト分とそれぞれのデバイスのものがあり上の定義ではBSP_PCIE0_H_CFGがホストのアドレスでBSP_PCIE0_D_CFG0 がデバイスのアドレスになります。
コンフィグレーションレジスタの先頭にはベンダーとデバイスのIDが16Bitづつあります。これを見てOSはどのデバイスドライバーを使うか判断します。
IO領域とメモリ領域はx86の様にIO空間がある場合はIO領域はIOアクセスでメモリ領域はメモリアクセスで処理を行います。蟹さん(MIPS)の場合はIO空間がないのでIO領域とメモリ領域はメモリアクセスで処理を行います。
PCI以前のISAカードではカード自体にアドレスが設定されていて、それが変更ができない場合は同じカードを2枚さすと、アドレスが重複してカードが使用できなくなりました。これを回避するためにPCIではOSからカードのアドレスを設定できるようになりました。その設定はコンフィグレーションレジスタのBAR(0x10から)の6つになります。BARの下位ビットは属性の設定に利用されていて0ビットが1の場合はIO領域になり、0の場合はメモリ領域になります。
BSP_PCIE0_D_CFG0のIO領域をBSP_PCIE0_D_IOで見えるようにするにはBSP_PCIE0_D_CFG0のBARにBSP_PCIE0_D_IOのアドレスを設定するのですが、蟹さんの場合は0x18C00000を設定しています。
一つ目のデバイスがたとえば64KのIO領域を使う場合は、二つ目のデバイスは64K後のアドレスをBARに設定します。デバイスからは必要領域のサイズの情報は取れないので、デバイスドライバーにハードコードされています。
なぜか蟹さんの場合BAR0がIO領域でBAR2がメモリ領域に固定されているようです。
割り込みもコンフィグレーションレジスタで設定できます。