1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Management-Controller-to-Driver Interface 4 * 5 * Copyright 2008-2013 Solarflare Communications Inc. 6 * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. 7 */ 8 #include <linux/delay.h> 9 #include <linux/slab.h> 10 #include <linux/io.h> 11 #include <linux/spinlock.h> 12 #include <linux/netdevice.h> 13 #include <linux/etherdevice.h> 14 #include <linux/ethtool.h> 15 #include <linux/if_vlan.h> 16 #include <linux/timer.h> 17 #include <linux/list.h> 18 #include <linux/pci.h> 19 #include <linux/device.h> 20 #include <linux/rwsem.h> 21 #include <linux/vmalloc.h> 22 #include <net/netevent.h> 23 #include <linux/log2.h> 24 #include <linux/net_tstamp.h> 25 #include <linux/wait.h> 26 27 #include "bitfield.h" 28 #include "mcdi.h" 29 30 static void cdx_mcdi_cancel_cmd(struct cdx_mcdi *cdx, struct cdx_mcdi_cmd *cmd); 31 static void cdx_mcdi_wait_for_cleanup(struct cdx_mcdi *cdx); 32 static int cdx_mcdi_rpc_async_internal(struct cdx_mcdi *cdx, 33 struct cdx_mcdi_cmd *cmd, 34 unsigned int *handle); 35 static void cdx_mcdi_start_or_queue(struct cdx_mcdi_iface *mcdi, 36 bool allow_retry); 37 static void cdx_mcdi_cmd_start_or_queue(struct cdx_mcdi_iface *mcdi, 38 struct cdx_mcdi_cmd *cmd); 39 static bool cdx_mcdi_complete_cmd(struct cdx_mcdi_iface *mcdi, 40 struct cdx_mcdi_cmd *cmd, 41 struct cdx_dword *outbuf, 42 int len, 43 struct list_head *cleanup_list); 44 static void cdx_mcdi_timeout_cmd(struct cdx_mcdi_iface *mcdi, 45 struct cdx_mcdi_cmd *cmd, 46 struct list_head *cleanup_list); 47 static void cdx_mcdi_cmd_work(struct work_struct *context); 48 static void cdx_mcdi_mode_fail(struct cdx_mcdi *cdx, struct list_head *cleanup_list); 49 static void _cdx_mcdi_display_error(struct cdx_mcdi *cdx, unsigned int cmd, 50 size_t inlen, int raw, int arg, int err_no); 51 52 static bool cdx_cmd_cancelled(struct cdx_mcdi_cmd *cmd) 53 { 54 return cmd->state == MCDI_STATE_RUNNING_CANCELLED; 55 } 56 57 static void cdx_mcdi_cmd_release(struct kref *ref) 58 { 59 kfree(container_of(ref, struct cdx_mcdi_cmd, ref)); 60 } 61 62 static unsigned int cdx_mcdi_cmd_handle(struct cdx_mcdi_cmd *cmd) 63 { 64 return cmd->handle; 65 } 66 67 static void _cdx_mcdi_remove_cmd(struct cdx_mcdi_iface *mcdi, 68 struct cdx_mcdi_cmd *cmd, 69 struct list_head *cleanup_list) 70 { 71 /* if cancelled, the completers have already been called */ 72 if (cdx_cmd_cancelled(cmd)) 73 return; 74 75 if (cmd->completer) { 76 list_add_tail(&cmd->cleanup_list, cleanup_list); 77 ++mcdi->outstanding_cleanups; 78 kref_get(&cmd->ref); 79 } 80 } 81 82 static void cdx_mcdi_remove_cmd(struct cdx_mcdi_iface *mcdi, 83 struct cdx_mcdi_cmd *cmd, 84 struct list_head *cleanup_list) 85 { 86 list_del(&cmd->list); 87 _cdx_mcdi_remove_cmd(mcdi, cmd, cleanup_list); 88 cmd->state = MCDI_STATE_FINISHED; 89 kref_put(&cmd->ref, cdx_mcdi_cmd_release); 90 if (list_empty(&mcdi->cmd_list)) 91 wake_up(&mcdi->cmd_complete_wq); 92 } 93 94 static unsigned long cdx_mcdi_rpc_timeout(struct cdx_mcdi *cdx, unsigned int cmd) 95 { 96 if (!cdx->mcdi_ops->mcdi_rpc_timeout) 97 return MCDI_RPC_TIMEOUT; 98 else 99 return cdx->mcdi_ops->mcdi_rpc_timeout(cdx, cmd); 100 } 101 102 int cdx_mcdi_init(struct cdx_mcdi *cdx) 103 { 104 struct cdx_mcdi_iface *mcdi; 105 int rc = -ENOMEM; 106 107 cdx->mcdi = kzalloc(sizeof(*cdx->mcdi), GFP_KERNEL); 108 if (!cdx->mcdi) 109 goto fail; 110 111 mcdi = cdx_mcdi_if(cdx); 112 mcdi->cdx = cdx; 113 114 mcdi->workqueue = alloc_ordered_workqueue("mcdi_wq", 0); 115 if (!mcdi->workqueue) 116 goto fail2; 117 mutex_init(&mcdi->iface_lock); 118 mcdi->mode = MCDI_MODE_EVENTS; 119 INIT_LIST_HEAD(&mcdi->cmd_list); 120 init_waitqueue_head(&mcdi->cmd_complete_wq); 121 122 mcdi->new_epoch = true; 123 124 return 0; 125 fail2: 126 kfree(cdx->mcdi); 127 cdx->mcdi = NULL; 128 fail: 129 return rc; 130 } 131 132 void cdx_mcdi_finish(struct cdx_mcdi *cdx) 133 { 134 struct cdx_mcdi_iface *mcdi; 135 136 mcdi = cdx_mcdi_if(cdx); 137 if (!mcdi) 138 return; 139 140 cdx_mcdi_wait_for_cleanup(cdx); 141 142 destroy_workqueue(mcdi->workqueue); 143 kfree(cdx->mcdi); 144 cdx->mcdi = NULL; 145 } 146 147 static bool cdx_mcdi_flushed(struct cdx_mcdi_iface *mcdi, bool ignore_cleanups) 148 { 149 bool flushed; 150 151 mutex_lock(&mcdi->iface_lock); 152 flushed = list_empty(&mcdi->cmd_list) && 153 (ignore_cleanups || !mcdi->outstanding_cleanups); 154 mutex_unlock(&mcdi->iface_lock); 155 return flushed; 156 } 157 158 /* Wait for outstanding MCDI commands to complete. */ 159 static void cdx_mcdi_wait_for_cleanup(struct cdx_mcdi *cdx) 160 { 161 struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx); 162 163 if (!mcdi) 164 return; 165 166 wait_event(mcdi->cmd_complete_wq, 167 cdx_mcdi_flushed(mcdi, false)); 168 } 169 170 int cdx_mcdi_wait_for_quiescence(struct cdx_mcdi *cdx, 171 unsigned int timeout_jiffies) 172 { 173 struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx); 174 DEFINE_WAIT_FUNC(wait, woken_wake_function); 175 int rc = 0; 176 177 if (!mcdi) 178 return -EINVAL; 179 180 flush_workqueue(mcdi->workqueue); 181 182 add_wait_queue(&mcdi->cmd_complete_wq, &wait); 183 184 while (!cdx_mcdi_flushed(mcdi, true)) { 185 rc = wait_woken(&wait, TASK_IDLE, timeout_jiffies); 186 if (rc) 187 continue; 188 break; 189 } 190 191 remove_wait_queue(&mcdi->cmd_complete_wq, &wait); 192 193 if (rc > 0) 194 rc = 0; 195 else if (rc == 0) 196 rc = -ETIMEDOUT; 197 198 return rc; 199 } 200 201 static u8 cdx_mcdi_payload_csum(const struct cdx_dword *hdr, size_t hdr_len, 202 const struct cdx_dword *sdu, size_t sdu_len) 203 { 204 u8 *p = (u8 *)hdr; 205 u8 csum = 0; 206 int i; 207 208 for (i = 0; i < hdr_len; i++) 209 csum += p[i]; 210 211 p = (u8 *)sdu; 212 for (i = 0; i < sdu_len; i++) 213 csum += p[i]; 214 215 return ~csum & 0xff; 216 } 217 218 static void cdx_mcdi_send_request(struct cdx_mcdi *cdx, 219 struct cdx_mcdi_cmd *cmd) 220 { 221 struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx); 222 const struct cdx_dword *inbuf = cmd->inbuf; 223 size_t inlen = cmd->inlen; 224 struct cdx_dword hdr[2]; 225 size_t hdr_len; 226 bool not_epoch; 227 u32 xflags; 228 229 if (!mcdi) 230 return; 231 232 mcdi->prev_seq = cmd->seq; 233 mcdi->seq_held_by[cmd->seq] = cmd; 234 mcdi->db_held_by = cmd; 235 cmd->started = jiffies; 236 237 not_epoch = !mcdi->new_epoch; 238 xflags = 0; 239 240 /* MCDI v2 */ 241 WARN_ON(inlen > MCDI_CTL_SDU_LEN_MAX_V2); 242 CDX_POPULATE_DWORD_7(hdr[0], 243 MCDI_HEADER_RESPONSE, 0, 244 MCDI_HEADER_RESYNC, 1, 245 MCDI_HEADER_CODE, MC_CMD_V2_EXTN, 246 MCDI_HEADER_DATALEN, 0, 247 MCDI_HEADER_SEQ, cmd->seq, 248 MCDI_HEADER_XFLAGS, xflags, 249 MCDI_HEADER_NOT_EPOCH, not_epoch); 250 CDX_POPULATE_DWORD_3(hdr[1], 251 MC_CMD_V2_EXTN_IN_EXTENDED_CMD, cmd->cmd, 252 MC_CMD_V2_EXTN_IN_ACTUAL_LEN, inlen, 253 MC_CMD_V2_EXTN_IN_MESSAGE_TYPE, 254 MC_CMD_V2_EXTN_IN_MCDI_MESSAGE_TYPE_PLATFORM); 255 hdr_len = 8; 256 257 hdr[0].cdx_u32 |= (__force __le32)(cdx_mcdi_payload_csum(hdr, hdr_len, inbuf, inlen) << 258 MCDI_HEADER_XFLAGS_LBN); 259 260 print_hex_dump_debug("MCDI REQ HEADER: ", DUMP_PREFIX_NONE, 32, 4, hdr, hdr_len, false); 261 print_hex_dump_debug("MCDI REQ PAYLOAD: ", DUMP_PREFIX_NONE, 32, 4, inbuf, inlen, false); 262 263 cdx->mcdi_ops->mcdi_request(cdx, hdr, hdr_len, inbuf, inlen); 264 265 mcdi->new_epoch = false; 266 } 267 268 static int cdx_mcdi_errno(struct cdx_mcdi *cdx, unsigned int mcdi_err) 269 { 270 switch (mcdi_err) { 271 case 0: 272 case MC_CMD_ERR_QUEUE_FULL: 273 return mcdi_err; 274 case MC_CMD_ERR_EPERM: 275 return -EPERM; 276 case MC_CMD_ERR_ENOENT: 277 return -ENOENT; 278 case MC_CMD_ERR_EINTR: 279 return -EINTR; 280 case MC_CMD_ERR_EAGAIN: 281 return -EAGAIN; 282 case MC_CMD_ERR_EACCES: 283 return -EACCES; 284 case MC_CMD_ERR_EBUSY: 285 return -EBUSY; 286 case MC_CMD_ERR_EINVAL: 287 return -EINVAL; 288 case MC_CMD_ERR_ERANGE: 289 return -ERANGE; 290 case MC_CMD_ERR_EDEADLK: 291 return -EDEADLK; 292 case MC_CMD_ERR_ENOSYS: 293 return -EOPNOTSUPP; 294 case MC_CMD_ERR_ETIME: 295 return -ETIME; 296 case MC_CMD_ERR_EALREADY: 297 return -EALREADY; 298 case MC_CMD_ERR_ENOSPC: 299 return -ENOSPC; 300 case MC_CMD_ERR_ENOMEM: 301 return -ENOMEM; 302 case MC_CMD_ERR_ENOTSUP: 303 return -EOPNOTSUPP; 304 case MC_CMD_ERR_ALLOC_FAIL: 305 return -ENOBUFS; 306 case MC_CMD_ERR_MAC_EXIST: 307 return -EADDRINUSE; 308 case MC_CMD_ERR_NO_EVB_PORT: 309 return -EAGAIN; 310 default: 311 return -EPROTO; 312 } 313 } 314 315 static void cdx_mcdi_process_cleanup_list(struct cdx_mcdi *cdx, 316 struct list_head *cleanup_list) 317 { 318 struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx); 319 unsigned int cleanups = 0; 320 321 if (!mcdi) 322 return; 323 324 while (!list_empty(cleanup_list)) { 325 struct cdx_mcdi_cmd *cmd = 326 list_first_entry(cleanup_list, 327 struct cdx_mcdi_cmd, cleanup_list); 328 cmd->completer(cdx, cmd->cookie, cmd->rc, 329 cmd->outbuf, cmd->outlen); 330 list_del(&cmd->cleanup_list); 331 kref_put(&cmd->ref, cdx_mcdi_cmd_release); 332 ++cleanups; 333 } 334 335 if (cleanups) { 336 bool all_done; 337 338 mutex_lock(&mcdi->iface_lock); 339 CDX_WARN_ON_PARANOID(cleanups > mcdi->outstanding_cleanups); 340 all_done = (mcdi->outstanding_cleanups -= cleanups) == 0; 341 mutex_unlock(&mcdi->iface_lock); 342 if (all_done) 343 wake_up(&mcdi->cmd_complete_wq); 344 } 345 } 346 347 static void _cdx_mcdi_cancel_cmd(struct cdx_mcdi_iface *mcdi, 348 unsigned int handle, 349 struct list_head *cleanup_list) 350 { 351 struct cdx_mcdi_cmd *cmd; 352 353 list_for_each_entry(cmd, &mcdi->cmd_list, list) 354 if (cdx_mcdi_cmd_handle(cmd) == handle) { 355 switch (cmd->state) { 356 case MCDI_STATE_QUEUED: 357 case MCDI_STATE_RETRY: 358 pr_debug("command %#x inlen %zu cancelled in queue\n", 359 cmd->cmd, cmd->inlen); 360 /* if not yet running, properly cancel it */ 361 cmd->rc = -EPIPE; 362 cdx_mcdi_remove_cmd(mcdi, cmd, cleanup_list); 363 break; 364 case MCDI_STATE_RUNNING: 365 case MCDI_STATE_RUNNING_CANCELLED: 366 case MCDI_STATE_FINISHED: 367 default: 368 /* invalid state? */ 369 WARN_ON(1); 370 } 371 break; 372 } 373 } 374 375 static void cdx_mcdi_cancel_cmd(struct cdx_mcdi *cdx, struct cdx_mcdi_cmd *cmd) 376 { 377 struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx); 378 LIST_HEAD(cleanup_list); 379 380 if (!mcdi) 381 return; 382 383 mutex_lock(&mcdi->iface_lock); 384 cdx_mcdi_timeout_cmd(mcdi, cmd, &cleanup_list); 385 mutex_unlock(&mcdi->iface_lock); 386 cdx_mcdi_process_cleanup_list(cdx, &cleanup_list); 387 } 388 389 struct cdx_mcdi_blocking_data { 390 struct kref ref; 391 bool done; 392 wait_queue_head_t wq; 393 int rc; 394 struct cdx_dword *outbuf; 395 size_t outlen; 396 size_t outlen_actual; 397 }; 398 399 static void cdx_mcdi_blocking_data_release(struct kref *ref) 400 { 401 kfree(container_of(ref, struct cdx_mcdi_blocking_data, ref)); 402 } 403 404 static void cdx_mcdi_rpc_completer(struct cdx_mcdi *cdx, unsigned long cookie, 405 int rc, struct cdx_dword *outbuf, 406 size_t outlen_actual) 407 { 408 struct cdx_mcdi_blocking_data *wait_data = 409 (struct cdx_mcdi_blocking_data *)cookie; 410 411 wait_data->rc = rc; 412 memcpy(wait_data->outbuf, outbuf, 413 min(outlen_actual, wait_data->outlen)); 414 wait_data->outlen_actual = outlen_actual; 415 /* memory barrier */ 416 smp_wmb(); 417 wait_data->done = true; 418 wake_up(&wait_data->wq); 419 kref_put(&wait_data->ref, cdx_mcdi_blocking_data_release); 420 } 421 422 static int cdx_mcdi_rpc_sync(struct cdx_mcdi *cdx, unsigned int cmd, 423 const struct cdx_dword *inbuf, size_t inlen, 424 struct cdx_dword *outbuf, size_t outlen, 425 size_t *outlen_actual, bool quiet) 426 { 427 struct cdx_mcdi_blocking_data *wait_data; 428 struct cdx_mcdi_cmd *cmd_item; 429 unsigned int handle; 430 int rc; 431 432 if (outlen_actual) 433 *outlen_actual = 0; 434 435 wait_data = kmalloc(sizeof(*wait_data), GFP_KERNEL); 436 if (!wait_data) 437 return -ENOMEM; 438 439 cmd_item = kmalloc(sizeof(*cmd_item), GFP_KERNEL); 440 if (!cmd_item) { 441 kfree(wait_data); 442 return -ENOMEM; 443 } 444 445 kref_init(&wait_data->ref); 446 wait_data->done = false; 447 init_waitqueue_head(&wait_data->wq); 448 wait_data->outbuf = outbuf; 449 wait_data->outlen = outlen; 450 451 kref_init(&cmd_item->ref); 452 cmd_item->quiet = quiet; 453 cmd_item->cookie = (unsigned long)wait_data; 454 cmd_item->completer = &cdx_mcdi_rpc_completer; 455 cmd_item->cmd = cmd; 456 cmd_item->inlen = inlen; 457 cmd_item->inbuf = inbuf; 458 459 /* Claim an extra reference for the completer to put. */ 460 kref_get(&wait_data->ref); 461 rc = cdx_mcdi_rpc_async_internal(cdx, cmd_item, &handle); 462 if (rc) { 463 kref_put(&wait_data->ref, cdx_mcdi_blocking_data_release); 464 goto out; 465 } 466 467 if (!wait_event_timeout(wait_data->wq, wait_data->done, 468 cdx_mcdi_rpc_timeout(cdx, cmd)) && 469 !wait_data->done) { 470 pr_err("MC command 0x%x inlen %zu timed out (sync)\n", 471 cmd, inlen); 472 473 cdx_mcdi_cancel_cmd(cdx, cmd_item); 474 475 wait_data->rc = -ETIMEDOUT; 476 wait_data->outlen_actual = 0; 477 } 478 479 if (outlen_actual) 480 *outlen_actual = wait_data->outlen_actual; 481 rc = wait_data->rc; 482 483 out: 484 kref_put(&wait_data->ref, cdx_mcdi_blocking_data_release); 485 486 return rc; 487 } 488 489 static bool cdx_mcdi_get_seq(struct cdx_mcdi_iface *mcdi, unsigned char *seq) 490 { 491 *seq = mcdi->prev_seq; 492 do { 493 *seq = (*seq + 1) % ARRAY_SIZE(mcdi->seq_held_by); 494 } while (mcdi->seq_held_by[*seq] && *seq != mcdi->prev_seq); 495 return !mcdi->seq_held_by[*seq]; 496 } 497 498 static int cdx_mcdi_rpc_async_internal(struct cdx_mcdi *cdx, 499 struct cdx_mcdi_cmd *cmd, 500 unsigned int *handle) 501 { 502 struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx); 503 LIST_HEAD(cleanup_list); 504 505 if (!mcdi) { 506 kref_put(&cmd->ref, cdx_mcdi_cmd_release); 507 return -ENETDOWN; 508 } 509 510 if (mcdi->mode == MCDI_MODE_FAIL) { 511 kref_put(&cmd->ref, cdx_mcdi_cmd_release); 512 return -ENETDOWN; 513 } 514 515 cmd->mcdi = mcdi; 516 INIT_WORK(&cmd->work, cdx_mcdi_cmd_work); 517 INIT_LIST_HEAD(&cmd->list); 518 INIT_LIST_HEAD(&cmd->cleanup_list); 519 cmd->rc = 0; 520 cmd->outbuf = NULL; 521 cmd->outlen = 0; 522 523 queue_work(mcdi->workqueue, &cmd->work); 524 return 0; 525 } 526 527 static void cdx_mcdi_cmd_start_or_queue(struct cdx_mcdi_iface *mcdi, 528 struct cdx_mcdi_cmd *cmd) 529 { 530 struct cdx_mcdi *cdx = mcdi->cdx; 531 u8 seq; 532 533 if (!mcdi->db_held_by && 534 cdx_mcdi_get_seq(mcdi, &seq)) { 535 cmd->seq = seq; 536 cmd->reboot_seen = false; 537 cdx_mcdi_send_request(cdx, cmd); 538 cmd->state = MCDI_STATE_RUNNING; 539 } else { 540 cmd->state = MCDI_STATE_QUEUED; 541 } 542 } 543 544 /* try to advance other commands */ 545 static void cdx_mcdi_start_or_queue(struct cdx_mcdi_iface *mcdi, 546 bool allow_retry) 547 { 548 struct cdx_mcdi_cmd *cmd, *tmp; 549 550 list_for_each_entry_safe(cmd, tmp, &mcdi->cmd_list, list) 551 if (cmd->state == MCDI_STATE_QUEUED || 552 (cmd->state == MCDI_STATE_RETRY && allow_retry)) 553 cdx_mcdi_cmd_start_or_queue(mcdi, cmd); 554 } 555 556 void cdx_mcdi_process_cmd(struct cdx_mcdi *cdx, struct cdx_dword *outbuf, int len) 557 { 558 struct cdx_mcdi_iface *mcdi; 559 struct cdx_mcdi_cmd *cmd; 560 LIST_HEAD(cleanup_list); 561 unsigned int respseq; 562 563 if (!len || !outbuf) { 564 pr_err("Got empty MC response\n"); 565 return; 566 } 567 568 mcdi = cdx_mcdi_if(cdx); 569 if (!mcdi) 570 return; 571 572 respseq = CDX_DWORD_FIELD(outbuf[0], MCDI_HEADER_SEQ); 573 574 mutex_lock(&mcdi->iface_lock); 575 cmd = mcdi->seq_held_by[respseq]; 576 577 if (cmd) { 578 if (cmd->state == MCDI_STATE_FINISHED) { 579 mutex_unlock(&mcdi->iface_lock); 580 kref_put(&cmd->ref, cdx_mcdi_cmd_release); 581 return; 582 } 583 584 cdx_mcdi_complete_cmd(mcdi, cmd, outbuf, len, &cleanup_list); 585 } else { 586 pr_err("MC response unexpected for seq : %0X\n", respseq); 587 } 588 589 mutex_unlock(&mcdi->iface_lock); 590 591 cdx_mcdi_process_cleanup_list(mcdi->cdx, &cleanup_list); 592 } 593 594 static void cdx_mcdi_cmd_work(struct work_struct *context) 595 { 596 struct cdx_mcdi_cmd *cmd = 597 container_of(context, struct cdx_mcdi_cmd, work); 598 struct cdx_mcdi_iface *mcdi = cmd->mcdi; 599 600 mutex_lock(&mcdi->iface_lock); 601 602 cmd->handle = mcdi->prev_handle++; 603 list_add_tail(&cmd->list, &mcdi->cmd_list); 604 cdx_mcdi_cmd_start_or_queue(mcdi, cmd); 605 606 mutex_unlock(&mcdi->iface_lock); 607 } 608 609 /* 610 * Returns true if the MCDI module is finished with the command. 611 * (examples of false would be if the command was proxied, or it was 612 * rejected by the MC due to lack of resources and requeued). 613 */ 614 static bool cdx_mcdi_complete_cmd(struct cdx_mcdi_iface *mcdi, 615 struct cdx_mcdi_cmd *cmd, 616 struct cdx_dword *outbuf, 617 int len, 618 struct list_head *cleanup_list) 619 { 620 size_t resp_hdr_len, resp_data_len; 621 struct cdx_mcdi *cdx = mcdi->cdx; 622 unsigned int respcmd, error; 623 bool completed = false; 624 int rc; 625 626 /* ensure the command can't go away before this function returns */ 627 kref_get(&cmd->ref); 628 629 respcmd = CDX_DWORD_FIELD(outbuf[0], MCDI_HEADER_CODE); 630 error = CDX_DWORD_FIELD(outbuf[0], MCDI_HEADER_ERROR); 631 632 if (respcmd != MC_CMD_V2_EXTN) { 633 resp_hdr_len = 4; 634 resp_data_len = CDX_DWORD_FIELD(outbuf[0], MCDI_HEADER_DATALEN); 635 } else { 636 resp_data_len = 0; 637 resp_hdr_len = 8; 638 if (len >= 8) 639 resp_data_len = 640 CDX_DWORD_FIELD(outbuf[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN); 641 } 642 643 if ((resp_hdr_len + resp_data_len) > len) { 644 pr_warn("Incomplete MCDI response received %d. Expected %zu\n", 645 len, (resp_hdr_len + resp_data_len)); 646 resp_data_len = 0; 647 } 648 649 print_hex_dump_debug("MCDI RESP HEADER: ", DUMP_PREFIX_NONE, 32, 4, 650 outbuf, resp_hdr_len, false); 651 print_hex_dump_debug("MCDI RESP PAYLOAD: ", DUMP_PREFIX_NONE, 32, 4, 652 outbuf + (resp_hdr_len / 4), resp_data_len, false); 653 654 if (error && resp_data_len == 0) { 655 /* MC rebooted during command */ 656 rc = -EIO; 657 } else { 658 if (WARN_ON_ONCE(error && resp_data_len < 4)) 659 resp_data_len = 4; 660 if (error) { 661 rc = CDX_DWORD_FIELD(outbuf[resp_hdr_len / 4], CDX_DWORD); 662 if (!cmd->quiet) { 663 int err_arg = 0; 664 665 if (resp_data_len >= MC_CMD_ERR_ARG_OFST + 4) { 666 int offset = (resp_hdr_len + MC_CMD_ERR_ARG_OFST) / 4; 667 668 err_arg = CDX_DWORD_VAL(outbuf[offset]); 669 } 670 671 _cdx_mcdi_display_error(cdx, cmd->cmd, 672 cmd->inlen, rc, err_arg, 673 cdx_mcdi_errno(cdx, rc)); 674 } 675 rc = cdx_mcdi_errno(cdx, rc); 676 } else { 677 rc = 0; 678 } 679 } 680 681 /* free doorbell */ 682 if (mcdi->db_held_by == cmd) 683 mcdi->db_held_by = NULL; 684 685 if (cdx_cmd_cancelled(cmd)) { 686 list_del(&cmd->list); 687 kref_put(&cmd->ref, cdx_mcdi_cmd_release); 688 completed = true; 689 } else if (rc == MC_CMD_ERR_QUEUE_FULL) { 690 cmd->state = MCDI_STATE_RETRY; 691 } else { 692 cmd->rc = rc; 693 cmd->outbuf = outbuf + DIV_ROUND_UP(resp_hdr_len, 4); 694 cmd->outlen = resp_data_len; 695 cdx_mcdi_remove_cmd(mcdi, cmd, cleanup_list); 696 completed = true; 697 } 698 699 /* free sequence number and buffer */ 700 mcdi->seq_held_by[cmd->seq] = NULL; 701 702 cdx_mcdi_start_or_queue(mcdi, rc != MC_CMD_ERR_QUEUE_FULL); 703 704 /* wake up anyone waiting for flush */ 705 wake_up(&mcdi->cmd_complete_wq); 706 707 kref_put(&cmd->ref, cdx_mcdi_cmd_release); 708 709 return completed; 710 } 711 712 static void cdx_mcdi_timeout_cmd(struct cdx_mcdi_iface *mcdi, 713 struct cdx_mcdi_cmd *cmd, 714 struct list_head *cleanup_list) 715 { 716 struct cdx_mcdi *cdx = mcdi->cdx; 717 718 pr_err("MC command 0x%x inlen %zu state %d timed out after %u ms\n", 719 cmd->cmd, cmd->inlen, cmd->state, 720 jiffies_to_msecs(jiffies - cmd->started)); 721 722 cmd->rc = -ETIMEDOUT; 723 cdx_mcdi_remove_cmd(mcdi, cmd, cleanup_list); 724 725 cdx_mcdi_mode_fail(cdx, cleanup_list); 726 } 727 728 /** 729 * cdx_mcdi_rpc - Issue an MCDI command and wait for completion 730 * @cdx: NIC through which to issue the command 731 * @cmd: Command type number 732 * @inbuf: Command parameters 733 * @inlen: Length of command parameters, in bytes. Must be a multiple 734 * of 4 and no greater than %MCDI_CTL_SDU_LEN_MAX_V1. 735 * @outbuf: Response buffer. May be %NULL if @outlen is 0. 736 * @outlen: Length of response buffer, in bytes. If the actual 737 * response is longer than @outlen & ~3, it will be truncated 738 * to that length. 739 * @outlen_actual: Pointer through which to return the actual response 740 * length. May be %NULL if this is not needed. 741 * 742 * This function may sleep and therefore must be called in process 743 * context. 744 * 745 * Return: A negative error code, or zero if successful. The error 746 * code may come from the MCDI response or may indicate a failure 747 * to communicate with the MC. In the former case, the response 748 * will still be copied to @outbuf and *@outlen_actual will be 749 * set accordingly. In the latter case, *@outlen_actual will be 750 * set to zero. 751 */ 752 int cdx_mcdi_rpc(struct cdx_mcdi *cdx, unsigned int cmd, 753 const struct cdx_dword *inbuf, size_t inlen, 754 struct cdx_dword *outbuf, size_t outlen, 755 size_t *outlen_actual) 756 { 757 return cdx_mcdi_rpc_sync(cdx, cmd, inbuf, inlen, outbuf, outlen, 758 outlen_actual, false); 759 } 760 761 /** 762 * cdx_mcdi_rpc_async - Schedule an MCDI command to run asynchronously 763 * @cdx: NIC through which to issue the command 764 * @cmd: Command type number 765 * @inbuf: Command parameters 766 * @inlen: Length of command parameters, in bytes 767 * @complete: Function to be called on completion or cancellation. 768 * @cookie: Arbitrary value to be passed to @complete. 769 * 770 * This function does not sleep and therefore may be called in atomic 771 * context. It will fail if event queues are disabled or if MCDI 772 * event completions have been disabled due to an error. 773 * 774 * If it succeeds, the @complete function will be called exactly once 775 * in process context, when one of the following occurs: 776 * (a) the completion event is received (in process context) 777 * (b) event queues are disabled (in the process that disables them) 778 */ 779 int 780 cdx_mcdi_rpc_async(struct cdx_mcdi *cdx, unsigned int cmd, 781 const struct cdx_dword *inbuf, size_t inlen, 782 cdx_mcdi_async_completer *complete, unsigned long cookie) 783 { 784 struct cdx_mcdi_cmd *cmd_item = 785 kmalloc(sizeof(struct cdx_mcdi_cmd) + inlen, GFP_ATOMIC); 786 787 if (!cmd_item) 788 return -ENOMEM; 789 790 kref_init(&cmd_item->ref); 791 cmd_item->quiet = true; 792 cmd_item->cookie = cookie; 793 cmd_item->completer = complete; 794 cmd_item->cmd = cmd; 795 cmd_item->inlen = inlen; 796 /* inbuf is probably not valid after return, so take a copy */ 797 cmd_item->inbuf = (struct cdx_dword *)(cmd_item + 1); 798 memcpy(cmd_item + 1, inbuf, inlen); 799 800 return cdx_mcdi_rpc_async_internal(cdx, cmd_item, NULL); 801 } 802 803 static void _cdx_mcdi_display_error(struct cdx_mcdi *cdx, unsigned int cmd, 804 size_t inlen, int raw, int arg, int err_no) 805 { 806 pr_err("MC command 0x%x inlen %d failed err_no=%d (raw=%d) arg=%d\n", 807 cmd, (int)inlen, err_no, raw, arg); 808 } 809 810 /* 811 * Set MCDI mode to fail to prevent any new commands, then cancel any 812 * outstanding commands. 813 * Caller must hold the mcdi iface_lock. 814 */ 815 static void cdx_mcdi_mode_fail(struct cdx_mcdi *cdx, struct list_head *cleanup_list) 816 { 817 struct cdx_mcdi_iface *mcdi = cdx_mcdi_if(cdx); 818 819 if (!mcdi) 820 return; 821 822 mcdi->mode = MCDI_MODE_FAIL; 823 824 while (!list_empty(&mcdi->cmd_list)) { 825 struct cdx_mcdi_cmd *cmd; 826 827 cmd = list_first_entry(&mcdi->cmd_list, struct cdx_mcdi_cmd, 828 list); 829 _cdx_mcdi_cancel_cmd(mcdi, cdx_mcdi_cmd_handle(cmd), cleanup_list); 830 } 831 } 832