什么是 PCI_SLOT 宏?

问题描述 投票:0回答:1

我不明白插槽是什么意思。 它是来自 dbdf(Domain:bus:device:function) 的设备号?

来自这里的代码:: https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/pci.h#L32

/*
 * The PCI interface treats multi-function devices as independent
 * devices.  The slot/function address of each device is encoded
 * in a single byte as follows:
 *
 *  7:3 = slot
 *  2:0 = function
 */
#define PCI_DEVFN(slot, func)   ((((slot) & 0x1f) << 3) | ((func) & 0x07))
#define PCI_SLOT(devfn)     (((devfn) >> 3) & 0x1f)
#define PCI_FUNC(devfn)     ((devfn) & 0x07)
linux-kernel linux-device-driver pci
1个回答
0
投票

每个 PCI 外围设备由总线号、设备号和功能标识 数字。每辆巴士最多可容纳 32 设备,每个设备可以是一个多功能板(如音频设备与 随附的 CD-ROM 驱动器)最多具有八个功能。所以, 每个功能都可以通过 16 位地址或密钥在硬件级别进行识别。

不过,为 Linux 编写的设备驱动程序不需要处理这些二进制地址, 因为它们使用特定的数据结构,称为 pci_dev,来作用于设备。

如评论所述:

PCI接口将多功能设备视为独立设备。

多功能板中的独立设备具有相同的设备号,又名PCI_SLOT(devfn),被视为一个物理插槽,称为pci_slot。

让我们深入研究代码以展示 PCI 外设的组织方式。

//in drivers/pci/probe.c
pci_scan_child_bus_extend() 

    //...
    dev_dbg(&bus->dev, "scanning bus\n");

    /* Go find them, Rover! */
    for (devfn = 0; devfn < 256; devfn += 8)
        pci_scan_slot(bus, devfn);

   //...

每个设备可以是一个最多八个功能的多功能板,也就是说一个物理pci_slot最多可以承载8个独立的pci_dev,所以linux扫描slot的步骤是8.

// in drivers/pci/probe.c
int pci_scan_slot(struct pci_bus *bus, int devfn)
{
    //...
    do {
        dev = pci_scan_single_device(bus, devfn + fn);
        if (dev) {
            if (!pci_dev_is_added(dev))
                nr++;
            if (fn > 0)
                dev->multifunction = 1;
        } else if (fn == 0) {
            /*
             * Function 0 is required unless we are running on
             * a hypervisor that passes through individual PCI
             * functions.
             */
            if (!hypervisor_isolated_pci_functions())
                break;
        }
        fn = next_fn(bus, dev, fn);
    } while (fn >= 0);

如果多功能板有多个功能,Linux 将扫描每个功能并为其分配一个 pci_dev 结构。对于非多功能板,只会分配一个 pci_dev。

pci_scan_child_bus()
    +-> pci_scan_child_bus_extend()
        +-> for (devfn = 0; devfn < 256; devfn += 8)
               pci_scan_slot()
                    +-> pci_scan_single_device()
                        +-> pci_scan_device()
                            +-> pci_bus_read_dev_vendor_id()
                            +-> pci_alloc_dev()
                            +-> pci_setup_device()
                                +-> pci_dev_assign_slot(dev);
                                    dev->slot = slot;

最后,多功能板中所有具有相同设备号的pci_dev将链接到同一个pci_slot。

参考:

  1. Linux 设备驱动程序,第 3 版
  2. https://elixir.bootlin.com/linux/v6.4-rc1/source/drivers/pci/probe.c#L2666
© www.soinside.com 2019 - 2024. All rights reserved.