/* * Read all of the groups statistics information. * * IN: * @groups: The lists of groups. * @device_name: The given device name. */ int read_all_groups(cg_group_lists* groups, const char* device_name) { int ret = 0, level; void *handle; struct cgroup_file_info info; cg_group* group = NULL; if (!groups || !device_name) { fprintf(stderr, "rd_stats: the input parameters is invalid.\n"); return -1; } /** Clear the history information.*/ clear_group(groups); /** Start the traversing of the directory. */ ret = cgroup_walk_tree_begin(device_name, BASE_DIR, DEPTH, &handle, &info, &level); if (ret) goto err; /** Walk to the next. */ while (!(ret = cgroup_walk_tree_next(0, &handle, &info, level))) { if (info.type == CGROUP_FILE_TYPE_DIR) { /** Initialized the group but the cpuset statistics information and the io * statistics information is NULL.*/ if ((ret = init_group(&group, info.path, info.full_path))) { #ifdef DEBUG fprintf(stderr, "rd_stats: initialize the group failed, group name: %s, path: %s.\n", info.path, info.full_path); #endif goto err; } /** Add the group into the lists.*/ if (group && add_group(groups, group)) { #ifdef DEBUG fprintf(stderr, "rd_stats: add the group into lists failed, group name: %s, path: %s.\n", info.path, info.full_path); #endif goto err; } group = NULL; } } /** End the traversing.*/ cgroup_walk_tree_end(&handle); return 0; err: if (group) uninit_group(group); group = NULL; clear_group(groups); cgroup_walk_tree_end(&handle); return ret; }
/* * Uninitialized the head of groups. * * IN: * @group_lists: The structure of cgroup_group_lists. */ void uninit_group_lists(cg_group_lists* group_lists) { if (!group_lists) return; if (!TAILQ_EMPTY(group_lists)) clear_group(group_lists); if (group_lists) free(group_lists); }
int rte_vfio_setup_device(const char *sysfs_base, const char *dev_addr, int *vfio_dev_fd, struct vfio_device_info *device_info) { struct vfio_group_status group_status = { .argsz = sizeof(group_status) }; int vfio_group_fd; int iommu_group_no; int ret; /* get group number */ ret = vfio_get_group_no(sysfs_base, dev_addr, &iommu_group_no); if (ret == 0) { RTE_LOG(WARNING, EAL, " %s not managed by VFIO driver, skipping\n", dev_addr); return 1; } /* if negative, something failed */ if (ret < 0) return -1; /* get the actual group fd */ vfio_group_fd = vfio_get_group_fd(iommu_group_no); if (vfio_group_fd < 0) return -1; /* if group_fd == 0, that means the device isn't managed by VFIO */ if (vfio_group_fd == 0) { RTE_LOG(WARNING, EAL, " %s not managed by VFIO driver, skipping\n", dev_addr); return 1; } /* * at this point, we know that this group is viable (meaning, all devices * are either bound to VFIO or not bound to anything) */ /* check if the group is viable */ ret = ioctl(vfio_group_fd, VFIO_GROUP_GET_STATUS, &group_status); if (ret) { RTE_LOG(ERR, EAL, " %s cannot get group status, " "error %i (%s)\n", dev_addr, errno, strerror(errno)); close(vfio_group_fd); clear_group(vfio_group_fd); return -1; } else if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE)) { RTE_LOG(ERR, EAL, " %s VFIO group is not viable!\n", dev_addr); close(vfio_group_fd); clear_group(vfio_group_fd); return -1; } /* check if group does not have a container yet */ if (!(group_status.flags & VFIO_GROUP_FLAGS_CONTAINER_SET)) { /* add group to a container */ ret = ioctl(vfio_group_fd, VFIO_GROUP_SET_CONTAINER, &vfio_cfg.vfio_container_fd); if (ret) { RTE_LOG(ERR, EAL, " %s cannot add VFIO group to container, " "error %i (%s)\n", dev_addr, errno, strerror(errno)); close(vfio_group_fd); clear_group(vfio_group_fd); return -1; } /* * pick an IOMMU type and set up DMA mappings for container * * needs to be done only once, only when first group is * assigned to a container and only in primary process. * Note this can happen several times with the hotplug * functionality. */ if (internal_config.process_type == RTE_PROC_PRIMARY && vfio_cfg.vfio_active_groups == 1) { /* select an IOMMU type which we will be using */ const struct vfio_iommu_type *t = vfio_set_iommu_type(vfio_cfg.vfio_container_fd); if (!t) { RTE_LOG(ERR, EAL, " %s failed to select IOMMU type\n", dev_addr); close(vfio_group_fd); clear_group(vfio_group_fd); return -1; } ret = t->dma_map_func(vfio_cfg.vfio_container_fd); if (ret) { RTE_LOG(ERR, EAL, " %s DMA remapping failed, error %i (%s)\n", dev_addr, errno, strerror(errno)); close(vfio_group_fd); clear_group(vfio_group_fd); return -1; } } } /* get a file descriptor for the device */ *vfio_dev_fd = ioctl(vfio_group_fd, VFIO_GROUP_GET_DEVICE_FD, dev_addr); if (*vfio_dev_fd < 0) { /* if we cannot get a device fd, this implies a problem with * the VFIO group or the container not having IOMMU configured. */ RTE_LOG(WARNING, EAL, "Getting a vfio_dev_fd for %s failed\n", dev_addr); close(vfio_group_fd); clear_group(vfio_group_fd); return -1; } /* test and setup the device */ ret = ioctl(*vfio_dev_fd, VFIO_DEVICE_GET_INFO, device_info); if (ret) { RTE_LOG(ERR, EAL, " %s cannot get device info, " "error %i (%s)\n", dev_addr, errno, strerror(errno)); close(*vfio_dev_fd); close(vfio_group_fd); clear_group(vfio_group_fd); return -1; } vfio_group_device_get(vfio_group_fd); return 0; } int rte_vfio_release_device(const char *sysfs_base, const char *dev_addr, int vfio_dev_fd) { struct vfio_group_status group_status = { .argsz = sizeof(group_status) }; int vfio_group_fd; int iommu_group_no; int ret; /* get group number */ ret = vfio_get_group_no(sysfs_base, dev_addr, &iommu_group_no); if (ret <= 0) { RTE_LOG(WARNING, EAL, " %s not managed by VFIO driver\n", dev_addr); /* This is an error at this point. */ return -1; } /* get the actual group fd */ vfio_group_fd = vfio_get_group_fd(iommu_group_no); if (vfio_group_fd <= 0) { RTE_LOG(INFO, EAL, "vfio_get_group_fd failed for %s\n", dev_addr); return -1; } /* At this point we got an active group. Closing it will make the * container detachment. If this is the last active group, VFIO kernel * code will unset the container and the IOMMU mappings. */ /* Closing a device */ if (close(vfio_dev_fd) < 0) { RTE_LOG(INFO, EAL, "Error when closing vfio_dev_fd for %s\n", dev_addr); return -1; } /* An VFIO group can have several devices attached. Just when there is * no devices remaining should the group be closed. */ vfio_group_device_put(vfio_group_fd); if (!vfio_group_device_count(vfio_group_fd)) { if (close(vfio_group_fd) < 0) { RTE_LOG(INFO, EAL, "Error when closing vfio_group_fd for %s\n", dev_addr); return -1; } if (clear_group(vfio_group_fd) < 0) { RTE_LOG(INFO, EAL, "Error when clearing group for %s\n", dev_addr); return -1; } } return 0; } int rte_vfio_enable(const char *modname) { /* initialize group list */ int i; int vfio_available; for (i = 0; i < VFIO_MAX_GROUPS; i++) { vfio_cfg.vfio_groups[i].fd = -1; vfio_cfg.vfio_groups[i].group_no = -1; vfio_cfg.vfio_groups[i].devices = 0; } /* inform the user that we are probing for VFIO */ RTE_LOG(INFO, EAL, "Probing VFIO support...\n"); /* check if vfio module is loaded */ vfio_available = rte_eal_check_module(modname); /* return error directly */ if (vfio_available == -1) { RTE_LOG(INFO, EAL, "Could not get loaded module details!\n"); return -1; } /* return 0 if VFIO modules not loaded */ if (vfio_available == 0) { RTE_LOG(DEBUG, EAL, "VFIO modules not loaded, " "skipping VFIO support...\n"); return 0; } vfio_cfg.vfio_container_fd = vfio_get_container_fd(); /* check if we have VFIO driver enabled */ if (vfio_cfg.vfio_container_fd != -1) { RTE_LOG(NOTICE, EAL, "VFIO support initialized\n"); vfio_cfg.vfio_enabled = 1; } else { RTE_LOG(NOTICE, EAL, "VFIO support could not be initialized\n"); } return 0; } int rte_vfio_is_enabled(const char *modname) { const int mod_available = rte_eal_check_module(modname) > 0; return vfio_cfg.vfio_enabled && mod_available; } const struct vfio_iommu_type * vfio_set_iommu_type(int vfio_container_fd) { unsigned idx; for (idx = 0; idx < RTE_DIM(iommu_types); idx++) { const struct vfio_iommu_type *t = &iommu_types[idx]; int ret = ioctl(vfio_container_fd, VFIO_SET_IOMMU, t->type_id); if (!ret) { RTE_LOG(NOTICE, EAL, " using IOMMU type %d (%s)\n", t->type_id, t->name); return t; } /* not an error, there may be more supported IOMMU types */ RTE_LOG(DEBUG, EAL, " set IOMMU type %d (%s) failed, " "error %i (%s)\n", t->type_id, t->name, errno, strerror(errno)); } /* if we didn't find a suitable IOMMU type, fail */ return NULL; }