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/module.h>
36 #include <linux/etherdevice.h>
37 #include <dev/mlx5/driver.h>
38 #include <dev/mlx5/mlx5_core/mlx5_core.h>
39 #include <dev/mlx5/mlx5_lib/mlx5.h>
40 #include <dev/mlx5/mlx5_fpga/core.h>
41 #include <dev/mlx5/mlx5_fpga/conn.h>
42 #include <dev/mlx5/mlx5_fpga/trans.h>
43
44 static LIST_HEAD(mlx5_fpga_devices);
45 static LIST_HEAD(mlx5_fpga_clients);
46 /* protects access between client un/registration and device add/remove calls */
47 static DEFINE_MUTEX(mlx5_fpga_mutex);
48
49 static const char *const mlx5_fpga_error_strings[] = {
50 "Null Syndrome",
51 "Corrupted DDR",
52 "Flash Timeout",
53 "Internal Link Error",
54 "Watchdog HW Failure",
55 "I2C Failure",
56 "Image Changed",
57 "Temperature Critical",
58 };
59
60 static const char * const mlx5_fpga_qp_error_strings[] = {
61 "Null Syndrome",
62 "Retry Counter Expired",
63 "RNR Expired",
64 };
65
66 static void client_context_destroy(struct mlx5_fpga_device *fdev,
67 struct mlx5_fpga_client_data *context)
68 {
69 mlx5_fpga_dbg(fdev, "Deleting client context %p of client %p\n",
70 context, context->client);
71 if (context->client->destroy)
72 context->client->destroy(fdev);
73 list_del(&context->list);
74 kfree(context);
75 }
76
77 static int client_context_create(struct mlx5_fpga_device *fdev,
78 struct mlx5_fpga_client *client,
79 struct mlx5_fpga_client_data **pctx)
80 {
81 struct mlx5_fpga_client_data *context;
82
83 context = kmalloc(sizeof(*context), GFP_KERNEL);
84 if (!context)
85 return -ENOMEM;
86
87 context->client = client;
88 context->data = NULL;
89 context->added = false;
90 list_add(&context->list, &fdev->client_data_list);
91
92 mlx5_fpga_dbg(fdev, "Adding client context %p client %p\n",
93 context, client);
94
95 if (client->create)
96 client->create(fdev);
97
98 if (pctx)
99 *pctx = context;
100 return 0;
101 }
102
103 static struct mlx5_fpga_device *mlx5_fpga_device_alloc(void)
104 {
105 struct mlx5_fpga_device *fdev = NULL;
106
107 fdev = kzalloc(sizeof(*fdev), GFP_KERNEL);
108 if (!fdev)
109 return NULL;
110
111 spin_lock_init(&fdev->state_lock);
112 init_completion(&fdev->load_event);
113 fdev->fdev_state = MLX5_FDEV_STATE_NONE;
114 INIT_LIST_HEAD(&fdev->client_data_list);
115 return fdev;
116 }
117
118 static const char *mlx5_fpga_image_name(enum mlx5_fpga_image image)
119 {
120 switch (image) {
121 case MLX5_FPGA_IMAGE_USER:
122 return "user";
123 case MLX5_FPGA_IMAGE_FACTORY:
124 return "factory";
125 default:
126 return "unknown";
127 }
128 }
129
130 static const char *mlx5_fpga_name(u32 fpga_id)
131 {
132 static char ret[32];
133
134 switch (fpga_id) {
135 case MLX5_FPGA_NEWTON:
136 return "Newton";
137 case MLX5_FPGA_EDISON:
138 return "Edison";
139 case MLX5_FPGA_MORSE:
140 return "Morse";
141 case MLX5_FPGA_MORSEQ:
142 return "MorseQ";
143 }
144
145 snprintf(ret, sizeof(ret), "Unknown %d", fpga_id);
146 return ret;
147 }
148
149 static int mlx5_fpga_device_load_check(struct mlx5_fpga_device *fdev)
150 {
151 struct mlx5_fpga_query query;
152 int err;
153 u32 fpga_id;
154
155 err = mlx5_fpga_query(fdev->mdev, &query);
156 if (err) {
157 mlx5_fpga_err(fdev, "Failed to query status: %d\n", err);
158 return err;
159 }
160
161 fdev->last_admin_image = query.admin_image;
162 fdev->last_oper_image = query.oper_image;
163 fdev->image_status = query.image_status;
164
165 mlx5_fpga_info(fdev, "Status %u; Admin image %u; Oper image %u\n",
166 query.image_status, query.admin_image, query.oper_image);
167
168 /* For Morse projects FPGA has no influence to network functionality */
169 fpga_id = MLX5_CAP_FPGA(fdev->mdev, fpga_id);
170 if (fpga_id == MLX5_FPGA_MORSE || fpga_id == MLX5_FPGA_MORSEQ)
171 return 0;
172
173 if (query.image_status != MLX5_FPGA_STATUS_SUCCESS) {
174 mlx5_fpga_err(fdev, "%s image failed to load; status %u\n",
175 mlx5_fpga_image_name(fdev->last_oper_image),
176 query.image_status);
177 return -EIO;
178 }
179
180 return 0;
181 }
182
183 static int mlx5_fpga_device_brb(struct mlx5_fpga_device *fdev)
184 {
185 int err;
186 struct mlx5_core_dev *mdev = fdev->mdev;
187
188 err = mlx5_fpga_ctrl_op(mdev, MLX5_FPGA_CTRL_OPERATION_SANDBOX_BYPASS_ON);
189 if (err) {
190 mlx5_fpga_err(fdev, "Failed to set bypass on: %d\n", err);
191 return err;
192 }
193 err = mlx5_fpga_ctrl_op(mdev, MLX5_FPGA_CTRL_OPERATION_RESET_SANDBOX);
194 if (err) {
195 mlx5_fpga_err(fdev, "Failed to reset SBU: %d\n", err);
196 return err;
197 }
198 err = mlx5_fpga_ctrl_op(mdev, MLX5_FPGA_CTRL_OPERATION_SANDBOX_BYPASS_OFF);
199 if (err) {
200 mlx5_fpga_err(fdev, "Failed to set bypass off: %d\n", err);
201 return err;
202 }
203 return 0;
204 }
205
206 int mlx5_fpga_device_start(struct mlx5_core_dev *mdev)
207 {
208 struct mlx5_fpga_client_data *client_context;
209 struct mlx5_fpga_device *fdev = mdev->fpga;
210 struct mlx5_fpga_conn_attr conn_attr = {0};
211 struct mlx5_fpga_conn *conn;
212 unsigned int max_num_qps;
213 unsigned long flags;
214 u32 fpga_id;
215 u32 vid;
216 u16 pid;
217 int err;
218
219 if (!fdev)
220 return 0;
221
222 err = mlx5_fpga_caps(fdev->mdev);
223 if (err)
224 goto out;
225
226 err = mlx5_fpga_device_load_check(fdev);
227 if (err)
228 goto out;
229
230 fpga_id = MLX5_CAP_FPGA(fdev->mdev, fpga_id);
231 mlx5_fpga_info(fdev, "FPGA card %s\n", mlx5_fpga_name(fpga_id));
232
233 if (fpga_id == MLX5_FPGA_MORSE || fpga_id == MLX5_FPGA_MORSEQ)
234 goto out;
235
236 mlx5_fpga_info(fdev, "%s(%d) image, version %u; SBU %06x:%04x version %d\n",
237 mlx5_fpga_image_name(fdev->last_oper_image),
238 fdev->last_oper_image,
239 MLX5_CAP_FPGA(fdev->mdev, image_version),
240 MLX5_CAP_FPGA(fdev->mdev, ieee_vendor_id),
241 MLX5_CAP_FPGA(fdev->mdev, sandbox_product_id),
242 MLX5_CAP_FPGA(fdev->mdev, sandbox_product_version));
243
244 max_num_qps = MLX5_CAP_FPGA(mdev, shell_caps.max_num_qps);
245 err = mlx5_core_reserve_gids(mdev, max_num_qps);
246 if (err)
247 goto out;
248
249 #ifdef NOT_YET
250 /* XXXKIB */
251 err = mlx5_fpga_conn_device_init(fdev);
252 #else
253 err = 0;
254 #endif
255 if (err)
256 goto err_rsvd_gid;
257
258 err = mlx5_fpga_trans_device_init(fdev);
259 if (err) {
260 mlx5_fpga_err(fdev, "Failed to init transaction: %d\n",
261 err);
262 goto err_conn_init;
263 }
264
265 conn_attr.tx_size = MLX5_FPGA_TID_COUNT;
266 conn_attr.rx_size = MLX5_FPGA_TID_COUNT;
267 conn_attr.recv_cb = mlx5_fpga_trans_recv;
268 conn_attr.cb_arg = fdev;
269 #ifdef NOT_YET
270 /* XXXKIB */
271 conn = mlx5_fpga_conn_create(fdev, &conn_attr,
272 MLX5_FPGA_QPC_QP_TYPE_SHELL_QP);
273 if (IS_ERR(conn)) {
274 err = PTR_ERR(conn);
275 mlx5_fpga_err(fdev, "Failed to create shell conn: %d\n", err);
276 goto err_trans;
277 }
278 #else
279 conn = NULL;
280 #endif
281 fdev->shell_conn = conn;
282
283 if (fdev->last_oper_image == MLX5_FPGA_IMAGE_USER) {
284 err = mlx5_fpga_device_brb(fdev);
285 if (err)
286 goto err_shell_conn;
287
288 vid = MLX5_CAP_FPGA(fdev->mdev, ieee_vendor_id);
289 pid = MLX5_CAP_FPGA(fdev->mdev, sandbox_product_id);
290 mutex_lock(&mlx5_fpga_mutex);
291 list_for_each_entry(client_context, &fdev->client_data_list,
292 list) {
293 if (client_context->client->add(fdev, vid, pid))
294 continue;
295 client_context->added = true;
296 }
297 mutex_unlock(&mlx5_fpga_mutex);
298 }
299
300 goto out;
301
302 err_shell_conn:
303 if (fdev->shell_conn) {
304 #ifdef NOT_YET
305 /* XXXKIB */
306 mlx5_fpga_conn_destroy(fdev->shell_conn);
307 #endif
308 fdev->shell_conn = NULL;
309 }
310
311 #ifdef NOT_YET
312 /* XXXKIB */
313 err_trans:
314 #endif
315 mlx5_fpga_trans_device_cleanup(fdev);
316
317 err_conn_init:
318 #ifdef NOT_YET
319 /* XXXKIB */
320 mlx5_fpga_conn_device_cleanup(fdev);
321 #endif
322
323 err_rsvd_gid:
324 mlx5_core_unreserve_gids(mdev, max_num_qps);
325 out:
326 spin_lock_irqsave(&fdev->state_lock, flags);
327 fdev->fdev_state = err ? MLX5_FDEV_STATE_FAILURE : MLX5_FDEV_STATE_SUCCESS;
328 spin_unlock_irqrestore(&fdev->state_lock, flags);
329 return err;
330 }
331
332 int mlx5_fpga_init(struct mlx5_core_dev *mdev)
333 {
334 struct mlx5_fpga_device *fdev = NULL;
335 struct mlx5_fpga_client *client;
336
337 if (!MLX5_CAP_GEN(mdev, fpga)) {
338 mlx5_core_dbg(mdev, "FPGA capability not present\n");
339 return 0;
340 }
341
342 mlx5_core_dbg(mdev, "Initializing FPGA\n");
343
344 fdev = mlx5_fpga_device_alloc();
345 if (!fdev)
346 return -ENOMEM;
347
348 fdev->mdev = mdev;
349 mdev->fpga = fdev;
350
351 mutex_lock(&mlx5_fpga_mutex);
352
353 list_add_tail(&fdev->list, &mlx5_fpga_devices);
354 list_for_each_entry(client, &mlx5_fpga_clients, list)
355 client_context_create(fdev, client, NULL);
356
357 mutex_unlock(&mlx5_fpga_mutex);
358 return 0;
359 }
360
361 void mlx5_fpga_device_stop(struct mlx5_core_dev *mdev)
362 {
363 struct mlx5_fpga_client_data *client_context;
364 struct mlx5_fpga_device *fdev = mdev->fpga;
365 unsigned int max_num_qps;
366 unsigned long flags;
367 int err;
368 u32 fpga_id;
369
370 if (!fdev)
371 return;
372
373 fpga_id = MLX5_CAP_FPGA(mdev, fpga_id);
374 if (fpga_id == MLX5_FPGA_MORSE || fpga_id == MLX5_FPGA_MORSEQ)
375 return;
376
377 spin_lock_irqsave(&fdev->state_lock, flags);
378
379 if (fdev->fdev_state != MLX5_FDEV_STATE_SUCCESS) {
380 spin_unlock_irqrestore(&fdev->state_lock, flags);
381 return;
382 }
383 fdev->fdev_state = MLX5_FDEV_STATE_NONE;
384 spin_unlock_irqrestore(&fdev->state_lock, flags);
385
386 if (fdev->last_oper_image == MLX5_FPGA_IMAGE_USER) {
387 err = mlx5_fpga_ctrl_op(mdev, MLX5_FPGA_CTRL_OPERATION_SANDBOX_BYPASS_ON);
388 if (err)
389 mlx5_fpga_err(fdev, "Failed to re-set SBU bypass on: %d\n",
390 err);
391 }
392
393 mutex_lock(&mlx5_fpga_mutex);
394 list_for_each_entry(client_context, &fdev->client_data_list, list) {
395 if (!client_context->added)
396 continue;
397 client_context->client->remove(fdev);
398 client_context->added = false;
399 }
400 mutex_unlock(&mlx5_fpga_mutex);
401
402 if (fdev->shell_conn) {
403 #ifdef NOT_YET
404 /* XXXKIB */
405 mlx5_fpga_conn_destroy(fdev->shell_conn);
406 #endif
407 fdev->shell_conn = NULL;
408 mlx5_fpga_trans_device_cleanup(fdev);
409 }
410 #ifdef NOT_YET
411 /* XXXKIB */
412 mlx5_fpga_conn_device_cleanup(fdev);
413 #endif
414 max_num_qps = MLX5_CAP_FPGA(mdev, shell_caps.max_num_qps);
415 mlx5_core_unreserve_gids(mdev, max_num_qps);
416 }
417
418 void mlx5_fpga_cleanup(struct mlx5_core_dev *mdev)
419 {
420 struct mlx5_fpga_client_data *context, *tmp;
421 struct mlx5_fpga_device *fdev = mdev->fpga;
422
423 if (!fdev)
424 return;
425
426 mutex_lock(&mlx5_fpga_mutex);
427
428 mlx5_fpga_device_stop(mdev);
429
430 list_for_each_entry_safe(context, tmp, &fdev->client_data_list, list)
431 client_context_destroy(fdev, context);
432
433 list_del(&fdev->list);
434 kfree(fdev);
435 mdev->fpga = NULL;
436
437 mutex_unlock(&mlx5_fpga_mutex);
438 }
439
440 static const char *mlx5_fpga_syndrome_to_string(u8 syndrome)
441 {
442 if (syndrome < ARRAY_SIZE(mlx5_fpga_error_strings))
443 return mlx5_fpga_error_strings[syndrome];
444 return "Unknown";
445 }
446
447 static const char *mlx5_fpga_qp_syndrome_to_string(u8 syndrome)
448 {
449 if (syndrome < ARRAY_SIZE(mlx5_fpga_qp_error_strings))
450 return mlx5_fpga_qp_error_strings[syndrome];
451 return "Unknown";
452 }
453
454 void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event, void *data)
455 {
456 struct mlx5_fpga_device *fdev = mdev->fpga;
457 const char *event_name;
458 bool teardown = false;
459 unsigned long flags;
460 u32 fpga_qpn;
461 u8 syndrome;
462
463 switch (event) {
464 case MLX5_EVENT_TYPE_FPGA_ERROR:
465 syndrome = MLX5_GET(fpga_error_event, data, syndrome);
466 event_name = mlx5_fpga_syndrome_to_string(syndrome);
467 break;
468 case MLX5_EVENT_TYPE_FPGA_QP_ERROR:
469 syndrome = MLX5_GET(fpga_qp_error_event, data, syndrome);
470 event_name = mlx5_fpga_qp_syndrome_to_string(syndrome);
471 fpga_qpn = MLX5_GET(fpga_qp_error_event, data, fpga_qpn);
472 mlx5_fpga_err(fdev, "Error %u on QP %u: %s\n",
473 syndrome, fpga_qpn, event_name);
474 break;
475 default:
476 mlx5_fpga_warn_ratelimited(fdev, "Unexpected event %u\n",
477 event);
478 return;
479 }
480
481 spin_lock_irqsave(&fdev->state_lock, flags);
482 switch (fdev->fdev_state) {
483 case MLX5_FDEV_STATE_SUCCESS:
484 mlx5_fpga_warn(fdev, "Error %u: %s\n", syndrome, event_name);
485 teardown = true;
486 break;
487 case MLX5_FDEV_STATE_IN_PROGRESS:
488 if (syndrome != MLX5_FPGA_ERROR_EVENT_SYNDROME_IMAGE_CHANGED)
489 mlx5_fpga_warn(fdev, "Error while loading %u: %s\n",
490 syndrome, event_name);
491 complete(&fdev->load_event);
492 break;
493 default:
494 mlx5_fpga_warn_ratelimited(fdev, "Unexpected error event %u: %s\n",
495 syndrome, event_name);
496 }
497 spin_unlock_irqrestore(&fdev->state_lock, flags);
498 /* We tear-down the card's interfaces and functionality because
499 * the FPGA bump-on-the-wire is misbehaving and we lose ability
500 * to communicate with the network. User may still be able to
501 * recover by re-programming or debugging the FPGA
502 */
503 if (teardown)
504 mlx5_trigger_health_work(fdev->mdev);
505 }
506
507 void mlx5_fpga_client_register(struct mlx5_fpga_client *client)
508 {
509 struct mlx5_fpga_client_data *context;
510 struct mlx5_fpga_device *fdev;
511 bool call_add = false;
512 unsigned long flags;
513 u32 vid;
514 u16 pid;
515 int err;
516
517 pr_debug("Client register %s\n", client->name);
518
519 mutex_lock(&mlx5_fpga_mutex);
520
521 list_add_tail(&client->list, &mlx5_fpga_clients);
522
523 list_for_each_entry(fdev, &mlx5_fpga_devices, list) {
524 err = client_context_create(fdev, client, &context);
525 if (err)
526 continue;
527
528 spin_lock_irqsave(&fdev->state_lock, flags);
529 call_add = (fdev->fdev_state == MLX5_FDEV_STATE_SUCCESS);
530 spin_unlock_irqrestore(&fdev->state_lock, flags);
531
532 if (call_add) {
533 vid = MLX5_CAP_FPGA(fdev->mdev, ieee_vendor_id);
534 pid = MLX5_CAP_FPGA(fdev->mdev, sandbox_product_id);
535 if (!client->add(fdev, vid, pid))
536 context->added = true;
537 }
538 }
539
540 mutex_unlock(&mlx5_fpga_mutex);
541 }
542 EXPORT_SYMBOL(mlx5_fpga_client_register);
543
544 void mlx5_fpga_client_unregister(struct mlx5_fpga_client *client)
545 {
546 struct mlx5_fpga_client_data *context, *tmp_context;
547 struct mlx5_fpga_device *fdev;
548
549 pr_debug("Client unregister %s\n", client->name);
550
551 mutex_lock(&mlx5_fpga_mutex);
552
553 list_for_each_entry(fdev, &mlx5_fpga_devices, list) {
554 list_for_each_entry_safe(context, tmp_context,
555 &fdev->client_data_list,
556 list) {
557 if (context->client != client)
558 continue;
559 if (context->added)
560 client->remove(fdev);
561 client_context_destroy(fdev, context);
562 break;
563 }
564 }
565
566 list_del(&client->list);
567 mutex_unlock(&mlx5_fpga_mutex);
568 }
569 EXPORT_SYMBOL(mlx5_fpga_client_unregister);
570
571 #if (__FreeBSD_version >= 1100000)
572 MODULE_DEPEND(mlx5fpga, linuxkpi, 1, 1, 1);
573 #endif
574 MODULE_DEPEND(mlx5fpga, mlx5, 1, 1, 1);
575 MODULE_VERSION(mlx5fpga, 1);
Cache object: aceae203a388d47ec3e86b5d064912e5
|