raw/ioat: configure idxd devices
[dpdk.git] / drivers / raw / ioat / idxd_vdev.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2020 Intel Corporation
3  */
4
5 #include <fcntl.h>
6 #include <unistd.h>
7 #include <limits.h>
8 #include <sys/mman.h>
9
10 #include <rte_memzone.h>
11 #include <rte_bus_vdev.h>
12 #include <rte_kvargs.h>
13 #include <rte_string_fns.h>
14 #include <rte_rawdev_pmd.h>
15
16 #include "ioat_private.h"
17
18 /** Name of the device driver */
19 #define IDXD_PMD_RAWDEV_NAME rawdev_idxd
20 /* takes a work queue(WQ) as parameter */
21 #define IDXD_ARG_WQ             "wq"
22
23 static const char * const valid_args[] = {
24         IDXD_ARG_WQ,
25         NULL
26 };
27
28 struct idxd_vdev_args {
29         uint8_t device_id;
30         uint8_t wq_id;
31 };
32
33 static const struct rte_rawdev_ops idxd_vdev_ops = {
34                 .dev_close = idxd_rawdev_close,
35                 .dev_selftest = idxd_rawdev_test,
36                 .dump = idxd_dev_dump,
37                 .dev_configure = idxd_dev_configure,
38 };
39
40 static void *
41 idxd_vdev_mmap_wq(struct idxd_vdev_args *args)
42 {
43         void *addr;
44         char path[PATH_MAX];
45         int fd;
46
47         snprintf(path, sizeof(path), "/dev/dsa/wq%u.%u",
48                         args->device_id, args->wq_id);
49         fd = open(path, O_RDWR);
50         if (fd < 0) {
51                 IOAT_PMD_ERR("Failed to open device path");
52                 return NULL;
53         }
54
55         addr = mmap(NULL, 0x1000, PROT_WRITE, MAP_SHARED, fd, 0);
56         close(fd);
57         if (addr == MAP_FAILED) {
58                 IOAT_PMD_ERR("Failed to mmap device");
59                 return NULL;
60         }
61
62         return addr;
63 }
64
65 static int
66 idxd_rawdev_parse_wq(const char *key __rte_unused, const char *value,
67                           void *extra_args)
68 {
69         struct idxd_vdev_args *args = (struct idxd_vdev_args *)extra_args;
70         int dev, wq, bytes = -1;
71         int read = sscanf(value, "%d.%d%n", &dev, &wq, &bytes);
72
73         if (read != 2 || bytes != (int)strlen(value)) {
74                 IOAT_PMD_ERR("Error parsing work-queue id. Must be in <dev_id>.<queue_id> format");
75                 return -EINVAL;
76         }
77
78         if (dev >= UINT8_MAX || wq >= UINT8_MAX) {
79                 IOAT_PMD_ERR("Device or work queue id out of range");
80                 return -EINVAL;
81         }
82
83         args->device_id = dev;
84         args->wq_id = wq;
85
86         return 0;
87 }
88
89 static int
90 idxd_vdev_parse_params(struct rte_kvargs *kvlist, struct idxd_vdev_args *args)
91 {
92         if (rte_kvargs_count(kvlist, IDXD_ARG_WQ) == 1) {
93                 if (rte_kvargs_process(kvlist, IDXD_ARG_WQ,
94                                 &idxd_rawdev_parse_wq, args) < 0) {
95                         IOAT_PMD_ERR("Error parsing %s", IDXD_ARG_WQ);
96                         goto free;
97                 }
98         } else {
99                 IOAT_PMD_ERR("%s is a mandatory arg", IDXD_ARG_WQ);
100                 return -EINVAL;
101         }
102
103         return 0;
104
105 free:
106         if (kvlist)
107                 rte_kvargs_free(kvlist);
108         return -EINVAL;
109 }
110
111 static int
112 idxd_vdev_get_max_batches(struct idxd_vdev_args *args)
113 {
114         char sysfs_path[PATH_MAX];
115         FILE *f;
116         int ret;
117
118         snprintf(sysfs_path, sizeof(sysfs_path),
119                         "/sys/bus/dsa/devices/wq%u.%u/size",
120                         args->device_id, args->wq_id);
121         f = fopen(sysfs_path, "r");
122         if (f == NULL)
123                 return -1;
124
125         if (fscanf(f, "%d", &ret) != 1)
126                 ret = -1;
127
128         fclose(f);
129         return ret;
130 }
131
132 static int
133 idxd_rawdev_probe_vdev(struct rte_vdev_device *vdev)
134 {
135         struct rte_kvargs *kvlist;
136         struct idxd_rawdev idxd = {{0}}; /* double {} to avoid error on BSD12 */
137         struct idxd_vdev_args vdev_args;
138         const char *name;
139         int ret = 0;
140
141         name = rte_vdev_device_name(vdev);
142         if (name == NULL)
143                 return -EINVAL;
144
145         IOAT_PMD_INFO("Initializing pmd_idxd for %s", name);
146
147         kvlist = rte_kvargs_parse(rte_vdev_device_args(vdev), valid_args);
148         if (kvlist == NULL) {
149                 IOAT_PMD_ERR("Invalid kvargs key");
150                 return -EINVAL;
151         }
152
153         ret = idxd_vdev_parse_params(kvlist, &vdev_args);
154         if (ret) {
155                 IOAT_PMD_ERR("Failed to parse kvargs");
156                 return -EINVAL;
157         }
158
159         idxd.qid = vdev_args.wq_id;
160         idxd.u.vdev.dsa_id = vdev_args.device_id;
161         idxd.max_batches = idxd_vdev_get_max_batches(&vdev_args);
162
163         idxd.public.portal = idxd_vdev_mmap_wq(&vdev_args);
164         if (idxd.public.portal == NULL) {
165                 IOAT_PMD_ERR("WQ mmap failed");
166                 return -ENOENT;
167         }
168
169         ret = idxd_rawdev_create(name, &vdev->device, &idxd, &idxd_vdev_ops);
170         if (ret) {
171                 IOAT_PMD_ERR("Failed to create rawdev %s", name);
172                 return ret;
173         }
174
175         return 0;
176 }
177
178 static int
179 idxd_rawdev_remove_vdev(struct rte_vdev_device *vdev)
180 {
181         struct idxd_rawdev *idxd;
182         const char *name;
183         struct rte_rawdev *rdev;
184         int ret = 0;
185
186         name = rte_vdev_device_name(vdev);
187         if (name == NULL)
188                 return -EINVAL;
189
190         IOAT_PMD_INFO("Remove DSA vdev %p", name);
191
192         rdev = rte_rawdev_pmd_get_named_dev(name);
193         if (!rdev) {
194                 IOAT_PMD_ERR("Invalid device name (%s)", name);
195                 return -EINVAL;
196         }
197
198         idxd = rdev->dev_private;
199
200         /* free context and memory */
201         if (rdev->dev_private != NULL) {
202                 IOAT_PMD_DEBUG("Freeing device driver memory");
203                 rdev->dev_private = NULL;
204
205                 if (munmap(idxd->public.portal, 0x1000) < 0) {
206                         IOAT_PMD_ERR("Error unmapping portal");
207                         ret = -errno;
208                 }
209
210                 rte_free(idxd->public.batch_ring);
211                 rte_free(idxd->public.hdl_ring);
212
213                 rte_memzone_free(idxd->mz);
214         }
215
216         if (rte_rawdev_pmd_release(rdev))
217                 IOAT_PMD_ERR("Device cleanup failed");
218
219         return ret;
220 }
221
222 struct rte_vdev_driver idxd_rawdev_drv_vdev = {
223         .probe = idxd_rawdev_probe_vdev,
224         .remove = idxd_rawdev_remove_vdev,
225 };
226
227 RTE_PMD_REGISTER_VDEV(IDXD_PMD_RAWDEV_NAME, idxd_rawdev_drv_vdev);
228 RTE_PMD_REGISTER_PARAM_STRING(IDXD_PMD_RAWDEV_NAME,
229                               "wq=<string>");