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
48struct mem_transfer {
49	struct mlx5_fpga_transaction t;
50	struct completion comp;
51	u8 status;
52};
53
54struct mlx5_fpga_conn *
55mlx5_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}
65EXPORT_SYMBOL(mlx5_fpga_sbu_conn_create);
66
67void 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}
74EXPORT_SYMBOL(mlx5_fpga_sbu_conn_destroy);
75
76int 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}
86EXPORT_SYMBOL(mlx5_fpga_sbu_conn_sendmsg);
87
88static 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
101static 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
128out:
129	return ret;
130}
131
132static 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
164static 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
195int 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}
226EXPORT_SYMBOL(mlx5_fpga_mem_read);
227
228int 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}
259EXPORT_SYMBOL(mlx5_fpga_mem_write);
260
261int 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}
265EXPORT_SYMBOL(mlx5_fpga_get_sbu_caps);
266
267u64 mlx5_fpga_ddr_size_get(struct mlx5_fpga_device *fdev)
268{
269	return (u64)MLX5_CAP_FPGA(fdev->mdev, fpga_ddr_size) << 10;
270}
271EXPORT_SYMBOL(mlx5_fpga_ddr_size_get);
272
273u64 mlx5_fpga_ddr_base_get(struct mlx5_fpga_device *fdev)
274{
275	return MLX5_CAP64_FPGA(fdev->mdev, fpga_ddr_start_addr);
276}
277EXPORT_SYMBOL(mlx5_fpga_ddr_base_get);
278
279void 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}
293EXPORT_SYMBOL(mlx5_fpga_client_data_set);
294
295void *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
309out:
310	return ret;
311}
312EXPORT_SYMBOL(mlx5_fpga_client_data_get);
313
314void 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}
325EXPORT_SYMBOL(mlx5_fpga_device_query);
326
327static 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");
362out:
363	return err;
364}
365
366int 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
458err_ipsec:
459	/* XXXKIB mlx5_accel_ipsec_cleanup(mdev); */
460err_fpga:
461	mlx5_fpga_device_stop(mdev);
462out:
463	mutex_unlock(&mdev->intf_state_mutex);
464	return err;
465}
466EXPORT_SYMBOL(mlx5_fpga_device_reload);
467
468int 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}
494EXPORT_SYMBOL(mlx5_fpga_flash_select);
495
496int 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}
520EXPORT_SYMBOL(mlx5_fpga_connectdisconnect);
521
522int 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}
527EXPORT_SYMBOL(mlx5_fpga_temperature);
528
529struct device *mlx5_fpga_dev(struct mlx5_fpga_device *fdev)
530{
531	return &fdev->mdev->pdev->dev;
532}
533EXPORT_SYMBOL(mlx5_fpga_dev);
534
535void 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}
543EXPORT_SYMBOL(mlx5_fpga_get_cap);
544