2 * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
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:
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
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.
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
35 #include <sys/param.h>
36 #include <sys/systm.h>
38 #include <dev/mlx5/mlx5io.h>
39 #include <dev/mlx5/mlx5_fpga_tools/tools_char.h>
41 #define CHUNK_SIZE (128 * 1024)
43 struct tools_context {
44 struct mlx5_fpga_tools_dev *tdev;
45 enum mlx5_fpga_access_type access_type;
49 tools_char_ctx_dtor(void *data)
56 tools_char_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
58 struct tools_context *context;
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);
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)
73 ret = sx_xlock_sig(&tdev->lock);
76 ret = mlx5_fpga_mem_read(tdev->fdev, count, address, buf, access_type);
77 sx_xunlock(&tdev->lock);
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);
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)
94 ret = sx_xlock_sig(&tdev->lock);
97 ret = mlx5_fpga_mem_write(tdev->fdev, count, address, buf, access_type);
98 sx_xunlock(&tdev->lock);
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);
110 tools_char_llseek(struct tools_context *context, struct uio *uio, ssize_t *len)
112 uint64_t fbase, fsize;
115 llen = uio->uio_resid;
120 if (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)
126 else if (uio->uio_offset + *len > fbase + fsize)
127 *len = fbase + fsize - uio->uio_offset;
133 tools_char_read(struct cdev *dev, struct uio *uio, int ioflag)
135 struct tools_context *context;
140 ret = devfs_get_cdevpriv((void **)&context);
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);
147 tools_char_llseek(context, uio, &len);
151 kbuf = malloc(len, M_DEVBUF, M_WAITOK);
152 ret = mem_read(context->tdev, kbuf, len, uio->uio_offset,
153 context->access_type, &len1);
155 ret = uiomove(kbuf, len1, uio);
156 free(kbuf, M_DEVBUF);
161 tools_char_write(struct cdev *dev, struct uio *uio, int ioflag)
163 struct tools_context *context;
169 ret = devfs_get_cdevpriv((void **)&context);
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);
176 tools_char_llseek(context, uio, &len);
180 kbuf = malloc(len, M_DEVBUF, M_WAITOK);
181 len1 = uio->uio_resid;
182 of = uio->uio_offset;
184 ret = uiomove(kbuf, len, uio);
186 len1 -= uio->uio_resid;
187 ret = mem_write(context->tdev, kbuf, len, of,
188 context->access_type, &len1);
190 free(kbuf, M_DEVBUF);
194 CTASSERT(MLX5_FPGA_CAP_ARR_SZ == MLX5_ST_SZ_DW(fpga_cap));
197 tools_char_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
200 struct tools_context *context;
201 struct mlx5_fpga_device *fdev;
202 struct mlx5_fpga_query query;
203 struct mlx5_fpga_temperature *temperature;
204 enum mlx5_fpga_connect *connect;
205 u32 fpga_cap[MLX5_ST_SZ_DW(fpga_cap)] = {0};
208 err = devfs_get_cdevpriv((void **)&context);
211 fdev = context->tdev->fdev;
216 case MLX5_FPGA_ACCESS_TYPE:
218 if (arg > MLX5_FPGA_ACCESS_TYPE_MAX) {
219 dev_err(mlx5_fpga_dev(fdev),
220 "unknown access type %u\n", arg);
224 context->access_type = arg;
228 if (arg > MLX5_FPGA_IMAGE_FACTORY) {
229 dev_err(mlx5_fpga_dev(fdev),
230 "unknown image type %u\n", arg);
234 err = mlx5_fpga_device_reload(fdev, arg);
236 case MLX5_FPGA_RESET:
237 err = mlx5_fpga_device_reload(fdev, MLX5_FPGA_IMAGE_RESET);
239 case MLX5_FPGA_RELOAD:
240 err = mlx5_fpga_device_reload(fdev, MLX5_FPGA_IMAGE_RELOAD);
242 case MLX5_FPGA_IMAGE_SEL:
244 if (arg > MLX5_FPGA_IMAGE_FACTORY) {
245 dev_err(mlx5_fpga_dev(fdev),
246 "unknown image type %u\n", arg);
250 err = mlx5_fpga_flash_select(fdev, arg);
252 case MLX5_FPGA_QUERY:
253 mlx5_fpga_device_query(fdev, &query);
254 bcopy(&query, data, sizeof(query));
258 mlx5_fpga_get_cap(fdev, fpga_cap);
259 bcopy(&fpga_cap, data, sizeof(fpga_cap));
262 case MLX5_FPGA_TEMPERATURE:
263 temperature = (struct mlx5_fpga_temperature *)data;
264 mlx5_fpga_temperature(fdev, temperature);
265 err = 0; /* XXXKIB */
267 case MLX5_FPGA_CONNECT:
268 connect = (enum mlx5_fpga_connect *)data;
269 mlx5_fpga_connectdisconnect(fdev, connect);
270 err = 0; /* XXXKIB */
273 dev_err(mlx5_fpga_dev(fdev),
274 "unknown ioctl command %#08lx\n", cmd);
280 static struct cdevsw mlx5_tools_char_cdevsw = {
281 .d_version = D_VERSION,
282 .d_name = "mlx5_tools_char",
283 .d_open = tools_char_open,
284 .d_read = tools_char_read,
285 .d_write = tools_char_write,
286 .d_ioctl = tools_char_ioctl,
290 mlx5_fpga_tools_char_add_one(struct mlx5_fpga_tools_dev *tdev)
292 struct make_dev_args mda;
297 make_dev_args_init(&mda);
298 mda.mda_flags = MAKEDEV_WAITOK | MAKEDEV_CHECKNAME;
299 mda.mda_devsw = &mlx5_tools_char_cdevsw;
300 mda.mda_uid = UID_ROOT;
301 mda.mda_gid = GID_OPERATOR;
303 mda.mda_si_drv1 = tdev;
304 bdev = mlx5_fpga_dev(tdev->fdev)->bsddev;
305 ret = make_dev_s(&mda, &cd,
306 "%04x:%02x:%02x.%x" MLX5_FPGA_TOOLS_NAME_SUFFIX,
307 pci_get_domain(bdev), pci_get_bus(bdev), pci_get_slot(bdev),
308 pci_get_function(bdev));
310 tdev->char_device = NULL;
311 dev_err(mlx5_fpga_dev(tdev->fdev),
312 "Failed to create a char device: %d\n", ret);
315 tdev->char_device = cd;
317 dev_dbg(mlx5_fpga_dev(tdev->fdev), "tools char device %s created\n",
322 void mlx5_fpga_tools_char_remove_one(struct mlx5_fpga_tools_dev *tdev)
325 dev_err(mlx5_fpga_dev(tdev->fdev), "tools char device %s destroyed\n",
326 ((struct cdev *)(tdev->char_device))->si_name);
327 destroy_dev((struct cdev *)(tdev->char_device));
331 mlx5_fpga_tools_char_init(void)
338 mlx5_fpga_tools_char_deinit(void)