第21章PCI设备驱动之PCI总线与配置空间

本文详细介绍了Linux系统中PCI设备驱动的相关知识,包括PCI总线的结构、配置空间、pci_driver结构体及其成员函数,以及PCI设备的Linux描述。文中讲解了PCI总线的层次式体系结构,如Host/PCI桥、PCI/ISA桥和PCI-to-PCI桥,还探讨了PCI设备的描述结构pci_dev。此外,还涉及了PCI DMA相关的API和其他常用驱动函数。
摘要由CSDN通过智能技术生成
本章重点

    PCI 总线在一般的小型手持设备中不太可能用到,但在工控和通信设备及其 PC 中却引领着潮流。在 Linux 系统中,PCI 设备驱动和 USB 设备驱动有共性,其驱动都由总线相关部分自身设备类型驱动两部分组成。

1、 PCI 总线及其配置空间, PCI 总线在 Linux 内核中的数据结构。PCI 设备驱动的 PCI 相关部分围绕着 pci_driver 结构体的成员函数展开,

2、 pci_driver 结构体及其成员函数的含义,分析PCI设备驱动的框架结构。

21.1 PCI总线与配置空间

21.1.1 PCI总线的 Linux 描述

    PCI 是 CPU 和外围设备通信的高速传输总线。PCI 规范能够实现 32 位并行数据传输,工作频率为 33MHz 或 66MHz,最大吞吐率达 266MB/s。


    PCI 总线体系结构是一种层次式的体系结构,在层次式体系结构中,PCI 桥设备占据着重要的地位,它将父总线与子总线连接在一起。树的顶端是系统的 CPU,它通过一个较为特殊的 PCI 桥设备 — Host/PCI 桥设备与根 PCI 总线连接起来。

    作为一种特殊的 PCI 设备,PCI 桥包括以下几种。

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

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

    PCI-to-PCI 桥:用于连接 PCI 主总线(primary bus)与次总线(secondary bus)。PCI 桥所处的 PCI 总线称为“主总线”(即次总线的父总线),桥设备所连接的 PCI 总线称为“次总线”(即主总线的子总线)。

    在 Linux 系统中,PCI 总线用 pci_bus 来描述,这个结构体记录了本 PCI 总线的信息以及本PCI 总线的父总线、子总线、桥设备信息,这个结构体的定义如代码清单 21.1 所示。

代码清单 21.1 pci_bus 结构体

include/linux/pci.h

 struct pci_bus {
         struct list_head node; /* 链表元素 node */
         struct pci_bus *parent; /*指向该 PCI 总线的父总线,即 PCI 桥所在的总线 */
         struct list_head children; /* 描述了这条 PCI 总线的子总线链表的表头 */
         struct list_head devices; /* 描述了这条 PCI 总线的逻辑设备链表的表头 */
         struct pci_dev *self; /* 指向引出这条 PCI 总线的桥设备的 pci_dev 结构 */
         struct resource *resource[PCI_BUS_NUM_RESOURCES];
         /* 指向应路由到这条 PCI 总线的地址空间资源 */

         struct pci_ops *ops; /* 这条 PCI 总线所使用的配置空间访问函数 */
         void *sysdata; /* 指向系统特定的扩展数据 */
         struct proc_dir_entry *procdir;/*该 PCI 总线在/proc/bus/pci 中对应的目录项*/

         unsigned char number; /* 这条 PCI 总线的总线编号 */
         unsigned char primary; /* 桥设备的主总线 */
         unsigned char secondary; /* PCI 总线的桥设备的次总线号 */

         unsigned char subordinate;/*PCI 总线的下属 PCI 总线的总线编号最大值*/

        char name[48];

         unsigned short bridge_ctl;
         pci_bus_flags_t bus_flags;
         struct device *bridge;
         struct class_device class_dev;
         struct bin_attribute *legacy_io;
         struct bin_attribute *legacy_mem;
         unsigned int is_added:1;
 };

    假定一个如图 21.1 所示的 PCI 总线系统,根总线 0 上有一个 PCI 桥,它引出子总线 Bus 1,Bus 1 上又有一个 PCI 桥引出 Bus 2。


    在上图中,Bus 0 总线的 pci_bus 结构体中的 number、primary、secondary 都应该为 0,因为它是通过 Host/PCI 桥引出的根总线;Bus 1 总线的 pci_bus 结构体中的 number 和 secondary 都为 1,但是它的 primary 应该为 0;Bus 2 总线的 pci_bus 结构体中的 number 和 secondary 都应该为 2,而其 primary 则应该等于 1。这 3 条总线的 subordinate 值都应该等于 2。

    系统中当前存在的所有根总线都通过其 pci_bus 结构体中的 node 成员链接成一条全局的根总线链表,其表头由 list 类型的全局变量 pci_root_buses 来描述。而根总线下面的所有下级总线通过其 pci_bus 结构体中的 node 成员链接到其父总线的 children 链表中。这样,通过这两种 PCI总线链表,Linux 内核就将所有的 pci_bus 结构体以一种倒置树的方式组织起来。

    假定对于如图 21.2所示的多根 PCI 总线体系结构,它所对应的总线链表结构将如图 21.3 所示。



21.1.2 PCI 设备的 Linux 描述

    在 Linux 系统中,所有种类的 PCI 设备用 pci_dev 结构体来描述,由于一个 PCI 接口卡上可能包含多个功能模块,每个功能被当作一个独立的逻辑设备,因此,每一个 PCI 功能,即PCI 逻辑设备都惟一地对应一个 pci_dev 设备描述符,该结构体的定义如代码清单 21.2 所示。

代码清单 21.2 pci_dev 结构体

include/linux/pci.h

/*
 * The pci_dev structure is used to describe PCI devices.
 */
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;       /* PCIe capability offset */
        u8              msi_cap;        /* MSI capability offset */
        u8              msix_cap;       /* MSI-X capability offset */
        u8              pcie_mpss:3;    /* PCIe 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 PCIe Capabilities Register */
        u8              dma_alias_devfn;/* devfn of DMA alias, if any */


        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    ignore_hotplug:1;       /* Ignore hotplug events */
        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    tran

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值