为 SR-IOV 驱动程序中的每个 VF 调用探测。我如何判断这是 PF 还是 VF?

Probe called for each VF in an SR-IOV driver. How do I tell if this is the PF or the VF?

这是我正在开发的 SR-IOV 驱动程序的起点。我以前从来没有做过 PCIe 驱动程序,所以很多这都是我弄清楚到底发生了什么。在这个驱动程序中,我寻找一个特定的供应商 ID 并加载驱动程序,然后我在日志文件中打印一堆东西以查看发生了什么。它加载并且当我 运行 lspci 时我可以看到 PF 和 4 VF。

我没想到(可能是因为我没想到)是每个 VF 的探测函数 运行。我在各处看到的 Intel 示例代码在其结构中都有一个 .sriov_configure 成员。我以为会被调用,但实际上并没有,所以也许我在这里做错了。

我的问题是,因为我想在 PF 探测中做某些事情,而当我查看 VF 时想做一些其他事情,"correct" 确定这个特定探测实例是否存在的方法是什么是 PF 还是 VF?

为了完整起见,下面是日志(很多日志)和来源。您可以看到 em_probe 被多次调用。 提前致谢。

[   10.516072] em: em initialize
[   10.526026] em: ENTER --> em_probe
[   10.546857] pci_em 0000:04:00.0: enabling device (0100 -> 0102)
[   10.571659] em: ====== em CONFIG SPACE ======
[   10.583073] em: VENDOR_ID           = 0x1172
[   10.593789] em: DEVICE_ID           = 0xBEAD
[   10.604454] em: SUBSYSTEM_ID        = 0x0011
[   10.615089] em: SUBSYSTEM VENDOR ID = 0xABCD
[   10.625698] em: Address Start : 0x00000000FBE00000
[   10.636847] em: Address End   : 0x00000000FBEFFFFF
[   10.670164] em: Address Length: 0x0000000000100000
[   10.681285] em: Address Base  : 0x000000000000E000
[   10.692352] em: PCI NUM VF before enable sriov: 0x0000000000000000
[   10.805976] em: ENTER --> em_probe
[   10.805984] pci_em 0000:04:00.1: enabling device (0000 -> 0002)
[   10.805997] em: ====== em CONFIG SPACE ======
[   10.805998] em: VENDOR_ID           = 0xFFFF
[   10.805999] em: DEVICE_ID           = 0xFFFF
[   10.806001] em: SUBSYSTEM_ID        = 0x0011
[   10.806002] em: SUBSYSTEM VENDOR ID = 0xABCD
[   10.806015] em: Address Start : 0x0000000090000000
[   10.806016] em: Address End   : 0x0000000090000FFF
[   10.806018] em: Address Length: 0x0000000000001000
[   10.806019] em: Address Base  : 0x0000000000396000
[   10.806020] em: PCI NUM VF before enable sriov: 0x0000000000000000
[   10.806021] em: PCI NUM VF after enable sriov: 0x0000000000000000
[   10.806025] em: SR-IOV CapID  : 0x0000
[   10.806026] em: SR-IOV CapVer : 0x0000
[   10.806027] em: EXIT <-- em_probe
[   10.807806] em: ENTER --> em_probe
[   10.807855] pci_em 0000:04:00.2: enabling device (0000 -> 0002)
[   10.807933] em: ====== em CONFIG SPACE ======
[   10.807934] em: VENDOR_ID           = 0xFFFF
[   10.807935] em: DEVICE_ID           = 0xFFFF
[   10.807938] em: SUBSYSTEM_ID        = 0x0011
[   10.807940] em: SUBSYSTEM VENDOR ID = 0xABCD
[   10.808018] em: Address Start : 0x0000000090001000
[   10.808019] em: Address End   : 0x0000000090001FFF
[   10.808026] em: Address Length: 0x0000000000001000
[   10.808027] em: Address Base  : 0x00000000003A6000
[   10.808033] em: PCI NUM VF before enable sriov: 0x0000000000000000
[   10.808035] em: PCI NUM VF after enable sriov: 0x0000000000000000
[   10.808046] em: SR-IOV CapID  : 0x0000
[   10.808048] em: SR-IOV CapVer : 0x0000
[   10.808049] em: EXIT <-- em_probe
[   10.811562] em: ENTER --> em_probe
[   10.811637] pci_em 0000:04:00.3: enabling device (0000 -> 0002)
[   10.811734] em: ====== em CONFIG SPACE ======
[   10.811735] em: VENDOR_ID           = 0xFFFF
[   10.811750] em: DEVICE_ID           = 0xFFFF
[   10.811751] em: SUBSYSTEM_ID        = 0x0011
[   10.811765] em: SUBSYSTEM VENDOR ID = 0xABCD
[   10.812144] em: Address Start : 0x0000000090002000
[   10.812151] em: Address End   : 0x0000000090002FFF
[   10.812158] em: Address Length: 0x0000000000001000
[   10.812162] em: Address Base  : 0x00000000003CC000
[   10.812172] em: PCI NUM VF before enable sriov: 0x0000000000000000
[   10.812180] em: PCI NUM VF after enable sriov: 0x0000000000000000
[   10.812184] em: SR-IOV CapID  : 0x0000
[   10.812185] em: SR-IOV CapVer : 0x0000
[   10.812185] em: EXIT <-- em_probe
[   10.812609] em: ENTER --> em_probe
[   10.812615] pci_em 0000:04:00.4: enabling device (0000 -> 0002)
[   10.812626] em: ====== em CONFIG SPACE ======
[   10.812627] em: VENDOR_ID           = 0xFFFF
[   10.812628] em: DEVICE_ID           = 0xFFFF
[   10.812629] em: SUBSYSTEM_ID        = 0x0011
[   10.812630] em: SUBSYSTEM VENDOR ID = 0xABCD
[   10.812648] em: Address Start : 0x0000000090003000
[   10.812649] em: Address End   : 0x0000000090003FFF
[   10.812650] em: Address Length: 0x0000000000001000
[   10.812651] em: Address Base  : 0x00000000003EE000
[   10.812652] em: PCI NUM VF before enable sriov: 0x0000000000000000
[   10.812653] em: PCI NUM VF after enable sriov: 0x0000000000000000
[   10.812657] em: SR-IOV CapID  : 0x0000
[   10.812658] em: SR-IOV CapVer : 0x0000
[   10.812659] em: EXIT <-- em_probe
[   10.812695] em: PCI NUM VF after enable sriov: 0x0000000000000004
[   10.812698] em: SR-IOV CapID  : 0x0010
[   10.812699] em: SR-IOV CapVer : 0x0001
[   10.812700] em: EXIT <-- em_probe



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

#define em_DEV_NAME "em"
#define NR_VIRTFN 4
#define SR_IOV_CAP_BASE_ADDR 0x200

MODULE_LICENSE("GPL"); 

static struct pci_device_id em_ids[] = {
    {PCI_DEVICE(0x1172,PCI_ANY_ID)},
   {0},
};
MODULE_DEVICE_TABLE(pci, em_ids);


static struct {
    /* (mmio) control registers i.e. the "register memory region" */
    void __iomem *regs_base_addr;
    resource_size_t regs_start;
   resource_size_t regs_end;
    resource_size_t regs_len;
   resource_size_t regs_flags;
   resource_size_t regs_sys_page_size;
   u16             sriov_capid;
   u16             sriov_capver;
   u16             numvf;
   u16             totalvf;
   /* irq handling */
    unsigned int irq;
} em_dev;

static u16 em_get_vendorid( struct pci_dev *pdev) 
{ 
   u16 vendorid; 
   pci_read_config_word( pdev, PCI_VENDOR_ID, &vendorid); 
   return vendorid; 
}

static u16 em_get_deviceid( struct pci_dev *pdev) 
{ 
   u16 deviceid; 
   pci_read_config_word( pdev, PCI_DEVICE_ID, &deviceid); 
   return deviceid; 
}

static unsigned char em_get_revision( struct pci_dev *pdev) 
{ 
   u8 revision; 
   pci_read_config_byte( pdev, PCI_REVISION_ID, &revision); 
   return revision; 
}

static u16 em_get_subsystemid( struct pci_dev *pdev) 
{ 
   u16 subsystemid; 
   pci_read_config_word( pdev, PCI_SUBSYSTEM_ID, &subsystemid); 
   return subsystemid; 
}

static u16 em_get_subsystemvendorid( struct pci_dev *pdev) 
{ 
   u16 subsystemvendorid; 
   pci_read_config_word( pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystemvendorid); 
   return subsystemvendorid; 
}

static u16 em_get_iov_capid( struct pci_dev *pdev)
{
   u16 result;
   pci_read_config_word(pdev, SR_IOV_CAP_BASE_ADDR, &result);
   return result;
}

static u16 em_get_iov_version( struct pci_dev *pdev)
{
   u16 result;
   pci_read_config_word(pdev, SR_IOV_CAP_BASE_ADDR+2, &result);
   result = result & 0x000F;
   return result;
}

static u16 em_get_num_vf( struct pci_dev *pdev)
{
   u16 result;
   pci_read_config_word(pdev, SR_IOV_CAP_BASE_ADDR+PCI_SRIOV_NUM_VF, &result);
   return result;
}

static u16 em_get_total_vf( struct pci_dev *pdev)
{
   u16 result;
   pci_read_config_word(pdev, SR_IOV_CAP_BASE_ADDR+PCI_SRIOV_TOTAL_VF, &result);
   return result;
}

static int em_probe(struct pci_dev *pdev,
             const struct pci_device_id *pdev_id)
{
   printk(KERN_ALERT "em: ENTER --> em_probe\n");
   u16 subsystemid;
   u16 subvendorid;
   u16 vendorid;
   u16 deviceid;

   int err;
    struct device *dev = &pdev->dev;

    if ((err = pci_enable_device(pdev))) {
        dev_err(dev, "em: pci_enable_device probe error %d for device %s\n",
            err, pci_name(pdev));
        return err;
    }

   if ((err = pci_request_regions(pdev, em_DEV_NAME)) < 0) {
        dev_err(dev, "pci_request_regions error %d\n", err);
        goto pci_disable;
    }

   subsystemid = em_get_subsystemid(pdev);
   subvendorid = em_get_subsystemvendorid(pdev);
   vendorid = em_get_vendorid(pdev);
   deviceid = em_get_deviceid(pdev);

   printk (KERN_ALERT "em: ====== em CONFIG SPACE ======\n");
   printk (KERN_ALERT "em: VENDOR_ID           = 0x%04X\n", vendorid);
   printk (KERN_ALERT "em: DEVICE_ID           = 0x%04X\n", deviceid);
   printk (KERN_ALERT "em: SUBSYSTEM_ID        = 0x%04X\n", subsystemid);
   printk (KERN_ALERT "em: SUBSYSTEM VENDOR ID = 0x%04X\n", subvendorid);

   /* bar0: control registers */
    em_dev.regs_start = pci_resource_start(pdev, 0);
   em_dev.regs_end = pci_resource_end(pdev, 0);
    em_dev.regs_len = pci_resource_len(pdev, 0);
    em_dev.regs_base_addr = pci_iomap(pdev, 0, 0x100);

    if (!em_dev.regs_base_addr) {
        dev_err(dev, "em: cannot ioremap registers of size %lu\n",
            (unsigned long)em_dev.regs_len);
        goto region_release;
    }

   printk (KERN_ALERT "em: Address Start : 0x%016X\n", em_dev.regs_start);
   printk (KERN_ALERT "em: Address End   : 0x%016X\n", em_dev.regs_end);
   printk (KERN_ALERT "em: Address Length: 0x%016X\n", em_dev.regs_len);
   printk (KERN_ALERT "em: Address Base  : 0x%016X\n", em_dev.regs_base_addr);

   em_dev.numvf = pci_num_vf(pdev);
   printk (KERN_ALERT "em: PCI NUM VF before enable sriov: 0x%016X\n", em_dev.numvf);

   pci_enable_sriov(pdev, NR_VIRTFN);

   em_dev.numvf = pci_num_vf(pdev);
   printk (KERN_ALERT "em: PCI NUM VF after enable sriov: 0x%016X\n", em_dev.numvf);

   em_dev.sriov_capid = em_get_iov_capid(pdev);
   em_dev.sriov_capver = em_get_iov_version(pdev);
   em_dev.totalvf = em_get_total_vf(pdev);
   printk (KERN_ALERT "em: SR-IOV CapID  : 0x%04X\n", em_dev.sriov_capid); 
   printk (KERN_ALERT "em: SR-IOV CapVer : 0x%04X\n", em_dev.sriov_capver); 


   printk(KERN_ALERT "em: EXIT <-- em_probe\n");
   return 0;
map_release:
   pci_iounmap(pdev, em_dev.regs_base_addr);
region_release:
   pci_release_regions(pdev);
pci_disable:
    pci_disable_device(pdev);
    return -EBUSY;
}

// Validate that the error path in em_probe is modeled after this 
// remove function.  Everything needs to be backed out in order and cleanly
// or we leave reserved memory in the kernel
static void em_remove(struct pci_dev *pdev)
{
   pci_enable_sriov(pdev, NR_VIRTFN);
   pci_iounmap(pdev, em_dev.regs_base_addr);
   pci_release_regions(pdev);
   pci_disable_device(pdev);
}


static int em_sriov_configure(struct pci_dev *dev, int numvfs)
{
   printk(KERN_ALERT "em: ENTER --> em_sriov_configure\n"); 
   if (numvfs > 0) {
      printk(KERN_ALERT "em: NUMVFS > 0 em_sriov_configure\n");
      pci_enable_sriov(dev,numvfs);
      return numvfs;
   }

   if (numvfs == 0) {
      printk(KERN_ALERT "em: NUMVFS == 0 em_sriov_configure\n");
      pci_disable_sriov(dev);
      return 0;
   }
   printk(KERN_ALERT "em: EXIT <-- em_sriov_configure\n"); 
}


static struct pci_driver em_pci_driver = {
   .name = "pci_em",
   .id_table = em_ids,
   .probe = em_probe,
   .remove = em_remove,
   .sriov_configure = em_sriov_configure,
};


static int em_init(void) 
{ 
   int err = -ENOMEM;
   printk(KERN_ALERT "em: em initialize\n"); 

   /* register pci device driver */
    if ((err = pci_register_driver(&em_pci_driver)) < 0) {
        pr_err("em: pci_register_driver error\n");
        goto exit;
    }

    return 0;

exit:
   return err;

} 

static void em_exit(void) 
{ 
   printk(KERN_ALERT "em: em exit\n");
   pci_unregister_driver(&em_pci_driver);
} 

module_init(em_init); 
module_exit(em_exit);

what is the "correct" method for determining if this particular instance of probe is for a PF or a VF?

您可以使用这些简单的条件

if (pdev->is_physfn) { .... }
if (pdev->is_virtfn) { .... }