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_trans.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 <dev/mlx5/mlx5_fpga/trans.h>
   36 #include <dev/mlx5/mlx5_fpga/conn.h>
   37 
   38 enum mlx5_fpga_transaction_state {
   39         TRANS_STATE_NONE,
   40         TRANS_STATE_SEND,
   41         TRANS_STATE_WAIT,
   42         TRANS_STATE_COMPLETE,
   43 };
   44 
   45 struct mlx5_fpga_trans_priv {
   46         const struct mlx5_fpga_transaction *user_trans;
   47         u8 tid;
   48         enum mlx5_fpga_transaction_state state;
   49         u8 status;
   50         u32 header[MLX5_ST_SZ_DW(fpga_shell_qp_packet)];
   51         struct mlx5_fpga_dma_buf buf;
   52         struct list_head list_item;
   53 };
   54 
   55 struct mlx5_fpga_trans_device_state {
   56         spinlock_t lock; /* Protects all members of this struct */
   57         struct list_head free_queue;
   58         struct mlx5_fpga_trans_priv transactions[MLX5_FPGA_TID_COUNT];
   59 };
   60 
   61 static struct mlx5_fpga_trans_priv *find_tid(struct mlx5_fpga_device *fdev,
   62                                              u8 tid)
   63 {
   64         if (tid >= MLX5_FPGA_TID_COUNT) {
   65                 mlx5_fpga_warn(fdev, "Unexpected transaction ID %u\n", tid);
   66                 return NULL;
   67         }
   68         return &fdev->trans->transactions[tid];
   69 }
   70 
   71 static struct mlx5_fpga_trans_priv *alloc_tid(struct mlx5_fpga_device *fdev)
   72 {
   73         struct mlx5_fpga_trans_priv *ret;
   74         unsigned long flags;
   75 
   76         spin_lock_irqsave(&fdev->trans->lock, flags);
   77 
   78         if (list_empty(&fdev->trans->free_queue)) {
   79                 mlx5_fpga_dbg(fdev, "No free transaction ID available\n");
   80                 ret = NULL;
   81                 goto out;
   82         }
   83 
   84         ret = list_first_entry(&fdev->trans->free_queue,
   85                                struct mlx5_fpga_trans_priv, list_item);
   86         list_del(&ret->list_item);
   87 
   88         ret->state = TRANS_STATE_NONE;
   89 out:
   90         spin_unlock_irqrestore(&fdev->trans->lock, flags);
   91         return ret;
   92 }
   93 
   94 static void free_tid(struct mlx5_fpga_device *fdev,
   95                      struct mlx5_fpga_trans_priv *trans_priv)
   96 {
   97         unsigned long flags;
   98 
   99         spin_lock_irqsave(&fdev->trans->lock, flags);
  100         list_add_tail(&trans_priv->list_item, &fdev->trans->free_queue);
  101         spin_unlock_irqrestore(&fdev->trans->lock, flags);
  102 }
  103 
  104 static void trans_complete(struct mlx5_fpga_device *fdev,
  105                            struct mlx5_fpga_trans_priv *trans_priv, u8 status)
  106 {
  107         const struct mlx5_fpga_transaction *user_trans;
  108         unsigned long flags;
  109 
  110         mlx5_fpga_dbg(fdev, "Transaction %u is complete with status %u\n",
  111                       trans_priv->tid, status);
  112 
  113         spin_lock_irqsave(&fdev->trans->lock, flags);
  114         trans_priv->state = TRANS_STATE_COMPLETE;
  115         trans_priv->status = status;
  116         spin_unlock_irqrestore(&fdev->trans->lock, flags);
  117 
  118         user_trans = trans_priv->user_trans;
  119         free_tid(fdev, trans_priv);
  120 
  121         if (user_trans->complete1)
  122                 user_trans->complete1(user_trans, status);
  123 }
  124 
  125 static void trans_send_complete(struct mlx5_fpga_conn *conn,
  126                                 struct mlx5_fpga_device *fdev,
  127                                 struct mlx5_fpga_dma_buf *buf, u8 status)
  128 {
  129         unsigned long flags;
  130         struct mlx5_fpga_trans_priv *trans_priv;
  131 
  132         trans_priv = container_of(buf, struct mlx5_fpga_trans_priv, buf);
  133         mlx5_fpga_dbg(fdev, "send complete tid %u. Status: %u\n",
  134                       trans_priv->tid, status);
  135         if (status) {
  136                 trans_complete(fdev, trans_priv, status);
  137                 return;
  138         }
  139 
  140         spin_lock_irqsave(&fdev->trans->lock, flags);
  141         if (trans_priv->state == TRANS_STATE_SEND)
  142                 trans_priv->state = TRANS_STATE_WAIT;
  143         spin_unlock_irqrestore(&fdev->trans->lock, flags);
  144 }
  145 
  146 static int trans_validate(struct mlx5_fpga_device *fdev, u64 addr, size_t size)
  147 {
  148         if (size > MLX5_FPGA_TRANSACTION_MAX_SIZE) {
  149                 mlx5_fpga_warn(fdev, "Cannot access %zu bytes at once. Max is %u\n",
  150                                size, MLX5_FPGA_TRANSACTION_MAX_SIZE);
  151                 return -EINVAL;
  152         }
  153         if (size & MLX5_FPGA_TRANSACTION_SEND_ALIGN_BITS) {
  154                 mlx5_fpga_warn(fdev, "Cannot access %zu bytes. Must be full dwords\n",
  155                                size);
  156                 return -EINVAL;
  157         }
  158         if (size < 1) {
  159                 mlx5_fpga_warn(fdev, "Cannot access %zu bytes. Empty transaction not allowed\n",
  160                                size);
  161                 return -EINVAL;
  162         }
  163         if (addr & MLX5_FPGA_TRANSACTION_SEND_ALIGN_BITS) {
  164                 mlx5_fpga_warn(fdev, "Cannot access %zu bytes at unaligned address %jx\n",
  165                                size, (uintmax_t)addr);
  166                 return -EINVAL;
  167         }
  168         if ((addr >> MLX5_FPGA_TRANSACTION_SEND_PAGE_BITS) !=
  169             ((addr + size - 1) >> MLX5_FPGA_TRANSACTION_SEND_PAGE_BITS)) {
  170                 mlx5_fpga_warn(fdev, "Cannot access %zu bytes at address %jx. Crosses page boundary\n",
  171                                size, (uintmax_t)addr);
  172                 return -EINVAL;
  173         }
  174         if (addr < mlx5_fpga_ddr_base_get(fdev)) {
  175                 if (size != sizeof(u32)) {
  176                         mlx5_fpga_warn(fdev, "Cannot access %zu bytes at cr-space address %jx. Must access a single dword\n",
  177                                        size, (uintmax_t)addr);
  178                         return -EINVAL;
  179                 }
  180         }
  181         return 0;
  182 }
  183 
  184 int mlx5_fpga_trans_exec(const struct mlx5_fpga_transaction *trans)
  185 {
  186         struct mlx5_fpga_conn *conn = trans->conn;
  187         struct mlx5_fpga_trans_priv *trans_priv;
  188         u32 *header;
  189         int err;
  190 
  191         if (!trans->complete1) {
  192                 mlx5_fpga_warn(conn->fdev, "Transaction must have a completion callback\n");
  193                 err = -EINVAL;
  194                 goto out;
  195         }
  196 
  197         err = trans_validate(conn->fdev, trans->addr, trans->size);
  198         if (err)
  199                 goto out;
  200 
  201         trans_priv = alloc_tid(conn->fdev);
  202         if (!trans_priv) {
  203                 err = -EBUSY;
  204                 goto out;
  205         }
  206         trans_priv->user_trans = trans;
  207         header = trans_priv->header;
  208 
  209         memset(header, 0, sizeof(trans_priv->header));
  210         memset(&trans_priv->buf, 0, sizeof(trans_priv->buf));
  211         MLX5_SET(fpga_shell_qp_packet, header, type,
  212                  (trans->direction == MLX5_FPGA_WRITE) ?
  213                  MLX5_FPGA_SHELL_QP_PACKET_TYPE_DDR_WRITE :
  214                  MLX5_FPGA_SHELL_QP_PACKET_TYPE_DDR_READ);
  215         MLX5_SET(fpga_shell_qp_packet, header, tid, trans_priv->tid);
  216         MLX5_SET(fpga_shell_qp_packet, header, len, trans->size);
  217         MLX5_SET64(fpga_shell_qp_packet, header, address, trans->addr);
  218 
  219         trans_priv->buf.sg[0].data = header;
  220         trans_priv->buf.sg[0].size = sizeof(trans_priv->header);
  221         if (trans->direction == MLX5_FPGA_WRITE) {
  222                 trans_priv->buf.sg[1].data = trans->data;
  223                 trans_priv->buf.sg[1].size = trans->size;
  224         }
  225 
  226         trans_priv->buf.complete = trans_send_complete;
  227         trans_priv->state = TRANS_STATE_SEND;
  228 
  229 #ifdef NOT_YET
  230         /* XXXKIB */
  231         err = mlx5_fpga_conn_send(conn->fdev->shell_conn, &trans_priv->buf);
  232 #else
  233         err = 0;
  234 #endif
  235         if (err)
  236                 goto out_buf_tid;
  237         goto out;
  238 
  239 out_buf_tid:
  240         free_tid(conn->fdev, trans_priv);
  241 out:
  242         return err;
  243 }
  244 
  245 void mlx5_fpga_trans_recv(void *cb_arg, struct mlx5_fpga_dma_buf *buf)
  246 {
  247         struct mlx5_fpga_device *fdev = cb_arg;
  248         struct mlx5_fpga_trans_priv *trans_priv;
  249         size_t payload_len;
  250         u8 status = 0;
  251         u8 tid, type;
  252 
  253         mlx5_fpga_dbg(fdev, "Rx QP message on core conn; %u bytes\n",
  254                       buf->sg[0].size);
  255 
  256         if (buf->sg[0].size < MLX5_ST_SZ_BYTES(fpga_shell_qp_packet)) {
  257                 mlx5_fpga_warn(fdev, "Short message %u bytes from device\n",
  258                                buf->sg[0].size);
  259                 goto out;
  260         }
  261         payload_len = buf->sg[0].size - MLX5_ST_SZ_BYTES(fpga_shell_qp_packet);
  262 
  263         tid = MLX5_GET(fpga_shell_qp_packet, buf->sg[0].data, tid);
  264         trans_priv = find_tid(fdev, tid);
  265         if (!trans_priv)
  266                 goto out;
  267 
  268         type = MLX5_GET(fpga_shell_qp_packet, buf->sg[0].data, type);
  269         switch (type) {
  270         case MLX5_FPGA_SHELL_QP_PACKET_TYPE_DDR_READ_RESPONSE:
  271                 if (trans_priv->user_trans->direction != MLX5_FPGA_READ) {
  272                         mlx5_fpga_warn(fdev, "Wrong answer type %u to a %u transaction\n",
  273                                        type, trans_priv->user_trans->direction);
  274                         status = -EIO;
  275                         goto complete;
  276                 }
  277                 if (payload_len != trans_priv->user_trans->size) {
  278                         mlx5_fpga_warn(fdev, "Incorrect transaction payload length %zu expected %zu\n",
  279                                        payload_len,
  280                                        trans_priv->user_trans->size);
  281                         goto complete;
  282                 }
  283                 memcpy(trans_priv->user_trans->data,
  284                        MLX5_ADDR_OF(fpga_shell_qp_packet, buf->sg[0].data,
  285                                     data), payload_len);
  286                 break;
  287         case MLX5_FPGA_SHELL_QP_PACKET_TYPE_DDR_WRITE_RESPONSE:
  288                 if (trans_priv->user_trans->direction != MLX5_FPGA_WRITE) {
  289                         mlx5_fpga_warn(fdev, "Wrong answer type %u to a %u transaction\n",
  290                                        type, trans_priv->user_trans->direction);
  291                         status = -EIO;
  292                         goto complete;
  293                 }
  294                 break;
  295         default:
  296                 mlx5_fpga_warn(fdev, "Unexpected message type %u len %u from device\n",
  297                                type, buf->sg[0].size);
  298                 status = -EIO;
  299                 goto complete;
  300         }
  301 
  302 complete:
  303         trans_complete(fdev, trans_priv, status);
  304 out:
  305         return;
  306 }
  307 
  308 int mlx5_fpga_trans_device_init(struct mlx5_fpga_device *fdev)
  309 {
  310         int ret = 0;
  311         int tid;
  312 
  313         fdev->trans = kzalloc(sizeof(*fdev->trans), GFP_KERNEL);
  314         if (!fdev->trans) {
  315                 ret = -ENOMEM;
  316                 goto out;
  317         }
  318 
  319         INIT_LIST_HEAD(&fdev->trans->free_queue);
  320         for (tid = 0; tid < ARRAY_SIZE(fdev->trans->transactions); tid++) {
  321                 fdev->trans->transactions[tid].tid = tid;
  322                 list_add_tail(&fdev->trans->transactions[tid].list_item,
  323                               &fdev->trans->free_queue);
  324         }
  325 
  326         spin_lock_init(&fdev->trans->lock);
  327 
  328 out:
  329         return ret;
  330 }
  331 
  332 void mlx5_fpga_trans_device_cleanup(struct mlx5_fpga_device *fdev)
  333 {
  334         kfree(fdev->trans);
  335 }

Cache object: 41590cc68b32f35631f71a09ae872f87


[ 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.