|
| 1 | +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB |
| 2 | +/* |
| 3 | + * Copyright (c) 2018-2025 Advanced Micro Devices, Inc. All rights reserved. |
| 4 | + */ |
| 5 | + |
| 6 | +#include <stdio.h> |
| 7 | +#include <stdlib.h> |
| 8 | + |
| 9 | +#include "ionic.h" |
| 10 | + |
| 11 | +extern const struct verbs_context_ops ionic_ctx_ops; |
| 12 | +struct ionic_global ionic_g; |
| 13 | +FILE *IONIC_DEBUG_FILE; |
| 14 | + |
| 15 | +static int ionic_env_val_def(const char *name, int def) |
| 16 | +{ |
| 17 | + const char *env = getenv(name); |
| 18 | + |
| 19 | + if (!env) |
| 20 | + return def; |
| 21 | + |
| 22 | + return atoi(env); |
| 23 | +} |
| 24 | + |
| 25 | +static int ionic_env_val(const char *name) |
| 26 | +{ |
| 27 | + return ionic_env_val_def(name, 0); |
| 28 | +} |
| 29 | + |
| 30 | +static int ionic_env_ovrd_cmb(const char *name) |
| 31 | +{ |
| 32 | + const char *env = getenv(name); |
| 33 | + int val; |
| 34 | + |
| 35 | + if (!env) |
| 36 | + return -1; |
| 37 | + |
| 38 | + /* flags can be represented as one number or as characters */ |
| 39 | + val = atoi(env); |
| 40 | + if (strchr(env, 'e')) |
| 41 | + val |= IONIC_CMB_ENABLE; |
| 42 | + if (strchr(env, 'x')) |
| 43 | + val |= IONIC_CMB_ENABLE | IONIC_CMB_EXPDB; |
| 44 | + if (strchr(env, 'r')) |
| 45 | + val |= IONIC_CMB_REQUIRE; |
| 46 | + if (strchr(env, 'w')) |
| 47 | + val |= IONIC_CMB_WC; |
| 48 | + if (strchr(env, 'u')) |
| 49 | + val |= IONIC_CMB_UC; |
| 50 | + |
| 51 | + return val; |
| 52 | +} |
| 53 | + |
| 54 | +static int ionic_env_ovrd_sq_cmb(void) |
| 55 | +{ |
| 56 | + return ionic_env_ovrd_cmb("IONIC_SQ_CMB"); |
| 57 | +} |
| 58 | + |
| 59 | +static int ionic_env_ovrd_rq_cmb(void) |
| 60 | +{ |
| 61 | + return ionic_env_ovrd_cmb("IONIC_RQ_CMB"); |
| 62 | +} |
| 63 | + |
| 64 | +static int ionic_env_debug(void) |
| 65 | +{ |
| 66 | + if (!(IONIC_DEBUG)) |
| 67 | + return 0; |
| 68 | + |
| 69 | + return ionic_env_val("IONIC_DEBUG"); |
| 70 | +} |
| 71 | + |
| 72 | +static void ionic_debug_file_close(void) |
| 73 | +{ |
| 74 | + fclose(IONIC_DEBUG_FILE); |
| 75 | +} |
| 76 | + |
| 77 | +static void ionic_debug_file_open(void) |
| 78 | +{ |
| 79 | + const char *name = getenv("IONIC_DEBUG_FILE"); |
| 80 | + |
| 81 | + pthread_mutex_init(&ionic_g.mut, NULL); |
| 82 | + list_head_init(&ionic_g.cq_list); |
| 83 | + list_head_init(&ionic_g.qp_list); |
| 84 | + ionic_g.init = true; |
| 85 | + |
| 86 | + if (!name) |
| 87 | + IONIC_DEBUG_FILE = IONIC_DEFAULT_DEBUG_FILE; |
| 88 | + else |
| 89 | + IONIC_DEBUG_FILE = fopen(name, "w"); |
| 90 | + |
| 91 | + if (!IONIC_DEBUG_FILE) { |
| 92 | + perror("ionic debug file: "); |
| 93 | + return; |
| 94 | + } |
| 95 | + |
| 96 | + if (ionic_env_debug()) |
| 97 | + _ionic_dbg(IONIC_DEBUG_FILE, "Initialized"); |
| 98 | + |
| 99 | + atexit(ionic_debug_file_close); |
| 100 | +} |
| 101 | + |
| 102 | +static void ionic_debug_file_init(void) |
| 103 | +{ |
| 104 | + static pthread_once_t once = PTHREAD_ONCE_INIT; |
| 105 | + |
| 106 | + pthread_once(&once, ionic_debug_file_open); |
| 107 | +} |
| 108 | + |
| 109 | +static struct verbs_context *ionic_alloc_context(struct ibv_device *ibdev, |
| 110 | + int cmd_fd, |
| 111 | + void *private_data) |
| 112 | +{ |
| 113 | + struct ionic_dev *dev; |
| 114 | + struct ionic_ctx *ctx; |
| 115 | + struct uionic_ctx req = {}; |
| 116 | + struct uionic_ctx_resp resp = {}; |
| 117 | + uint64_t mask; |
| 118 | + int rc; |
| 119 | + |
| 120 | + ionic_debug_file_init(); |
| 121 | + |
| 122 | + dev = to_ionic_dev(ibdev); |
| 123 | + ctx = verbs_init_and_alloc_context(ibdev, cmd_fd, ctx, vctx, |
| 124 | + RDMA_DRIVER_IONIC); |
| 125 | + if (!ctx) { |
| 126 | + rc = errno; |
| 127 | + goto err_ctx; |
| 128 | + } |
| 129 | + |
| 130 | + rc = ibv_cmd_get_context(&ctx->vctx, &req.ibv_cmd, sizeof(req), |
| 131 | + NULL, &resp.ibv_resp, sizeof(resp)); |
| 132 | + if (rc) |
| 133 | + goto err_cmd; |
| 134 | + |
| 135 | + ctx->pg_shift = resp.page_shift; |
| 136 | + |
| 137 | + if (resp.version < IONIC_MIN_RDMA_VERSION) { |
| 138 | + fprintf(stderr, "ionic: Firmware RDMA Version %u\n", |
| 139 | + resp.version); |
| 140 | + fprintf(stderr, "ionic: Driver Min RDMA Version %u\n", |
| 141 | + IONIC_MIN_RDMA_VERSION); |
| 142 | + rc = EINVAL; |
| 143 | + goto err_cmd; |
| 144 | + } |
| 145 | + |
| 146 | + if (resp.version > IONIC_MAX_RDMA_VERSION) { |
| 147 | + fprintf(stderr, "ionic: Firmware RDMA Version %u\n", |
| 148 | + resp.version); |
| 149 | + fprintf(stderr, "ionic: Driver Max RDMA Version %u\n", |
| 150 | + IONIC_MAX_RDMA_VERSION); |
| 151 | + rc = EINVAL; |
| 152 | + goto err_cmd; |
| 153 | + } |
| 154 | + |
| 155 | + ctx->version = resp.version; |
| 156 | + ctx->opcodes = resp.qp_opcodes; |
| 157 | + if (ctx->version == 1 && ctx->opcodes <= IONIC_V1_OP_BIND_MW) { |
| 158 | + fprintf(stderr, "ionic: qp opcodes %d want min %d\n", |
| 159 | + ctx->opcodes, IONIC_V1_OP_BIND_MW + 1); |
| 160 | + rc = EINVAL; |
| 161 | + goto err_cmd; |
| 162 | + } |
| 163 | + |
| 164 | + if (resp.udma_count != 1 && resp.udma_count != 2) { |
| 165 | + fprintf(stderr, "ionic: udma_count %d invalid\n", |
| 166 | + resp.udma_count); |
| 167 | + rc = EINVAL; |
| 168 | + goto err_cmd; |
| 169 | + } |
| 170 | + ctx->udma_count = resp.udma_count; |
| 171 | + |
| 172 | + ctx->sq_qtype = resp.sq_qtype; |
| 173 | + ctx->rq_qtype = resp.rq_qtype; |
| 174 | + ctx->cq_qtype = resp.cq_qtype; |
| 175 | + |
| 176 | + ctx->max_stride = resp.max_stride; |
| 177 | + |
| 178 | + ctx->expdb_mask = resp.expdb_mask; |
| 179 | + ctx->sq_expdb = !!(resp.expdb_qtypes & IONIC_EXPDB_SQ); |
| 180 | + ctx->rq_expdb = !!(resp.expdb_qtypes & IONIC_EXPDB_RQ); |
| 181 | + |
| 182 | + ctx->ovrd_sq_cmb = ionic_env_ovrd_sq_cmb(); |
| 183 | + ctx->ovrd_rq_cmb = ionic_env_ovrd_rq_cmb(); |
| 184 | + |
| 185 | + mask = (1u << ctx->pg_shift) - 1; |
| 186 | + ctx->dbpage_page = ionic_map_device(1u << ctx->pg_shift, cmd_fd, |
| 187 | + resp.dbell_offset & ~mask); |
| 188 | + if (!ctx->dbpage_page) { |
| 189 | + rc = errno; |
| 190 | + goto err_cmd; |
| 191 | + } |
| 192 | + ctx->dbpage = ctx->dbpage_page + (resp.dbell_offset & mask); |
| 193 | + |
| 194 | + pthread_mutex_init(&ctx->mut, NULL); |
| 195 | + ionic_tbl_init(&ctx->qp_tbl); |
| 196 | + |
| 197 | + verbs_set_ops(&ctx->vctx, &ionic_ctx_ops); |
| 198 | + |
| 199 | + if (dev->abi_ver <= 1) { |
| 200 | + ctx->spec = 0; |
| 201 | + } else { |
| 202 | + ctx->spec = resp.max_spec; |
| 203 | + if (ctx->spec < 0 || ctx->spec > 16) |
| 204 | + ctx->spec = 0; |
| 205 | + } |
| 206 | + |
| 207 | + if (ionic_env_debug()) { |
| 208 | + ctx->dbg_file = IONIC_DEBUG_FILE; |
| 209 | + ionic_dbg(ctx, "Attached to ctx %p", ctx); |
| 210 | + } |
| 211 | + |
| 212 | + return &ctx->vctx; |
| 213 | + |
| 214 | +err_cmd: |
| 215 | + verbs_uninit_context(&ctx->vctx); |
| 216 | +err_ctx: |
| 217 | + errno = rc; |
| 218 | + return NULL; |
| 219 | +} |
| 220 | + |
| 221 | +static const struct verbs_match_ent cna_table[] = { |
| 222 | + VERBS_DRIVER_ID(RDMA_DRIVER_IONIC), |
| 223 | + {} |
| 224 | +}; |
| 225 | + |
| 226 | +static struct verbs_device *ionic_alloc_device(struct verbs_sysfs_dev *sdev) |
| 227 | +{ |
| 228 | + struct ionic_dev *dev; |
| 229 | + |
| 230 | + static_assert(sizeof(struct ionic_v1_cqe) == 32, "bad size"); |
| 231 | + static_assert(sizeof(struct ionic_v1_base_hdr) == 16, "bad size"); |
| 232 | + static_assert(sizeof(struct ionic_v1_recv_bdy) == 48, "bad size"); |
| 233 | + static_assert(sizeof(struct ionic_v1_common_bdy) == 48, "bad size"); |
| 234 | + static_assert(sizeof(struct ionic_v1_atomic_bdy) == 48, "bad size"); |
| 235 | + static_assert(sizeof(struct ionic_v1_bind_mw_bdy) == 48, "bad size"); |
| 236 | + static_assert(sizeof(struct ionic_v1_wqe) == 64, "bad size"); |
| 237 | + |
| 238 | + dev = calloc(1, sizeof(*dev)); |
| 239 | + if (!dev) |
| 240 | + return NULL; |
| 241 | + |
| 242 | + dev->abi_ver = sdev->abi_ver; |
| 243 | + |
| 244 | + return &dev->vdev; |
| 245 | +} |
| 246 | + |
| 247 | +static void ionic_uninit_device(struct verbs_device *vdev) |
| 248 | +{ |
| 249 | + struct ionic_dev *dev = to_ionic_dev(&vdev->device); |
| 250 | + |
| 251 | + free(dev); |
| 252 | +} |
| 253 | + |
| 254 | +static const struct verbs_device_ops ionic_dev_ops = { |
| 255 | + .name = "ionic", |
| 256 | + .match_min_abi_version = IONIC_ABI_VERSION, |
| 257 | + .match_max_abi_version = IONIC_ABI_VERSION, |
| 258 | + .match_table = cna_table, |
| 259 | + .alloc_device = ionic_alloc_device, |
| 260 | + .uninit_device = ionic_uninit_device, |
| 261 | + .alloc_context = ionic_alloc_context, |
| 262 | +}; |
| 263 | + |
| 264 | +PROVIDER_DRIVER(ionic, ionic_dev_ops); |
0 commit comments