xref: /freebsd/sys/dev/mlx5/mlx5_fpga/mlx5fpga_sdk.c (revision 19fae0f66023a97a9b464b3beeeabb2081f575b3)
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 static int mlx5_fpga_device_reload_cmd(struct mlx5_fpga_device *fdev)
328 {
329 	struct mlx5_core_dev *mdev = fdev->mdev;
330 	unsigned long timeout;
331 	unsigned long flags;
332 	int err = 0;
333 
334 	mlx5_fpga_info(fdev, "mlx5/fpga - reload started\n");
335 	fdev->fdev_state = MLX5_FDEV_STATE_IN_PROGRESS;
336 	reinit_completion(&fdev->load_event);
337 	err = mlx5_fpga_ctrl_op(mdev, MLX5_FPGA_CTRL_OPERATION_RELOAD);
338 	if (err) {
339 		mlx5_fpga_err(fdev, "Failed to request reload: %d\n",
340 			      err);
341 		goto out;
342 	}
343 	timeout = jiffies + msecs_to_jiffies(MLX5_FPGA_LOAD_TIMEOUT);
344 	err = wait_for_completion_timeout(&fdev->load_event,
345 					  timeout - jiffies);
346 	if (err < 0) {
347 		mlx5_fpga_err(fdev, "Failed waiting for reload: %d\n", err);
348 		fdev->fdev_state = MLX5_FDEV_STATE_FAILURE;
349 		goto out;
350 	}
351 	/* Check device loaded successful */
352 	err = mlx5_fpga_device_start(mdev);
353 	if (err) {
354 		mlx5_fpga_err(fdev, "Failed load check for reload: %d\n", err);
355 		fdev->fdev_state = MLX5_FDEV_STATE_FAILURE;
356 		goto out;
357 	}
358 	spin_lock_irqsave(&fdev->state_lock, flags);
359 	fdev->fdev_state = MLX5_FDEV_STATE_SUCCESS;
360 	spin_unlock_irqrestore(&fdev->state_lock, flags);
361 	mlx5_fpga_info(fdev, "mlx5/fpga - reload ended\n");
362 out:
363 	return err;
364 }
365 
366 int mlx5_fpga_device_reload(struct mlx5_fpga_device *fdev,
367 			    enum mlx5_fpga_image image)
368 {
369 	struct mlx5_core_dev *mdev = fdev->mdev;
370 	unsigned long timeout;
371 	unsigned long flags;
372 	int err = 0;
373 
374 	spin_lock_irqsave(&fdev->state_lock, flags);
375 	switch (fdev->fdev_state) {
376 	case MLX5_FDEV_STATE_NONE:
377 		err = -ENODEV;
378 		break;
379 	case MLX5_FDEV_STATE_IN_PROGRESS:
380 		err = -EBUSY;
381 		break;
382 	case MLX5_FDEV_STATE_SUCCESS:
383 	case MLX5_FDEV_STATE_FAILURE:
384 	case MLX5_FDEV_STATE_DISCONNECTED:
385 		break;
386 	}
387 	spin_unlock_irqrestore(&fdev->state_lock, flags);
388 	if (err)
389 		return err;
390 
391 	mutex_lock(&mdev->intf_state_mutex);
392 
393 	if (image == MLX5_FPGA_IMAGE_RELOAD) {
394 		err = mlx5_fpga_device_reload_cmd(fdev);
395 		goto out;
396 	}
397 
398 	clear_bit(MLX5_INTERFACE_STATE_UP, &mdev->intf_state);
399 
400 	mlx5_unregister_device(mdev);
401 	/* XXXKIB	mlx5_accel_ipsec_cleanup(mdev); */
402 	mlx5_fpga_device_stop(mdev);
403 
404 	fdev->fdev_state = MLX5_FDEV_STATE_IN_PROGRESS;
405 	reinit_completion(&fdev->load_event);
406 
407 	if (image <= MLX5_FPGA_IMAGE_FACTORY) {
408 		mlx5_fpga_info(fdev, "Loading from flash\n");
409 		err = mlx5_fpga_load(mdev, image);
410 		if (err) {
411 			mlx5_fpga_err(fdev, "Failed to request load: %d\n",
412 				      err);
413 			goto out;
414 		}
415 	} else if (image == MLX5_FPGA_IMAGE_RESET) {
416 		mlx5_fpga_info(fdev, "Resetting\n");
417 		err = mlx5_fpga_ctrl_op(mdev, MLX5_FPGA_CTRL_OPERATION_RESET);
418 		if (err) {
419 			mlx5_fpga_err(fdev, "Failed to request reset: %d\n",
420 				      err);
421 			goto out;
422 		}
423 	} else {
424 		mlx5_fpga_err(fdev, "Unknown command: %d\n",
425 			      image);
426 		goto out;
427 	}
428 
429 	timeout = jiffies + msecs_to_jiffies(MLX5_FPGA_LOAD_TIMEOUT);
430 	err = wait_for_completion_timeout(&fdev->load_event, timeout - jiffies);
431 	if (err < 0) {
432 		mlx5_fpga_err(fdev, "Failed waiting for FPGA load: %d\n", err);
433 		fdev->fdev_state = MLX5_FDEV_STATE_FAILURE;
434 		goto out;
435 	}
436 
437 	err = mlx5_fpga_device_start(mdev);
438 	if (err) {
439 		mlx5_core_err(mdev, "fpga device start failed %d\n", err);
440 		goto out;
441 	}
442 	/* XXXKIB err = mlx5_accel_ipsec_init(mdev); */
443 	if (err) {
444 		mlx5_core_err(mdev, "IPSec device start failed %d\n", err);
445 		goto err_fpga;
446 	}
447 
448 	err = mlx5_register_device(mdev);
449 	if (err) {
450 		mlx5_core_err(mdev, "mlx5_register_device failed %d\n", err);
451 		fdev->fdev_state = MLX5_FDEV_STATE_FAILURE;
452 		goto err_ipsec;
453 	}
454 
455 	set_bit(MLX5_INTERFACE_STATE_UP, &mdev->intf_state);
456 	goto out;
457 
458 err_ipsec:
459 	/* XXXKIB mlx5_accel_ipsec_cleanup(mdev); */
460 err_fpga:
461 	mlx5_fpga_device_stop(mdev);
462 out:
463 	mutex_unlock(&mdev->intf_state_mutex);
464 	return err;
465 }
466 EXPORT_SYMBOL(mlx5_fpga_device_reload);
467 
468 int mlx5_fpga_flash_select(struct mlx5_fpga_device *fdev,
469 			   enum mlx5_fpga_image image)
470 {
471 	unsigned long flags;
472 	int err;
473 
474 	spin_lock_irqsave(&fdev->state_lock, flags);
475 	switch (fdev->fdev_state) {
476 	case MLX5_FDEV_STATE_NONE:
477 		spin_unlock_irqrestore(&fdev->state_lock, flags);
478 		return -ENODEV;
479 	case MLX5_FDEV_STATE_DISCONNECTED:
480 	case MLX5_FDEV_STATE_IN_PROGRESS:
481 	case MLX5_FDEV_STATE_SUCCESS:
482 	case MLX5_FDEV_STATE_FAILURE:
483 		break;
484 	}
485 	spin_unlock_irqrestore(&fdev->state_lock, flags);
486 
487 	err = mlx5_fpga_image_select(fdev->mdev, image);
488 	if (err)
489 		mlx5_fpga_err(fdev, "Failed to select flash image: %d\n", err);
490 	else
491 		fdev->last_admin_image = image;
492 	return err;
493 }
494 EXPORT_SYMBOL(mlx5_fpga_flash_select);
495 
496 int mlx5_fpga_connectdisconnect(struct mlx5_fpga_device *fdev,
497 				enum mlx5_fpga_connect *connect)
498 {
499 	unsigned long flags;
500 	int err;
501 
502 	spin_lock_irqsave(&fdev->state_lock, flags);
503 	switch (fdev->fdev_state) {
504 	case MLX5_FDEV_STATE_NONE:
505 		spin_unlock_irqrestore(&fdev->state_lock, flags);
506 		return -ENODEV;
507 	case MLX5_FDEV_STATE_IN_PROGRESS:
508 	case MLX5_FDEV_STATE_SUCCESS:
509 	case MLX5_FDEV_STATE_FAILURE:
510 	case MLX5_FDEV_STATE_DISCONNECTED:
511 		break;
512 	}
513 	spin_unlock_irqrestore(&fdev->state_lock, flags);
514 
515 	err = mlx5_fpga_ctrl_connect(fdev->mdev, connect);
516 	if (err)
517 		mlx5_fpga_err(fdev, "Failed to connect/disconnect: %d\n", err);
518 	return err;
519 }
520 EXPORT_SYMBOL(mlx5_fpga_connectdisconnect);
521 
522 int mlx5_fpga_temperature(struct mlx5_fpga_device *fdev,
523 			  struct mlx5_fpga_temperature *temp)
524 {
525 	return mlx5_fpga_query_mtmp(fdev->mdev, temp);
526 }
527 EXPORT_SYMBOL(mlx5_fpga_temperature);
528 
529 struct device *mlx5_fpga_dev(struct mlx5_fpga_device *fdev)
530 {
531 	return &fdev->mdev->pdev->dev;
532 }
533 EXPORT_SYMBOL(mlx5_fpga_dev);
534 
535 void mlx5_fpga_get_cap(struct mlx5_fpga_device *fdev, u32 *fpga_caps)
536 {
537 	unsigned long flags;
538 
539 	spin_lock_irqsave(&fdev->state_lock, flags);
540 	memcpy(fpga_caps, &fdev->mdev->caps.fpga, sizeof(fdev->mdev->caps.fpga));
541 	spin_unlock_irqrestore(&fdev->state_lock, flags);
542 }
543 EXPORT_SYMBOL(mlx5_fpga_get_cap);
544