dpdk源码---vfio(zym)
主要想找到从nvme设备 到 vfio驱动的代码路径
[spdk/lib/nvme/nvme_pcie.c]
nvme_pcie_ctrlr_scan(struct spdk_nvme_probe_ctx *probe_ctx,bool direct_connect) (nvme_tcp,nvme_rdma等都有自己的scan,probe等函数,统一被封装起来,如下)
1 int nvme_transport_ctrlr_scan(struct spdk_nvme_probe_ctx *probe_ctx, 2 bool direct_connect) 3 { 4 NVME_TRANSPORT_CALL(probe_ctx->trid.trtype, ctrlr_scan, (probe_ctx, direct_connect)); 5 }
1.nvme_pcie_ctrl_scan:
1 int 2 nvme_pcie_ctrlr_scan(struct spdk_nvme_probe_ctx *probe_ctx, 3 bool direct_connect) 4 { 5 .......//若probe_ctx中有指定nvme pci id,has_pci_addr=true 6 if (enum_ctx.has_pci_addr == false) { 7 return spdk_pci_enumerate(spdk_pci_nvme_get_driver(),//若没有指定 8 pcie_nvme_enum_cb, &enum_ctx); 9 } else { 10 return spdk_pci_device_attach(spdk_pci_nvme_get_driver(),//指定了话直接attach 11 pcie_nvme_enum_cb, &enum_ctx, &enum_ctx.pci_addr); 12 } 13
spdk_pci_enumerate:
1 int 2 spdk_pci_enumerate(struct spdk_pci_driver *driver, 3 spdk_pci_enum_cb enum_cb, 4 void *enum_ctx) 5 { 6 struct spdk_pci_device *dev; 7 int rc; 8 9 cleanup_pci_devices(); 10 11 pthread_mutex_lock(&g_pci_mutex); 12 TAILQ_FOREACH(dev, &g_pci_devices, internal.tailq) { //遍历g_pci_devices 13 if (dev->internal.attached || 14 dev->internal.driver != driver || 15 dev->internal.pending_removal) { 16 continue; 17 } 18 19 rc = enum_cb(enum_ctx, dev);// 从g_pci_devices找到我们要的driver,那么调用回调函数进行后续的ctrl_construct工作 20 if (rc == 0) { 21 dev->internal.attached = true;//构建成功,attach设置为true 22 } else if (rc < 0) { 23 pthread_mutex_unlock(&g_pci_mutex); 24 return -1; 25 } 26 } 27 pthread_mutex_unlock(&g_pci_mutex); 28 29 if (!driver->is_registered) {//若改driver还没注册,那么register到rte_pci_bus.driver_list 30 driver->is_registered = true; 31 rte_pci_register(&driver->driver); 32 } 33 //上面不是找到了吗,下面这些是干啥?为啥要scan和probe??上面只是放到rte_pci_bus.driver_list了,后面还需做什么? 34 driver->cb_fn = enum_cb; 35 driver->cb_arg = enum_ctx; 36 37 if (rte_bus_scan() != 0 || rte_bus_probe() != 0) {//若bus scan和probe都不成功 38 driver->cb_arg = NULL; 39 driver->cb_fn = NULL; 40 return -1; 41 } 42 43 driver->cb_arg = NULL; 44 driver->cb_fn = NULL; 45 46 cleanup_pci_devices(); 47 return 0; 48 }
回调函数pcie_nvme_enum_cb:
主要是执行nvme_ctrlr_probe(&trid, enum_ctx->probe_ctx, pci_dev) 从而构建相应type的ctrl:nvme_transport_ctrlr_construct(trid, &opts, devhandle),这些不放在这里介绍,会在spdk的源码解读里面分析。
rte_pci_register:
1 /* register a driver */ 2 void 3 rte_pci_register(struct rte_pci_driver *driver) 4 { 5 TAILQ_INSERT_TAIL(&rte_pci_bus.driver_list, driver, next); 6 driver->bus = &rte_pci_bus; 7 }
//注意这个
struct rte_pci_bus rte_pci_bus = {
.bus = {
.scan = rte_pci_scan,
.probe = rte_pci_probe,
.find_device = pci_find_device,
.plug = pci_plug,
.unplug = pci_unplug,
.parse = pci_parse,
.dma_map = pci_dma_map,
.dma_unmap = pci_dma_unmap,
.get_iommu_class = rte_pci_get_iommu_class,
.dev_iterate = rte_pci_dev_iterate,
.hot_unplug_handler = pci_hot_unplug_handler,
.sigbus_handler = pci_sigbus_handler,
},
.device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list),
.driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
};
rte_bus_scan()和rte_bus_probe() 对所有bus进行scan和probe,若是pci_bus,执行的是上面注册的
.scan = rte_pci_scan,
.probe = rte_pci_probe,
回到 1 中的attach函数:
spdk_pci_device_attach:跟原来看的有些不一样,之前看的版本直接调用的是rte_pci_scan
1 int 2 spdk_pci_device_attach(struct spdk_pci_driver *driver, 3 spdk_pci_enum_cb enum_cb, 4 void *enum_ctx, struct spdk_pci_addr *pci_address) 5 { 6 struct spdk_pci_device *dev; 7 int rc; 8 char bdf[32]; 9 10 spdk_pci_addr_fmt(bdf, sizeof(bdf), pci_address); 11 12 cleanup_pci_devices(); 13 14 TAILQ_FOREACH(dev, &g_pci_devices, internal.tailq) { 15 if (spdk_pci_addr_compare(&dev->addr, pci_address) == 0) { 16 break; 17 } 18 } 19 20 if (dev != NULL && dev->internal.driver == driver) { 21 pthread_mutex_lock(&g_pci_mutex); 22 if (dev->internal.attached || dev->internal.pending_removal) { 23 pthread_mutex_unlock(&g_pci_mutex); 24 return -1; 25 } 26 27 rc = enum_cb(enum_ctx, dev);//执行construct ctrl等 28 if (rc == 0) { 29 dev->internal.attached = true; 30 } 31 pthread_mutex_unlock(&g_pci_mutex); 32 return rc; 33 } 34 35 if (!driver->is_registered) { 36 driver->is_registered = true; 37 rte_pci_register(&driver->driver);//register到rte_pci_bus.driver_list 38 } 39 40 driver->cb_fn = enum_cb; 41 driver->cb_arg = enum_ctx; 42 43 #if RTE_VERSION >= RTE_VERSION_NUM(18, 11, 0, 0) 44 int i = 0; 45 46 do { 47 rc = rte_eal_hotplug_add("pci", bdf, ""); 48 } while (rc == -ENOMSG && ++i <= DPDK_HOTPLUG_RETRY_COUNT); 49 50 if (i > 1 && rc == -EEXIST) { 51 /* Even though the previous request timed out, the device 52 * was attached successfully. 53 */ 54 rc = 0; 55 } 56 #else 57 rc = rte_eal_dev_attach(bdf, "");//这个函数在旧版本的dpdk中 58 #endif 59 60 driver->cb_arg = NULL; 61 driver->cb_fn = NULL; 62 63 cleanup_pci_devices(); 64 return rc == 0 ? 0 : -1; 65 }
rte_eal_hotplug_add:
--------rte_dev_probe(devargs)
1 int 2 rte_dev_probe(const char *devargs) 3 { 4 struct eal_dev_mp_req req; 5 struct rte_device *dev; 6 int ret; 7 8 memset(&req, 0, sizeof(req)); 9 req.t = EAL_DEV_REQ_TYPE_ATTACH; 10 strlcpy(req.devargs, devargs, EAL_DEV_MP_DEV_ARGS_MAX_LEN); 11 12 if (rte_eal_process_type() != RTE_PROC_PRIMARY) {//不是primary进程 13 /** 14 * If in secondary process, just send IPC request to 15 * primary process. 16 */ 17 ret = eal_dev_hotplug_request_to_primary(&req);//那么给primary进程发attch的请求 18 if (ret != 0) { 19 RTE_LOG(ERR, EAL, 20 "Failed to send hotplug request to primary\n"); 21 return -ENOMSG; 22 } 23 if (req.result != 0) 24 RTE_LOG(ERR, EAL, 25 "Failed to hotplug add device\n"); 26 return req.result; 27 } 28 29 /* attach a shared device from primary start from here: */ 31 /* primary attach the new device itself. */ 32 ret = local_dev_probe(devargs, &dev);//其中会执行da->bus->scan() 33 34 if (ret != 0) { 35 RTE_LOG(ERR, EAL, 36 "Failed to attach device on primary process\n"); 37 38 /** 39 * it is possible that secondary process failed to attached a 40 * device that primary process have during initialization, 41 * so for -EEXIST case, we still need to sync with secondary 42 * process. 43 */ 44 if (ret != -EEXIST) 45 return ret; 46 } 47 48 /* primary send attach sync request to secondary. */ 49 ret = eal_dev_hotplug_request_to_secondary(&req);//给secondary进程发消息同步attach情况 50 51 /* if any communication error, we need to rollback. */ 52 if (ret != 0) { 53 RTE_LOG(ERR, EAL, 54 "Failed to send hotplug add request to secondary\n"); 55 ret = -ENOMSG; 56 goto rollback; 57 } 59 /** 60 * if any secondary failed to attach, we need to consider if rollback 61 * is necessary. 62 */ 63 if (req.result != 0) { 64 RTE_LOG(ERR, EAL, 65 "Failed to attach device on secondary process\n"); 66 ret = req.result; 67 68 /* for -EEXIST, we don't need to rollback. */ 69 if (ret == -EEXIST) 70 return ret; 71 goto rollback; 72 } 73 74 return 0; 75 76 rollback: 77 req.t = EAL_DEV_REQ_TYPE_ATTACH_ROLLBACK; 78 79 /* primary send rollback request to secondary. */ 80 if (eal_dev_hotplug_request_to_secondary(&req) != 0) 81 RTE_LOG(WARNING, EAL, 82 "Failed to rollback device attach on secondary." 83 "Devices in secondary may not sync with primary\n"); 84 85 /* primary rollback itself. */ 86 if (local_dev_remove(dev) != 0) 87 RTE_LOG(WARNING, EAL, 88 "Failed to rollback device attach on primary." 89 "Devices in secondary may not sync with primary\n"); 90 91 return ret; 92 }
local_dev_probe:
最终也是调用rte_pci_scan和pci_probe_all_drivers
1 /* probe device at local process. */ 2 int 3 local_dev_probe(const char *devargs, struct rte_device **new_dev) 4 { 5 struct rte_device *dev; 6 struct rte_devargs *da; 7 int ret; 8 9 *new_dev = NULL; 10 da = calloc(1, sizeof(*da)); 11 if (da == NULL) 12 return -ENOMEM; 13 14 ret = rte_devargs_parse(da, devargs); 15 if (ret) 16 goto err_devarg; 17 18 if (da->bus->plug == NULL) { 19 RTE_LOG(ERR, EAL, "Function plug not supported by bus (%s)\n", 20 da->bus->name); 21 ret = -ENOTSUP; 22 goto err_devarg; 23 } 24 25 ret = rte_devargs_insert(&da); 26 if (ret) 27 goto err_devarg; 28 29 /* the rte_devargs will be referenced in the matching rte_device */ 30 ret = da->bus->scan();//pci的话执行register函数中注册的rte_pci_scan 31 if (ret) 32 goto err_devarg; 33 34 dev = da->bus->find_device(NULL, cmp_dev_name, da->name); 35 if (dev == NULL) { 36 RTE_LOG(ERR, EAL, "Cannot find device (%s)\n", 37 da->name); 38 ret = -ENODEV; 39 goto err_devarg; 40 } 41 /* Since there is a matching device, it is now its responsibility 42 * to manage the devargs we've just inserted. From this point 43 * those devargs shouldn't be removed manually anymore. 44 */ 45 46 ret = dev->bus->plug(dev);//rte_pci_plug中执行的是pci_probe_all_drivers(RTE_DEV_TO_PCI(dev)) 47 if (ret > 0) 48 ret = -ENOTSUP; 49 50 if (ret && !rte_dev_is_probed(dev)) { /* if hasn't ever succeeded */ 51 RTE_LOG(ERR, EAL, "Driver cannot attach the device (%s)\n", 52 dev->name); 53 return ret; 54 } 55 56 *new_dev = dev; 57 return ret; 58 59 err_devarg: 60 if (rte_devargs_remove(da) != 0) { 61 free(da->args); 62 free(da); 63 } 64 return ret; 65 }
所以 1 中 nvme_pcie_ctrl_scan 不管是spdk_pci_enumerate还是spdk_pci_device_attach,核心的流程都是一样的:
执行回调函数pcie_nvme_enum_cb;
rte_pci_scan
rte_pci_probe/pci_probe_all_drivers (rte_pci_probe也是调用pci_probe_all_drivers)
所以后面我们看 rte_pci_bus.scan(rte_pci_scan)和rte_pci_bus.probe(rte_pci_probe)的实现。
rte_pci_scan:
1 /*
2 * Scan the content of the PCI bus, and the devices in the devices
3 * list
4 */
5 int
6 rte_pci_scan(void)
7 {
8 struct dirent *e;
9 DIR *dir;
10 char dirname[PATH_MAX];
11 struct rte_pci_addr addr;
12
13 ........
14 dir = opendir(rte_pci_get_sysfs_path()); ///sys/bus/pci/devices
15
16 ........
17 while ((e = readdir(dir)) != NULL) {
18 if (e->d_name[0] == '.')
19 continue;
20
21 if (parse_pci_addr_format(e->d_name, sizeof(e->d_name), &addr) != 0)
22 continue;
23
24 snprintf(dirname, sizeof(dirname), "%s/%s",
25 rte_pci_get_sysfs_path(), e->d_name);
26
27 if (pci_scan_one(dirname, &addr) < 0)//扫描/sys/bus/pci/devices下面每个目录
28 goto error;
29 }
30 closedir(dir);
31 return 0;
32 ..........
33 }
ls /sys/bus/pci/devices/
0000:00:00.0 0000:00:04.4 0000:00:1c.6 0000:03:00.0 0000:ff:0d.1 0000:ff:12.2 0000:ff:14.5 0000:ff:17.6
0000:00:01.0 0000:00:04.5 0000:00:1c.7 0000:05:00.0 0000:ff:0f.0 0000:ff:12.4 0000:ff:14.6 0000:ff:17.7
1 /* Scan one pci sysfs entry, and fill the devices list from it. */ 2 static int 3 pci_scan_one(const char *dirname, const struct rte_pci_addr *addr) 4 { 5 char filename[PATH_MAX]; 6 unsigned long tmp; 7 struct rte_pci_device *dev; 8 char driver[PATH_MAX]; 9 int ret; 10 11 dev = malloc(sizeof(*dev)); 12 if (dev == NULL) 13 return -1; 14 15 memset(dev, 0, sizeof(*dev)); 16 dev->device.bus = &rte_pci_bus.bus; 17 dev->addr = *addr; 18 19 /* get vendor id */ 20 snprintf(filename, sizeof(filename), "%s/vendor", dirname); 21 if (eal_parse_sysfs_value(filename, &tmp) < 0) { 22 free(dev); 23 return -1; 24 } 25 dev->id.vendor_id = (uint16_t)tmp; 26 27 /* get device id */ 28 snprintf(filename, sizeof(filename), "%s/device", dirname); 29 if (eal_parse_sysfs_value(filename, &tmp) < 0) { 30 free(dev); 31 return -1; 32 } 33 dev->id.device_id = (uint16_t)tmp; 34 35 /* get subsystem_vendor id */ 36 snprintf(filename, sizeof(filename), "%s/subsystem_vendor", 37 dirname); 38 if (eal_parse_sysfs_value(filename, &tmp) < 0) { 39 free(dev); 40 return -1; 41 } 42 dev->id.subsystem_vendor_id = (uint16_t)tmp; 43 44 /* get subsystem_device id */ 45 snprintf(filename, sizeof(filename), "%s/subsystem_device", 46 dirname); 47 if (eal_parse_sysfs_value(filename, &tmp) < 0) { 48 free(dev); 49 return -1; 50 } 51 dev->id.subsystem_device_id = (uint16_t)tmp; 52 53 /* get class_id */ 54 snprintf(filename, sizeof(filename), "%s/class", 55 dirname); 56 if (eal_parse_sysfs_value(filename, &tmp) < 0) { 57 free(dev); 58 return -1; 59 } 60 /* the least 24 bits are valid: class, subclass, program interface */ 61 dev->id.class_id = (uint32_t)tmp & RTE_CLASS_ANY_ID; 62 63 /* get max_vfs */ 64 dev->max_vfs = 0; 65 snprintf(filename, sizeof(filename), "%s/max_vfs", dirname); 66 if (!access(filename, F_OK) && 67 eal_parse_sysfs_value(filename, &tmp) == 0) 68 dev->max_vfs = (uint16_t)tmp; 69 else { 70 /* for non igb_uio driver, need kernel version >= 3.8 */ 71 snprintf(filename, sizeof(filename), 72 "%s/sriov_numvfs", dirname); 73 if (!access(filename, F_OK) && 74 eal_parse_sysfs_value(filename, &tmp) == 0) 75 dev->max_vfs = (uint16_t)tmp; 76 } 77 78 /* get numa node, default to 0 if not present */ 79 snprintf(filename, sizeof(filename), "%s/numa_node", 80 dirname); 81 82 if (access(filename, F_OK) != -1) { 83 if (eal_parse_sysfs_value(filename, &tmp) == 0) 84 dev->device.numa_node = tmp; 85 else 86 dev->device.numa_node = -1; 87 } else { 88 dev->device.numa_node = 0; 89 } 90 91 pci_name_set(dev); 92 93 /* parse resources */ 94 snprintf(filename, sizeof(filename), "%s/resource", dirname); 95 if (pci_parse_sysfs_resource(filename, dev) < 0) { 96 RTE_LOG(ERR, EAL, "%s(): cannot parse resource\n", __func__); 97 free(dev); 98 return -1; 99 } 100 101 /* parse driver */ 102 snprintf(filename, sizeof(filename), "%s/driver", dirname);///sys/bus/pci/drivers 103 ret = pci_get_kernel_driver_by_path(filename, driver, sizeof(driver)); 104 if (ret < 0) { 105 RTE_LOG(ERR, EAL, "Fail to get kernel driver\n"); 106 free(dev); 107 return -1; 108 } 109 110 if (!ret) { 111 if (!strcmp(driver, "vfio-pci")) 112 dev->kdrv = RTE_KDRV_VFIO; 113 else if (!strcmp(driver, "igb_uio")) 114 dev->kdrv = RTE_KDRV_IGB_UIO; 115 else if (!strcmp(driver, "uio_pci_generic")) 116 dev->kdrv = RTE_KDRV_UIO_GENERIC; 117 else 118 dev->kdrv = RTE_KDRV_UNKNOWN; 119 } else 120 dev->kdrv = RTE_KDRV_NONE; 121 122 /* device is valid, add in list (sorted) */ 123 if (TAILQ_EMPTY(&rte_pci_bus.device_list)) { 124 rte_pci_add_device(dev); 125 } else { 126 struct rte_pci_device *dev2; 127 int ret; 128 129 TAILQ_FOREACH(dev2, &rte_pci_bus.device_list, next) { 130 ret = rte_pci_addr_cmp(&dev->addr, &dev2->addr); 131 if (ret > 0) 132 continue; 133 134 if (ret < 0) { 135 rte_pci_insert_device(dev2, dev); 136 } else { /* already registered */ 137 if (!rte_dev_is_probed(&dev2->device)) { 138 dev2->kdrv = dev->kdrv; 139 dev2->max_vfs = dev->max_vfs; 140 pci_name_set(dev2); 141 memmove(dev2->mem_resource, 142 dev->mem_resource, 143 sizeof(dev->mem_resource)); 144 } else { 145 /** 146 * If device is plugged and driver is 147 * probed already, (This happens when 148 * we call rte_dev_probe which will 149 * scan all device on the bus) we don't 150 * need to do anything here unless... 151 **/ 152 if (dev2->kdrv != dev->kdrv || 153 dev2->max_vfs != dev->max_vfs) 154 /* 155 * This should not happens. 156 * But it is still possible if 157 * we unbind a device from 158 * vfio or uio before hotplug 159 * remove and rebind it with 160 * a different configure. 161 * So we just print out the 162 * error as an alarm. 163 */ 164 RTE_LOG(ERR, EAL, "Unexpected device scan at %s!\n", 165 filename); 166 } 167 free(dev); 168 } 169 return 0; 170 } 171 172 rte_pci_add_device(dev); 173 } 174 175 return 0; 176 }
rte_pci_probe:
------FOREACH_DEVICE_ON_PCIBUS(dev) pci_probe_all_drivers(dev)
------------FOREACH_DRIVER_ON_PCIBUS(dr) rte_pci_probe_one_driver(dr, dev)
1 /* 2 * If vendor/device ID match, call the probe() function of the 3 * driver. 4 */ 5 static int 6 rte_pci_probe_one_driver(struct rte_pci_driver *dr, 7 struct rte_pci_device *dev) 8 { 9 int ret; 10 bool already_probed; 11 struct rte_pci_addr *loc; 12 13 if ((dr == NULL) || (dev == NULL)) 14 return -EINVAL; 15 16 loc = &dev->addr; 17 18 /* The device is not blacklisted; Check if driver supports it */ 19 if (!rte_pci_match(dr, dev)) 20 /* Match of device and driver failed */ 21 return 1; 22 23 RTE_LOG(INFO, EAL, "PCI device "PCI_PRI_FMT" on NUMA socket %i\n", 24 loc->domain, loc->bus, loc->devid, loc->function, 25 dev->device.numa_node); 26 27 /* no initialization when blacklisted, return without error */ 28 if (dev->device.devargs != NULL && 29 dev->device.devargs->policy == 30 RTE_DEV_BLACKLISTED) { 31 RTE_LOG(INFO, EAL, " Device is blacklisted, not" 32 " initializing\n"); 33 return 1; 34 } 35 36 if (dev->device.numa_node < 0) { 37 RTE_LOG(WARNING, EAL, " Invalid NUMA socket, default to 0\n"); 38 dev->device.numa_node = 0; 39 } 40 41 already_probed = rte_dev_is_probed(&dev->device); 42 if (already_probed && !(dr->drv_flags & RTE_PCI_DRV_PROBE_AGAIN)) { 43 RTE_LOG(DEBUG, EAL, "Device %s is already probed\n", 44 dev->device.name); 45 return -EEXIST; 46 } 47 48 RTE_LOG(INFO, EAL, " probe driver: %x:%x %s\n", dev->id.vendor_id, 49 dev->id.device_id, dr->driver.name); 50 51 /* 52 * reference driver structure 53 * This needs to be before rte_pci_map_device(), as it enables to use 54 * driver flags for adjusting configuration. 55 */ 56 if (!already_probed) { 57 enum rte_iova_mode dev_iova_mode; 58 enum rte_iova_mode iova_mode; 59 60 dev_iova_mode = pci_device_iova_mode(dr, dev);//从设备绑定的驱动判断dev_iova_mode,例如若是UIO驱动,则这里是PA 61 iova_mode = rte_eal_iova_mode();//dpdk初始化过程判断的,首先会去判断设备的驱动,如果驱动还没注册,那么里面是根据机器上是否有iommu等判断。而spdk中nvme
驱动是在dpdk初始化之后才注册进去的,所以即使是用uio驱动,dpdk给出的iova_mode也是VA,所以这里有点小问题!
62 if (dev_iova_mode != RTE_IOVA_DC && 63 dev_iova_mode != iova_mode) { 64 RTE_LOG(ERR, EAL, " Expecting '%s' IOVA mode but current mode is '%s', not initializing\n", 65 dev_iova_mode == RTE_IOVA_PA ? "PA" : "VA", 66 iova_mode == RTE_IOVA_PA ? "PA" : "VA"); 67 return -EINVAL; 68 } 69 70 dev->driver = dr; 71 } 72 73 if (!already_probed && (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)) { 74 /* map resources for devices that use igb_uio */???注释有问题?? 75 ret = rte_pci_map_device(dev); 76 if (ret != 0) { 77 dev->driver = NULL; 78 return ret; 79 } 80 } 81 82 /* call the driver probe() function */ 83 ret = dr->probe(dr, dev); //在哪里????? 84 if (already_probed) 85 return ret; /* no rollback if already succeeded earlier */ 86 if (ret) { 87 dev->driver = NULL; 88 if ((dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING) && 89 /* Don't unmap if device is unsupported and 90 * driver needs mapped resources. 91 */ 92 !(ret > 0 && 93 (dr->drv_flags & RTE_PCI_DRV_KEEP_MAPPED_RES))) 94 rte_pci_unmap_device(dev); 95 } else { 96 dev->device.driver = &dr->driver; 97 } 98 99 return ret; 100 }
rte_pci_map_device 从这遍开始和vfio,uio等相关
1 /* Map pci device */ 2 int 3 rte_pci_map_device(struct rte_pci_device *dev) 4 { 5 int ret = -1; 6 7 /* try mapping the NIC resources using VFIO if it exists */ 8 switch (dev->kdrv) { 9 case RTE_KDRV_VFIO: 10 #ifdef VFIO_PRESENT 11 if (pci_vfio_is_enabled()) 12 ret = pci_vfio_map_resource(dev); 13 #endif 14 break; 15 case RTE_KDRV_IGB_UIO: 16 case RTE_KDRV_UIO_GENERIC: 17 if (rte_eal_using_phys_addrs()) { 18 /* map resources for devices that use uio */ 19 ret = pci_uio_map_resource(dev); 20 } 21 break; 22 default: 23 RTE_LOG(DEBUG, EAL, 24 " Not managed by a supported kernel driver, skipped\n"); 25 ret = 1; 26 break; 27 } 28 29 return ret; 30 }
pci_vfio_map_resource:
---1---pci_vfio_map_resource_primary 若设primary进程
------pci_vfio_map_resource_secondary
-------2---------rte_vfio_setup_device
------------3------------vfio_mem_event_callback
这三个函数要重点看。。。。