JF Linux Kernel 2.6 Documentation: /usr/src/linux/Documentation/io_ordering.txt

io_ordering.txt

I/O 順序付け [プレインテキスト版]


幾つかのプラットフォームでは、いわゆるメモリマップト I/O は、弱く順序付け
されています (ウィークオーダ)。このようなプラットフォームでは、デバイス上の
メモリマップされたアドレスへの I/O 書込みが意図した順番に届くことを保証する
のは、ドライバ開発者の責任です。これは通常、「安全な」デバイスもしくはブリッジ
レジスタを読み込むことによりおこないますが、これは、読込みが投入される前に
保留中のデバイスへの書込みを I/O チップセットにフラッシュさせるものです。
ドライバは通常、スピンロックで保護されたクリティカルセクションコードから
抜ける直前に、この技を使います。これにより、後に続く I/O 空間への書込みが、
(この読込み命令に) 先行する全ての書込みより後に到着することが保証されます
(メモリバリアオペレーション mb() に相当しますが、I/O に関してだけです)。

仮想的なデバイスドライバからの、より具体的な例は次のようになります。

        ...
CPU A:  spin_lock_irqsave(&dev_lock, flags)
CPU A:  val = readl(my_status);
CPU A:  ...
CPU A:  writel(newval, ring_ptr);
CPU A:  spin_unlock_irqrestore(&dev_lock, flags)
        ...
CPU B:  spin_lock_irqsave(&dev_lock, flags)
CPU B:  val = readl(my_status);
CPU B:  ...
CPU B:  writel(newval2, ring_ptr);
CPU B:  spin_unlock_irqrestore(&dev_lock, flags)
        ...

上記の例の場合、デバイスは newval を受け取る前に newval2 を受け取る可能性が
ありますが、これは問題となるでしょう。しかし、これを直すのは簡単です。

        ...
CPU A:  spin_lock_irqsave(&dev_lock, flags)
CPU A:  val = readl(my_status);
CPU A:  ...
CPU A:  writel(newval, ring_ptr);
CPU A:  (void)readl(safe_register); /* たぶん設定レジスタ? */
CPU A:  spin_unlock_irqrestore(&dev_lock, flags)
        ...
CPU B:  spin_lock_irqsave(&dev_lock, flags)
CPU B:  val = readl(my_status);
CPU B:  ...
CPU B:  writel(newval2, ring_ptr);
CPU B:  (void)readl(safe_register); /* たぶん設定レジスタ? */
CPU B:  spin_unlock_irqrestore(&dev_lock, flags)

この例では、safe_register から読み込むことにより、I/O チップセットに、実際に
チップセットに読込みが投入される前に保留中の書込みを全てフラッシュする動作を
おこなわせるため、データ破壊を防ぐことができます。

Linux カーネル 2.6 付属文書一覧へ戻る