1
2
3
4
5#include <dirent.h>
6#include <libgen.h>
7#include <string.h>
8#include <errno.h>
9#include <unistd.h>
10#include <fcntl.h>
11#include <sys/mman.h>
12
13#include <rte_bus.h>
14#include <rte_log.h>
15#include <rte_string_fns.h>
16#include "ioat_private.h"
17
18
19#define DSA_DEV_PATH "/dev/dsa"
20#define DSA_SYSFS_PATH "/sys/bus/dsa/devices"
21
22static unsigned int devcount;
23
24
25struct dsa_wq_addr {
26 uint16_t device_id;
27 uint16_t wq_id;
28};
29
30
31struct rte_dsa_device {
32 struct rte_device device;
33 TAILQ_ENTRY(rte_dsa_device) next;
34
35 char wq_name[32];
36 struct dsa_wq_addr addr;
37};
38
39
40struct dsa_bus;
41static int dsa_scan(void);
42static int dsa_probe(void);
43static struct rte_device *dsa_find_device(const struct rte_device *start,
44 rte_dev_cmp_t cmp, const void *data);
45static enum rte_iova_mode dsa_get_iommu_class(void);
46static int dsa_addr_parse(const char *name, void *addr);
47
48
49TAILQ_HEAD(dsa_device_list, rte_dsa_device);
50
51
52
53
54struct dsa_bus {
55 struct rte_bus bus;
56 struct rte_driver driver;
57 struct dsa_device_list device_list;
58};
59
60struct dsa_bus dsa_bus = {
61 .bus = {
62 .scan = dsa_scan,
63 .probe = dsa_probe,
64 .find_device = dsa_find_device,
65 .get_iommu_class = dsa_get_iommu_class,
66 .parse = dsa_addr_parse,
67 },
68 .driver = {
69 .name = "rawdev_idxd"
70 },
71 .device_list = TAILQ_HEAD_INITIALIZER(dsa_bus.device_list),
72};
73
74static inline const char *
75dsa_get_dev_path(void)
76{
77 const char *path = getenv("DSA_DEV_PATH");
78 return path ? path : DSA_DEV_PATH;
79}
80
81static inline const char *
82dsa_get_sysfs_path(void)
83{
84 const char *path = getenv("DSA_SYSFS_PATH");
85 return path ? path : DSA_SYSFS_PATH;
86}
87
88static const struct rte_rawdev_ops idxd_vdev_ops = {
89 .dev_close = idxd_rawdev_close,
90 .dev_selftest = ioat_rawdev_test,
91 .dump = idxd_dev_dump,
92 .dev_configure = idxd_dev_configure,
93 .dev_info_get = idxd_dev_info_get,
94 .xstats_get = ioat_xstats_get,
95 .xstats_get_names = ioat_xstats_get_names,
96 .xstats_reset = ioat_xstats_reset,
97};
98
99static void *
100idxd_vdev_mmap_wq(struct rte_dsa_device *dev)
101{
102 void *addr;
103 char path[PATH_MAX];
104 int fd;
105
106 snprintf(path, sizeof(path), "%s/%s", dsa_get_dev_path(), dev->wq_name);
107 fd = open(path, O_RDWR);
108 if (fd < 0) {
109 IOAT_PMD_ERR("Failed to open device path: %s", path);
110 return NULL;
111 }
112
113 addr = mmap(NULL, 0x1000, PROT_WRITE, MAP_SHARED, fd, 0);
114 close(fd);
115 if (addr == MAP_FAILED) {
116 IOAT_PMD_ERR("Failed to mmap device %s", path);
117 return NULL;
118 }
119
120 return addr;
121}
122
123static int
124read_wq_string(struct rte_dsa_device *dev, const char *filename,
125 char *value, size_t valuelen)
126{
127 char sysfs_node[PATH_MAX];
128 int len;
129 int fd;
130
131 snprintf(sysfs_node, sizeof(sysfs_node), "%s/%s/%s",
132 dsa_get_sysfs_path(), dev->wq_name, filename);
133 fd = open(sysfs_node, O_RDONLY);
134 if (fd < 0) {
135 IOAT_PMD_ERR("%s(): opening file '%s' failed: %s",
136 __func__, sysfs_node, strerror(errno));
137 return -1;
138 }
139
140 len = read(fd, value, valuelen - 1);
141 close(fd);
142 if (len < 0) {
143 IOAT_PMD_ERR("%s(): error reading file '%s': %s",
144 __func__, sysfs_node, strerror(errno));
145 return -1;
146 }
147 value[len] = '\0';
148 return 0;
149}
150
151static int
152read_wq_int(struct rte_dsa_device *dev, const char *filename,
153 int *value)
154{
155 char sysfs_node[PATH_MAX];
156 FILE *f;
157 int ret = 0;
158
159 snprintf(sysfs_node, sizeof(sysfs_node), "%s/%s/%s",
160 dsa_get_sysfs_path(), dev->wq_name, filename);
161 f = fopen(sysfs_node, "r");
162 if (f == NULL) {
163 IOAT_PMD_ERR("%s(): opening file '%s' failed: %s",
164 __func__, sysfs_node, strerror(errno));
165 return -1;
166 }
167
168 if (fscanf(f, "%d", value) != 1) {
169 IOAT_PMD_ERR("%s(): error reading file '%s': %s",
170 __func__, sysfs_node, strerror(errno));
171 ret = -1;
172 }
173
174 fclose(f);
175 return ret;
176}
177
178static int
179read_device_int(struct rte_dsa_device *dev, const char *filename,
180 int *value)
181{
182 char sysfs_node[PATH_MAX];
183 FILE *f;
184 int ret = 0;
185
186 snprintf(sysfs_node, sizeof(sysfs_node), "%s/dsa%d/%s",
187 dsa_get_sysfs_path(), dev->addr.device_id, filename);
188 f = fopen(sysfs_node, "r");
189 if (f == NULL) {
190 IOAT_PMD_ERR("%s(): opening file '%s' failed: %s",
191 __func__, sysfs_node, strerror(errno));
192 return -1;
193 }
194
195 if (fscanf(f, "%d", value) != 1) {
196 IOAT_PMD_ERR("%s(): error reading file '%s': %s",
197 __func__, sysfs_node, strerror(errno));
198 ret = -1;
199 }
200
201 fclose(f);
202 return ret;
203}
204
205static int
206idxd_rawdev_probe_dsa(struct rte_dsa_device *dev)
207{
208 struct idxd_rawdev idxd = {{0}};
209 int ret = 0;
210
211 IOAT_PMD_INFO("Probing device %s on numa node %d",
212 dev->wq_name, dev->device.numa_node);
213 if (read_wq_int(dev, "size", &ret) < 0)
214 return -1;
215 idxd.max_batches = ret;
216 idxd.qid = dev->addr.wq_id;
217 idxd.u.vdev.dsa_id = dev->addr.device_id;
218
219 idxd.public.portal = idxd_vdev_mmap_wq(dev);
220 if (idxd.public.portal == NULL) {
221 IOAT_PMD_ERR("WQ mmap failed");
222 return -ENOENT;
223 }
224
225 ret = idxd_rawdev_create(dev->wq_name, &dev->device, &idxd, &idxd_vdev_ops);
226 if (ret) {
227 IOAT_PMD_ERR("Failed to create rawdev %s", dev->wq_name);
228 return ret;
229 }
230
231 return 0;
232}
233
234static int
235is_for_this_process_use(const char *name)
236{
237 char *runtime_dir = strdup(rte_eal_get_runtime_dir());
238 char *prefix = basename(runtime_dir);
239 int prefixlen = strlen(prefix);
240 int retval = 0;
241
242 if (strncmp(name, "dpdk_", 5) == 0)
243 retval = 1;
244 if (strncmp(name, prefix, prefixlen) == 0 && name[prefixlen] == '_')
245 retval = 1;
246
247 free(runtime_dir);
248 return retval;
249}
250
251static int
252dsa_probe(void)
253{
254 struct rte_dsa_device *dev;
255
256 TAILQ_FOREACH(dev, &dsa_bus.device_list, next) {
257 char type[64], name[64];
258
259 if (read_wq_string(dev, "type", type, sizeof(type)) < 0 ||
260 read_wq_string(dev, "name", name, sizeof(name)) < 0)
261 continue;
262
263 if (strncmp(type, "user", 4) == 0 && is_for_this_process_use(name)) {
264 dev->device.driver = &dsa_bus.driver;
265 idxd_rawdev_probe_dsa(dev);
266 continue;
267 }
268 IOAT_PMD_DEBUG("WQ '%s', not allocated to DPDK", dev->wq_name);
269 }
270
271 return 0;
272}
273
274static int
275dsa_scan(void)
276{
277 const char *path = dsa_get_dev_path();
278 struct dirent *wq;
279 DIR *dev_dir;
280
281 dev_dir = opendir(path);
282 if (dev_dir == NULL) {
283 if (errno == ENOENT)
284 return 0;
285 IOAT_PMD_ERR("%s(): opendir '%s' failed: %s",
286 __func__, path, strerror(errno));
287 return -1;
288 }
289
290 while ((wq = readdir(dev_dir)) != NULL) {
291 struct rte_dsa_device *dev;
292 int numa_node = -1;
293
294 if (strncmp(wq->d_name, "wq", 2) != 0)
295 continue;
296 if (strnlen(wq->d_name, sizeof(dev->wq_name)) == sizeof(dev->wq_name)) {
297 IOAT_PMD_ERR("%s(): wq name too long: '%s', skipping",
298 __func__, wq->d_name);
299 continue;
300 }
301 IOAT_PMD_DEBUG("%s(): found %s/%s", __func__, path, wq->d_name);
302
303 dev = malloc(sizeof(*dev));
304 if (dsa_addr_parse(wq->d_name, &dev->addr) < 0) {
305 IOAT_PMD_ERR("Error parsing WQ name: %s", wq->d_name);
306 free(dev);
307 continue;
308 }
309 dev->device.bus = &dsa_bus.bus;
310 strlcpy(dev->wq_name, wq->d_name, sizeof(dev->wq_name));
311 TAILQ_INSERT_TAIL(&dsa_bus.device_list, dev, next);
312 devcount++;
313
314 read_device_int(dev, "numa_node", &numa_node);
315 dev->device.numa_node = numa_node;
316 dev->device.name = dev->wq_name;
317 }
318
319 closedir(dev_dir);
320 return 0;
321}
322
323static struct rte_device *
324dsa_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
325 const void *data)
326{
327 struct rte_dsa_device *dev = TAILQ_FIRST(&dsa_bus.device_list);
328
329
330 RTE_BUILD_BUG_ON(offsetof(struct rte_dsa_device, device) != 0);
331
332 if (start != NULL)
333 dev = TAILQ_NEXT((const struct rte_dsa_device *)start, next);
334 while (dev != NULL) {
335 if (cmp(&dev->device, data) == 0)
336 return &dev->device;
337 dev = TAILQ_NEXT(dev, next);
338 }
339 return NULL;
340}
341
342static enum rte_iova_mode
343dsa_get_iommu_class(void)
344{
345
346 return devcount > 0 ? RTE_IOVA_VA : RTE_IOVA_DC;
347}
348
349static int
350dsa_addr_parse(const char *name, void *addr)
351{
352 struct dsa_wq_addr *wq = addr;
353 unsigned int device_id, wq_id;
354
355 if (sscanf(name, "wq%u.%u", &device_id, &wq_id) != 2) {
356 IOAT_PMD_DEBUG("Parsing WQ name failed: %s", name);
357 return -1;
358 }
359
360 wq->device_id = device_id;
361 wq->wq_id = wq_id;
362 return 0;
363}
364
365RTE_REGISTER_BUS(dsa, dsa_bus.bus);
366