Проверка, вызываемая для каждого VF в драйвере SR-IOV. Как мне определить, является ли это PF или VF?

#linux-kernel #linux-device-driver #pci #pci-e

#linux-ядро #linux-device-driver #pci #pci-e

Вопрос:

Это отправная точка для драйвера SR-IOV, над которым я работаю. Я никогда раньше не делал драйвер PCIe, поэтому многое из этого я выясняю, что, черт возьми, происходит. В этом драйвере я ищу конкретный идентификатор поставщика и просто загружаю драйвер, затем я печатаю кучу материала в файле журнала, чтобы посмотреть, что произошло. Он загружается, и я могу видеть PF и 4 VF при запуске lspci.

Чего я не ожидал (вероятно, потому, что я не думал об этом), так это того, что функция probe будет выполняться для каждого VF. Пример кода Intel, который я вижу повсюду, имеет в своей структуре элемент .sriov_configure. Я думал, что это будет вызвано, но этого не происходит, так что, возможно, я сделал что-то не так здесь.

Мой вопрос в том, что, поскольку я хочу выполнить определенные действия в probe для PF и некоторые другие вещи, когда я смотрю на VF, каков «правильный» метод для определения, является ли этот конкретный экземпляр probe для 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, amp;vendorid); 
   return vendorid; 
}

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

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

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

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

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

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

static u16 em_get_num_vf( struct pci_dev *pdev)
{
   u16 resu<
   pci_read_config_word(pdev, SR_IOV_CAP_BASE_ADDR PCI_SRIOV_NUM_VF, amp;result);
   return resu<
}

static u16 em_get_total_vf( struct pci_dev *pdev)
{
   u16 resu<
   pci_read_config_word(pdev, SR_IOV_CAP_BASE_ADDR PCI_SRIOV_TOTAL_VF, amp;result);
   return resu<
}

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

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

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

   if ((err = pci_request_regions(pdev, em_DEV_NAME)) < 0) {
        dev_err(dev, "pci_request_regions error %dn", 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           = 0xXn", vendorid);
   printk (KERN_ALERT "em: DEVICE_ID           = 0xXn", deviceid);
   printk (KERN_ALERT "em: SUBSYSTEM_ID        = 0xXn", subsystemid);
   printk (KERN_ALERT "em: SUBSYSTEM VENDOR ID = 0xXn", 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 %lun",
            (unsigned long)em_dev.regs_len);
        goto region_release;
    }

   printk (KERN_ALERT "em: Address Start : 0x6Xn", em_dev.regs_start);
   printk (KERN_ALERT "em: Address End   : 0x6Xn", em_dev.regs_end);
   printk (KERN_ALERT "em: Address Length: 0x6Xn", em_dev.regs_len);
   printk (KERN_ALERT "em: Address Base  : 0x6Xn", em_dev.regs_base_addr);

   em_dev.numvf = pci_num_vf(pdev);
   printk (KERN_ALERT "em: PCI NUM VF before enable sriov: 0x6Xn", 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: 0x6Xn", 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  : 0xXn", em_dev.sriov_capid); 
   printk (KERN_ALERT "em: SR-IOV CapVer : 0xXn", em_dev.sriov_capver); 


   printk(KERN_ALERT "em: EXIT <-- em_proben");
   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_configuren"); 
   if (numvfs > 0) {
      printk(KERN_ALERT "em: NUMVFS > 0 em_sriov_configuren");
      pci_enable_sriov(dev,numvfs);
      return numvfs;
   }

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


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 initializen"); 

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

    return 0;

exit:
   return err;

} 

static void em_exit(void) 
{ 
   printk(KERN_ALERT "em: em exitn");
   pci_unregister_driver(amp;em_pci_driver);
} 

module_init(em_init); 
module_exit(em_exit);
  

Ответ №1:

каков «правильный» метод для определения, предназначен ли этот конкретный экземпляр probe для PF или VF?

Вы можете использовать эти простые условные обозначения

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