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 } 336