2 * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
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:
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
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.
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
35 #include <dev/mlx5/mlx5_fpga/trans.h>
36 #include <dev/mlx5/mlx5_fpga/conn.h>
38 enum mlx5_fpga_transaction_state {
45 struct mlx5_fpga_trans_priv {
46 const struct mlx5_fpga_transaction *user_trans;
48 enum mlx5_fpga_transaction_state state;
50 u32 header[MLX5_ST_SZ_DW(fpga_shell_qp_packet)];
51 struct mlx5_fpga_dma_buf buf;
52 struct list_head list_item;
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];
61 static struct mlx5_fpga_trans_priv *find_tid(struct mlx5_fpga_device *fdev,
64 if (tid >= MLX5_FPGA_TID_COUNT) {
65 mlx5_fpga_warn(fdev, "Unexpected transaction ID %u\n", tid);
68 return &fdev->trans->transactions[tid];
71 static struct mlx5_fpga_trans_priv *alloc_tid(struct mlx5_fpga_device *fdev)
73 struct mlx5_fpga_trans_priv *ret;
76 spin_lock_irqsave(&fdev->trans->lock, flags);
78 if (list_empty(&fdev->trans->free_queue)) {
79 mlx5_fpga_dbg(fdev, "No free transaction ID available\n");
84 ret = list_first_entry(&fdev->trans->free_queue,
85 struct mlx5_fpga_trans_priv, list_item);
86 list_del(&ret->list_item);
88 ret->state = TRANS_STATE_NONE;
90 spin_unlock_irqrestore(&fdev->trans->lock, flags);
94 static void free_tid(struct mlx5_fpga_device *fdev,
95 struct mlx5_fpga_trans_priv *trans_priv)
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);
104 static void trans_complete(struct mlx5_fpga_device *fdev,
105 struct mlx5_fpga_trans_priv *trans_priv, u8 status)
107 const struct mlx5_fpga_transaction *user_trans;
110 mlx5_fpga_dbg(fdev, "Transaction %u is complete with status %u\n",
111 trans_priv->tid, status);
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);
118 user_trans = trans_priv->user_trans;
119 free_tid(fdev, trans_priv);
121 if (user_trans->complete1)
122 user_trans->complete1(user_trans, status);
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)
130 struct mlx5_fpga_trans_priv *trans_priv;
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);
136 trans_complete(fdev, trans_priv, status);
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);
146 static int trans_validate(struct mlx5_fpga_device *fdev, u64 addr, size_t size)
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);
153 if (size & MLX5_FPGA_TRANSACTION_SEND_ALIGN_BITS) {
154 mlx5_fpga_warn(fdev, "Cannot access %zu bytes. Must be full dwords\n",
159 mlx5_fpga_warn(fdev, "Cannot access %zu bytes. Empty transaction not allowed\n",
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);
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);
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);
184 int mlx5_fpga_trans_exec(const struct mlx5_fpga_transaction *trans)
186 struct mlx5_fpga_conn *conn = trans->conn;
187 struct mlx5_fpga_trans_priv *trans_priv;
191 if (!trans->complete1) {
192 mlx5_fpga_warn(conn->fdev, "Transaction must have a completion callback\n");
197 err = trans_validate(conn->fdev, trans->addr, trans->size);
201 trans_priv = alloc_tid(conn->fdev);
206 trans_priv->user_trans = trans;
207 header = trans_priv->header;
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);
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;
226 trans_priv->buf.complete = trans_send_complete;
227 trans_priv->state = TRANS_STATE_SEND;
231 err = mlx5_fpga_conn_send(conn->fdev->shell_conn, &trans_priv->buf);
240 free_tid(conn->fdev, trans_priv);
245 void mlx5_fpga_trans_recv(void *cb_arg, struct mlx5_fpga_dma_buf *buf)
247 struct mlx5_fpga_device *fdev = cb_arg;
248 struct mlx5_fpga_trans_priv *trans_priv;
253 mlx5_fpga_dbg(fdev, "Rx QP message on core conn; %u bytes\n",
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",
261 payload_len = buf->sg[0].size - MLX5_ST_SZ_BYTES(fpga_shell_qp_packet);
263 tid = MLX5_GET(fpga_shell_qp_packet, buf->sg[0].data, tid);
264 trans_priv = find_tid(fdev, tid);
268 type = MLX5_GET(fpga_shell_qp_packet, buf->sg[0].data, 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);
277 if (payload_len != trans_priv->user_trans->size) {
278 mlx5_fpga_warn(fdev, "Incorrect transaction payload length %zu expected %zu\n",
280 trans_priv->user_trans->size);
283 memcpy(trans_priv->user_trans->data,
284 MLX5_ADDR_OF(fpga_shell_qp_packet, buf->sg[0].data,
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);
296 mlx5_fpga_warn(fdev, "Unexpected message type %u len %u from device\n",
297 type, buf->sg[0].size);
303 trans_complete(fdev, trans_priv, status);
308 int mlx5_fpga_trans_device_init(struct mlx5_fpga_device *fdev)
313 fdev->trans = kzalloc(sizeof(*fdev->trans), GFP_KERNEL);
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);
326 spin_lock_init(&fdev->trans->lock);
332 void mlx5_fpga_trans_device_cleanup(struct mlx5_fpga_device *fdev)