PCIe Port 总线驱动

2.1 关于本指南

本指南介绍了PCI Express Port Bus驱动程序的基础知识,并提供了如何使服务驱动程序向PCI Express Port Bus driver注册/注销的信息。

2.2 什么是PCIe端口总线驱动程序 

PCI Express Port是一种逻辑PCI-PCI桥接结构。有两种类型的PCI Express端口:Root Port 和 Switch Port。Root Port从PCI Express根Complex生成PCI Express链接,而Switch Port将PCI Express链接连接到内部逻辑PCI总线。switch端口,它的副总线代表了switch的内部路由逻辑,被称为swicth的上行端口。switch的下行端口从switch的内部路由总线桥接到PCI Express switch下行PCI Express链路的总线。

根据端口类型的不同,PCI Express Port最多可以提供四种不同的功能,在本文档中称为服务。PCI Express Port的服务包括本地热插拔支持(HP)、电源管理事件支持(PME)、高级错误报告支持(AER)和虚拟通道支持(VC)。这些服务可以由单个复杂的驱动程序处理,也可以由相应的服务驱动程序单独分发和处理。

2.3 为什么使用PCI Express端口总线驱动程序?

在现有的Linux内核中,Linux设备驱动程序模型只允许单个驱动程序处理物理设备。PCI Express Port是具有多种不同服务的PCI-PCI桥接设备。为了维护一个干净和简单的解决方案,每个服务可能都有自己的软件服务驱动程序。在这种情况下,多个服务驱动程序将竞争单个PCI-PCI桥设备。例如,如果首先加载PCI Express根端口热插拔服务驱动程序,那么它将声明一个PCI-PCI桥根端口。因此,内核不会为该根端口加载其他服务驱动程序。换句话说,不可能使用当前驱动程序模型在PCI-PCI Bridge设备上同时加载和运行多个服务驱动程序。

要启用多个服务驱动程序同时运行,需要有一个PCI Express Port Bus驱动程序,该驱动程序管理所有填充的PCI Express Ports,并根据需要将所有提供的服务请求分发给相应的服务驱动程序。使用PCI Express Port Bus驱动程序的一些关键优势如下:

  • 允许多个服务驱动程序在PCI-PCI桥端口设备上同时运行。
  • 允许以独立的分阶段方法实现的服务驱动程序。
  • 允许一个服务驱动程序在多个PCI-PCI桥端口设备上运行。
  • 管理和分配PCI-PCI桥端口设备的资源到请求的服务驱动程序。

2.4 配置PCI Express端口总线驱动程序与服务驱动程序

2.4.1 将PCI Express Port 总线驱动支持包含到内核中 

是否包含PCI Express端口总线驱动程序取决于内核配置中是否包含PCI Express支持。当在内核中启用PCI Express支持时,内核将自动包含PCI Express Port Bus驱动作为内核驱动程序。

2.4.2 启用service驱动支持

基于Linux设备驱动程序模型实现了PCI设备驱动程序。所有服务驱动程序都是PCI设备驱动程序。如上所述,一旦内核加载了PCI Express端口总线驱动程序,就不可能加载任何服务驱动程序。要满足PCI Express端口总线驱动程序模型,需要对现有服务驱动程序进行一些最小的更改,而这些更改不会影响现有服务驱动程序的功能。

服务驱动程序需要使用下面所示的两个api来将其服务注册到PCI Express Port Bus驱动程序。重要的是,服务驱动程序在调用这些api之前初始化头文件/include/linux/pcieport_if.h中包含的pcie_port_service_driver数据结构。如果不这样做,将导致标识不匹配,从而阻止PCI Express Port Bus驱动程序加载服务驱动程序。

2.4.2.1 pcie_port_service_register

int pcie_port_service_register(struct pcie_port_service_driver *new)

这个API替换了Linux驱动模型的pci_register_driver API。服务驱动程序应该总是在模块init上调用pcie_port_service_register。注意,在加载服务驱动程序之后,像pci_enable_device(dev)和pci_set_master(dev)这样的调用就不再需要了,因为这些调用是由PCI Port Bus驱动程序执行的。

2.4.2.2 pcie_port_service_unregister

void pcie_port_service_unregister(struct pcie_port_service_driver *new)

pcie_port_service_unregister替换Linux驱动模型的pci_unregister_driver。它总是在模块退出时被服务驱动程序调用。

2.4.2.3 Sample Code

下面是初始化port service driver数据结构的示例代码。

static struct pcie_port_service_id service_id[] = { {
  .vendor = PCI_ANY_ID,   .device = PCI_ANY_ID,   .port_type = PCIE_RC_PORT,
  .service_type = PCIE_PORT_SERVICE_AER, }, { /* end: all zeroes */ } }; static struct pcie_port_service_driver root_aerdrv = { .name = (char *)device_name, .id_table = &service_id[0], .probe = aerdrv_load, .remove = aerdrv_unload, .suspend = aerdrv_suspend, .resume = aerdrv_resume, };

下面是注册/注销服务驱动程序的示例代码。

static int __init aerdrv_service_init(void)
{
    int retval = 0;

    retval = pcie_port_service_register(&root_aerdrv);
    if (!retval) {
      /*
      * FIX ME
      */
    }
    return retval;
}

static void __exit aerdrv_service_exit(void)
{
    pcie_port_service_unregister(&root_aerdrv);
}

module_init(aerdrv_service_init);
module_exit(aerdrv_service_exit);

 

2.5 可能的资源冲突

由于PCI-PCI Bridge Port设备的所有服务驱动程序都允许同时运行,下面列出了一些与建议的解决方案可能发生的资源冲突。

2.5.1  MSI 和 MSI-X Vector Resource

一旦MSI或MSI- x中断在设备上被启用,它将保持在该模式,直到它们再次被禁用。由于相同PCI-PCI Bridge端口的服务驱动共享相同的物理设备,如果单个服务驱动启用或禁用MSI/MSI- x模式,可能会导致不可预知的行为。

为了避免这种情况,所有的服务驱动程序都不允许在其设备上切换中断模式。PCI Express Port Bus驱动程序负责确定中断模式,这对服务驱动程序是透明的。服务驱动只需要知道分配给结构体pcie_device的字段IRQ的矢量IRQ,当PCI Express Port Bus驱动探测每个服务驱动时,传入这个字段。服务驱动应该使用(struct pcie_device*)dev->irq来调用request_irq/free_irq。此外,中断模式存储在struct pcie_device的interrupt_mode字段中。

2.5.2 PCI Memory/IO 映射区域

PCI Express端口上用于访问PCI配置空间的PME、AER、HP和VC服务驱动程序。在所有情况下,被访问的寄存器都是相互独立的。这个补丁假定所有的服务驱动程序都是良好的,并且不会覆盖其他服务驱动程序的配置设置。

2.5.3 PCI配置寄存器

除了PCI Express结构外,每个服务驱动程序都在自己的这个补丁假定所有的服务驱动程序都是良好的,并且不会覆盖其他服务驱动程序的配置设置。这个补丁假定所有的服务驱动程序都是良好的,并且不会覆盖其他服务驱动程序的配置设置。

上一篇:实验6 虚拟局域网(VLAN)实验


下一篇:半实物仿真测试平台技术指标及案例