xref: /freebsd/sys/dev/mlx5/mlx5_fpga/mlx5fpga_sdk.c (revision cddbc3b40812213ff00041f79174cac0be360a2a)
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 <linux/errno.h>
36 #include <linux/err.h>
37 #include <linux/completion.h>
38 #include <dev/mlx5/device.h>
39 #include <dev/mlx5/mlx5_fpga/core.h>
40 #include <dev/mlx5/mlx5_fpga/conn.h>
41 #include <dev/mlx5/mlx5_fpga/sdk.h>
42 #include <dev/mlx5/mlx5_fpga/xfer.h>
43 #include <dev/mlx5/mlx5_core/mlx5_core.h>
44 /* #include "accel/ipsec.h" */
45 
46 #define MLX5_FPGA_LOAD_TIMEOUT 25000 /* msec */
47 
48 struct mem_transfer {
49 	struct mlx5_fpga_transaction t;
50 	struct completion comp;
51 	u8 status;
52 };
53 
54 struct mlx5_fpga_conn *
55 mlx5_fpga_sbu_conn_create(struct mlx5_fpga_device *fdev,
56 			  struct mlx5_fpga_conn_attr *attr)
57 {
58 #ifdef NOT_YET
59 	/* XXXKIB */
60 	return mlx5_fpga_conn_create(fdev, attr, MLX5_FPGA_QPC_QP_TYPE_SANDBOX_QP);
61 #else
62 	return (NULL);
63 #endif
64 }
65 EXPORT_SYMBOL(mlx5_fpga_sbu_conn_create);
66 
67 void mlx5_fpga_sbu_conn_destroy(struct mlx5_fpga_conn *conn)
68 {
69 #ifdef NOT_YET
70 	/* XXXKIB */
71 	mlx5_fpga_conn_destroy(conn);
72 #endif
73 }
74 EXPORT_SYMBOL(mlx5_fpga_sbu_conn_destroy);
75 
76 int mlx5_fpga_sbu_conn_sendmsg(struct mlx5_fpga_conn *conn,
77 			       struct mlx5_fpga_dma_buf *buf)
78 {
79 #ifdef NOT_YET
80 	/* XXXKIB */
81 	return mlx5_fpga_conn_send(conn, buf);
82 #else
83 	return (0);
84 #endif
85 }
86 EXPORT_SYMBOL(mlx5_fpga_sbu_conn_sendmsg);
87 
88 static void mem_complete(const struct mlx5_fpga_transaction *complete,
89 			 u8 status)
90 {
91 	struct mem_transfer *xfer;
92 
93 	mlx5_fpga_dbg(complete->conn->fdev,
94 		      "transaction %p complete status %u", complete, status);
95 
96 	xfer = container_of(complete, struct mem_transfer, t);
97 	xfer->status = status;
98 	complete_all(&xfer->comp);
99 }
100 
101 static int mem_transaction(struct mlx5_fpga_device *fdev, size_t size, u64 addr,
102 			   void *buf, enum mlx5_fpga_direction direction)
103 {
104 	int ret;
105 	struct mem_transfer xfer;
106 
107 	if (!fdev->shell_conn) {
108 		ret = -ENOTCONN;
109 		goto out;
110 	}
111 
112 	xfer.t.data = buf;
113 	xfer.t.size = size;
114 	xfer.t.addr = addr;
115 	xfer.t.conn = fdev->shell_conn;
116 	xfer.t.direction = direction;
117 	xfer.t.complete1 = mem_complete;
118 	init_completion(&xfer.comp);
119 	ret = mlx5_fpga_xfer_exec(&xfer.t);
120 	if (ret) {
121 		mlx5_fpga_dbg(fdev, "Transfer execution failed: %d\n", ret);
122 		goto out;
123 	}
124 	wait_for_completion(&xfer.comp);
125 	if (xfer.status != 0)
126 		ret = -EIO;
127 
128 out:
129 	return ret;
130 }
131 
132 static int mlx5_fpga_mem_read_i2c(struct mlx5_fpga_device *fdev, size_t size,
133 				  u64 addr, u8 *buf)
134 {
135 	size_t max_size = MLX5_FPGA_ACCESS_REG_SIZE_MAX;
136 	size_t bytes_done = 0;
137 	u8 actual_size;
138 	int err = 0;
139 
140 	if (!size)
141 		return -EINVAL;
142 
143 	if (!fdev->mdev)
144 		return -ENOTCONN;
145 
146 	while (bytes_done < size) {
147 		actual_size = min(max_size, (size - bytes_done));
148 
149 		err = mlx5_fpga_access_reg(fdev->mdev, actual_size,
150 					   addr + bytes_done,
151 					   buf + bytes_done, false);
152 		if (err) {
153 			mlx5_fpga_err(fdev, "Failed to read over I2C: %d\n",
154 				      err);
155 			break;
156 		}
157 
158 		bytes_done += actual_size;
159 	}
160 
161 	return err;
162 }
163 
164 static int mlx5_fpga_mem_write_i2c(struct mlx5_fpga_device *fdev, size_t size,
165 				   u64 addr, u8 *buf)
166 {
167 	size_t max_size = MLX5_FPGA_ACCESS_REG_SIZE_MAX;
168 	size_t bytes_done = 0;
169 	u8 actual_size;
170 	int err = 0;
171 
172 	if (!size)
173 		return -EINVAL;
174 
175 	if (!fdev->mdev)
176 		return -ENOTCONN;
177 
178 	while (bytes_done < size) {
179 		actual_size = min(max_size, (size - bytes_done));
180 
181 		err = mlx5_fpga_access_reg(fdev->mdev, actual_size,
182 					   addr + bytes_done,
183 					   buf + bytes_done, true);
184 		if (err) {
185 			mlx5_fpga_err(fdev, "Failed to write FPGA crspace\n");
186 			break;
187 		}
188 
189 		bytes_done += actual_size;
190 	}
191 
192 	return err;
193 }
194 
195 int mlx5_fpga_mem_read(struct mlx5_fpga_device *fdev, size_t size, u64 addr,
196 		       void *buf, enum mlx5_fpga_access_type access_type)
197 {
198 	int ret;
199 
200 	if (access_type == MLX5_FPGA_ACCESS_TYPE_DONTCARE)
201 		access_type = fdev->shell_conn ? MLX5_FPGA_ACCESS_TYPE_RDMA :
202 						 MLX5_FPGA_ACCESS_TYPE_I2C;
203 
204 	mlx5_fpga_dbg(fdev, "Reading %zu bytes at 0x%jx over %s",
205 		      size, (uintmax_t)addr, access_type ? "RDMA" : "I2C");
206 
207 	switch (access_type) {
208 	case MLX5_FPGA_ACCESS_TYPE_RDMA:
209 		ret = mem_transaction(fdev, size, addr, buf, MLX5_FPGA_READ);
210 		if (ret)
211 			return ret;
212 		break;
213 	case MLX5_FPGA_ACCESS_TYPE_I2C:
214 		ret = mlx5_fpga_mem_read_i2c(fdev, size, addr, buf);
215 		if (ret)
216 			return ret;
217 		break;
218 	default:
219 		mlx5_fpga_warn(fdev, "Unexpected read access_type %u\n",
220 			       access_type);
221 		return -EACCES;
222 	}
223 
224 	return size;
225 }
226 EXPORT_SYMBOL(mlx5_fpga_mem_read);
227 
228 int mlx5_fpga_mem_write(struct mlx5_fpga_device *fdev, size_t size, u64 addr,
229 			void *buf, enum mlx5_fpga_access_type access_type)
230 {
231 	int ret;
232 
233 	if (access_type == MLX5_FPGA_ACCESS_TYPE_DONTCARE)
234 		access_type = fdev->shell_conn ? MLX5_FPGA_ACCESS_TYPE_RDMA :
235 						 MLX5_FPGA_ACCESS_TYPE_I2C;
236 
237 	mlx5_fpga_dbg(fdev, "Writing %zu bytes at 0x%jx over %s",
238 		      size, (uintmax_t)addr, access_type ? "RDMA" : "I2C");
239 
240 	switch (access_type) {
241 	case MLX5_FPGA_ACCESS_TYPE_RDMA:
242 		ret = mem_transaction(fdev, size, addr, buf, MLX5_FPGA_WRITE);
243 		if (ret)
244 			return ret;
245 		break;
246 	case MLX5_FPGA_ACCESS_TYPE_I2C:
247 		ret = mlx5_fpga_mem_write_i2c(fdev, size, addr, buf);
248 		if (ret)
249 			return ret;
250 		break;
251 	default:
252 		mlx5_fpga_warn(fdev, "Unexpected write access_type %u\n",
253 			       access_type);
254 		return -EACCES;
255 	}
256 
257 	return size;
258 }
259 EXPORT_SYMBOL(mlx5_fpga_mem_write);
260 
261 int mlx5_fpga_get_sbu_caps(struct mlx5_fpga_device *fdev, int size, void *buf)
262 {
263 	return mlx5_fpga_sbu_caps(fdev->mdev, buf, size);
264 }
265 EXPORT_SYMBOL(mlx5_fpga_get_sbu_caps);
266 
267 u64 mlx5_fpga_ddr_size_get(struct mlx5_fpga_device *fdev)
268 {
269 	return (u64)MLX5_CAP_FPGA(fdev->mdev, fpga_ddr_size) << 10;
270 }
271 EXPORT_SYMBOL(mlx5_fpga_ddr_size_get);
272 
273 u64 mlx5_fpga_ddr_base_get(struct mlx5_fpga_device *fdev)
274 {
275 	return MLX5_CAP64_FPGA(fdev->mdev, fpga_ddr_start_addr);
276 }
277 EXPORT_SYMBOL(mlx5_fpga_ddr_base_get);
278 
279 void mlx5_fpga_client_data_set(struct mlx5_fpga_device *fdev,
280 			       struct mlx5_fpga_client *client, void *data)
281 {
282 	struct mlx5_fpga_client_data *context;
283 
284 	list_for_each_entry(context, &fdev->client_data_list, list) {
285 		if (context->client != client)
286 			continue;
287 		context->data = data;
288 		return;
289 	}
290 
291 	mlx5_fpga_warn(fdev, "No client context found for %s\n", client->name);
292 }
293 EXPORT_SYMBOL(mlx5_fpga_client_data_set);
294 
295 void *mlx5_fpga_client_data_get(struct mlx5_fpga_device *fdev,
296 				struct mlx5_fpga_client *client)
297 {
298 	struct mlx5_fpga_client_data *context;
299 	void *ret = NULL;
300 
301 	list_for_each_entry(context, &fdev->client_data_list, list) {
302 		if (context->client != client)
303 			continue;
304 		ret = context->data;
305 		goto out;
306 	}
307 	mlx5_fpga_warn(fdev, "No client context found for %s\n", client->name);
308 
309 out:
310 	return ret;
311 }
312 EXPORT_SYMBOL(mlx5_fpga_client_data_get);
313 
314 void mlx5_fpga_device_query(struct mlx5_fpga_device *fdev,
315 			    struct mlx5_fpga_query *query)
316 {
317 	unsigned long flags;
318 
319 	spin_lock_irqsave(&fdev->state_lock, flags);
320 	query->image_status = fdev->image_status;
321 	query->admin_image = fdev->last_admin_image;
322 	query->oper_image = fdev->last_oper_image;
323 	spin_unlock_irqrestore(&fdev->state_lock, flags);
324 }
325 EXPORT_SYMBOL(mlx5_fpga_device_query);
326 
327 int mlx5_fpga_device_reload(struct mlx5_fpga_device *fdev,
328 			    enum mlx5_fpga_image image)
329 {
330 	struct mlx5_core_dev *mdev = fdev->mdev;
331 	unsigned long timeout;
332 	unsigned long flags;
333 	int err = 0;
334 
335 	spin_lock_irqsave(&fdev->state_lock, flags);
336 	switch (fdev->fdev_state) {
337 	case MLX5_FDEV_STATE_NONE:
338 		err = -ENODEV;
339 		break;
340 	case MLX5_FDEV_STATE_IN_PROGRESS:
341 		err = -EBUSY;
342 		break;
343 	case MLX5_FDEV_STATE_SUCCESS:
344 	case MLX5_FDEV_STATE_FAILURE:
345 	case MLX5_FDEV_STATE_DISCONNECTED:
346 		break;
347 	}
348 	spin_unlock_irqrestore(&fdev->state_lock, flags);
349 	if (err)
350 		return err;
351 
352 	mutex_lock(&mdev->intf_state_mutex);
353 	clear_bit(MLX5_INTERFACE_STATE_UP, &mdev->intf_state);
354 
355 	mlx5_unregister_device(mdev);
356 	/* XXXKIB	mlx5_accel_ipsec_cleanup(mdev); */
357 	mlx5_fpga_device_stop(mdev);
358 
359 	fdev->fdev_state = MLX5_FDEV_STATE_IN_PROGRESS;
360 	reinit_completion(&fdev->load_event);
361 
362 	if (image <= MLX5_FPGA_IMAGE_MAX) {
363 		mlx5_fpga_info(fdev, "Loading from flash\n");
364 		err = mlx5_fpga_load(mdev, image);
365 		if (err) {
366 			mlx5_fpga_err(fdev, "Failed to request load: %d\n",
367 				      err);
368 			goto out;
369 		}
370 	} else {
371 		mlx5_fpga_info(fdev, "Resetting\n");
372 		err = mlx5_fpga_ctrl_op(mdev, MLX5_FPGA_CTRL_OPERATION_RESET);
373 		if (err) {
374 			mlx5_fpga_err(fdev, "Failed to request reset: %d\n",
375 				      err);
376 			goto out;
377 		}
378 	}
379 
380 	timeout = jiffies + msecs_to_jiffies(MLX5_FPGA_LOAD_TIMEOUT);
381 	err = wait_for_completion_timeout(&fdev->load_event, timeout - jiffies);
382 	if (err < 0) {
383 		mlx5_fpga_err(fdev, "Failed waiting for FPGA load: %d\n", err);
384 		fdev->fdev_state = MLX5_FDEV_STATE_FAILURE;
385 		goto out;
386 	}
387 
388 	err = mlx5_fpga_device_start(mdev);
389 	if (err) {
390 		mlx5_core_err(mdev, "fpga device start failed %d\n", err);
391 		goto out;
392 	}
393 	/* XXXKIB err = mlx5_accel_ipsec_init(mdev); */
394 	if (err) {
395 		mlx5_core_err(mdev, "IPSec device start failed %d\n", err);
396 		goto err_fpga;
397 	}
398 
399 	err = mlx5_register_device(mdev);
400 	if (err) {
401 		mlx5_core_err(mdev, "mlx5_register_device failed %d\n", err);
402 		fdev->fdev_state = MLX5_FDEV_STATE_FAILURE;
403 		goto err_ipsec;
404 	}
405 
406 	set_bit(MLX5_INTERFACE_STATE_UP, &mdev->intf_state);
407 	goto out;
408 
409 err_ipsec:
410 	/* XXXKIB mlx5_accel_ipsec_cleanup(mdev); */
411 err_fpga:
412 	mlx5_fpga_device_stop(mdev);
413 out:
414 	mutex_unlock(&mdev->intf_state_mutex);
415 	return err;
416 }
417 EXPORT_SYMBOL(mlx5_fpga_device_reload);
418 
419 int mlx5_fpga_flash_select(struct mlx5_fpga_device *fdev,
420 			   enum mlx5_fpga_image image)
421 {
422 	unsigned long flags;
423 	int err;
424 
425 	spin_lock_irqsave(&fdev->state_lock, flags);
426 	switch (fdev->fdev_state) {
427 	case MLX5_FDEV_STATE_NONE:
428 		spin_unlock_irqrestore(&fdev->state_lock, flags);
429 		return -ENODEV;
430 	case MLX5_FDEV_STATE_DISCONNECTED:
431 	case MLX5_FDEV_STATE_IN_PROGRESS:
432 	case MLX5_FDEV_STATE_SUCCESS:
433 	case MLX5_FDEV_STATE_FAILURE:
434 		break;
435 	}
436 	spin_unlock_irqrestore(&fdev->state_lock, flags);
437 
438 	err = mlx5_fpga_image_select(fdev->mdev, image);
439 	if (err)
440 		mlx5_fpga_err(fdev, "Failed to select flash image: %d\n", err);
441 	else
442 		fdev->last_admin_image = image;
443 	return err;
444 }
445 EXPORT_SYMBOL(mlx5_fpga_flash_select);
446 
447 int mlx5_fpga_connectdisconnect(struct mlx5_fpga_device *fdev,
448 				enum mlx5_fpga_connect *connect)
449 {
450 	unsigned long flags;
451 	int err;
452 
453 	spin_lock_irqsave(&fdev->state_lock, flags);
454 	switch (fdev->fdev_state) {
455 	case MLX5_FDEV_STATE_NONE:
456 		spin_unlock_irqrestore(&fdev->state_lock, flags);
457 		return -ENODEV;
458 	case MLX5_FDEV_STATE_IN_PROGRESS:
459 	case MLX5_FDEV_STATE_SUCCESS:
460 	case MLX5_FDEV_STATE_FAILURE:
461 	case MLX5_FDEV_STATE_DISCONNECTED:
462 		break;
463 	}
464 	spin_unlock_irqrestore(&fdev->state_lock, flags);
465 
466 	err = mlx5_fpga_ctrl_connect(fdev->mdev, connect);
467 	if (err)
468 		mlx5_fpga_err(fdev, "Failed to connect/disconnect: %d\n", err);
469 	return err;
470 }
471 EXPORT_SYMBOL(mlx5_fpga_connectdisconnect);
472 
473 int mlx5_fpga_temperature(struct mlx5_fpga_device *fdev,
474 			  struct mlx5_fpga_temperature *temp)
475 {
476 	return mlx5_fpga_query_mtmp(fdev->mdev, temp);
477 }
478 EXPORT_SYMBOL(mlx5_fpga_temperature);
479 
480 struct device *mlx5_fpga_dev(struct mlx5_fpga_device *fdev)
481 {
482 	return &fdev->mdev->pdev->dev;
483 }
484 EXPORT_SYMBOL(mlx5_fpga_dev);
485 
486 void mlx5_fpga_get_cap(struct mlx5_fpga_device *fdev, u32 *fpga_caps)
487 {
488 	unsigned long flags;
489 
490 	spin_lock_irqsave(&fdev->state_lock, flags);
491 	memcpy(fpga_caps, &fdev->mdev->caps.fpga, sizeof(fdev->mdev->caps.fpga));
492 	spin_unlock_irqrestore(&fdev->state_lock, flags);
493 }
494 EXPORT_SYMBOL(mlx5_fpga_get_cap);
495