mishuang 发表于 2009-05-31 13:30

Solaris PCI相关解读


                我们以e1000g网卡驱动为例,驱动程序由pci_config_setup(9F)或者ddi_regs_map_setup(9F)得到访问配置地址空间的句柄。下面我们通过mdb来看看这个句柄是个怎样的数据结构。
# mdb -k
> ::prtconf ! grep e1000g
      300004271b0      pci8086,1001, instance #0 (driver name: e1000g)
> 300004271b0::print -t struct dev_info devi_driver_data |::print -t e1000g_t osdep.cfg_handle |::print -t struct ddi_acc_hdl ah_addr
caddr_t ah_addr = 0x29ebf9e3800
> 0x29ebf9e3800::sfmmu_vtop
virtual 29ebf9e3800 mapped to physical 7fe00001800
> 300004271b0::print -t struct dev_info devi_driver_data |::print -t e1000g_t osdep.cfg_handle |::print -t struct ddi_acc_hdl
{
    int ah_vers = 0x1
    void *ah_bus_private = 0
    void *ah_platform_private = 0x60011a99cc0
    dev_info_t *ah_dip = 0x300004271b0
    uint_t ah_rnumber = 0
    caddr_t ah_addr = 0x29ebf9e3800
    off_t ah_offset = 0
    off_t ah_len = 0
    uint_t ah_hat_flags = 0x2000
    pfn_t ah_pfn = 0x3ff00000
    uint_t ah_pnum = 0x1
    ulong_t ah_xfermodes = 0
    ddi_device_acc_attr_t ah_acc = {
      ushort_t devacc_attr_version = 0x2
      uchar_t devacc_attr_endian_flags = 0x1
      uchar_t devacc_attr_dataorder = 0
      uchar_t devacc_attr_access = 0x2
    }
}
驱动程序通过pci_config_setup(9F)或者ddi_regs_map_setup(9F)建立了PCI设备配置地址空间和内核虚拟地址之间的映射,在上例中,配置地址空间的物理地址是0x7fe00001800,内核虚拟地址是0x29ebf9e3800。这个物理地址也可以通过pcitool得到验证:
# pcitool -v
...
Bus Number: 0 Device Number: 3 Function Number: 0
Physical Address: 0x7fe00001800
Vendor ID: 8086
Device ID: 1026
Command: 0157
Status: 0230
Revision ID: 04
Class Code: 020000
Cache Line Size: 10
Latency Timer: 40
Header Type: 00
BIST: 00
Base Address Register 0 (@10): 00100004
Base Address Register 1 (@14): 00000000
Base Address Register 2 (@18): 00140004
Base Address Register 3 (@1C): 00000000
Base Address Register 4 (@20): 00000941
Base Address Register 5 (@24): 00000000
Expansion ROM Base Address Register (@30): 00180000
...
BAR0的内核虚拟地址和物理地址也可以通过类似的方法得到:
# mdb -k
> ::prtconf ! grep e1000g
      300004271b0      pci8086,1001, instance #0 (driver name: e1000g)
> 300004271b0::print -t struct dev_info devi_driver_data |::print -t e1000g_t osdep.reg_handle |::print -t struct ddi_acc_hdl ah_addr
caddr_t ah_addr = 0x29ebf9e4000
> 0x29ebf9e4000::sfmmu_vtop
virtual 29ebf9e4000 mapped to physical 7ff00100000
> 300004271b0::print -t struct dev_info devi_driver_data |::print -t e1000g_t osdep.reg_handle |::print -t struct ddi_acc_hdl
{
    int ah_vers = 0x1
    void *ah_bus_private = 0
    void *ah_platform_private = 0x60011a99b80
    dev_info_t *ah_dip = 0x300004271b0
    uint_t ah_rnumber = 0x1
    caddr_t ah_addr = 0x29ebf9e4000
    off_t ah_offset = 0
    off_t ah_len = 0x20000
    uint_t ah_hat_flags = 0x2000
    pfn_t ah_pfn = 0x3ff80080
    uint_t ah_pnum = 0x10
    ulong_t ah_xfermodes = 0
    ddi_device_acc_attr_t ah_acc = {
      ushort_t devacc_attr_version = 0x1
      uchar_t devacc_attr_endian_flags = 0x1
      uchar_t devacc_attr_dataorder = 0
      uchar_t devacc_attr_access = 0x1
    }
}
或者
> 300004271b0::print -t struct dev_info devi_driver_data |::print -t e1000g_t shared.hw_addr
u8 *shared.hw_addr = 0x29ebf9e4000
Solaris在SPARC平台下没有scanpci和lspci等相应的命令,prtconf是一个可以得到系统配置信息的命令,当然也包括PCI设备。
# prtconf -vp
...
      Node 0xf00d1b0c
            assigned-addresses:83001810.00000000.00100000.00000000.00020000.83001818.00000000.00140000.00000000.00040000.81001820.00000000.00000940.0000000
0.00000040.82001830.00000000.00180000.00000000.00040000
            reg:00001800.00000000.00000000.00000000.00000000.03001810.00000000.00000000.00000000.00020000.03001818.00000000.00000000.00000000.00040000.0100
1820.00000000.00000000.00000000.00000040.02001830.00000000.00000000.00000000.00040000
            compatible: 'pci8086,1026.8086.1001.4' + 'pci8086,1026.8086.1001' + 'pci8086,1001' + 'pci8086,1026.4' + 'pci8086,1026' + 'pciclass,020000' + 'pciclass,0200'
            name:'ethernet'
            66mhz-capable:
            devsel-speed:00000001
            class-code:00020000
            interrupts:00000001
            latency-timer:00000040
            cache-line-size:00000010
            max-latency:00000000
            min-grant:000000ff
            subsystem-id:00001001
            subsystem-vendor-id:00008086
            revision-id:00000004
            device-id:00001026
            vendor-id:00008086
...
其中reg属性中包含了什么信息可以从pci(4) man page中得到,也可以通过下面的C程序得到。
#include
/*
                   Bits 0 - 7         8-bit register number
                   Bits 8 - 10          3-bit function number
                   Bits 11 - 15         5-bit device number
                   Bits 16 - 23         8-bit bus number
                   Bits 24 - 25         2-bit address space type identifier
                   Bits 28 - 31         Register number extended bits8:11
                                        for extended config space. Zero for
                                        conventional configuration space.
                   Theaddressspacetypeidentifiercanbe
                   interpreted as follows:
                   0x0                  configuration space
                   0x1                  I/O space
                   0x2                  32-bit memory space address
                   0x3                  64-bit memory space address
*/
#define REG 0x000000ff
#define FUN 0x00000700
#define DEV 0x0000f800
#define BUS 0x00ff0000
#define ADD 0x03000000
#define EXT 0xf0000000
int main(int argc, char *argv[])
{
    int i, regs[]={
/*
            0x0200c810,
            0x8200c814,
            0x8100c818,
            0x0000c800,
            0x0200c810,
            0x0200c814,
            0x0100c818,
            0,
            0x83001110,
            0x83001010,
            0,
            0x83001810,
*/
            0x00001800,
            0x03001810,
            0x03001818,
            0x01001820,
            0x02001830,
            1 };
    for(i=0; regs != 1; i++) {
      if (regs == 0) {
            printf("\n");
            continue;
      }
      printf("REG: %x\t", regs & REG);
      printf("FUN: %x\t", (regs & FUN) >> 8);
      printf("DEV: %x\t", (regs & DEV) >> 11);
      printf("BUS: %x\t", (regs & BUS) >> 16);
      printf("ADD: %x\t", (regs & ADD) >> 24);
      printf("EXT: %x\n", (regs & EXT) >> 28);
    }
    return 0;
}
# ./reg
REG: 0    FUN: 0    DEV: 3    BUS: 0    ADD: 0    EXT: 0
REG: 10    FUN: 0    DEV: 3    BUS: 0    ADD: 3    EXT: 0
REG: 18    FUN: 0    DEV: 3    BUS: 0    ADD: 3    EXT: 0
REG: 20    FUN: 0    DEV: 3    BUS: 0    ADD: 1    EXT: 0
REG: 30    FUN: 0    DEV: 3    BUS: 0    ADD: 2    EXT: 0
               
               
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/23177/showart_1950293.html
页: [1]
查看完整版本: Solaris PCI相关解读