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