1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <fcntl.h> 3 #include <unistd.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <linux/limits.h> 7 8 #include <libvfio.h> 9 10 #define readlink_safe(_path, _buf) ({ \ 11 int __ret; \ 12 \ 13 _Static_assert(!__builtin_types_compatible_p( \ 14 __typeof__(_buf), char *), \ 15 "readlink_safe: _buf must be an array, not a pointer"); \ 16 \ 17 __ret = readlink(_path, _buf, sizeof(_buf) - 1); \ 18 if (__ret != -1) \ 19 _buf[__ret] = 0; \ 20 __ret; \ 21 }) 22 23 static void readlink_base(const char *path, const char *data_fmt, void *out_data) 24 { 25 char rl_path[PATH_MAX]; 26 int ret; 27 28 ret = readlink_safe(path, rl_path); 29 VFIO_ASSERT_NE(ret, -1); 30 31 ret = sscanf(basename(rl_path), data_fmt, out_data); 32 VFIO_ASSERT_EQ(ret, 1); 33 } 34 35 static int sysfs_val_get_int(const char *component, const char *name, 36 const char *file) 37 { 38 char path[PATH_MAX]; 39 char buf[32]; 40 int ret; 41 int fd; 42 43 snprintf_assert(path, PATH_MAX, "/sys/bus/pci/%s/%s/%s", component, name, file); 44 fd = open(path, O_RDONLY); 45 if (fd < 0) 46 return fd; 47 48 VFIO_ASSERT_GT(read(fd, buf, ARRAY_SIZE(buf)), 0); 49 VFIO_ASSERT_EQ(close(fd), 0); 50 51 errno = 0; 52 ret = strtol(buf, NULL, 0); 53 VFIO_ASSERT_EQ(errno, 0, "sysfs path \"%s\" is not an integer: \"%s\"\n", path, buf); 54 55 return ret; 56 } 57 58 static void sysfs_val_set(const char *component, const char *name, 59 const char *file, const char *val) 60 { 61 char path[PATH_MAX]; 62 int fd; 63 64 snprintf_assert(path, PATH_MAX, "/sys/bus/pci/%s/%s/%s", component, name, file); 65 VFIO_ASSERT_GT(fd = open(path, O_WRONLY), 0); 66 67 VFIO_ASSERT_EQ(write(fd, val, strlen(val)), strlen(val)); 68 VFIO_ASSERT_EQ(close(fd), 0); 69 } 70 71 static int sysfs_device_val_get(const char *bdf, const char *file) 72 { 73 return sysfs_val_get_int("devices", bdf, file); 74 } 75 76 static void sysfs_device_val_set(const char *bdf, const char *file, const char *val) 77 { 78 sysfs_val_set("devices", bdf, file, val); 79 } 80 81 static void sysfs_device_val_set_int(const char *bdf, const char *file, int val) 82 { 83 char val_str[32]; 84 85 snprintf_assert(val_str, sizeof(val_str), "%d", val); 86 sysfs_device_val_set(bdf, file, val_str); 87 } 88 89 int sysfs_sriov_totalvfs_get(const char *bdf) 90 { 91 return sysfs_device_val_get(bdf, "sriov_totalvfs"); 92 } 93 94 int sysfs_sriov_numvfs_get(const char *bdf) 95 { 96 return sysfs_device_val_get(bdf, "sriov_numvfs"); 97 } 98 99 void sysfs_sriov_numvfs_set(const char *bdf, int numvfs) 100 { 101 sysfs_device_val_set_int(bdf, "sriov_numvfs", numvfs); 102 } 103 104 char *sysfs_sriov_vf_bdf_get(const char *pf_bdf, int i) 105 { 106 char path[PATH_MAX]; 107 char *out_vf_bdf; 108 109 /* Fit "0000:00:00.0" */ 110 out_vf_bdf = calloc(16, sizeof(char)); 111 VFIO_ASSERT_NOT_NULL(out_vf_bdf); 112 113 snprintf_assert(path, PATH_MAX, "/sys/bus/pci/devices/%s/virtfn%d", pf_bdf, i); 114 readlink_base(path, "%s", out_vf_bdf); 115 116 return out_vf_bdf; 117 } 118 119 int sysfs_iommu_group_get(const char *bdf) 120 { 121 char path[PATH_MAX]; 122 int group; 123 124 snprintf_assert(path, PATH_MAX, "/sys/bus/pci/devices/%s/iommu_group", bdf); 125 readlink_base(path, "%d", &group); 126 127 return group; 128 } 129 130 char *sysfs_driver_get(const char *bdf) 131 { 132 char driver_path[PATH_MAX]; 133 char path[PATH_MAX]; 134 char *out_driver; 135 int ret; 136 137 snprintf_assert(path, PATH_MAX, "/sys/bus/pci/devices/%s/driver", bdf); 138 ret = readlink_safe(path, driver_path); 139 if (ret == -1) { 140 if (errno == ENOENT) 141 return NULL; 142 143 VFIO_FAIL("Failed to read %s\n", path); 144 } 145 146 out_driver = strdup(basename(driver_path)); 147 VFIO_ASSERT_NOT_NULL(out_driver); 148 149 return out_driver; 150 } 151