]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/mlx5/mlx5_fpga_tools/mlx5fpga_tools_char.c
MFC r341573 amd r341643:
[FreeBSD/FreeBSD.git] / sys / dev / mlx5 / mlx5_fpga_tools / mlx5fpga_tools_char.c
1 /*-
2  * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * OpenIB.org BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  *
32  * $FreeBSD$
33  */
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/conf.h>
38 #include <dev/mlx5/mlx5io.h>
39 #include <dev/mlx5/mlx5_fpga_tools/tools_char.h>
40
41 #define CHUNK_SIZE (128 * 1024)
42
43 struct tools_context {
44         struct mlx5_fpga_tools_dev *tdev;
45         enum mlx5_fpga_access_type access_type;
46 };
47
48 static void
49 tools_char_ctx_dtor(void *data)
50 {
51
52         free(data, M_DEVBUF);
53 }
54
55 static int
56 tools_char_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
57 {
58         struct tools_context *context;
59
60         context = malloc(sizeof(*context), M_DEVBUF, M_WAITOK);
61         context->tdev = dev->si_drv1;
62         context->access_type = MLX5_FPGA_ACCESS_TYPE_DONTCARE;
63         devfs_set_cdevpriv(context, tools_char_ctx_dtor);
64         return (0);
65 }
66
67 static int
68 mem_read(struct mlx5_fpga_tools_dev *tdev, void *buf, size_t count,
69     u64 address, enum mlx5_fpga_access_type access_type, size_t *retcnt)
70 {
71         int ret;
72
73         ret = sx_xlock_sig(&tdev->lock);
74         if (ret != 0)
75                 return (ret);
76         ret = mlx5_fpga_mem_read(tdev->fdev, count, address, buf, access_type);
77         sx_xunlock(&tdev->lock);
78         if (ret < 0) {
79                 dev_dbg(mlx5_fpga_dev(tdev->fdev),
80                         "Failed to read %zu bytes at address 0x%jx: %d\n",
81                         count, (uintmax_t)address, ret);
82                 return (-ret);
83         }
84         *retcnt = ret;
85         return (0);
86 }
87
88 static int
89 mem_write(struct mlx5_fpga_tools_dev *tdev, void *buf, size_t count,
90     u64 address, enum mlx5_fpga_access_type access_type, size_t *retcnt)
91 {
92         int ret;
93
94         ret = sx_xlock_sig(&tdev->lock);
95         if (ret != 0)
96                 return (ret);
97         ret = mlx5_fpga_mem_write(tdev->fdev, count, address, buf, access_type);
98         sx_xunlock(&tdev->lock);
99         if (ret < 0) {
100                 dev_dbg(mlx5_fpga_dev(tdev->fdev),
101                         "Failed to write %zu bytes at address 0x%jx: %d\n",
102                         count, (uintmax_t)address, ret);
103                 return (-ret);
104         }
105         *retcnt = ret;
106         return (0);
107 }
108
109 static void
110 tools_char_llseek(struct tools_context *context, struct uio *uio, ssize_t *len)
111 {
112         uint64_t fbase, fsize;
113         size_t llen;
114
115         llen = uio->uio_resid;
116         if (llen < 1) {
117                 *len = 0;
118                 return;
119         }
120         if (llen > CHUNK_SIZE)
121                 llen = CHUNK_SIZE;
122         fbase = mlx5_fpga_ddr_base_get(context->tdev->fdev);
123         fsize = mlx5_fpga_ddr_size_get(context->tdev->fdev);
124         if (uio->uio_offset > fbase)
125                 *len = 0;
126         else if (uio->uio_offset + *len > fbase + fsize)
127                 *len = fbase + fsize - uio->uio_offset;
128         else
129                 *len = llen;
130 }
131
132 static int
133 tools_char_read(struct cdev *dev, struct uio *uio, int ioflag)
134 {
135         struct tools_context *context;
136         void *kbuf;
137         size_t len, len1;
138         int ret;
139
140         ret = devfs_get_cdevpriv((void **)&context);
141         if (ret != 0)
142                 return (ret);
143         dev_dbg(mlx5_fpga_dev(context->tdev->fdev),
144             "tools char device reading %zu bytes at 0x%jx\n", uio->uio_resid,
145              (uintmax_t)uio->uio_offset);
146
147         tools_char_llseek(context, uio, &len);
148         if (len == 0)
149                 return (0);
150
151         kbuf = malloc(len, M_DEVBUF, M_WAITOK);
152         ret = mem_read(context->tdev, kbuf, len, uio->uio_offset,
153             context->access_type, &len1);
154         if (ret == 0)
155                 ret = uiomove(kbuf, len1, uio);
156         free(kbuf, M_DEVBUF);
157         return (ret);
158 }
159
160 static int
161 tools_char_write(struct cdev *dev, struct uio *uio, int ioflag)
162 {
163         struct tools_context *context;
164         void *kbuf;
165         off_t of;
166         size_t len, len1;
167         int ret;
168
169         ret = devfs_get_cdevpriv((void **)&context);
170         if (ret != 0)
171                 return (ret);
172         dev_dbg(mlx5_fpga_dev(context->tdev->fdev),
173             "tools char device reading %zu bytes at 0x%jx\n", uio->uio_resid,
174             (uintmax_t)uio->uio_offset);
175
176         tools_char_llseek(context, uio, &len);
177         if (len == 0)
178                 return (0);
179
180         kbuf = malloc(len, M_DEVBUF, M_WAITOK);
181         len1 = uio->uio_resid;
182         of = uio->uio_offset;
183
184         ret = uiomove(kbuf, len, uio);
185         if (ret == 0) {
186                 len1 -= uio->uio_resid;
187                 ret = mem_write(context->tdev, kbuf, len, of,
188                     context->access_type, &len1);
189         }
190         free(kbuf, M_DEVBUF);
191         return (ret);
192 }
193
194 CTASSERT(MLX5_FPGA_CAP_ARR_SZ == MLX5_ST_SZ_DW(fpga_cap));
195
196 static int
197 tools_char_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
198     struct thread *td)
199 {
200         struct tools_context *context;
201         struct mlx5_fpga_device *fdev;
202         struct mlx5_fpga_query query;
203         u32 fpga_cap[MLX5_ST_SZ_DW(fpga_cap)] = {0};
204         int arg, err;
205
206         err = devfs_get_cdevpriv((void **)&context);
207         if (err != 0)
208                 return (err);
209         fdev = context->tdev->fdev;
210         if (fdev == NULL)
211                 return (ENXIO);
212
213         switch (cmd) {
214         case MLX5_FPGA_ACCESS_TYPE:
215                 arg = *(int *)data;
216                 if (arg > MLX5_FPGA_ACCESS_TYPE_MAX) {
217                         dev_err(mlx5_fpga_dev(fdev),
218                             "unknown access type %u\n", arg);
219                         err = EINVAL;
220                         break;
221                 }
222                 context->access_type = arg;
223                 break;
224         case MLX5_FPGA_LOAD:
225                 arg = *(int *)data;
226                 if (arg > MLX5_FPGA_IMAGE_MAX) {
227                         dev_err(mlx5_fpga_dev(fdev),
228                                 "unknown image type %u\n", arg);
229                         err = EINVAL;
230                         break;
231                 }
232                 err = mlx5_fpga_device_reload(fdev, arg);
233                 break;
234         case MLX5_FPGA_RESET:
235                 err = mlx5_fpga_device_reload(fdev, MLX5_FPGA_IMAGE_MAX + 1);
236                 break;
237         case MLX5_FPGA_IMAGE_SEL:
238                 arg = *(int *)data;
239                 if (arg > MLX5_FPGA_IMAGE_MAX) {
240                         dev_err(mlx5_fpga_dev(fdev),
241                             "unknown image type %u\n", arg);
242                         err = EINVAL;
243                         break;
244                 }
245                 err = mlx5_fpga_flash_select(fdev, arg);
246                 break;
247         case MLX5_FPGA_QUERY:
248                 mlx5_fpga_device_query(fdev, &query);
249                 bcopy(&query, data, sizeof(query));
250                 err = 0;
251                 break;
252         case MLX5_FPGA_CAP:
253                 mlx5_fpga_get_cap(fdev, fpga_cap);
254                 bcopy(&fpga_cap, data, sizeof(fpga_cap));
255                 err = 0;
256                 break;
257         default:
258                 dev_err(mlx5_fpga_dev(fdev),
259                         "unknown ioctl command %#08lx\n", cmd);
260                 err = ENOTTY;
261         }
262         return (err);
263 }
264
265 static struct cdevsw mlx5_tools_char_cdevsw = {
266         .d_version =    D_VERSION,
267         .d_name =       "mlx5_tools_char",
268         .d_open =       tools_char_open,
269         .d_read =       tools_char_read,
270         .d_write =      tools_char_write,
271         .d_ioctl =      tools_char_ioctl,
272 };
273
274 int
275 mlx5_fpga_tools_char_add_one(struct mlx5_fpga_tools_dev *tdev)
276 {
277         struct make_dev_args mda;
278         struct cdev *cd;
279         device_t bdev;
280         int ret;
281
282         make_dev_args_init(&mda);
283         mda.mda_flags = MAKEDEV_WAITOK | MAKEDEV_CHECKNAME;
284         mda.mda_devsw = &mlx5_tools_char_cdevsw;
285         mda.mda_uid = UID_ROOT;
286         mda.mda_gid = GID_OPERATOR;
287         mda.mda_mode = 0660;
288         mda.mda_si_drv1 = tdev;
289         bdev = mlx5_fpga_dev(tdev->fdev)->bsddev;
290         ret = make_dev_s(&mda, &cd,
291             "%04x:%02x:%02x.%x" MLX5_FPGA_TOOLS_NAME_SUFFIX,
292             pci_get_domain(bdev), pci_get_bus(bdev), pci_get_slot(bdev),
293             pci_get_function(bdev));
294         if (ret != 0) {
295                 tdev->char_device = NULL;
296                 dev_err(mlx5_fpga_dev(tdev->fdev),
297                     "Failed to create a char device: %d\n", ret);
298                 return (-ret);
299         }
300         tdev->char_device = cd;
301
302         dev_dbg(mlx5_fpga_dev(tdev->fdev), "tools char device %s created\n",
303             cd->si_name);
304         return (0);
305 }
306
307 void mlx5_fpga_tools_char_remove_one(struct mlx5_fpga_tools_dev *tdev)
308 {
309
310         dev_err(mlx5_fpga_dev(tdev->fdev), "tools char device %s destroyed\n",
311             ((struct cdev *)(tdev->char_device))->si_name);
312         destroy_dev((struct cdev *)(tdev->char_device));
313 }
314
315 int
316 mlx5_fpga_tools_char_init(void)
317 {
318
319         return (0);
320 }
321
322 void
323 mlx5_fpga_tools_char_deinit(void)
324 {
325 }