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/errno.h> 36 #include <linux/err.h> 37 #include <linux/completion.h> 38 #include <dev/mlx5/device.h> 39 #include <dev/mlx5/mlx5_fpga/core.h> 40 #include <dev/mlx5/mlx5_fpga/conn.h> 41 #include <dev/mlx5/mlx5_fpga/sdk.h> 42 #include <dev/mlx5/mlx5_fpga/xfer.h> 43 #include <dev/mlx5/mlx5_core/mlx5_core.h> 44 /* #include "accel/ipsec.h" */ 45 46 #define MLX5_FPGA_LOAD_TIMEOUT 25000 /* msec */ 47 48 struct mem_transfer { 49 struct mlx5_fpga_transaction t; 50 struct completion comp; 51 u8 status; 52 }; 53 54 struct mlx5_fpga_conn * 55 mlx5_fpga_sbu_conn_create(struct mlx5_fpga_device *fdev, 56 struct mlx5_fpga_conn_attr *attr) 57 { 58 #ifdef NOT_YET 59 /* XXXKIB */ 60 return mlx5_fpga_conn_create(fdev, attr, MLX5_FPGA_QPC_QP_TYPE_SANDBOX_QP); 61 #else 62 return (NULL); 63 #endif 64 } 65 EXPORT_SYMBOL(mlx5_fpga_sbu_conn_create); 66 67 void mlx5_fpga_sbu_conn_destroy(struct mlx5_fpga_conn *conn) 68 { 69 #ifdef NOT_YET 70 /* XXXKIB */ 71 mlx5_fpga_conn_destroy(conn); 72 #endif 73 } 74 EXPORT_SYMBOL(mlx5_fpga_sbu_conn_destroy); 75 76 int mlx5_fpga_sbu_conn_sendmsg(struct mlx5_fpga_conn *conn, 77 struct mlx5_fpga_dma_buf *buf) 78 { 79 #ifdef NOT_YET 80 /* XXXKIB */ 81 return mlx5_fpga_conn_send(conn, buf); 82 #else 83 return (0); 84 #endif 85 } 86 EXPORT_SYMBOL(mlx5_fpga_sbu_conn_sendmsg); 87 88 static void mem_complete(const struct mlx5_fpga_transaction *complete, 89 u8 status) 90 { 91 struct mem_transfer *xfer; 92 93 mlx5_fpga_dbg(complete->conn->fdev, 94 "transaction %p complete status %u", complete, status); 95 96 xfer = container_of(complete, struct mem_transfer, t); 97 xfer->status = status; 98 complete_all(&xfer->comp); 99 } 100 101 static int mem_transaction(struct mlx5_fpga_device *fdev, size_t size, u64 addr, 102 void *buf, enum mlx5_fpga_direction direction) 103 { 104 int ret; 105 struct mem_transfer xfer; 106 107 if (!fdev->shell_conn) { 108 ret = -ENOTCONN; 109 goto out; 110 } 111 112 xfer.t.data = buf; 113 xfer.t.size = size; 114 xfer.t.addr = addr; 115 xfer.t.conn = fdev->shell_conn; 116 xfer.t.direction = direction; 117 xfer.t.complete1 = mem_complete; 118 init_completion(&xfer.comp); 119 ret = mlx5_fpga_xfer_exec(&xfer.t); 120 if (ret) { 121 mlx5_fpga_dbg(fdev, "Transfer execution failed: %d\n", ret); 122 goto out; 123 } 124 wait_for_completion(&xfer.comp); 125 if (xfer.status != 0) 126 ret = -EIO; 127 128 out: 129 return ret; 130 } 131 132 static int mlx5_fpga_mem_read_i2c(struct mlx5_fpga_device *fdev, size_t size, 133 u64 addr, u8 *buf) 134 { 135 size_t max_size = MLX5_FPGA_ACCESS_REG_SIZE_MAX; 136 size_t bytes_done = 0; 137 u8 actual_size; 138 int err = 0; 139 140 if (!size) 141 return -EINVAL; 142 143 if (!fdev->mdev) 144 return -ENOTCONN; 145 146 while (bytes_done < size) { 147 actual_size = min(max_size, (size - bytes_done)); 148 149 err = mlx5_fpga_access_reg(fdev->mdev, actual_size, 150 addr + bytes_done, 151 buf + bytes_done, false); 152 if (err) { 153 mlx5_fpga_err(fdev, "Failed to read over I2C: %d\n", 154 err); 155 break; 156 } 157 158 bytes_done += actual_size; 159 } 160 161 return err; 162 } 163 164 static int mlx5_fpga_mem_write_i2c(struct mlx5_fpga_device *fdev, size_t size, 165 u64 addr, u8 *buf) 166 { 167 size_t max_size = MLX5_FPGA_ACCESS_REG_SIZE_MAX; 168 size_t bytes_done = 0; 169 u8 actual_size; 170 int err = 0; 171 172 if (!size) 173 return -EINVAL; 174 175 if (!fdev->mdev) 176 return -ENOTCONN; 177 178 while (bytes_done < size) { 179 actual_size = min(max_size, (size - bytes_done)); 180 181 err = mlx5_fpga_access_reg(fdev->mdev, actual_size, 182 addr + bytes_done, 183 buf + bytes_done, true); 184 if (err) { 185 mlx5_fpga_err(fdev, "Failed to write FPGA crspace\n"); 186 break; 187 } 188 189 bytes_done += actual_size; 190 } 191 192 return err; 193 } 194 195 int mlx5_fpga_mem_read(struct mlx5_fpga_device *fdev, size_t size, u64 addr, 196 void *buf, enum mlx5_fpga_access_type access_type) 197 { 198 int ret; 199 200 if (access_type == MLX5_FPGA_ACCESS_TYPE_DONTCARE) 201 access_type = fdev->shell_conn ? MLX5_FPGA_ACCESS_TYPE_RDMA : 202 MLX5_FPGA_ACCESS_TYPE_I2C; 203 204 mlx5_fpga_dbg(fdev, "Reading %zu bytes at 0x%jx over %s", 205 size, (uintmax_t)addr, access_type ? "RDMA" : "I2C"); 206 207 switch (access_type) { 208 case MLX5_FPGA_ACCESS_TYPE_RDMA: 209 ret = mem_transaction(fdev, size, addr, buf, MLX5_FPGA_READ); 210 if (ret) 211 return ret; 212 break; 213 case MLX5_FPGA_ACCESS_TYPE_I2C: 214 ret = mlx5_fpga_mem_read_i2c(fdev, size, addr, buf); 215 if (ret) 216 return ret; 217 break; 218 default: 219 mlx5_fpga_warn(fdev, "Unexpected read access_type %u\n", 220 access_type); 221 return -EACCES; 222 } 223 224 return size; 225 } 226 EXPORT_SYMBOL(mlx5_fpga_mem_read); 227 228 int mlx5_fpga_mem_write(struct mlx5_fpga_device *fdev, size_t size, u64 addr, 229 void *buf, enum mlx5_fpga_access_type access_type) 230 { 231 int ret; 232 233 if (access_type == MLX5_FPGA_ACCESS_TYPE_DONTCARE) 234 access_type = fdev->shell_conn ? MLX5_FPGA_ACCESS_TYPE_RDMA : 235 MLX5_FPGA_ACCESS_TYPE_I2C; 236 237 mlx5_fpga_dbg(fdev, "Writing %zu bytes at 0x%jx over %s", 238 size, (uintmax_t)addr, access_type ? "RDMA" : "I2C"); 239 240 switch (access_type) { 241 case MLX5_FPGA_ACCESS_TYPE_RDMA: 242 ret = mem_transaction(fdev, size, addr, buf, MLX5_FPGA_WRITE); 243 if (ret) 244 return ret; 245 break; 246 case MLX5_FPGA_ACCESS_TYPE_I2C: 247 ret = mlx5_fpga_mem_write_i2c(fdev, size, addr, buf); 248 if (ret) 249 return ret; 250 break; 251 default: 252 mlx5_fpga_warn(fdev, "Unexpected write access_type %u\n", 253 access_type); 254 return -EACCES; 255 } 256 257 return size; 258 } 259 EXPORT_SYMBOL(mlx5_fpga_mem_write); 260 261 int mlx5_fpga_get_sbu_caps(struct mlx5_fpga_device *fdev, int size, void *buf) 262 { 263 return mlx5_fpga_sbu_caps(fdev->mdev, buf, size); 264 } 265 EXPORT_SYMBOL(mlx5_fpga_get_sbu_caps); 266 267 u64 mlx5_fpga_ddr_size_get(struct mlx5_fpga_device *fdev) 268 { 269 return (u64)MLX5_CAP_FPGA(fdev->mdev, fpga_ddr_size) << 10; 270 } 271 EXPORT_SYMBOL(mlx5_fpga_ddr_size_get); 272 273 u64 mlx5_fpga_ddr_base_get(struct mlx5_fpga_device *fdev) 274 { 275 return MLX5_CAP64_FPGA(fdev->mdev, fpga_ddr_start_addr); 276 } 277 EXPORT_SYMBOL(mlx5_fpga_ddr_base_get); 278 279 void mlx5_fpga_client_data_set(struct mlx5_fpga_device *fdev, 280 struct mlx5_fpga_client *client, void *data) 281 { 282 struct mlx5_fpga_client_data *context; 283 284 list_for_each_entry(context, &fdev->client_data_list, list) { 285 if (context->client != client) 286 continue; 287 context->data = data; 288 return; 289 } 290 291 mlx5_fpga_warn(fdev, "No client context found for %s\n", client->name); 292 } 293 EXPORT_SYMBOL(mlx5_fpga_client_data_set); 294 295 void *mlx5_fpga_client_data_get(struct mlx5_fpga_device *fdev, 296 struct mlx5_fpga_client *client) 297 { 298 struct mlx5_fpga_client_data *context; 299 void *ret = NULL; 300 301 list_for_each_entry(context, &fdev->client_data_list, list) { 302 if (context->client != client) 303 continue; 304 ret = context->data; 305 goto out; 306 } 307 mlx5_fpga_warn(fdev, "No client context found for %s\n", client->name); 308 309 out: 310 return ret; 311 } 312 EXPORT_SYMBOL(mlx5_fpga_client_data_get); 313 314 void mlx5_fpga_device_query(struct mlx5_fpga_device *fdev, 315 struct mlx5_fpga_query *query) 316 { 317 unsigned long flags; 318 319 spin_lock_irqsave(&fdev->state_lock, flags); 320 query->image_status = fdev->image_status; 321 query->admin_image = fdev->last_admin_image; 322 query->oper_image = fdev->last_oper_image; 323 spin_unlock_irqrestore(&fdev->state_lock, flags); 324 } 325 EXPORT_SYMBOL(mlx5_fpga_device_query); 326 327 int mlx5_fpga_device_reload(struct mlx5_fpga_device *fdev, 328 enum mlx5_fpga_image image) 329 { 330 struct mlx5_core_dev *mdev = fdev->mdev; 331 unsigned long timeout; 332 unsigned long flags; 333 int err = 0; 334 335 spin_lock_irqsave(&fdev->state_lock, flags); 336 switch (fdev->fdev_state) { 337 case MLX5_FDEV_STATE_NONE: 338 err = -ENODEV; 339 break; 340 case MLX5_FDEV_STATE_IN_PROGRESS: 341 err = -EBUSY; 342 break; 343 case MLX5_FDEV_STATE_SUCCESS: 344 case MLX5_FDEV_STATE_FAILURE: 345 case MLX5_FDEV_STATE_DISCONNECTED: 346 break; 347 } 348 spin_unlock_irqrestore(&fdev->state_lock, flags); 349 if (err) 350 return err; 351 352 mutex_lock(&mdev->intf_state_mutex); 353 clear_bit(MLX5_INTERFACE_STATE_UP, &mdev->intf_state); 354 355 mlx5_unregister_device(mdev); 356 /* XXXKIB mlx5_accel_ipsec_cleanup(mdev); */ 357 mlx5_fpga_device_stop(mdev); 358 359 fdev->fdev_state = MLX5_FDEV_STATE_IN_PROGRESS; 360 reinit_completion(&fdev->load_event); 361 362 if (image <= MLX5_FPGA_IMAGE_MAX) { 363 mlx5_fpga_info(fdev, "Loading from flash\n"); 364 err = mlx5_fpga_load(mdev, image); 365 if (err) { 366 mlx5_fpga_err(fdev, "Failed to request load: %d\n", 367 err); 368 goto out; 369 } 370 } else { 371 mlx5_fpga_info(fdev, "Resetting\n"); 372 err = mlx5_fpga_ctrl_op(mdev, MLX5_FPGA_CTRL_OPERATION_RESET); 373 if (err) { 374 mlx5_fpga_err(fdev, "Failed to request reset: %d\n", 375 err); 376 goto out; 377 } 378 } 379 380 timeout = jiffies + msecs_to_jiffies(MLX5_FPGA_LOAD_TIMEOUT); 381 err = wait_for_completion_timeout(&fdev->load_event, timeout - jiffies); 382 if (err < 0) { 383 mlx5_fpga_err(fdev, "Failed waiting for FPGA load: %d\n", err); 384 fdev->fdev_state = MLX5_FDEV_STATE_FAILURE; 385 goto out; 386 } 387 388 err = mlx5_fpga_device_start(mdev); 389 if (err) { 390 mlx5_core_err(mdev, "fpga device start failed %d\n", err); 391 goto out; 392 } 393 /* XXXKIB err = mlx5_accel_ipsec_init(mdev); */ 394 if (err) { 395 mlx5_core_err(mdev, "IPSec device start failed %d\n", err); 396 goto err_fpga; 397 } 398 399 err = mlx5_register_device(mdev); 400 if (err) { 401 mlx5_core_err(mdev, "mlx5_register_device failed %d\n", err); 402 fdev->fdev_state = MLX5_FDEV_STATE_FAILURE; 403 goto err_ipsec; 404 } 405 406 set_bit(MLX5_INTERFACE_STATE_UP, &mdev->intf_state); 407 goto out; 408 409 err_ipsec: 410 /* XXXKIB mlx5_accel_ipsec_cleanup(mdev); */ 411 err_fpga: 412 mlx5_fpga_device_stop(mdev); 413 out: 414 mutex_unlock(&mdev->intf_state_mutex); 415 return err; 416 } 417 EXPORT_SYMBOL(mlx5_fpga_device_reload); 418 419 int mlx5_fpga_flash_select(struct mlx5_fpga_device *fdev, 420 enum mlx5_fpga_image image) 421 { 422 unsigned long flags; 423 int err; 424 425 spin_lock_irqsave(&fdev->state_lock, flags); 426 switch (fdev->fdev_state) { 427 case MLX5_FDEV_STATE_NONE: 428 spin_unlock_irqrestore(&fdev->state_lock, flags); 429 return -ENODEV; 430 case MLX5_FDEV_STATE_DISCONNECTED: 431 case MLX5_FDEV_STATE_IN_PROGRESS: 432 case MLX5_FDEV_STATE_SUCCESS: 433 case MLX5_FDEV_STATE_FAILURE: 434 break; 435 } 436 spin_unlock_irqrestore(&fdev->state_lock, flags); 437 438 err = mlx5_fpga_image_select(fdev->mdev, image); 439 if (err) 440 mlx5_fpga_err(fdev, "Failed to select flash image: %d\n", err); 441 else 442 fdev->last_admin_image = image; 443 return err; 444 } 445 EXPORT_SYMBOL(mlx5_fpga_flash_select); 446 447 int mlx5_fpga_connectdisconnect(struct mlx5_fpga_device *fdev, 448 enum mlx5_fpga_connect *connect) 449 { 450 unsigned long flags; 451 int err; 452 453 spin_lock_irqsave(&fdev->state_lock, flags); 454 switch (fdev->fdev_state) { 455 case MLX5_FDEV_STATE_NONE: 456 spin_unlock_irqrestore(&fdev->state_lock, flags); 457 return -ENODEV; 458 case MLX5_FDEV_STATE_IN_PROGRESS: 459 case MLX5_FDEV_STATE_SUCCESS: 460 case MLX5_FDEV_STATE_FAILURE: 461 case MLX5_FDEV_STATE_DISCONNECTED: 462 break; 463 } 464 spin_unlock_irqrestore(&fdev->state_lock, flags); 465 466 err = mlx5_fpga_ctrl_connect(fdev->mdev, connect); 467 if (err) 468 mlx5_fpga_err(fdev, "Failed to connect/disconnect: %d\n", err); 469 return err; 470 } 471 EXPORT_SYMBOL(mlx5_fpga_connectdisconnect); 472 473 int mlx5_fpga_temperature(struct mlx5_fpga_device *fdev, 474 struct mlx5_fpga_temperature *temp) 475 { 476 return mlx5_fpga_query_mtmp(fdev->mdev, temp); 477 } 478 EXPORT_SYMBOL(mlx5_fpga_temperature); 479 480 struct device *mlx5_fpga_dev(struct mlx5_fpga_device *fdev) 481 { 482 return &fdev->mdev->pdev->dev; 483 } 484 EXPORT_SYMBOL(mlx5_fpga_dev); 485 486 void mlx5_fpga_get_cap(struct mlx5_fpga_device *fdev, u32 *fpga_caps) 487 { 488 unsigned long flags; 489 490 spin_lock_irqsave(&fdev->state_lock, flags); 491 memcpy(fpga_caps, &fdev->mdev->caps.fpga, sizeof(fdev->mdev->caps.fpga)); 492 spin_unlock_irqrestore(&fdev->state_lock, flags); 493 } 494 EXPORT_SYMBOL(mlx5_fpga_get_cap); 495