• ioread/iowrite vs read/write vs read_relaxed/write_relaxedの違い

    A thumbnail image

    Linuxのドライバで使われるioread/iowriteread/writeread_relaxed/write_relaxedの違いをまとめます。
    カーネルは、5.16.9を参考にしています。
    アーキテクチャによって、内部実装が異なることに注意してください。

    ioread/iowrite

    memory mapped I/O (I/O memory) or port mapped I/Oにアクセスする際に使用します。 ioread*/iowrite*関数は、与えられたアドレスがmemory mapped I/Oかport mapped I/Oかを判定してレジスタのリード/ライトを行います。
    内部的には、read* or in* / write* or out*を呼び出しています。
    memory mapped I/Oにアクセスする際、addrにはioremap()で取得したアドレスを与えます。

    unsigned int ioread8(const volatile void __iomem *addr);
    unsigned int ioread16(const volatile void __iomem *addr);
    unsigned int ioread32(const volatile void __iomem *addr);
    
    void iowrite8(u8 value, volatile void __iomem *addr);
    void iowrite16(u16 value, volatile void __iomem *addr);
    void iowrite32(u32 value, volatile void __iomem *addr);
    

    read/write

    型チェックを行っていないこれらの関数の使用は、現在は推奨されていません。
    armアーキテクチャの場合、これらの関数はマクロで定義されており、型チェックを行っていません。
    内部的には、read*_relaxed / write*_relaxedの呼び出しを行っています。
    read*_relaxedの呼出し後にメモリバリアがあり、レジスタの読み込み順序が保護されます。 write*_relaxedを呼び出す前にメモリバリアがあり、レジスタの書き込み順序が保護されます。

    unsigned int readb(addr);
    unsigned int readw(addr);
    unsigned int readl(addr);
    
    void writeb(unsigned value, address);
    void writew(unsigned value, address);
    void writel(unsigned value, address);
    
    メモリバリア参考:
    ハードウェアレベルへのアクセス順序が変わらないことを保証する。ハードウェアは書き出す/読
    み込むデータだけでなく、アクセスのタイミング、順序も重要な要素となるため、たとえ非効率で
    あったとしてもその順序を維持する必要がある。
    

    read_relaxed/write_relaxed

    レジスタの読み込み/書き込み順序が保証されないが、順序を保証しないでデータの読み書きを行いたい場合に使用します。

    unsigned int readb_relaxed(addr);
    unsigned int readw_relaxed(addr);
    unsigned int readl_relaxed(addr);
    
    void writeb_relaxed(unsigned value, address);
    void writew_relaxed(unsigned value, address);
    void writel_relaxed(unsigned value, address);
    

    Reference

    comments powered by Disqus