linux中pci设备知识

简介: linux中pci设备知识   Linux PCI设备驱动实际包括Linux PCI设备驱动和设备本身驱动两部分。PCI(Periheral Component Interconnect)有三种地址空间:PCI I/O空间、PCI内存地址空间和PCI配置空间。

linux中pci设备知识

  Linux PCI设备驱动实际包括Linux PCI设备驱动和设备本身驱动两部分。PCI(Periheral Component Interconnect)有三种地址空间:PCI I/O空间、PCI内存地址空间和PCI配置空间。其中,PCI I/O空间和PCI内存地址空间由设备驱动程序使用,而PCI配置空间由Linux PCI初始化代码使用,用于配置PCI设备,比如中断号以及I/O或内存基地址。

1.1.1 内核工作

  Linux内核主要就做了对PCI设备的枚举和配置;在Linux内核初始化时完成的。

  对于PCI总线,有一个叫做PCI桥的设备用来将父总线与子总线连接。作为一种特殊的PCI设备,PCI桥主要包括以下三种:

    1). Host/PCI桥:  用于连接CPU与PCI根总线,第1个根总线的编号为0。在PC中,内存控制器也通常被集成到Host/PCI桥设备芯片中,因此Host/PCI桥通常也被称为“北桥芯片组(North Bridge Chipset)”。

    2). PCI/ISA桥:   用于连接旧的ISA总线。通常,PCI中类似i8359A中断控制器这样的设备也会被集成到PCI/ISA桥设备中。因此,PCI/ISA桥通常也被称为“南桥芯片组(South Bridge Chipset)”

    3). PCI-to-PCI桥(以下称为PCI-PCI桥):  用于连接PCI主总线(Primary Bus)和次总线(Secondary Bus)。PCI-PCI桥所处的PCI总线称为主总线,即次总线的父总线;PCI-PCI桥所连接的PCI总线称为次总线,即主总线的子总线。

 

1.1.2 遍历

从Host/PCI桥开始进行探测和扫描,逐个“枚举”连接在第一条PCI总线上的所有设备并记录在案。如果其中的某个设备是PCI-PCI桥,则又进一步再探测和扫描连在这个桥上的次级PCI总线。就这样递归下去,直到穷尽系统中的所有PCI设备。其结果,是在内存中建立起一棵代表着这些PCI总线和设备的PCI树。

每个PCI设备(包括PCI桥设备)都由一个pci_dev结构体来表示,而每条PCI总线则由pci_bus结构来表示。

 

1.1.3 配置

PCI设备中一般都带有一些RAM和ROM 空间,通常的控制/状态寄存器和数据寄存器也往往以RAM区间的形式出现,而这些区间的地址在设备内部一般都是从0开始编址的,那么当总线上挂接了多个设备时,对这些空间的访问就会产生冲突。所以,这些地址都要先映射到系统总线上,再进一步映射到内核的虚拟地址空间。

配置就是通过对PCI配置空间的寄存器进行操作从而完成地址的映射。

 

1.1.4 数据结构

  pci_driver数据结构定义在:include/linux/pci.h文件中。

struct pci_driver {

        struct list_head node;

        const char *name;

        const struct pci_device_id *id_table;   /* must be non-NULL for probe to be called */

        int  (*probe)  (struct pci_dev *dev, const struct pci_device_id *id);   /* New device inserted */

        void (*remove) (struct pci_dev *dev);   /* Device removed (NULL if not a hot-plug capable driver) */

        int  (*suspend) (struct pci_dev *dev, pm_message_t state);      /* Device suspended */

        int  (*suspend_late) (struct pci_dev *dev, pm_message_t state);

        int  (*resume_early) (struct pci_dev *dev);

        int  (*resume) (struct pci_dev *dev);                   /* Device woken up */

        void (*shutdown) (struct pci_dev *dev);

        int (*sriov_configure) (struct pci_dev *dev, int num_vfs); /* PF pdev */

        const struct pci_error_handlers *err_handler;

        struct device_driver    driver;

        struct pci_dynids dynids;

};

 

  pci_dev也定义在include/linux/pci.h文件中。

详细描述了一个PCI设备几乎所有的硬件信息,包括厂商ID、设备ID、各种资源等.

struct pci_dev {

        struct list_head bus_list;      /* node in per-bus list */

        struct pci_bus  *bus;           /* bus this device is on */

        struct pci_bus  *subordinate;   /* bus this device bridges to */

 

        void            *sysdata;       /* hook for sys-specific extension */

        struct proc_dir_entry *procent; /* device entry in /proc/bus/pci */

        struct pci_slot *slot;          /* Physical slot this device is in */

 

        unsigned int    devfn;          /* encoded device & function index */

        unsigned short  vendor;

        unsigned short  device;

        unsigned short  subsystem_vendor;

        unsigned short  subsystem_device;

        unsigned int    class;          /* 3 bytes: (base,sub,prog-if) */

        u8              revision;       /* PCI revision, low byte of class word */

        u8              hdr_type;       /* PCI header type (`multi' flag masked out) */

        u8              pcie_cap;       /* PCI-E capability offset */

        u8              msi_cap;        /* MSI capability offset */

        u8              msix_cap;       /* MSI-X capability offset */

        u8              pcie_mpss:3;    /* PCI-E Max Payload Size Supported */

        u8              rom_base_reg;   /* which config register controls the ROM */

        u8              pin;            /* which interrupt pin this device uses */

        u16             pcie_flags_reg; /* cached PCI-E Capabilities Register */

 

        struct pci_driver *driver;      /* which driver has allocated this device */

        u64             dma_mask;       /* Mask of the bits of bus address this

                                           device implements.  Normally this is

                                           0xffffffff.  You only need to change

                                           this if your device has broken DMA

                                           or supports 64-bit transfers.  */

 

        struct device_dma_parameters dma_parms;

        pci_power_t     current_state;  /* Current operating state. In ACPI-speak,

                                           this is D0-D3, D0 being fully functional,

                                           and D3 being off. */

        u8              pm_cap;         /* PM capability offset */

        unsigned int    pme_support:5/* Bitmask of states from which PME#

                                           can be generated */

        unsigned int    pme_interrupt:1;

        unsigned int    pme_poll:1;     /* Poll device's PME status bit */

        unsigned int    d1_support:1;   /* Low power state D1 is supported */

        unsigned int    d2_support:1;   /* Low power state D2 is supported */

        unsigned int    no_d1d2:1;      /* D1 and D2 are forbidden */

        unsigned int    no_d3cold:1;    /* D3cold is forbidden */

        unsigned int    d3cold_allowed:1;       /* D3cold is allowed by user */

        unsigned int    mmio_always_on:1;       /* disallow turning off io/mem

                                                   decoding during bar sizing */

        unsigned int    wakeup_prepared:1;

        unsigned int    runtime_d3cold:1;       /* whether go through runtime

                                                   D3cold, not set for devices

                                                   powered on/off by the

                                                   corresponding bridge */

        unsigned int    d3_delay;       /* D3->D0 transition time in ms */

        unsigned int    d3cold_delay;   /* D3cold->D0 transition time in ms */

 

#ifdef CONFIG_PCIEASPM

        struct pcie_link_state  *link_state;    /* ASPM link state. */

#endif

 

        pci_channel_state_t error_state;        /* current connectivity state */

        struct  device  dev;            /* Generic device interface */

 

        int             cfg_size;       /* Size of configuration space */

 

        /*

         * Instead of touching interrupt line and base address registers

         * directly, use the values stored here. They might be different!

         */

        unsigned int    irq;

        struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */

 

        bool match_driver;              /* Skip attaching driver */

        /* These fields are used by common fixups */

        unsigned int    transparent:1/* Transparent PCI bridge */

        unsigned int    multifunction:1;/* Part of multi-function device */

        /* keep track of device state */

        unsigned int    is_added:1;

        unsigned int    is_busmaster:1; /* device is busmaster */

        unsigned int    no_msi:1;       /* device may not use msi */

        unsigned int    block_cfg_access:1;     /* config space access is blocked */

        unsigned int    broken_parity_status:1; /* Device generates false positive parity */

        unsigned int    irq_reroute_variant:2/* device needs IRQ rerouting variant */

        unsigned int    msi_enabled:1;

        unsigned int    msix_enabled:1;

        unsigned int    ari_enabled:1/* ARI forwarding */

        unsigned int    is_managed:1;

        unsigned int    is_pcie:1;      /* Obsolete. Will be removed.

                                           Use pci_is_pcie() instead */

        unsigned int    needs_freset:1; /* Dev requires fundamental reset */

        unsigned int    state_saved:1;

        unsigned int    is_physfn:1;

        unsigned int    is_virtfn:1;

        unsigned int    reset_fn:1;

        unsigned int    is_hotplug_bridge:1;

        unsigned int    __aer_firmware_first_valid:1;

        unsigned int    __aer_firmware_first:1;

        unsigned int    broken_intx_masking:1;

        unsigned int    io_window_1k:1; /* Intel P2P bridge 1K I/O windows */

        pci_dev_flags_t dev_flags;

        atomic_t        enable_cnt;     /* pci_enable_device has been called */

        u32             saved_config_space[16]; /* config space saved at suspend time */

        struct hlist_head saved_cap_space;

        struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */

        int rom_attr_enabled;           /* has display of the rom attribute been enabled? */

        struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */

        struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */

#ifdef CONFIG_PCI_MSI

        struct list_head msi_list;

        struct kset *msi_kset;

#endif

        struct pci_vpd *vpd;

#ifdef CONFIG_PCI_ATS

        union {

                struct pci_sriov *sriov;        /* SR-IOV capability related */

                struct pci_dev *physfn; /* the PF this VF is associated with */

        };

        struct pci_ats  *ats;   /* Address Translation Service */

#endif

        phys_addr_t rom; /* Physical address of ROM if it's not from the BAR */

        size_t romlen; /* Length of ROM if it's not from the BAR */

};

 

static inline struct pci_dev *pci_physfn(struct pci_dev *dev)

{

#ifdef CONFIG_PCI_IOV

        if (dev->is_virtfn)

                dev = dev->physfn;

#endif

 

        return dev;

}

 

1.1.5 pci初始化流程

pci这块代码在两个地方,一个是driver/pci另一个是arch/x86/pci中。

1.1.5.1  关于入口

pci系统中入口函数处理subsys_initcall之外,还有arch_initcall,postcore_initcall等等。

pci系统的初始化工作有内核来完成,在drivers/pci/probe.c文件中,调用postcore_initcall(pcibus_class_init);函数,在sys/class/下创建一个pci_bus目录

drivers/pci/pci-driver.c文件,postcore_initcall(pci_driver_init); 注册pci总线,并在/sys/bus/下创建了一个pci目录

drivers/pci/pci-acpi.c文件中,调用arch_initcall(acpi_pci_init);

arch/x86/pci/init.c文件中

arch_initcall(pci_arch_init);体系架构相关,对于64 bit x86来说使用CONFIG_PCI_DIRECT的方式进行访问PCI配置空间。在内核编译时候可以指定。

drivers/pci/slot.c文件中,subsys_initcall(pci_slot_init); 创建/sys/bus/slots文件。

 


目录
相关文章
|
1月前
|
Shell Linux C语言
【Shell 命令集合 设备管理 】Linux 创建设备文件 MAKEDEV命令 使用指南
【Shell 命令集合 设备管理 】Linux 创建设备文件 MAKEDEV命令 使用指南
33 0
|
1月前
|
监控 Linux Shell
【Shell 命令集合 网络通讯 】Linux管理终端设备的登录过程 getty命令 使用指南
【Shell 命令集合 网络通讯 】Linux管理终端设备的登录过程 getty命令 使用指南
33 0
|
1月前
|
监控 Linux Shell
【Shell 命令集合 磁盘维护 】Linux 交换分区的特殊文件或设备 swapon命令使用指南
【Shell 命令集合 磁盘维护 】Linux 交换分区的特殊文件或设备 swapon命令使用指南
38 1
|
1月前
|
存储 Shell Linux
【Shell 命令集合 磁盘维护 】Linux 创建一个用作交换空间(swap space)的特殊文件或设备 mkswap命令使用教程
【Shell 命令集合 磁盘维护 】Linux 创建一个用作交换空间(swap space)的特殊文件或设备 mkswap命令使用教程
33 0
|
1月前
|
安全 Shell Linux
【Shell 命令集合 网络通讯 】Linux 打开终端设备 mingetty命令 使用指南
【Shell 命令集合 网络通讯 】Linux 打开终端设备 mingetty命令 使用指南
39 0
|
15天前
|
网络协议 Linux SDN
虚拟网络设备与Linux网络协议栈
在现代计算环境中,虚拟网络设备在实现灵活的网络配置和隔离方面发挥了至关重要的作用🔧,特别是在容器化和虚拟化技术广泛应用的今天🌐。而Linux网络协议栈则是操作系统处理网络通信的核心💻,它支持广泛的协议和网络服务🌍,确保数据正确地在网络中传输。本文将深入分析虚拟网络设备与Linux网络协议栈的关联,揭示它们如何共同工作以支持复杂的网络需求。
|
16天前
|
存储 缓存 固态存储
Linux设备全览:从字符到块,揭秘每种设备的秘密
在Linux的世界里,设备是构成系统的基础,它们使得计算机能够与外界互动。Linux设备可以大致分为几种类型,每种类型都有其独特的特性和用途。🌌让我们一起探索这些设备类型及其特性。
|
1月前
|
Shell Linux C语言
【Shell 命令集合 系统设置 】Linux 配置鼠标设备的相关设置 mouseconfig命令 使用指南
【Shell 命令集合 系统设置 】Linux 配置鼠标设备的相关设置 mouseconfig命令 使用指南
37 0
|
1月前
|
存储 编解码 Shell
【Shell 命令集合 系统设置 】⭐Linux 设置和调整帧缓冲设备 fbset命令 使用指南
【Shell 命令集合 系统设置 】⭐Linux 设置和调整帧缓冲设备 fbset命令 使用指南
30 0
|
1月前
|
存储 安全 Linux
【Shell 命令集合 设备管理 】Linux 更改根文件系统的设备号 rdev命令 使用指南
【Shell 命令集合 设备管理 】Linux 更改根文件系统的设备号 rdev命令 使用指南
31 0