Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

HID: intel-ish-hid: ipc: Always schedule FW reset work on RESET_NOTIFY/ACK

Both ISH firmware and driver can actively send MNG_RESET_NOTIFY to initiate
an FW reset handshake. Upon receiving this, the peer should reply with
MNG_RESET_NOTIFY_ACK. Therefore, the driver should schedule the FW reset
handshake work function when receiving either MNG_RESET_NOTIFY or
MNG_RESET_NOTIFY_ACK.

Previously, driver only scheduled the work function on MNG_RESET_NOTIFY.
This patch ensures the work function is scheduled on both messages, but
only replies with MNG_RESET_NOTIFY_ACK when receiving MNG_RESET_NOTIFY.

Signed-off-by: Zhang Lixu <lixu.zhang@intel.com>
Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>

authored by

Zhang Lixu and committed by
Jiri Kosina
9e097dc9 bd1b9a8d

+19 -20
+19 -20
drivers/hid/intel-ish-hid/ipc/ipc.c
··· 481 481 return ret; 482 482 } 483 483 484 + static void ish_send_reset_notify_ack(struct ishtp_device *dev) 485 + { 486 + /* Read reset ID */ 487 + u32 reset_id = ish_reg_read(dev, IPC_REG_ISH2HOST_MSG) & 0xFFFF; 488 + 489 + /* 490 + * Set HOST2ISH.ILUP. Apparently we need this BEFORE sending 491 + * RESET_NOTIFY_ACK - FW will be checking for it 492 + */ 493 + ish_set_host_rdy(dev); 494 + /* Send RESET_NOTIFY_ACK (with reset_id) */ 495 + ipc_send_mng_msg(dev, MNG_RESET_NOTIFY_ACK, &reset_id, sizeof(u32)); 496 + } 497 + 484 498 #define TIME_SLICE_FOR_FW_RDY_MS 100 485 499 #define TIME_SLICE_FOR_INPUT_RDY_MS 100 486 500 #define TIMEOUT_FOR_FW_RDY_MS 2000 ··· 510 496 */ 511 497 static int ish_fw_reset_handler(struct ishtp_device *dev) 512 498 { 513 - uint32_t reset_id; 514 499 unsigned long flags; 515 500 int ret; 516 - 517 - /* Read reset ID */ 518 - reset_id = ish_reg_read(dev, IPC_REG_ISH2HOST_MSG) & 0xFFFF; 519 501 520 502 /* Clear IPC output queue */ 521 503 spin_lock_irqsave(&dev->wr_processing_spinlock, flags); ··· 530 520 531 521 /* Send clock sync at once after reset */ 532 522 ishtp_dev->prev_sync = 0; 533 - 534 - /* 535 - * Set HOST2ISH.ILUP. Apparently we need this BEFORE sending 536 - * RESET_NOTIFY_ACK - FW will be checking for it 537 - */ 538 - ish_set_host_rdy(dev); 539 - /* Send RESET_NOTIFY_ACK (with reset_id) */ 540 - ipc_send_mng_msg(dev, MNG_RESET_NOTIFY_ACK, &reset_id, 541 - sizeof(uint32_t)); 542 523 543 524 /* Wait for ISH FW'es ILUP and ISHTP_READY */ 544 525 ret = timed_wait_for_timeout(dev, WAIT_FOR_FW_RDY, ··· 564 563 if (!rv) { 565 564 /* ISH is ILUP & ISHTP-ready. Restart ISHTP */ 566 565 msleep_interruptible(TIMEOUT_FOR_HW_RDY_MS); 567 - ishtp_dev->recvd_hw_ready = 1; 568 - wake_up_interruptible(&ishtp_dev->wait_hw_ready); 569 566 570 567 /* ISHTP notification in IPC_RESET sequence completion */ 571 568 if (!work_pending(work)) ··· 624 625 break; 625 626 626 627 case MNG_RESET_NOTIFY: 627 - if (!ishtp_dev) { 628 - ishtp_dev = dev; 629 - } 630 - queue_work(dev->unbound_wq, &fw_reset_work); 631 - break; 628 + ish_send_reset_notify_ack(ishtp_dev); 629 + fallthrough; 632 630 633 631 case MNG_RESET_NOTIFY_ACK: 634 632 dev->recvd_hw_ready = 1; 635 633 wake_up_interruptible(&dev->wait_hw_ready); 634 + if (!work_pending(&fw_reset_work)) 635 + queue_work(dev->unbound_wq, &fw_reset_work); 636 636 break; 637 637 } 638 638 } ··· 999 1001 list_add_tail(&tx_buf->link, &dev->wr_free_list); 1000 1002 } 1001 1003 1004 + ishtp_dev = dev; 1002 1005 ret = devm_work_autocancel(&pdev->dev, &fw_reset_work, fw_reset_work_fn); 1003 1006 if (ret) { 1004 1007 dev_err(dev->devc, "Failed to initialise FW reset work\n");