projects/linux·blob master · refs

149 lines · 3.4 KiB

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
23static 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
35static 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
58static 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
71static int sysfs_device_val_get(const char *bdf, const char *file)
72{
73 return sysfs_val_get_int("devices", bdf, file);
74}
75
76static 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
81static 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
89int sysfs_sriov_totalvfs_get(const char *bdf)
90{
91 return sysfs_device_val_get(bdf, "sriov_totalvfs");
92}
93
94int sysfs_sriov_numvfs_get(const char *bdf)
95{
96 return sysfs_device_val_get(bdf, "sriov_numvfs");
97}
98
99void sysfs_sriov_numvfs_set(const char *bdf, int numvfs)
100{
101 sysfs_device_val_set_int(bdf, "sriov_numvfs", numvfs);
102}
103
104char *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_assert(16, sizeof(char));
111
112 snprintf_assert(path, PATH_MAX, "/sys/bus/pci/devices/%s/virtfn%d", pf_bdf, i);
113 readlink_base(path, "%s", out_vf_bdf);
114
115 return out_vf_bdf;
116}
117
118int sysfs_iommu_group_get(const char *bdf)
119{
120 char path[PATH_MAX];
121 int group;
122
123 snprintf_assert(path, PATH_MAX, "/sys/bus/pci/devices/%s/iommu_group", bdf);
124 readlink_base(path, "%d", &group);
125
126 return group;
127}
128
129char *sysfs_driver_get(const char *bdf)
130{
131 char driver_path[PATH_MAX];
132 char path[PATH_MAX];
133 char *out_driver;
134 int ret;
135
136 snprintf_assert(path, PATH_MAX, "/sys/bus/pci/devices/%s/driver", bdf);
137 ret = readlink_safe(path, driver_path);
138 if (ret == -1) {
139 if (errno == ENOENT)
140 return NULL;
141
142 VFIO_FAIL("Failed to read %s\n", path);
143 }
144
145 out_driver = strdup(basename(driver_path));
146 VFIO_ASSERT_NOT_NULL(out_driver);
147
148 return out_driver;
149}