Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2021 Intel Corporation
3 : : */
4 : :
5 : : #include <dirent.h>
6 : : #include <fcntl.h>
7 : : #include <unistd.h>
8 : : #include <sys/mman.h>
9 : : #include <libgen.h>
10 : :
11 : : #include <bus_driver.h>
12 : : #include <dev_driver.h>
13 : : #include <rte_devargs.h>
14 : : #include <rte_eal.h>
15 : : #include <rte_memory.h>
16 : : #include <rte_log.h>
17 : : #include <rte_dmadev_pmd.h>
18 : : #include <rte_string_fns.h>
19 : :
20 : : #include "idxd_internal.h"
21 : :
22 : : /* default value for DSA paths, but allow override in environment for testing */
23 : : #define DSA_DEV_PATH "/dev/dsa"
24 : : #define DSA_SYSFS_PATH "/sys/bus/dsa/devices"
25 : :
26 : : static unsigned int devcount;
27 : :
28 : : /** unique identifier for a DSA device/WQ instance */
29 : : struct dsa_wq_addr {
30 : : uint16_t device_id;
31 : : uint16_t wq_id;
32 : : };
33 : :
34 : : /** a DSA device instance */
35 : : struct rte_dsa_device {
36 : : struct rte_device device; /**< Inherit core device */
37 : :
38 : : char wq_name[32]; /**< the workqueue name/number e.g. wq0.1 */
39 : : struct dsa_wq_addr addr; /**< Identifies the specific WQ */
40 : : };
41 : :
42 : : /* forward prototypes */
43 : : static int dsa_scan(void);
44 : : static bool dsa_match(const struct rte_driver *drv, const struct rte_device *dev);
45 : : static int dsa_probe_device(struct rte_driver *drv, struct rte_device *dev);
46 : : static enum rte_iova_mode dsa_get_iommu_class(void);
47 : : static int dsa_addr_parse(const char *name, void *addr);
48 : :
49 : : struct rte_bus dsa_bus = {
50 : : .scan = dsa_scan,
51 : : .probe = rte_bus_generic_probe,
52 : : .match = dsa_match,
53 : : .probe_device = dsa_probe_device,
54 : : .find_device = rte_bus_generic_find_device,
55 : : .get_iommu_class = dsa_get_iommu_class,
56 : : .parse = dsa_addr_parse,
57 : : };
58 : :
59 : : struct rte_driver dsa_driver = {
60 : : .name = "dmadev_idxd",
61 : : };
62 : :
63 : : static inline const char *
64 : : dsa_get_dev_path(void)
65 : : {
66 : 225 : const char *path = getenv("DSA_DEV_PATH");
67 [ + - - - ]: 225 : return path ? path : DSA_DEV_PATH;
68 : : }
69 : :
70 : : static inline const char *
71 : : dsa_get_sysfs_path(void)
72 : : {
73 : 0 : const char *path = getenv("DSA_SYSFS_PATH");
74 [ # # # # : 0 : return path ? path : DSA_SYSFS_PATH;
# # ]
75 : : }
76 : :
77 : : static int
78 : 0 : idxd_dev_close(struct rte_dma_dev *dev)
79 : : {
80 : 0 : struct idxd_dmadev *idxd = dev->data->dev_private;
81 : 0 : munmap(RTE_CAST_PTR(void *, idxd->portal), 0x1000);
82 : 0 : return 0;
83 : : }
84 : :
85 : : static const struct rte_dma_dev_ops idxd_bus_ops = {
86 : : .dev_close = idxd_dev_close,
87 : : .dev_dump = idxd_dump,
88 : : .dev_configure = idxd_configure,
89 : : .vchan_setup = idxd_vchan_setup,
90 : : .dev_info_get = idxd_info_get,
91 : : .stats_get = idxd_stats_get,
92 : : .stats_reset = idxd_stats_reset,
93 : : .vchan_status = idxd_vchan_status,
94 : : };
95 : :
96 : : static void *
97 : 0 : idxd_bus_mmap_wq(struct rte_dsa_device *dev)
98 : : {
99 : : void *addr;
100 : : char path[PATH_MAX];
101 : : int fd;
102 : :
103 : 0 : snprintf(path, sizeof(path), "%s/%s", dsa_get_dev_path(), dev->wq_name);
104 : : fd = open(path, O_RDWR);
105 [ # # ]: 0 : if (fd < 0) {
106 : 0 : IDXD_PMD_ERR("Failed to open device path: %s", path);
107 : 0 : return NULL;
108 : : }
109 : :
110 : 0 : addr = mmap(NULL, 0x1000, PROT_WRITE, MAP_SHARED, fd, 0);
111 : 0 : close(fd);
112 [ # # ]: 0 : if (addr == MAP_FAILED) {
113 : 0 : IDXD_PMD_ERR("Failed to mmap device %s", path);
114 : 0 : return NULL;
115 : : }
116 : :
117 : : return addr;
118 : : }
119 : :
120 : : static int
121 : 0 : read_wq_string(const struct rte_dsa_device *dev, const char *filename,
122 : : char *value, size_t valuelen)
123 : : {
124 : : char sysfs_node[PATH_MAX];
125 : : int len;
126 : : int fd;
127 : :
128 : : snprintf(sysfs_node, sizeof(sysfs_node), "%s/%s/%s",
129 : 0 : dsa_get_sysfs_path(), dev->wq_name, filename);
130 : : fd = open(sysfs_node, O_RDONLY);
131 [ # # ]: 0 : if (fd < 0) {
132 : 0 : IDXD_PMD_ERR("%s(): opening file '%s' failed: %s",
133 : : __func__, sysfs_node, strerror(errno));
134 : 0 : return -1;
135 : : }
136 : :
137 [ # # ]: 0 : len = read(fd, value, valuelen - 1);
138 : 0 : close(fd);
139 [ # # ]: 0 : if (len < 0) {
140 : 0 : IDXD_PMD_ERR("%s(): error reading file '%s': %s",
141 : : __func__, sysfs_node, strerror(errno));
142 : 0 : return -1;
143 : : }
144 : 0 : value[len] = '\0';
145 : 0 : return 0;
146 : : }
147 : :
148 : : static int
149 : 0 : read_wq_int(struct rte_dsa_device *dev, const char *filename,
150 : : int *value)
151 : : {
152 : : char sysfs_node[PATH_MAX];
153 : : FILE *f;
154 : : int ret = 0;
155 : :
156 : : snprintf(sysfs_node, sizeof(sysfs_node), "%s/%s/%s",
157 : 0 : dsa_get_sysfs_path(), dev->wq_name, filename);
158 : 0 : f = fopen(sysfs_node, "r");
159 [ # # ]: 0 : if (f == NULL) {
160 : 0 : IDXD_PMD_ERR("%s(): opening file '%s' failed: %s",
161 : : __func__, sysfs_node, strerror(errno));
162 : 0 : return -1;
163 : : }
164 : :
165 [ # # ]: 0 : if (fscanf(f, "%d", value) != 1) {
166 : 0 : IDXD_PMD_ERR("%s(): error reading file '%s': %s",
167 : : __func__, sysfs_node, strerror(errno));
168 : : ret = -1;
169 : : }
170 : :
171 : 0 : fclose(f);
172 : 0 : return ret;
173 : : }
174 : :
175 : : static int
176 : 0 : read_device_int(struct rte_dsa_device *dev, const char *filename,
177 : : int *value)
178 : : {
179 : : char sysfs_node[PATH_MAX];
180 : : FILE *f;
181 : : int ret = 0;
182 : :
183 : 0 : snprintf(sysfs_node, sizeof(sysfs_node), "%s/dsa%d/%s",
184 : 0 : dsa_get_sysfs_path(), dev->addr.device_id, filename);
185 : 0 : f = fopen(sysfs_node, "r");
186 [ # # ]: 0 : if (f == NULL) {
187 : 0 : IDXD_PMD_ERR("%s(): opening file '%s' failed: %s",
188 : : __func__, sysfs_node, strerror(errno));
189 : 0 : return -1;
190 : : }
191 : :
192 [ # # ]: 0 : if (fscanf(f, "%d", value) != 1) {
193 : 0 : IDXD_PMD_ERR("%s(): error reading file '%s': %s",
194 : : __func__, sysfs_node, strerror(errno));
195 : : ret = -1;
196 : : }
197 : :
198 : 0 : fclose(f);
199 : 0 : return ret;
200 : : }
201 : :
202 : : static int
203 : 0 : dsa_probe_device(__rte_unused struct rte_driver *drv, struct rte_device *dev)
204 : : {
205 : : struct rte_dsa_device *dsa_dev = RTE_BUS_DEVICE(dev, *dsa_dev);
206 : 0 : struct idxd_dmadev idxd = {0};
207 : 0 : int ret = 0;
208 : :
209 : 0 : IDXD_PMD_INFO("Probing device %s on numa node %d",
210 : : dsa_dev->wq_name, dsa_dev->device.numa_node);
211 [ # # ]: 0 : if (read_wq_int(dsa_dev, "size", &ret) < 0)
212 : : return -1;
213 : 0 : idxd.max_batches = ret;
214 [ # # ]: 0 : if (read_wq_int(dsa_dev, "max_batch_size", &ret) < 0)
215 : : return -1;
216 : 0 : idxd.max_batch_size = ret;
217 : 0 : idxd.qid = dsa_dev->addr.wq_id;
218 : 0 : idxd.u.bus.dsa_id = dsa_dev->addr.device_id;
219 : 0 : idxd.sva_support = 1;
220 : :
221 : 0 : idxd.portal = idxd_bus_mmap_wq(dsa_dev);
222 [ # # ]: 0 : if (idxd.portal == NULL) {
223 : 0 : IDXD_PMD_ERR("WQ mmap failed");
224 : 0 : return -ENOENT;
225 : : }
226 : :
227 : 0 : ret = idxd_dmadev_create(dsa_dev->wq_name, dev, &idxd, &idxd_bus_ops);
228 [ # # ]: 0 : if (ret) {
229 : 0 : IDXD_PMD_ERR("Failed to create dmadev %s", dsa_dev->wq_name);
230 : 0 : return ret;
231 : : }
232 : :
233 : : return 0;
234 : : }
235 : :
236 : : static int
237 : 0 : is_for_this_process_use(const char *name)
238 : : {
239 : : char prefix[256];
240 : : int retval = 0;
241 : : size_t prefixlen;
242 : :
243 : 0 : prefixlen = rte_basename(rte_eal_get_runtime_dir(), prefix, sizeof(prefix));
244 [ # # # # ]: 0 : if (prefixlen >= sizeof(prefix) || strcmp(prefix, ".") == 0)
245 : : return retval;
246 : :
247 [ # # ]: 0 : if (strncmp(name, "dpdk_", 5) == 0)
248 : : retval = 1;
249 [ # # # # ]: 0 : if (strncmp(name, prefix, prefixlen) == 0 && name[prefixlen] == '_')
250 : : retval = 1;
251 : :
252 : : return retval;
253 : : }
254 : :
255 : 0 : static bool dsa_match(const struct rte_driver *drv, const struct rte_device *dev)
256 : : {
257 : : const struct rte_dsa_device *dsa_dev = RTE_BUS_DEVICE(dev, *dsa_dev);
258 : :
259 [ # # ]: 0 : if (drv == &dsa_driver) {
260 : : char type[64], name[64];
261 : :
262 [ # # # # ]: 0 : if (read_wq_string(dsa_dev, "type", type, sizeof(type)) >= 0 &&
263 : 0 : read_wq_string(dsa_dev, "name", name, sizeof(name)) >= 0) {
264 [ # # # # ]: 0 : return strncmp(type, "user", 4) == 0 && is_for_this_process_use(name);
265 : : }
266 : : }
267 : :
268 : : return false;
269 : : }
270 : :
271 : : static int
272 : 225 : dsa_scan(void)
273 : : {
274 : : const char *path = dsa_get_dev_path();
275 : : struct dirent *wq;
276 : : DIR *dev_dir;
277 : :
278 : 225 : dev_dir = opendir(path);
279 [ + - ]: 225 : if (dev_dir == NULL) {
280 [ - + ]: 225 : if (errno == ENOENT)
281 : : return 0; /* no bus, return without error */
282 : 0 : IDXD_PMD_ERR("%s(): opendir '%s' failed: %s",
283 : : __func__, path, strerror(errno));
284 : 0 : return -1;
285 : : }
286 : :
287 [ # # ]: 0 : while ((wq = readdir(dev_dir)) != NULL) {
288 : : struct rte_dsa_device *dev;
289 : 0 : int numa_node = SOCKET_ID_ANY;
290 : :
291 [ # # ]: 0 : if (strncmp(wq->d_name, "wq", 2) != 0)
292 : 0 : continue;
293 [ # # ]: 0 : if (strnlen(wq->d_name, sizeof(dev->wq_name)) == sizeof(dev->wq_name)) {
294 : 0 : IDXD_PMD_ERR("%s(): wq name too long: '%s', skipping",
295 : : __func__, wq->d_name);
296 : 0 : continue;
297 : : }
298 : 0 : IDXD_PMD_DEBUG("%s(): found %s/%s", __func__, path, wq->d_name);
299 : :
300 : 0 : dev = calloc(1, sizeof(*dev));
301 [ # # ]: 0 : if (dev == NULL) {
302 : 0 : closedir(dev_dir);
303 : 0 : return -ENOMEM;
304 : : }
305 [ # # ]: 0 : if (dsa_addr_parse(wq->d_name, &dev->addr) < 0) {
306 : 0 : IDXD_PMD_ERR("Error parsing WQ name: %s", wq->d_name);
307 : 0 : free(dev);
308 : 0 : continue;
309 : : }
310 : 0 : strlcpy(dev->wq_name, wq->d_name, sizeof(dev->wq_name));
311 : 0 : rte_bus_add_device(&dsa_bus, &dev->device);
312 : 0 : devcount++;
313 : :
314 : 0 : read_device_int(dev, "numa_node", &numa_node);
315 : 0 : dev->device.numa_node = numa_node;
316 : 0 : dev->device.name = dev->wq_name;
317 : : }
318 : :
319 : 0 : closedir(dev_dir);
320 : 0 : return 0;
321 : : }
322 : :
323 : : static enum rte_iova_mode
324 : 225 : dsa_get_iommu_class(void)
325 : : {
326 : : /* if there are no devices, report don't care, otherwise VA mode */
327 [ + - ]: 225 : return devcount > 0 ? RTE_IOVA_VA : RTE_IOVA_DC;
328 : : }
329 : :
330 : : static int
331 : 15 : dsa_addr_parse(const char *name, void *addr)
332 : : {
333 : : struct dsa_wq_addr *wq = addr;
334 : : unsigned int device_id, wq_id;
335 : :
336 [ + - ]: 15 : if (sscanf(name, "wq%u.%u", &device_id, &wq_id) != 2) {
337 : 15 : IDXD_PMD_DEBUG("Parsing WQ name failed: %s", name);
338 : 15 : return -1;
339 : : }
340 : :
341 [ # # ]: 0 : if (wq != NULL) {
342 : 0 : wq->device_id = device_id;
343 : 0 : wq->wq_id = wq_id;
344 : : }
345 : :
346 : : return 0;
347 : : }
348 : :
349 : 301 : RTE_REGISTER_BUS(dsa, dsa_bus);
350 : 301 : RTE_INIT(dsa_bus_init)
351 : : {
352 : 301 : rte_bus_add_driver(&dsa_bus, &dsa_driver);
353 : 301 : }
|