Skip to content

Commit 59c752c

Browse files
author
Jiri Kosina
committed
Merge branch 'for-6.19/intel-ish-v2' into for-linus
- Power management/hibernation improvements in intel-ish (Zhang Lixu) - Switch of intel-ish to unbound workqueues (Zhang Lixu)
2 parents b68822a + 3644f44 commit 59c752c

8 files changed

Lines changed: 126 additions & 55 deletions

File tree

drivers/hid/intel-ish-hid/ipc/ipc.c

Lines changed: 58 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,20 @@ static int timed_wait_for_timeout(struct ishtp_device *dev, int condition,
481481
return ret;
482482
}
483483

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+
484498
#define TIME_SLICE_FOR_FW_RDY_MS 100
485499
#define TIME_SLICE_FOR_INPUT_RDY_MS 100
486500
#define TIMEOUT_FOR_FW_RDY_MS 2000
@@ -496,13 +510,9 @@ static int timed_wait_for_timeout(struct ishtp_device *dev, int condition,
496510
*/
497511
static int ish_fw_reset_handler(struct ishtp_device *dev)
498512
{
499-
uint32_t reset_id;
500513
unsigned long flags;
501514
int ret;
502515

503-
/* Read reset ID */
504-
reset_id = ish_reg_read(dev, IPC_REG_ISH2HOST_MSG) & 0xFFFF;
505-
506516
/* Clear IPC output queue */
507517
spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
508518
list_splice_init(&dev->wr_processing_list, &dev->wr_free_list);
@@ -521,15 +531,6 @@ static int ish_fw_reset_handler(struct ishtp_device *dev)
521531
/* Send clock sync at once after reset */
522532
ishtp_dev->prev_sync = 0;
523533

524-
/*
525-
* Set HOST2ISH.ILUP. Apparently we need this BEFORE sending
526-
* RESET_NOTIFY_ACK - FW will be checking for it
527-
*/
528-
ish_set_host_rdy(dev);
529-
/* Send RESET_NOTIFY_ACK (with reset_id) */
530-
ipc_send_mng_msg(dev, MNG_RESET_NOTIFY_ACK, &reset_id,
531-
sizeof(uint32_t));
532-
533534
/* Wait for ISH FW'es ILUP and ISHTP_READY */
534535
ret = timed_wait_for_timeout(dev, WAIT_FOR_FW_RDY,
535536
TIME_SLICE_FOR_FW_RDY_MS,
@@ -563,8 +564,6 @@ static void fw_reset_work_fn(struct work_struct *work)
563564
if (!rv) {
564565
/* ISH is ILUP & ISHTP-ready. Restart ISHTP */
565566
msleep_interruptible(TIMEOUT_FOR_HW_RDY_MS);
566-
ishtp_dev->recvd_hw_ready = 1;
567-
wake_up_interruptible(&ishtp_dev->wait_hw_ready);
568567

569568
/* ISHTP notification in IPC_RESET sequence completion */
570569
if (!work_pending(work))
@@ -625,15 +624,14 @@ static void recv_ipc(struct ishtp_device *dev, uint32_t doorbell_val)
625624
break;
626625

627626
case MNG_RESET_NOTIFY:
628-
if (!ishtp_dev) {
629-
ishtp_dev = dev;
630-
}
631-
schedule_work(&fw_reset_work);
632-
break;
627+
ish_send_reset_notify_ack(ishtp_dev);
628+
fallthrough;
633629

634630
case MNG_RESET_NOTIFY_ACK:
635631
dev->recvd_hw_ready = 1;
636632
wake_up_interruptible(&dev->wait_hw_ready);
633+
if (!work_pending(&fw_reset_work))
634+
queue_work(dev->unbound_wq, &fw_reset_work);
637635
break;
638636
}
639637
}
@@ -730,22 +728,28 @@ int ish_disable_dma(struct ishtp_device *dev)
730728
* ish_wakeup() - wakeup ishfw from waiting-for-host state
731729
* @dev: ishtp device pointer
732730
*
733-
* Set the dma enable bit and send a void message to FW,
731+
* Set the dma enable bit and send a IPC RESET message to FW,
734732
* it wil wakeup FW from waiting-for-host state.
733+
*
734+
* Return: 0 for success else error code.
735735
*/
736-
static void ish_wakeup(struct ishtp_device *dev)
736+
static int ish_wakeup(struct ishtp_device *dev)
737737
{
738+
int ret;
739+
738740
/* Set dma enable bit */
739741
ish_reg_write(dev, IPC_REG_ISH_RMP2, IPC_RMP2_DMA_ENABLED);
740742

741743
/*
742-
* Send 0 IPC message so that ISH FW wakes up if it was already
744+
* Send IPC RESET message so that ISH FW wakes up if it was already
743745
* asleep.
744746
*/
745-
ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, IPC_DRBL_BUSY_BIT);
747+
ret = ish_ipc_reset(dev);
746748

747749
/* Flush writes to doorbell and REMAP2 */
748750
ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
751+
752+
return ret;
749753
}
750754

751755
/**
@@ -794,11 +798,11 @@ static int _ish_hw_reset(struct ishtp_device *dev)
794798
pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, csr);
795799

796800
/* Now we can enable ISH DMA operation and wakeup ISHFW */
797-
ish_wakeup(dev);
798-
799-
return 0;
801+
return ish_wakeup(dev);
800802
}
801803

804+
#define RECVD_HW_READY_TIMEOUT (10 * HZ)
805+
802806
/**
803807
* _ish_ipc_reset() - IPC reset
804808
* @dev: ishtp device pointer
@@ -833,7 +837,8 @@ static int _ish_ipc_reset(struct ishtp_device *dev)
833837
}
834838

835839
wait_event_interruptible_timeout(dev->wait_hw_ready,
836-
dev->recvd_hw_ready, 2 * HZ);
840+
dev->recvd_hw_ready,
841+
RECVD_HW_READY_TIMEOUT);
837842
if (!dev->recvd_hw_ready) {
838843
dev_err(dev->devc, "Timed out waiting for HW ready\n");
839844
rv = -ENODEV;
@@ -857,21 +862,7 @@ int ish_hw_start(struct ishtp_device *dev)
857862
set_host_ready(dev);
858863

859864
/* After that we can enable ISH DMA operation and wakeup ISHFW */
860-
ish_wakeup(dev);
861-
862-
/* wait for FW-initiated reset flow */
863-
if (!dev->recvd_hw_ready)
864-
wait_event_interruptible_timeout(dev->wait_hw_ready,
865-
dev->recvd_hw_ready,
866-
10 * HZ);
867-
868-
if (!dev->recvd_hw_ready) {
869-
dev_err(dev->devc,
870-
"[ishtp-ish]: Timed out waiting for FW-initiated reset\n");
871-
return -ENODEV;
872-
}
873-
874-
return 0;
865+
return ish_wakeup(dev);
875866
}
876867

877868
/**
@@ -933,6 +924,25 @@ static const struct ishtp_hw_ops ish_hw_ops = {
933924
.dma_no_cache_snooping = _dma_no_cache_snooping
934925
};
935926

927+
static void ishtp_free_workqueue(void *wq)
928+
{
929+
destroy_workqueue(wq);
930+
}
931+
932+
static struct workqueue_struct *devm_ishtp_alloc_workqueue(struct device *dev)
933+
{
934+
struct workqueue_struct *wq;
935+
936+
wq = alloc_workqueue("ishtp_unbound_%d", WQ_UNBOUND, 0, dev->id);
937+
if (!wq)
938+
return NULL;
939+
940+
if (devm_add_action_or_reset(dev, ishtp_free_workqueue, wq))
941+
return NULL;
942+
943+
return wq;
944+
}
945+
936946
/**
937947
* ish_dev_init() -Initialize ISH devoce
938948
* @pdev: PCI device
@@ -953,6 +963,10 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev)
953963
if (!dev)
954964
return NULL;
955965

966+
dev->unbound_wq = devm_ishtp_alloc_workqueue(&pdev->dev);
967+
if (!dev->unbound_wq)
968+
return NULL;
969+
956970
dev->devc = &pdev->dev;
957971
ishtp_device_init(dev);
958972

@@ -982,6 +996,7 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev)
982996
list_add_tail(&tx_buf->link, &dev->wr_free_list);
983997
}
984998

999+
ishtp_dev = dev;
9851000
ret = devm_work_autocancel(&pdev->dev, &fw_reset_work, fw_reset_work_fn);
9861001
if (ret) {
9871002
dev_err(dev->devc, "Failed to initialise FW reset work\n");

drivers/hid/intel-ish-hid/ipc/pci-ish.c

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,12 @@ static inline bool ish_should_enter_d0i3(struct pci_dev *pdev)
147147

148148
static inline bool ish_should_leave_d0i3(struct pci_dev *pdev)
149149
{
150+
struct ishtp_device *dev = pci_get_drvdata(pdev);
151+
u32 fwsts = dev->ops->get_fw_status(dev);
152+
153+
if (dev->suspend_flag || !IPC_IS_ISH_ILUP(fwsts))
154+
return false;
155+
150156
return !pm_resume_via_firmware() || pdev->device == PCI_DEVICE_ID_INTEL_ISH_CHV;
151157
}
152158

@@ -277,10 +283,8 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work)
277283
{
278284
struct pci_dev *pdev = to_pci_dev(ish_resume_device);
279285
struct ishtp_device *dev = pci_get_drvdata(pdev);
280-
uint32_t fwsts = dev->ops->get_fw_status(dev);
281286

282-
if (ish_should_leave_d0i3(pdev) && !dev->suspend_flag
283-
&& IPC_IS_ISH_ILUP(fwsts)) {
287+
if (ish_should_leave_d0i3(pdev)) {
284288
if (device_may_wakeup(&pdev->dev))
285289
disable_irq_wake(pdev->irq);
286290

@@ -384,12 +388,29 @@ static int __maybe_unused ish_resume(struct device *device)
384388
ish_resume_device = device;
385389
dev->resume_flag = 1;
386390

387-
schedule_work(&resume_work);
391+
/* If ISH resume from D3, reset ishtp clients before return */
392+
if (!ish_should_leave_d0i3(pdev))
393+
ishtp_reset_handler(dev);
394+
395+
queue_work(dev->unbound_wq, &resume_work);
388396

389397
return 0;
390398
}
391399

392-
static SIMPLE_DEV_PM_OPS(ish_pm_ops, ish_suspend, ish_resume);
400+
static int __maybe_unused ish_freeze(struct device *device)
401+
{
402+
struct pci_dev *pdev = to_pci_dev(device);
403+
404+
return pci_save_state(pdev);
405+
}
406+
407+
static const struct dev_pm_ops __maybe_unused ish_pm_ops = {
408+
.suspend = pm_sleep_ptr(ish_suspend),
409+
.resume = pm_sleep_ptr(ish_resume),
410+
.freeze = pm_sleep_ptr(ish_freeze),
411+
.restore = pm_sleep_ptr(ish_resume),
412+
.poweroff = pm_sleep_ptr(ish_suspend),
413+
};
393414

394415
static ssize_t base_version_show(struct device *cdev,
395416
struct device_attribute *attr, char *buf)

drivers/hid/intel-ish-hid/ishtp-hid-client.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -757,8 +757,15 @@ static void hid_ishtp_cl_resume_handler(struct work_struct *work)
757757
struct ishtp_cl *hid_ishtp_cl = client_data->hid_ishtp_cl;
758758

759759
if (ishtp_wait_resume(ishtp_get_ishtp_device(hid_ishtp_cl))) {
760-
client_data->suspended = false;
761-
wake_up_interruptible(&client_data->ishtp_resume_wait);
760+
/*
761+
* Clear the suspended flag only when the connection is established.
762+
* If the connection is not established, the suspended flag will be cleared after
763+
* the connection is made.
764+
*/
765+
if (ishtp_get_connection_state(hid_ishtp_cl) == ISHTP_CL_CONNECTED) {
766+
client_data->suspended = false;
767+
wake_up_interruptible(&client_data->ishtp_resume_wait);
768+
}
762769
} else {
763770
hid_ishtp_trace(client_data, "hid client: wait for resume timed out");
764771
dev_err(cl_data_to_dev(client_data), "wait for resume timed out");
@@ -860,7 +867,7 @@ static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device)
860867
hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
861868
hid_ishtp_cl);
862869

863-
schedule_work(&client_data->work);
870+
queue_work(ishtp_get_workqueue(cl_device), &client_data->work);
864871

865872
return 0;
866873
}
@@ -902,7 +909,7 @@ static int hid_ishtp_cl_resume(struct device *device)
902909

903910
hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
904911
hid_ishtp_cl);
905-
schedule_work(&client_data->resume_work);
912+
queue_work(ishtp_get_workqueue(cl_device), &client_data->resume_work);
906913
return 0;
907914
}
908915

drivers/hid/intel-ish-hid/ishtp/bus.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ void ishtp_cl_bus_rx_event(struct ishtp_cl_device *device)
541541
return;
542542

543543
if (device->event_cb)
544-
schedule_work(&device->event_work);
544+
queue_work(device->ishtp_dev->unbound_wq, &device->event_work);
545545
}
546546

547547
/**
@@ -876,6 +876,22 @@ struct device *ishtp_get_pci_device(struct ishtp_cl_device *device)
876876
}
877877
EXPORT_SYMBOL(ishtp_get_pci_device);
878878

879+
/**
880+
* ishtp_get_workqueue - Retrieve the workqueue associated with an ISHTP device
881+
* @cl_device: Pointer to the ISHTP client device structure
882+
*
883+
* Returns the workqueue_struct pointer (unbound_wq) associated with the given
884+
* ISHTP client device. This workqueue is typically used for scheduling work
885+
* related to the device.
886+
*
887+
* Return: Pointer to struct workqueue_struct.
888+
*/
889+
struct workqueue_struct *ishtp_get_workqueue(struct ishtp_cl_device *cl_device)
890+
{
891+
return cl_device->ishtp_dev->unbound_wq;
892+
}
893+
EXPORT_SYMBOL(ishtp_get_workqueue);
894+
879895
/**
880896
* ishtp_trace_callback() - Return trace callback
881897
* @cl_device: ISH-TP client device instance

drivers/hid/intel-ish-hid/ishtp/client.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,12 @@ void ishtp_set_connection_state(struct ishtp_cl *cl, int state)
12611261
}
12621262
EXPORT_SYMBOL(ishtp_set_connection_state);
12631263

1264+
int ishtp_get_connection_state(struct ishtp_cl *cl)
1265+
{
1266+
return cl->state;
1267+
}
1268+
EXPORT_SYMBOL(ishtp_get_connection_state);
1269+
12641270
void ishtp_cl_set_fw_client_id(struct ishtp_cl *cl, int fw_client_id)
12651271
{
12661272
cl->fw_client_id = fw_client_id;

drivers/hid/intel-ish-hid/ishtp/hbm.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ void ishtp_hbm_dispatch(struct ishtp_device *dev,
573573

574574
/* Start firmware loading process if it has loader capability */
575575
if (version_res->host_version_supported & ISHTP_SUPPORT_CAP_LOADER)
576-
schedule_work(&dev->work_fw_loader);
576+
queue_work(dev->unbound_wq, &dev->work_fw_loader);
577577

578578
dev->version.major_version = HBM_MAJOR_VERSION;
579579
dev->version.minor_version = HBM_MINOR_VERSION;
@@ -864,7 +864,7 @@ void recv_hbm(struct ishtp_device *dev, struct ishtp_msg_hdr *ishtp_hdr)
864864
dev->rd_msg_fifo_tail = (dev->rd_msg_fifo_tail + IPC_PAYLOAD_SIZE) %
865865
(RD_INT_FIFO_SIZE * IPC_PAYLOAD_SIZE);
866866
spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
867-
schedule_work(&dev->bh_hbm_work);
867+
queue_work(dev->unbound_wq, &dev->bh_hbm_work);
868868
eoi:
869869
return;
870870
}

drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ struct ishtp_device {
175175
struct hbm_version version;
176176
int transfer_path; /* Choice of transfer path: IPC or DMA */
177177

178+
/* Alloc a dedicated unbound workqueue for ishtp device */
179+
struct workqueue_struct *unbound_wq;
180+
178181
/* work structure for scheduling firmware loading tasks */
179182
struct work_struct work_fw_loader;
180183
/* waitq for waiting for command response from the firmware loader */

include/linux/intel-ish-client-if.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ bool ishtp_wait_resume(struct ishtp_device *dev);
8787
ishtp_print_log ishtp_trace_callback(struct ishtp_cl_device *cl_device);
8888
/* Get device pointer of PCI device for DMA acces */
8989
struct device *ishtp_get_pci_device(struct ishtp_cl_device *cl_device);
90+
/* Get the ISHTP workqueue */
91+
struct workqueue_struct *ishtp_get_workqueue(struct ishtp_cl_device *cl_device);
9092

9193
struct ishtp_cl *ishtp_cl_allocate(struct ishtp_cl_device *cl_device);
9294
void ishtp_cl_free(struct ishtp_cl *cl);
@@ -107,6 +109,7 @@ struct ishtp_device *ishtp_get_ishtp_device(struct ishtp_cl *cl);
107109
void ishtp_set_tx_ring_size(struct ishtp_cl *cl, int size);
108110
void ishtp_set_rx_ring_size(struct ishtp_cl *cl, int size);
109111
void ishtp_set_connection_state(struct ishtp_cl *cl, int state);
112+
int ishtp_get_connection_state(struct ishtp_cl *cl);
110113
void ishtp_cl_set_fw_client_id(struct ishtp_cl *cl, int fw_client_id);
111114

112115
void ishtp_put_device(struct ishtp_cl_device *cl_dev);

0 commit comments

Comments
 (0)