| 1 | |
| 2 |
|
| 3 |
|
| 4 | #include <linux/printk.h>
|
| 5 | #include <linux/dynamic_debug.h>
|
| 6 | #include <linux/module.h>
|
| 7 | #include <linux/netdevice.h>
|
| 8 | #include <linux/utsname.h>
|
| 9 | #include <generated/utsrelease.h>
|
| 10 | #include <linux/ctype.h>
|
| 11 |
|
| 12 | #include "ionic.h"
|
| 13 | #include "ionic_bus.h"
|
| 14 | #include "ionic_lif.h"
|
| 15 | #include "ionic_debugfs.h"
|
| 16 |
|
| 17 | MODULE_DESCRIPTION(IONIC_DRV_DESCRIPTION);
|
| 18 | MODULE_AUTHOR("Shannon Nelson <[email protected]>");
|
| 19 | MODULE_LICENSE("GPL");
|
| 20 |
|
| 21 | static const char *ionic_error_to_str(enum ionic_status_code code)
|
| 22 | {
|
| 23 | switch (code) {
|
| 24 | case IONIC_RC_SUCCESS:
|
| 25 | return "IONIC_RC_SUCCESS";
|
| 26 | case IONIC_RC_EVERSION:
|
| 27 | return "IONIC_RC_EVERSION";
|
| 28 | case IONIC_RC_EOPCODE:
|
| 29 | return "IONIC_RC_EOPCODE";
|
| 30 | case IONIC_RC_EIO:
|
| 31 | return "IONIC_RC_EIO";
|
| 32 | case IONIC_RC_EPERM:
|
| 33 | return "IONIC_RC_EPERM";
|
| 34 | case IONIC_RC_EQID:
|
| 35 | return "IONIC_RC_EQID";
|
| 36 | case IONIC_RC_EQTYPE:
|
| 37 | return "IONIC_RC_EQTYPE";
|
| 38 | case IONIC_RC_ENOENT:
|
| 39 | return "IONIC_RC_ENOENT";
|
| 40 | case IONIC_RC_EINTR:
|
| 41 | return "IONIC_RC_EINTR";
|
| 42 | case IONIC_RC_EAGAIN:
|
| 43 | return "IONIC_RC_EAGAIN";
|
| 44 | case IONIC_RC_ENOMEM:
|
| 45 | return "IONIC_RC_ENOMEM";
|
| 46 | case IONIC_RC_EFAULT:
|
| 47 | return "IONIC_RC_EFAULT";
|
| 48 | case IONIC_RC_EBUSY:
|
| 49 | return "IONIC_RC_EBUSY";
|
| 50 | case IONIC_RC_EEXIST:
|
| 51 | return "IONIC_RC_EEXIST";
|
| 52 | case IONIC_RC_EINVAL:
|
| 53 | return "IONIC_RC_EINVAL";
|
| 54 | case IONIC_RC_ENOSPC:
|
| 55 | return "IONIC_RC_ENOSPC";
|
| 56 | case IONIC_RC_ERANGE:
|
| 57 | return "IONIC_RC_ERANGE";
|
| 58 | case IONIC_RC_BAD_ADDR:
|
| 59 | return "IONIC_RC_BAD_ADDR";
|
| 60 | case IONIC_RC_DEV_CMD:
|
| 61 | return "IONIC_RC_DEV_CMD";
|
| 62 | case IONIC_RC_ENOSUPP:
|
| 63 | return "IONIC_RC_ENOSUPP";
|
| 64 | case IONIC_RC_ERROR:
|
| 65 | return "IONIC_RC_ERROR";
|
| 66 | case IONIC_RC_ERDMA:
|
| 67 | return "IONIC_RC_ERDMA";
|
| 68 | case IONIC_RC_EBAD_FW:
|
| 69 | return "IONIC_RC_EBAD_FW";
|
| 70 | default:
|
| 71 | return "IONIC_RC_UNKNOWN";
|
| 72 | }
|
| 73 | }
|
| 74 |
|
| 75 | int ionic_error_to_errno(enum ionic_status_code code)
|
| 76 | {
|
| 77 | switch (code) {
|
| 78 | case IONIC_RC_SUCCESS:
|
| 79 | return 0;
|
| 80 | case IONIC_RC_EVERSION:
|
| 81 | case IONIC_RC_EQTYPE:
|
| 82 | case IONIC_RC_EQID:
|
| 83 | case IONIC_RC_EINVAL:
|
| 84 | return -EINVAL;
|
| 85 | case IONIC_RC_ENOSUPP:
|
| 86 | return -EOPNOTSUPP;
|
| 87 | case IONIC_RC_EPERM:
|
| 88 | return -EPERM;
|
| 89 | case IONIC_RC_ENOENT:
|
| 90 | return -ENOENT;
|
| 91 | case IONIC_RC_EAGAIN:
|
| 92 | return -EAGAIN;
|
| 93 | case IONIC_RC_ENOMEM:
|
| 94 | return -ENOMEM;
|
| 95 | case IONIC_RC_EFAULT:
|
| 96 | return -EFAULT;
|
| 97 | case IONIC_RC_EBUSY:
|
| 98 | return -EBUSY;
|
| 99 | case IONIC_RC_EEXIST:
|
| 100 | return -EEXIST;
|
| 101 | case IONIC_RC_ENOSPC:
|
| 102 | return -ENOSPC;
|
| 103 | case IONIC_RC_ERANGE:
|
| 104 | return -ERANGE;
|
| 105 | case IONIC_RC_BAD_ADDR:
|
| 106 | return -EFAULT;
|
| 107 | case IONIC_RC_EOPCODE:
|
| 108 | case IONIC_RC_EINTR:
|
| 109 | case IONIC_RC_DEV_CMD:
|
| 110 | case IONIC_RC_ERROR:
|
| 111 | case IONIC_RC_ERDMA:
|
| 112 | case IONIC_RC_EIO:
|
| 113 | default:
|
| 114 | return -EIO;
|
| 115 | }
|
| 116 | }
|
| 117 | EXPORT_SYMBOL_NS(ionic_error_to_errno, "NET_IONIC");
|
| 118 |
|
| 119 | static const char *ionic_opcode_to_str(enum ionic_cmd_opcode opcode)
|
| 120 | {
|
| 121 | switch (opcode) {
|
| 122 | case IONIC_CMD_NOP:
|
| 123 | return "IONIC_CMD_NOP";
|
| 124 | case IONIC_CMD_INIT:
|
| 125 | return "IONIC_CMD_INIT";
|
| 126 | case IONIC_CMD_RESET:
|
| 127 | return "IONIC_CMD_RESET";
|
| 128 | case IONIC_CMD_IDENTIFY:
|
| 129 | return "IONIC_CMD_IDENTIFY";
|
| 130 | case IONIC_CMD_GETATTR:
|
| 131 | return "IONIC_CMD_GETATTR";
|
| 132 | case IONIC_CMD_SETATTR:
|
| 133 | return "IONIC_CMD_SETATTR";
|
| 134 | case IONIC_CMD_PORT_IDENTIFY:
|
| 135 | return "IONIC_CMD_PORT_IDENTIFY";
|
| 136 | case IONIC_CMD_PORT_INIT:
|
| 137 | return "IONIC_CMD_PORT_INIT";
|
| 138 | case IONIC_CMD_PORT_RESET:
|
| 139 | return "IONIC_CMD_PORT_RESET";
|
| 140 | case IONIC_CMD_PORT_GETATTR:
|
| 141 | return "IONIC_CMD_PORT_GETATTR";
|
| 142 | case IONIC_CMD_PORT_SETATTR:
|
| 143 | return "IONIC_CMD_PORT_SETATTR";
|
| 144 | case IONIC_CMD_LIF_INIT:
|
| 145 | return "IONIC_CMD_LIF_INIT";
|
| 146 | case IONIC_CMD_LIF_RESET:
|
| 147 | return "IONIC_CMD_LIF_RESET";
|
| 148 | case IONIC_CMD_LIF_IDENTIFY:
|
| 149 | return "IONIC_CMD_LIF_IDENTIFY";
|
| 150 | case IONIC_CMD_LIF_SETATTR:
|
| 151 | return "IONIC_CMD_LIF_SETATTR";
|
| 152 | case IONIC_CMD_LIF_GETATTR:
|
| 153 | return "IONIC_CMD_LIF_GETATTR";
|
| 154 | case IONIC_CMD_LIF_SETPHC:
|
| 155 | return "IONIC_CMD_LIF_SETPHC";
|
| 156 | case IONIC_CMD_RX_MODE_SET:
|
| 157 | return "IONIC_CMD_RX_MODE_SET";
|
| 158 | case IONIC_CMD_RX_FILTER_ADD:
|
| 159 | return "IONIC_CMD_RX_FILTER_ADD";
|
| 160 | case IONIC_CMD_RX_FILTER_DEL:
|
| 161 | return "IONIC_CMD_RX_FILTER_DEL";
|
| 162 | case IONIC_CMD_Q_IDENTIFY:
|
| 163 | return "IONIC_CMD_Q_IDENTIFY";
|
| 164 | case IONIC_CMD_Q_INIT:
|
| 165 | return "IONIC_CMD_Q_INIT";
|
| 166 | case IONIC_CMD_Q_CONTROL:
|
| 167 | return "IONIC_CMD_Q_CONTROL";
|
| 168 | case IONIC_CMD_RDMA_RESET_LIF:
|
| 169 | return "IONIC_CMD_RDMA_RESET_LIF";
|
| 170 | case IONIC_CMD_RDMA_CREATE_EQ:
|
| 171 | return "IONIC_CMD_RDMA_CREATE_EQ";
|
| 172 | case IONIC_CMD_RDMA_CREATE_CQ:
|
| 173 | return "IONIC_CMD_RDMA_CREATE_CQ";
|
| 174 | case IONIC_CMD_RDMA_CREATE_ADMINQ:
|
| 175 | return "IONIC_CMD_RDMA_CREATE_ADMINQ";
|
| 176 | case IONIC_CMD_FW_DOWNLOAD:
|
| 177 | return "IONIC_CMD_FW_DOWNLOAD";
|
| 178 | case IONIC_CMD_FW_CONTROL:
|
| 179 | return "IONIC_CMD_FW_CONTROL";
|
| 180 | case IONIC_CMD_FW_DOWNLOAD_V1:
|
| 181 | return "IONIC_CMD_FW_DOWNLOAD_V1";
|
| 182 | case IONIC_CMD_FW_CONTROL_V1:
|
| 183 | return "IONIC_CMD_FW_CONTROL_V1";
|
| 184 | case IONIC_CMD_VF_GETATTR:
|
| 185 | return "IONIC_CMD_VF_GETATTR";
|
| 186 | case IONIC_CMD_VF_SETATTR:
|
| 187 | return "IONIC_CMD_VF_SETATTR";
|
| 188 | default:
|
| 189 | return "DEVCMD_UNKNOWN";
|
| 190 | }
|
| 191 | }
|
| 192 |
|
| 193 | static void ionic_adminq_flush(struct ionic_lif *lif)
|
| 194 | {
|
| 195 | struct ionic_admin_desc_info *desc_info;
|
| 196 | struct ionic_admin_cmd *desc;
|
| 197 | unsigned long irqflags;
|
| 198 | struct ionic_queue *q;
|
| 199 |
|
| 200 | spin_lock_irqsave(&lif->adminq_lock, irqflags);
|
| 201 | if (!lif->adminqcq) {
|
| 202 | spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
|
| 203 | return;
|
| 204 | }
|
| 205 |
|
| 206 | q = &lif->adminqcq->q;
|
| 207 |
|
| 208 | while (q->tail_idx != q->head_idx) {
|
| 209 | desc = &q->adminq[q->tail_idx];
|
| 210 | desc_info = &q->admin_info[q->tail_idx];
|
| 211 | memset(desc, 0, sizeof(union ionic_adminq_cmd));
|
| 212 | desc_info->ctx = NULL;
|
| 213 | q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);
|
| 214 | }
|
| 215 | spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
|
| 216 | }
|
| 217 |
|
| 218 | void ionic_adminq_netdev_err_print(struct ionic_lif *lif, u8 opcode,
|
| 219 | u8 status, int err)
|
| 220 | {
|
| 221 | const char *stat_str;
|
| 222 |
|
| 223 | stat_str = (err == -ETIMEDOUT) ? "TIMEOUT" :
|
| 224 | ionic_error_to_str(status);
|
| 225 |
|
| 226 | netdev_err(lif->netdev, "%s (%d) failed: %s (%d)\n",
|
| 227 | ionic_opcode_to_str(opcode), opcode, stat_str, err);
|
| 228 | }
|
| 229 |
|
| 230 | static int ionic_adminq_check_err(struct ionic_lif *lif,
|
| 231 | struct ionic_admin_ctx *ctx,
|
| 232 | const bool timeout,
|
| 233 | const bool do_msg)
|
| 234 | {
|
| 235 | int err = 0;
|
| 236 |
|
| 237 | if (ctx->comp.comp.status || timeout) {
|
| 238 | err = timeout ? -ETIMEDOUT :
|
| 239 | ionic_error_to_errno(ctx->comp.comp.status);
|
| 240 |
|
| 241 | if (do_msg)
|
| 242 | ionic_adminq_netdev_err_print(lif, ctx->cmd.cmd.opcode,
|
| 243 | ctx->comp.comp.status, err);
|
| 244 |
|
| 245 | if (timeout)
|
| 246 | ionic_adminq_flush(lif);
|
| 247 | }
|
| 248 |
|
| 249 | return err;
|
| 250 | }
|
| 251 |
|
| 252 | bool ionic_notifyq_service(struct ionic_cq *cq)
|
| 253 | {
|
| 254 | struct ionic_deferred_work *work;
|
| 255 | union ionic_notifyq_comp *comp;
|
| 256 | struct net_device *netdev;
|
| 257 | struct ionic_queue *q;
|
| 258 | struct ionic_lif *lif;
|
| 259 | u64 eid;
|
| 260 |
|
| 261 | comp = &((union ionic_notifyq_comp *)cq->base)[cq->tail_idx];
|
| 262 |
|
| 263 | q = cq->bound_q;
|
| 264 | lif = q->admin_info[0].ctx;
|
| 265 | netdev = lif->netdev;
|
| 266 | eid = le64_to_cpu(comp->event.eid);
|
| 267 |
|
| 268 |
|
| 269 | if ((s64)(eid - lif->last_eid) <= 0)
|
| 270 | return false;
|
| 271 |
|
| 272 | dma_rmb();
|
| 273 |
|
| 274 | lif->last_eid = eid;
|
| 275 |
|
| 276 | dev_dbg(lif->ionic->dev, "notifyq event:\n");
|
| 277 | dynamic_hex_dump("event ", DUMP_PREFIX_OFFSET, 16, 1,
|
| 278 | comp, sizeof(*comp), true);
|
| 279 |
|
| 280 | switch (le16_to_cpu(comp->event.ecode)) {
|
| 281 | case IONIC_EVENT_LINK_CHANGE:
|
| 282 | ionic_link_status_check_request(lif, CAN_NOT_SLEEP);
|
| 283 | break;
|
| 284 | case IONIC_EVENT_RESET:
|
| 285 | if (lif->ionic->idev.fw_status_ready &&
|
| 286 | !test_bit(IONIC_LIF_F_FW_RESET, lif->state) &&
|
| 287 | !test_and_set_bit(IONIC_LIF_F_FW_STOPPING, lif->state)) {
|
| 288 | work = kzalloc_obj(*work, GFP_ATOMIC);
|
| 289 | if (!work) {
|
| 290 | netdev_err(lif->netdev, "Reset event dropped\n");
|
| 291 | clear_bit(IONIC_LIF_F_FW_STOPPING, lif->state);
|
| 292 | } else {
|
| 293 | work->type = IONIC_DW_TYPE_LIF_RESET;
|
| 294 | ionic_lif_deferred_enqueue(lif, work);
|
| 295 | }
|
| 296 | }
|
| 297 | break;
|
| 298 | default:
|
| 299 | netdev_warn(netdev, "Notifyq event ecode=%d eid=%lld\n",
|
| 300 | comp->event.ecode, eid);
|
| 301 | break;
|
| 302 | }
|
| 303 |
|
| 304 | return true;
|
| 305 | }
|
| 306 |
|
| 307 | bool ionic_adminq_service(struct ionic_cq *cq)
|
| 308 | {
|
| 309 | struct ionic_admin_desc_info *desc_info;
|
| 310 | struct ionic_queue *q = cq->bound_q;
|
| 311 | struct ionic_admin_comp *comp;
|
| 312 | u16 index;
|
| 313 |
|
| 314 | comp = &((struct ionic_admin_comp *)cq->base)[cq->tail_idx];
|
| 315 |
|
| 316 | if (!color_match(comp->color, cq->done_color))
|
| 317 | return false;
|
| 318 |
|
| 319 | dma_rmb();
|
| 320 |
|
| 321 |
|
| 322 | if (q->tail_idx == q->head_idx)
|
| 323 | return false;
|
| 324 |
|
| 325 | do {
|
| 326 | desc_info = &q->admin_info[q->tail_idx];
|
| 327 | index = q->tail_idx;
|
| 328 | q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);
|
| 329 | if (likely(desc_info->ctx)) {
|
| 330 | struct ionic_admin_ctx *ctx = desc_info->ctx;
|
| 331 |
|
| 332 | memcpy(&ctx->comp, comp, sizeof(*comp));
|
| 333 |
|
| 334 | dev_dbg(q->dev, "comp admin queue command:\n");
|
| 335 | dynamic_hex_dump("comp ", DUMP_PREFIX_OFFSET, 16, 1,
|
| 336 | &ctx->comp, sizeof(ctx->comp), true);
|
| 337 | complete_all(&ctx->work);
|
| 338 | desc_info->ctx = NULL;
|
| 339 | }
|
| 340 | } while (index != le16_to_cpu(comp->comp_index));
|
| 341 |
|
| 342 | return true;
|
| 343 | }
|
| 344 |
|
| 345 | bool ionic_adminq_poke_doorbell(struct ionic_queue *q)
|
| 346 | {
|
| 347 | struct ionic_lif *lif = q->lif;
|
| 348 | unsigned long now, then, dif;
|
| 349 | unsigned long irqflags;
|
| 350 |
|
| 351 | spin_lock_irqsave(&lif->adminq_lock, irqflags);
|
| 352 |
|
| 353 | if (q->tail_idx == q->head_idx) {
|
| 354 | spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
|
| 355 | return false;
|
| 356 | }
|
| 357 |
|
| 358 | now = READ_ONCE(jiffies);
|
| 359 | then = q->dbell_jiffies;
|
| 360 | dif = now - then;
|
| 361 |
|
| 362 | if (dif > q->dbell_deadline) {
|
| 363 | ionic_dbell_ring(q->lif->kern_dbpage, q->hw_type,
|
| 364 | q->dbval | q->head_idx);
|
| 365 |
|
| 366 | q->dbell_jiffies = now;
|
| 367 | }
|
| 368 |
|
| 369 | spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
|
| 370 |
|
| 371 | return true;
|
| 372 | }
|
| 373 |
|
| 374 | int ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
|
| 375 | {
|
| 376 | struct ionic_admin_desc_info *desc_info;
|
| 377 | struct ionic_admin_cmd *desc;
|
| 378 | unsigned long irqflags;
|
| 379 | struct ionic_queue *q;
|
| 380 | int err = 0;
|
| 381 |
|
| 382 | spin_lock_irqsave(&lif->adminq_lock, irqflags);
|
| 383 | if (!lif->adminqcq) {
|
| 384 | spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
|
| 385 | return -EIO;
|
| 386 | }
|
| 387 |
|
| 388 | q = &lif->adminqcq->q;
|
| 389 |
|
| 390 | if (!ionic_q_has_space(q, 1)) {
|
| 391 | err = -ENOSPC;
|
| 392 | goto err_out;
|
| 393 | }
|
| 394 |
|
| 395 | err = ionic_heartbeat_check(lif->ionic);
|
| 396 | if (err)
|
| 397 | goto err_out;
|
| 398 |
|
| 399 | desc_info = &q->admin_info[q->head_idx];
|
| 400 | desc_info->ctx = ctx;
|
| 401 |
|
| 402 | desc = &q->adminq[q->head_idx];
|
| 403 | memcpy(desc, &ctx->cmd, sizeof(ctx->cmd));
|
| 404 |
|
| 405 | dev_dbg(&lif->netdev->dev, "post admin queue command:\n");
|
| 406 | dynamic_hex_dump("cmd ", DUMP_PREFIX_OFFSET, 16, 1,
|
| 407 | &ctx->cmd, sizeof(ctx->cmd), true);
|
| 408 |
|
| 409 | ionic_q_post(q, true);
|
| 410 |
|
| 411 | err_out:
|
| 412 | spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
|
| 413 |
|
| 414 | return err;
|
| 415 | }
|
| 416 |
|
| 417 | int ionic_adminq_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx,
|
| 418 | const int err, const bool do_msg)
|
| 419 | {
|
| 420 | struct net_device *netdev = lif->netdev;
|
| 421 | unsigned long time_limit;
|
| 422 | unsigned long time_start;
|
| 423 | unsigned long time_done;
|
| 424 | unsigned long remaining;
|
| 425 | const char *name;
|
| 426 |
|
| 427 | name = ionic_opcode_to_str(ctx->cmd.cmd.opcode);
|
| 428 |
|
| 429 | if (err) {
|
| 430 | if (do_msg && !test_bit(IONIC_LIF_F_FW_RESET, lif->state))
|
| 431 | netdev_err(netdev, "Posting of %s (%d) failed: %d\n",
|
| 432 | name, ctx->cmd.cmd.opcode, err);
|
| 433 | ctx->comp.comp.status = IONIC_RC_ERROR;
|
| 434 | return err;
|
| 435 | }
|
| 436 |
|
| 437 | time_start = jiffies;
|
| 438 | time_limit = time_start + HZ * (ulong)DEVCMD_TIMEOUT;
|
| 439 | do {
|
| 440 | remaining = wait_for_completion_timeout(&ctx->work,
|
| 441 | IONIC_ADMINQ_TIME_SLICE);
|
| 442 |
|
| 443 |
|
| 444 | if (remaining)
|
| 445 | break;
|
| 446 |
|
| 447 |
|
| 448 | ionic_heartbeat_check(lif->ionic);
|
| 449 | if ((test_bit(IONIC_LIF_F_FW_RESET, lif->state) &&
|
| 450 | !lif->ionic->idev.fw_status_ready) ||
|
| 451 | test_bit(IONIC_LIF_F_FW_STOPPING, lif->state)) {
|
| 452 | if (do_msg)
|
| 453 | netdev_warn(netdev, "%s (%d) interrupted, FW in reset\n",
|
| 454 | name, ctx->cmd.cmd.opcode);
|
| 455 | ctx->comp.comp.status = IONIC_RC_ERROR;
|
| 456 | return -ENXIO;
|
| 457 | }
|
| 458 |
|
| 459 | } while (time_before(jiffies, time_limit));
|
| 460 | time_done = jiffies;
|
| 461 |
|
| 462 | dev_dbg(lif->ionic->dev, "%s: elapsed %d msecs\n",
|
| 463 | __func__, jiffies_to_msecs(time_done - time_start));
|
| 464 |
|
| 465 | return ionic_adminq_check_err(lif, ctx,
|
| 466 | time_after_eq(time_done, time_limit),
|
| 467 | do_msg);
|
| 468 | }
|
| 469 |
|
| 470 | static int __ionic_adminq_post_wait(struct ionic_lif *lif,
|
| 471 | struct ionic_admin_ctx *ctx,
|
| 472 | const bool do_msg)
|
| 473 | {
|
| 474 | int err;
|
| 475 |
|
| 476 | if (!ionic_is_fw_running(&lif->ionic->idev))
|
| 477 | return 0;
|
| 478 |
|
| 479 | err = ionic_adminq_post(lif, ctx);
|
| 480 |
|
| 481 | return ionic_adminq_wait(lif, ctx, err, do_msg);
|
| 482 | }
|
| 483 |
|
| 484 | int ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
|
| 485 | {
|
| 486 | return __ionic_adminq_post_wait(lif, ctx, true);
|
| 487 | }
|
| 488 | EXPORT_SYMBOL_NS(ionic_adminq_post_wait, "NET_IONIC");
|
| 489 |
|
| 490 | int ionic_adminq_post_wait_nomsg(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
|
| 491 | {
|
| 492 | return __ionic_adminq_post_wait(lif, ctx, false);
|
| 493 | }
|
| 494 |
|
| 495 | static void ionic_dev_cmd_clean(struct ionic *ionic)
|
| 496 | {
|
| 497 | struct ionic_dev *idev = &ionic->idev;
|
| 498 |
|
| 499 | if (!idev->dev_cmd_regs)
|
| 500 | return;
|
| 501 |
|
| 502 | iowrite32(0, &idev->dev_cmd_regs->doorbell);
|
| 503 | memset_io(&idev->dev_cmd_regs->cmd, 0, sizeof(idev->dev_cmd_regs->cmd));
|
| 504 | }
|
| 505 |
|
| 506 | void ionic_dev_cmd_dev_err_print(struct ionic *ionic, u8 opcode, u8 status,
|
| 507 | int err)
|
| 508 | {
|
| 509 | const char *stat_str;
|
| 510 |
|
| 511 | stat_str = (err == -ETIMEDOUT) ? "TIMEOUT" :
|
| 512 | ionic_error_to_str(status);
|
| 513 |
|
| 514 | dev_err(ionic->dev, "DEV_CMD %s (%d) error, %s (%d) failed\n",
|
| 515 | ionic_opcode_to_str(opcode), opcode, stat_str, err);
|
| 516 | }
|
| 517 |
|
| 518 | static int __ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds,
|
| 519 | const bool do_msg)
|
| 520 | {
|
| 521 | struct ionic_dev *idev = &ionic->idev;
|
| 522 | unsigned long start_time;
|
| 523 | unsigned long max_wait;
|
| 524 | unsigned long duration;
|
| 525 | bool fw_up;
|
| 526 | int opcode;
|
| 527 | bool done;
|
| 528 | int err;
|
| 529 |
|
| 530 | |
| 531 | * but don't wait any longer than max_seconds.
|
| 532 |
|
| 533 | max_wait = jiffies + (max_seconds * HZ);
|
| 534 | try_again:
|
| 535 | done = false;
|
| 536 | opcode = idev->opcode;
|
| 537 | start_time = jiffies;
|
| 538 | for (fw_up = ionic_is_fw_running(idev);
|
| 539 | !done && fw_up && time_before(jiffies, max_wait);
|
| 540 | fw_up = ionic_is_fw_running(idev)) {
|
| 541 | done = ionic_dev_cmd_done(idev);
|
| 542 | if (done)
|
| 543 | break;
|
| 544 | usleep_range(100, 200);
|
| 545 | }
|
| 546 | duration = jiffies - start_time;
|
| 547 |
|
| 548 | dev_dbg(ionic->dev, "DEVCMD %s (%d) done=%d took %ld secs (%ld jiffies)\n",
|
| 549 | ionic_opcode_to_str(opcode), opcode,
|
| 550 | done, duration / HZ, duration);
|
| 551 |
|
| 552 | if (!done && !fw_up) {
|
| 553 | ionic_dev_cmd_clean(ionic);
|
| 554 | dev_warn(ionic->dev, "DEVCMD %s (%d) interrupted - FW is down\n",
|
| 555 | ionic_opcode_to_str(opcode), opcode);
|
| 556 | return -ENXIO;
|
| 557 | }
|
| 558 |
|
| 559 | if (!done && !time_before(jiffies, max_wait)) {
|
| 560 | ionic_dev_cmd_clean(ionic);
|
| 561 | dev_warn(ionic->dev, "DEVCMD %s (%d) timeout after %ld secs\n",
|
| 562 | ionic_opcode_to_str(opcode), opcode, max_seconds);
|
| 563 | return -ETIMEDOUT;
|
| 564 | }
|
| 565 |
|
| 566 | err = ionic_dev_cmd_status(&ionic->idev);
|
| 567 | if (err) {
|
| 568 | if (err == IONIC_RC_EAGAIN &&
|
| 569 | time_before(jiffies, (max_wait - HZ))) {
|
| 570 | dev_dbg(ionic->dev, "DEV_CMD %s (%d), %s (%d) retrying...\n",
|
| 571 | ionic_opcode_to_str(opcode), opcode,
|
| 572 | ionic_error_to_str(err), err);
|
| 573 |
|
| 574 | iowrite32(0, &idev->dev_cmd_regs->done);
|
| 575 | msleep(1000);
|
| 576 | iowrite32(1, &idev->dev_cmd_regs->doorbell);
|
| 577 | goto try_again;
|
| 578 | }
|
| 579 |
|
| 580 | if (!(opcode == IONIC_CMD_FW_CONTROL && err == IONIC_RC_EAGAIN))
|
| 581 | if (do_msg)
|
| 582 | ionic_dev_cmd_dev_err_print(ionic, opcode, err,
|
| 583 | ionic_error_to_errno(err));
|
| 584 |
|
| 585 | return ionic_error_to_errno(err);
|
| 586 | }
|
| 587 |
|
| 588 | ionic_dev_cmd_clean(ionic);
|
| 589 |
|
| 590 | return 0;
|
| 591 | }
|
| 592 |
|
| 593 | int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds)
|
| 594 | {
|
| 595 | return __ionic_dev_cmd_wait(ionic, max_seconds, true);
|
| 596 | }
|
| 597 |
|
| 598 | int ionic_dev_cmd_wait_nomsg(struct ionic *ionic, unsigned long max_seconds)
|
| 599 | {
|
| 600 | return __ionic_dev_cmd_wait(ionic, max_seconds, false);
|
| 601 | }
|
| 602 |
|
| 603 | int ionic_setup(struct ionic *ionic)
|
| 604 | {
|
| 605 | int err;
|
| 606 |
|
| 607 | err = ionic_dev_setup(ionic);
|
| 608 | if (err)
|
| 609 | return err;
|
| 610 | ionic_reset(ionic);
|
| 611 |
|
| 612 | return 0;
|
| 613 | }
|
| 614 |
|
| 615 | int ionic_identify(struct ionic *ionic)
|
| 616 | {
|
| 617 | struct ionic_identity *ident = &ionic->ident;
|
| 618 | struct ionic_dev *idev = &ionic->idev;
|
| 619 | size_t sz;
|
| 620 | int err;
|
| 621 |
|
| 622 | memset(ident, 0, sizeof(*ident));
|
| 623 |
|
| 624 | ident->drv.os_type = cpu_to_le32(IONIC_OS_TYPE_LINUX);
|
| 625 | strscpy(ident->drv.driver_ver_str, UTS_RELEASE,
|
| 626 | sizeof(ident->drv.driver_ver_str));
|
| 627 |
|
| 628 | mutex_lock(&ionic->dev_cmd_lock);
|
| 629 |
|
| 630 | sz = min(sizeof(ident->drv), sizeof(idev->dev_cmd_regs->data));
|
| 631 | memcpy_toio(&idev->dev_cmd_regs->data, &ident->drv, sz);
|
| 632 |
|
| 633 | ionic_dev_cmd_identify(idev, IONIC_DEV_IDENTITY_VERSION_2);
|
| 634 | err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
|
| 635 | if (!err) {
|
| 636 | sz = min(sizeof(ident->dev), sizeof(idev->dev_cmd_regs->data));
|
| 637 | memcpy_fromio(&ident->dev, &idev->dev_cmd_regs->data, sz);
|
| 638 | }
|
| 639 | mutex_unlock(&ionic->dev_cmd_lock);
|
| 640 |
|
| 641 | if (err) {
|
| 642 | dev_err(ionic->dev, "Cannot identify ionic: %d\n", err);
|
| 643 | goto err_out;
|
| 644 | }
|
| 645 |
|
| 646 | if (isprint(idev->dev_info.fw_version[0]) &&
|
| 647 | isascii(idev->dev_info.fw_version[0]))
|
| 648 | dev_info(ionic->dev, "FW: %.*s\n",
|
| 649 | (int)(sizeof(idev->dev_info.fw_version) - 1),
|
| 650 | idev->dev_info.fw_version);
|
| 651 | else
|
| 652 | dev_info(ionic->dev, "FW: (invalid string) 0x%02x 0x%02x 0x%02x 0x%02x ...\n",
|
| 653 | (u8)idev->dev_info.fw_version[0],
|
| 654 | (u8)idev->dev_info.fw_version[1],
|
| 655 | (u8)idev->dev_info.fw_version[2],
|
| 656 | (u8)idev->dev_info.fw_version[3]);
|
| 657 |
|
| 658 | err = ionic_lif_identify(ionic, IONIC_LIF_TYPE_CLASSIC,
|
| 659 | &ionic->ident.lif);
|
| 660 | if (err) {
|
| 661 | dev_err(ionic->dev, "Cannot identify LIFs: %d\n", err);
|
| 662 | goto err_out;
|
| 663 | }
|
| 664 |
|
| 665 | return 0;
|
| 666 |
|
| 667 | err_out:
|
| 668 | return err;
|
| 669 | }
|
| 670 |
|
| 671 | int ionic_init(struct ionic *ionic)
|
| 672 | {
|
| 673 | struct ionic_dev *idev = &ionic->idev;
|
| 674 | int err;
|
| 675 |
|
| 676 | mutex_lock(&ionic->dev_cmd_lock);
|
| 677 | ionic_dev_cmd_init(idev);
|
| 678 | err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
|
| 679 | mutex_unlock(&ionic->dev_cmd_lock);
|
| 680 |
|
| 681 | return err;
|
| 682 | }
|
| 683 |
|
| 684 | int ionic_reset(struct ionic *ionic)
|
| 685 | {
|
| 686 | struct ionic_dev *idev = &ionic->idev;
|
| 687 | int err;
|
| 688 |
|
| 689 | if (!ionic_is_fw_running(idev))
|
| 690 | return 0;
|
| 691 |
|
| 692 | mutex_lock(&ionic->dev_cmd_lock);
|
| 693 | ionic_dev_cmd_reset(idev);
|
| 694 | err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
|
| 695 | mutex_unlock(&ionic->dev_cmd_lock);
|
| 696 |
|
| 697 | return err;
|
| 698 | }
|
| 699 |
|
| 700 | int ionic_port_identify(struct ionic *ionic)
|
| 701 | {
|
| 702 | struct ionic_identity *ident = &ionic->ident;
|
| 703 | struct ionic_dev *idev = &ionic->idev;
|
| 704 | size_t sz;
|
| 705 | int err;
|
| 706 |
|
| 707 | mutex_lock(&ionic->dev_cmd_lock);
|
| 708 |
|
| 709 | ionic_dev_cmd_port_identify(idev);
|
| 710 | err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
|
| 711 | if (!err) {
|
| 712 | sz = min(sizeof(ident->port), sizeof(idev->dev_cmd_regs->data));
|
| 713 | memcpy_fromio(&ident->port, &idev->dev_cmd_regs->data, sz);
|
| 714 | }
|
| 715 |
|
| 716 | mutex_unlock(&ionic->dev_cmd_lock);
|
| 717 |
|
| 718 | return err;
|
| 719 | }
|
| 720 |
|
| 721 | int ionic_port_init(struct ionic *ionic)
|
| 722 | {
|
| 723 | struct ionic_identity *ident = &ionic->ident;
|
| 724 | struct ionic_dev *idev = &ionic->idev;
|
| 725 | size_t sz;
|
| 726 | int err;
|
| 727 |
|
| 728 | if (!idev->port_info) {
|
| 729 | idev->port_info_sz = ALIGN(sizeof(*idev->port_info), PAGE_SIZE);
|
| 730 | idev->port_info = dma_alloc_coherent(ionic->dev,
|
| 731 | idev->port_info_sz,
|
| 732 | &idev->port_info_pa,
|
| 733 | GFP_KERNEL);
|
| 734 | if (!idev->port_info)
|
| 735 | return -ENOMEM;
|
| 736 | }
|
| 737 |
|
| 738 | |
| 739 | * make sure these stats are marked as invalid.
|
| 740 |
|
| 741 | memset(&idev->port_info->extra_stats, 0xff,
|
| 742 | sizeof(idev->port_info->extra_stats));
|
| 743 |
|
| 744 | WRITE_ONCE(idev->link_down_count_init, false);
|
| 745 |
|
| 746 | sz = min(sizeof(ident->port.config), sizeof(idev->dev_cmd_regs->data));
|
| 747 |
|
| 748 | mutex_lock(&ionic->dev_cmd_lock);
|
| 749 |
|
| 750 | memcpy_toio(&idev->dev_cmd_regs->data, &ident->port.config, sz);
|
| 751 | ionic_dev_cmd_port_init(idev);
|
| 752 | err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
|
| 753 |
|
| 754 | ionic_dev_cmd_port_state(&ionic->idev, IONIC_PORT_ADMIN_STATE_UP);
|
| 755 | ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
|
| 756 |
|
| 757 | mutex_unlock(&ionic->dev_cmd_lock);
|
| 758 | if (err) {
|
| 759 | dev_err(ionic->dev, "Failed to init port\n");
|
| 760 | dma_free_coherent(ionic->dev, idev->port_info_sz,
|
| 761 | idev->port_info, idev->port_info_pa);
|
| 762 | idev->port_info = NULL;
|
| 763 | idev->port_info_pa = 0;
|
| 764 | }
|
| 765 |
|
| 766 | return err;
|
| 767 | }
|
| 768 |
|
| 769 | int ionic_port_reset(struct ionic *ionic)
|
| 770 | {
|
| 771 | struct ionic_dev *idev = &ionic->idev;
|
| 772 | int err = 0;
|
| 773 |
|
| 774 | if (!idev->port_info)
|
| 775 | return 0;
|
| 776 |
|
| 777 | if (ionic_is_fw_running(idev)) {
|
| 778 | mutex_lock(&ionic->dev_cmd_lock);
|
| 779 | ionic_dev_cmd_port_reset(idev);
|
| 780 | err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
|
| 781 | mutex_unlock(&ionic->dev_cmd_lock);
|
| 782 | }
|
| 783 |
|
| 784 | dma_free_coherent(ionic->dev, idev->port_info_sz,
|
| 785 | idev->port_info, idev->port_info_pa);
|
| 786 |
|
| 787 | idev->port_info = NULL;
|
| 788 | idev->port_info_pa = 0;
|
| 789 |
|
| 790 | return err;
|
| 791 | }
|
| 792 |
|
| 793 | static int __init ionic_init_module(void)
|
| 794 | {
|
| 795 | int ret;
|
| 796 |
|
| 797 | ionic_debugfs_create();
|
| 798 | ret = ionic_bus_register_driver();
|
| 799 | if (ret)
|
| 800 | ionic_debugfs_destroy();
|
| 801 |
|
| 802 | return ret;
|
| 803 | }
|
| 804 |
|
| 805 | static void __exit ionic_cleanup_module(void)
|
| 806 | {
|
| 807 | ionic_bus_unregister_driver();
|
| 808 | ionic_debugfs_destroy();
|
| 809 |
|
| 810 | pr_info("%s removed\n", IONIC_DRV_NAME);
|
| 811 | }
|
| 812 |
|
| 813 | module_init(ionic_init_module);
|
| 814 | module_exit(ionic_cleanup_module);
|