メモ (PCI 関連)

色々調べものなソレをメモ。詳解 Linux カーネル 3 版でもデバイスドライバなソレを読んでいるトコなんですが、それは別途で。今回は 8139too なエントリでヤると言ってた pci_*_config_* な手続きについて。ちょっとへろへろなんでどこまでイケるか微妙。
まず、pci_{read, write}_config_{byte, word, dword} な手続きは include/linux/pci.h にて定義。

static inline int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val)
{       
        return pci_bus_read_config_byte (dev->bus, dev->devfn, where, val);
}
static inline int pci_read_config_word(struct pci_dev *dev, int where, u16 *val)
{       
        return pci_bus_read_config_word (dev->bus, dev->devfn, where, val);
}
static inline int pci_read_config_dword(struct pci_dev *dev, int where, u32 *val)
{       
        return pci_bus_read_config_dword (dev->bus, dev->devfn, where, val);
}
static inline int pci_write_config_byte(struct pci_dev *dev, int where, u8 val)
{       
        return pci_bus_write_config_byte (dev->bus, dev->devfn, where, val);
}
static inline int pci_write_config_word(struct pci_dev *dev, int where, u16 val)
{       
        return pci_bus_write_config_word (dev->bus, dev->devfn, where, val);
}
static inline int pci_write_config_dword(struct pci_dev *dev, int where, u32 val)
{       
        return pci_bus_write_config_dword (dev->bus, dev->devfn, where, val);
}

同じヘッダに pci_bus_* な手続きのプロトタイプが宣言されている。これらが定義されているのは drivers/pci/access.c な模様。read では以下の手続きで読み込んでいる模様。

        res = bus->ops->read(bus, devfn, pos, len, &data);              \

bus は struct pci_bus 型へのポインタ。定義は include/linux/pci.h にある。メンバに struct pci_ops 型へのポインタとして ops が定義。struct pci_ops 型も同様に include/linux/pci.h にて定義。短いので引用しとく。

/* Low-level architecture-dependent routines */

struct pci_ops {
        int (*read)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val);
        int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val);
};

直下には struct pci_raw_ops 型の定義もある (けど引用は略)。ちなみに上記の構造体メンバの引数は Linux カーネル解析入門の p.202 にて引用されている arch/i386/pci/common.c な以下の手続きと戻り値の型やら引数等も同じ、という事でおそらくはメンバに関数ポインタが代入されているものと類推 (現時点で根拠ナシ)。

struct pci_raw_ops *raw_pci_ops;

static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
{       
        return raw_pci_ops->read(0, bus->number, devfn, where, size, value);
}

static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
{       
        return raw_pci_ops->write(0, bus->number, devfn, where, size, value);
}

ちなみに raw_pci_ops はグローバルな変数になっており、Linux カーネル解析入門の p.198 から p.201 にて引用されている arch/i386/pci/direct.c において値が設定されている模様。

Linux カーネル解析入門の第 5 章 PCI はスルーしてたんですが、やっぱ読まねぇと話が見えない。ただ、もう少しスルーを増やしてざくざく読んだ方が良さげかも。