PCI (Peripheral Component Interconnect)

PCI (Peripheral Component Interconnect) は、PCのプロセッサと周辺機器との間の通信を行うためのバスアーキテクチャの一つです。

下図は、少し古めのノートパソコンに内蔵されているPCIデバイスの論理的な接続を示したものです。図にありますように、1つのシステムには複数のPCIバスが、PCI-PCIブリッジを介して接続できます。

1つのPCIバスには、複数のデバイスが接続でき、また1つのデバイスには複数の「機能」を備えることができます。かつてノートパソコンで主流であったCardBusデバイスも、PCI-CardBusブリッジの先の一種のPCIデバイスとして見える形です。

PCIデバイスからの割り込み

PCIバスにおいては、1つのデバイスにはINT#A, INT#B, INT#C, INT#Dの4本のI/O割り込み線が存在します。x86アーキテクチャでは、これらは (共有の上) I/O APICのいずれかのピンに接続されます。
PCIデバイスの各機能は、4つの割り込み線のうち1つを選択して利用します。

PCI割り込みの特徴の1つは、割り込みが通常のデータ転送を行なうPCIバスを通らず、専用の信号線を用いて、すなわちoutbandで伝達されることです。

PCIデバイスは、自らがバスマスタとなって直接主記憶に書き込みを行ない、完了すると割り込みを上げるのが普通の動作です。しかし、主記憶への書き込みは、PCIバスブリッジやメモリコントローラが他のバスマスタとの競合を避けるためにバッファリングなどを行なうことがあり、割り込みの原因となった書き込みが完了しないうちに割り込みがCPUに届いてしまうような事態が発生し得ます。

また、PCIは割り込み共有を行うために、レベルトリガになっています。レベルトリガの対義語はエッジトリガで、信号が0→1または1→0に変化したときを割り込みの発生と見なします。レベルトリガでは、割り込みは状態であり、1 (または0) である間割り込みが入っている状態であると見なされます。

割り込みを受けたデバイスドライバなどは、割り込みルーチンから戻る前にこの割り込み状態を解除しなければなりません。それでも割り込み状態が維持されたままであるということは、この割り込み線を共有する他のデバイスも割り込みをかけていることを意味します。
エッジトリガでは、割り込みは状態ではなく変化なので、割り込み線を共有することができない訳です。

PCI割り込みルーティング

典型的な (Intelのチップセットを使ったような) PCでは、各PCIデバイスの4つの割り込み線は、PIRQ (PCI IRQ) A~Hの8つのいずれかに繋がります。たとえば、下図のように共有して接続されます。

PCI世代のサーバでは、I/O APICを増設することで、共有を避けることも行なわれました。
こうした接続情報は、メーカーやモデルに固有のものですので、ACPIを経由してOSに情報を提供しています。

PCI割り込みルータ

各PIRQをPICまたはI/O APICのどの接続ピンにつなぐかを決めます。

  • PIC利用時
    16 (-α) のIRQにプログラム可能。
  • I/O APIC利用時
    たいていのPCでは単一のI/O APICのpin 16~23にPIRQA~Hが固定的に割り当てられる。複数のI/O APICを持つサーバでも固定割り当てであることが多い。ACPIで情報を取得可能。

ACPIによる割り込み情報の取得

ACPIで記述される主な割り込み情報は、以下のようになっています。

 

  • GSI (Global System Interrupt) 番号
    ACPIでは、システムの全ての割り込みコントローラに存在する割り込みピンに0から始まる番号を振っています。典型的なPCでは、システムに1つのI/O APICがあり、24本のピンを持っていますので、通常GSI番号は0から23までとなります。
    I/O APICは、ACPIのMADT (Multiple APIC Descriptor Table) にその情報が記述されており、その中にGSI baseという項があります。最初のI/O APICのGSI baseは0で、I/O APICを複数持つシステムでは、第2のI/O APICのGSI baseが、典型的には24となります。
    GSI baseが24のI/O APICのピン0のGSI番号は24、ピン1は25、…という感じです。
  • PCI Interrupt Linkデバイス (PNP0C0F)
    「PCI割り込みルーティング」で示した図に登場する各PIRQについて、宛先となる割り込みコントローラのピン (など) を管理するデバイスです。ピンはGSI番号で表されます。
    以下は、手元のPCのDSDT (Differentiated System Description Table) からの抜粋です。
Name (PRSA, ResourceTemplate ()
{
    IRQ (Level, ActiveLow, Shared, )
        {3,4,5,6,7,10,11,12,14,15}
})

Device (LNKA)
{
    Name (_HID, EisaId ("PNP0C0F"))
    Name (_UID, One)

    Method (_PRS, 0, NotSerialized)
    {
        Return (PRSA)
    }

    Method (_CRS, 0, NotSerialized)
    {
        And (PIRA, 0x0F, Local0)
        ShiftLeft (One, Local0, IRA0)
        Return (BUFA)
    }

    Method (_SRS, 1, NotSerialized)
    {
        CreateWordField (Arg0, One, IRA)
        FindSetRightBit (IRA, Local0)
        Decrement (Local0)
        Store (Local0, PIRA)
    }
}

_PRSは、Possible Resource Settingsで、LNKAデバイスの取り得る設定値です。上記ではGSI 3~7、10~15を取り得ることが分かります。
_CRS、_SRSは、それぞれCurrent Resource Settings, Set Resource Settingsで、現在の設定値の取得と設定の変更を行ないます。

  • _PRT (PCI Routing Table)
    DSDTのPCIバスブリッジなどの定義中に現れるメソッドで、各デバイス・機能の各割り込み線が、どのGSIまたはInterrupt Linkデバイスと繋がっているかを示します。PICモードとAPICモードのそれぞれで違う値を返すのが普通でしょう。4つの値の組で与えられ、
    たとえば、
Package (0x04)
{
    0x0002FFFF, 
    0x03, 
    LNKF, 
    Zero
}

これは、このPCIバスのデバイス番号0x2の全ての機能 (0xFFFF) のINT#D (0x03、INT#Aが0、INT#Bが1、INT#Cが2) が、Interrupt LinkデバイスLNKFに繋がっていることを示します。

Package (0x04)
{
    0x001CFFFF, 
    0x02, 
    Zero, 
    0x12
}, 

これは、このPCIバスのデバイス番号0x1cの全ての機能のINT#Cが、GSI番号0x12に繋がっていることを示します。
このような4値を、繋がっている全てのPCIデバイスまたは空きスロットだけ並べたものを、_PRTが返すようになっています。
MADTのI/O APICの定義、Interrupt Linkデバイスの設定、_PRTの返り値から、全てのPCIデバイスのINT#A~INT#Dが、I/O APICのどのピンに繋げる、あるいは繋がっているかを知ることができます。

メッセージ シグナル割り込み

メッセージシグナル割り込みは、PCI仕様2.2以降、およびPCI Expressで追加された割り込み通知方法です。
さらに、PCI 3.0以降ではMSI-X (拡張メッセージシグナル割り込み、MSIExtended) が追加されました。
メッセージ シグナル割り込みは、PCIバスを通じて (inbandで) 割り込み情報を送信します。

あらかじめデバイスに割り込み先CPUやベクタ番号を含む情報を設定しておくことで、割り込み発生時にCPUに直接割り込みがかかります。このため、I/O APICのピン数が少ないことから発生する割り込み共有が抑制されます。さらに、前節にあるような複雑な割り込みルーティングの迷路を通る必要もありません。

しかし、割り込みベクタが224しかないため、それでも共有の可能性はあります。また、割り込みハンドラ内での遅延を以下の理由で抑制しています。

 

  • INTx割り込みは、PCIの通常のトランザクション (割り込みの原因になった処理を含む) を追い越す可能性があるため、割り込みハンドラ内で必ずPCIの通常のトランザクションを発生させ、その終了を待つ必要がある。
  • 割り込みを共有しているため、割り込みハンドラ内で実際に割り込み状態にあるかを確認する必要がある。
  • 単一の機能が複数のメッセージ (割り込みハンドラ) を持つことができるため、INT#A~Dのうちいずれか1つしか持てない旧来の割り込みで必要であった、割り込み原因の特定のための処理が省略できる。

以下にMSIとMSI-Xの特徴をそれぞれまとめました。

MSI (Message Signaled Interrupt)

  • 単一のfunctionが32までの複数のメッセージ (割り込みハンドラ) を持つことができる。
    ただし、x86のRed Hat Enterprise Linux 5 / 6 では1つのみのサポート。
  • PCIのconfiguration registerに、アドレス (32/64bit) とデータ (16bit) を設定。
    デバイスは割り込み時に設定したアドレスに設定したデータを書き込んでくる。これを割り込みと解釈する。
  • 複数メッセージの際は、メッセージによってデータの下位ビットが変更される。したがって、ベクタ番号は連続である必要がある。
  • x86では、アドレスは0xfeeXXXXX、Local APICのアドレス。
    アドレスの中に宛先のCPU、データの中に配送モードや割り込みベクタを埋め込む。

MSI-X (MSI Extended)

  • MSIの拡張版。
  • 32ではなく、2048までのメッセージ (割り込みハンドラ) を持つことができる。
  • 複数メッセージの場合、アドレス、データともに独立。したがって、ベクタ番号は連続である必要はない。