The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/mlx5/mlx5_fpga/mlx5fpga_core.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.