ixgbe 如何开启vf

    xiaoxiao2021-04-12  54

    在drivers/net/ethernet/intel/ixgbe/ixgbe_main.c 中会注册一个pci driver static struct pci_driver ixgbe_driver = {     .name     = ixgbe_driver_name,     .id_table = ixgbe_pci_tbl,     .probe    = ixgbe_probe,     .remove   = ixgbe_remove, #ifdef CONFIG_PM     .suspend  = ixgbe_suspend,     .resume   = ixgbe_resume, #endif     .shutdown = ixgbe_shutdown,     .sriov_configure = ixgbe_pci_sriov_configure,     .err_handler = &ixgbe_err_handler };  每个pcie设备都有一个pci_driver。其中提供了一个sriov_configure 用于开启vf。 int ixgbe_pci_sriov_configure(struct pci_dev *dev, int num_vfs) {     if (num_vfs == 0)         return ixgbe_pci_sriov_disable(dev);     else         return ixgbe_pci_sriov_enable(dev, num_vfs); } ixgbe_pci_sriov_configure 接受两个参数,一个是struct pci_dev *dev 代表这个pcie 设备,也就是pf,int num_vfs 也就是需要开启的vf的序列号,因为一个pf可以支持多个vf,所以要选择启动哪个vf.pf支持的vf个数是在sriov_init 中就已经初始化好的. 如果num_vfs 不是0的话,就调用ixgbe_pci_sriov_enable static int ixgbe_pci_sriov_enable(struct pci_dev *dev, int num_vfs) { #ifdef CONFIG_PCI_IOV     struct ixgbe_adapter *adapter = pci_get_drvdata(dev);     int err = 0;     int i;     int pre_existing_vfs = pci_num_vf(dev);     err = pci_enable_sriov(dev, num_vfs);     if (err) {         e_dev_warn("Failed to enable PCI sriov: %d\n", err);         return err;     }     return num_vfs; #else     return 0; #endif } 要使用vf,kernel必须打开CONFIG_PCI_IOV。随后调用pci_enable_sriov来启动vf pci_enable_sriov->sriov_enable->pci_iov_add_virtfn int pci_iov_add_virtfn(struct pci_dev *dev, int id, int reset) {     int i;     int rc = -ENOMEM;     u64 size;     char buf[VIRTFN_ID_LEN];     struct pci_dev *virtfn;     struct resource *res;     struct pci_sriov *iov = dev->sriov;     struct pci_bus *bus;     mutex_lock(&iov->dev->sriov->lock); //得到vf的bus     bus = virtfn_add_bus(dev->bus, pci_iov_virtfn_bus(dev, id));     if (!bus)         goto failed; //申请一个struct pci_dev *virtfn; 作为vf,在kernel中用pci_dev 表示一个pcie end point,从这里能看出vf和pf在kernel中的结构体是一样的     virtfn = pci_alloc_dev(bus);     if (!virtfn)         goto failed0;     virtfn->devfn = pci_iov_virtfn_devfn(dev, id);     virtfn->vendor = dev->vendor;     pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_DID, &virtfn->device); //初始化virtfn     rc = pci_setup_device(virtfn);     if (rc)         goto failed0;     virtfn->dev.parent = dev->dev.parent;     virtfn->physfn = pci_dev_get(dev);     virtfn->is_virtfn = 1;     virtfn->multifunction = 0; //为vf准备bar资源,所以vf是有独立的bar资源的.     for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {         res = &dev->resource[i + PCI_IOV_RESOURCES];         if (!res->parent)             continue;         virtfn->resource[i].name = pci_name(virtfn);         virtfn->resource[i].flags = res->flags;         size = pci_iov_resource_size(dev, i + PCI_IOV_RESOURCES);         virtfn->resource[i].start = res->start + size * id;         virtfn->resource[i].end = virtfn->resource[i].start + size - 1;         rc = request_resource(res, &virtfn->resource[i]);         BUG_ON(rc);     }     if (reset)         __pci_reset_function(virtfn); //添加device     pci_device_add(virtfn, virtfn->bus);     mutex_unlock(&iov->dev->sriov->lock);     pci_bus_add_device(virtfn);     sprintf(buf, "virtfn%u", id); //为vf建立sysfs接口     rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf);     if (rc)         goto failed1;     rc = sysfs_create_link(&virtfn->dev.kobj, &dev->dev.kobj, "physfn");     if (rc)         goto failed2;     kobject_uevent(&virtfn->dev.kobj, KOBJ_CHANGE);     return 0; failed2:     sysfs_remove_link(&dev->dev.kobj, buf); failed1:     pci_dev_put(dev);     mutex_lock(&iov->dev->sriov->lock);     pci_stop_and_remove_bus_device(virtfn); failed0:     virtfn_remove_bus(dev->bus, bus); failed:     mutex_unlock(&iov->dev->sriov->lock);     return rc; }  总结一下,要使用vf必须通过pf中的sriov_configure,在kernel中vf和pf都是用pci_dev,且初始化的flow也都是一样的,也就是说vf是一个独立的pcie 设备.且vf本身自己拥有资源.
    转载请注明原文地址: https://ju.6miu.com/read-667311.html

    最新回复(0)