PCIE subsystem

PCIE Subsystem Framework

PCIe (Peripheral Component Interconnect Express) is a high-speed serial bus standard used to connect computer peripherals. The PCIE subsystem framework is the basic framework used by the Linux kernel to support drivers for PCIe devices. It includes a series of interfaces and functions that allow driver developers to more easily write, test, and debug drivers for PCIe devices.

The core of the PCIE subsystem framework is the PCIe bus driver, which is responsible for managing functions such as initialization, configuration, addressing, and access of the PCIe bus. Driver developers can use the interface provided by the PCIe bus driver to register PCIe device drivers, handle interrupts, read and write registers, and DMA operations, etc. In addition, the PCIe subsystem framework also provides some auxiliary functions and macro definitions to simplify the driver's writing process.

Some important interfaces and functions of the PCIE subsystem framework include:

pci_register_driver()/pci_unregister_driver():用于注册和注销PCIe设备驱动程序。

pci_enable_device()/pci_disable_device():用于启用和禁用PCIe设备,并分配和释放设备资源。

pci_request_regions()/pci_release_regions():用于请求和释放设备的I/O端口、内存映射和中断资源等。

pci_iomap()/pci_iounmap():用于映射和解除映射设备的I/O端口或内存空间。

pci_enable_msi()/pci_disable_msi():用于启用和禁用设备的MSI(Message Signaled Interrupts)中断。

pci_irq_vector():用于获取设备的中断向量。

pci_map_sg()/pci_unmap_sg():用于将设备内存映射到散列表中。

pci_dma_sync_sg_for_cpu()/pci_dma_sync_sg_for_device():用于同步DMA缓冲区和设备内存之间的数据传输。

pci_set_drvdata()/pci_get_drvdata():用于存储和获取设备特定数据的指针。

Using the PCIE Subsystem Framework, driver developers can develop drivers for PCIe devices more quickly and with fewer errors and failures.

The following are some commonly used interface functions in the PCIe subsystem:

pci_register_driver() 和 pci_unregister_driver():分别用于注册和注销 PCI 驱动程序。

pci_enable_device() 和 pci_disable_device():分别用于启用和禁用 PCI 设备。

pci_request_region() 和 pci_release_region():分别用于请求和释放 PCI 区域。

pci_request_irq() 和 pci_free_irq():分别用于请求和释放 PCI 设备的中断。

pci_set_master() 和 pci_clear_master():分别用于设置和清除 PCI 设备的总线主控模式。

pci_enable_msi() 和 pci_disable_msi():分别用于启用和禁用 PCI 设备的 MSI 中断。

pci_enable_msix() 和 pci_disable_msix():分别用于启用和禁用 PCI 设备的 MSIX 中断。

pci_enable_sriov() 和 pci_disable_sriov():分别用于启用和禁用 PCI 设备的 SR-IOV 功能。

pci_find_capability() 和 pci_read_config_dword():分别用于查找和读取 PCI 设备的配置寄存器。

pci_set_drvdata() 和 pci_get_drvdata():分别用于设置和获取 PCI 设备的私有数据。

pci_save_state() 和 pci_restore_state():分别用于保存和恢复 PCI 设备的状态。

pci_bus_read_config_byte() 和 pci_bus_write_config_byte():分别用于读取和写入 PCI 总线的配置寄存器。

pci_find_device() 和 pci_find_slot():分别用于查找指定设备ID或槽位号的PCI设备。

pci_get_domain_bus_and_slot():用于查找指定域、总线和槽位号的PCI设备。

These interface functions can access the PCI bus through the PCI subsystem framework to develop the PCI device driver.

sample program

The following is a sample code of a simple PCIe driver, including device tree and driver code.

Device tree:

/dts-v1/;
/include/ "dtsi/pinctrl-jetson-io.h"

/ {
    
    
    model = "NVIDIA Jetson Nano Developer Kit";
    compatible = "nvidia,jetson-nano-pcie", "nvidia,jetson-nano";

    fragment@0 {
    
    
        target = <&pcie>;

        __overlay__ {
    
    
            status = "okay";
            num-lanes = <1>;
            max-speed = <2>;
            bus-range = <0 1>;
            ranges = <0x02000000 0 0x80000000 0x80000000 0 0x1000000>; // 2GB window

            mydevice: mydevice@0,0 {
    
    
                compatible = "mycompany,mydevice";
                reg = <0x0 0x0 0x0 0x0>;
            };
        };
    };
};

Driver code:

#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>

static const struct pci_device_id mydevice_pci_ids[] = {
    
    
    {
    
     PCI_DEVICE(0x1234, 0x5678) },
    {
    
     0, }
};

MODULE_DEVICE_TABLE(pci, mydevice_pci_ids);

static int mydevice_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
    
    
    int ret;

    /* enable the device */
    ret = pci_enable_device(pdev);
    if (ret < 0) {
    
    
        dev_err(&pdev->dev, "failed to enable device\n");
        return ret;
    }

    /* configure the device */
    pci_set_master(pdev);

    /* register a platform device */
    ret = platform_device_register_simple("mydevice", -1, NULL, 0);
    if (ret < 0) {
    
    
        dev_err(&pdev->dev, "failed to register platform device\n");
        pci_disable_device(pdev);
        return ret;
    }

    return 0;
}

static void mydevice_remove(struct pci_dev *pdev)
{
    
    
    /* unregister the platform device */
    platform_device_unregister(platform_device_find("mydevice", -1));

    /* disable the device */
    pci_disable_device(pdev);
}

static struct pci_driver mydevice_driver = {
    
    
    .name = "mydevice",
    .id_table = mydevice_pci_ids,
    .probe = mydevice_probe,
    .remove = mydevice_remove,
};

module_pci_driver(mydevice_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("My PCIe device driver");

This driver will look for a PCIe device with ID 0x1234:0x5678 and create a platform device mydevice for it. Platform devices are also automatically deregistered when the device is removed.

Guess you like

Origin blog.csdn.net/qq_31057589/article/details/130512623