Skip to content

Commit e48bf29

Browse files
yeapaJiri Kosina
authored andcommitted
HID: intel-ish-hid: use async resume function
ISH IPC driver uses asynchronous workqueue to do resume now, but there is a potential timing issue: when child devices resume before bus driver, it will cause child devices resume failed and cannot be recovered until reboot. The current implementation in this case do wait for IPC to resume but fail to accommodate for a case when there is no ISH reboot and soft resume is taking time. This issue is apparent on Tiger Lake platform with 5.11.13 kernel when doing suspend to idle then resume(s0ix) test. To resolve this issue, we change ISHTP HID client to use asynchronous resume callback too. In the asynchronous resume callback, it waits for the ISHTP resume done event, and then notify ISHTP HID client link ready. Signed-off-by: Ye Xiang <xiang.ye@intel.com> Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
1 parent df04fbe commit e48bf29

4 files changed

Lines changed: 39 additions & 8 deletions

File tree

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,17 @@ static void hid_ishtp_cl_reset_handler(struct work_struct *work)
784784
}
785785
}
786786

787+
static void hid_ishtp_cl_resume_handler(struct work_struct *work)
788+
{
789+
struct ishtp_cl_data *client_data = container_of(work, struct ishtp_cl_data, resume_work);
790+
struct ishtp_cl *hid_ishtp_cl = client_data->hid_ishtp_cl;
791+
792+
if (ishtp_wait_resume(ishtp_get_ishtp_device(hid_ishtp_cl))) {
793+
client_data->suspended = false;
794+
wake_up_interruptible(&client_data->ishtp_resume_wait);
795+
}
796+
}
797+
787798
ishtp_print_log ishtp_hid_print_trace;
788799

789800
/**
@@ -822,6 +833,8 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
822833
init_waitqueue_head(&client_data->ishtp_resume_wait);
823834

824835
INIT_WORK(&client_data->work, hid_ishtp_cl_reset_handler);
836+
INIT_WORK(&client_data->resume_work, hid_ishtp_cl_resume_handler);
837+
825838

826839
ishtp_hid_print_trace = ishtp_trace_callback(cl_device);
827840

@@ -921,7 +934,7 @@ static int hid_ishtp_cl_resume(struct device *device)
921934

922935
hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
923936
hid_ishtp_cl);
924-
client_data->suspended = false;
937+
schedule_work(&client_data->resume_work);
925938
return 0;
926939
}
927940

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ struct ishtp_cl_data {
135135
int multi_packet_cnt;
136136

137137
struct work_struct work;
138+
struct work_struct resume_work;
138139
struct ishtp_cl_device *cl_device;
139140
};
140141

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

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -314,13 +314,6 @@ static int ishtp_cl_device_resume(struct device *dev)
314314
if (!device)
315315
return 0;
316316

317-
/*
318-
* When ISH needs hard reset, it is done asynchrnously, hence bus
319-
* resume will be called before full ISH resume
320-
*/
321-
if (device->ishtp_dev->resume_flag)
322-
return 0;
323-
324317
driver = to_ishtp_cl_driver(dev->driver);
325318
if (driver && driver->driver.pm) {
326319
if (driver->driver.pm->resume)
@@ -849,6 +842,28 @@ struct device *ishtp_device(struct ishtp_cl_device *device)
849842
}
850843
EXPORT_SYMBOL(ishtp_device);
851844

845+
/**
846+
* ishtp_wait_resume() - Wait for IPC resume
847+
*
848+
* Wait for IPC resume
849+
*
850+
* Return: resume complete or not
851+
*/
852+
bool ishtp_wait_resume(struct ishtp_device *dev)
853+
{
854+
/* 50ms to get resume response */
855+
#define WAIT_FOR_RESUME_ACK_MS 50
856+
857+
/* Waiting to get resume response */
858+
if (dev->resume_flag)
859+
wait_event_interruptible_timeout(dev->resume_wait,
860+
!dev->resume_flag,
861+
msecs_to_jiffies(WAIT_FOR_RESUME_ACK_MS));
862+
863+
return (!dev->resume_flag);
864+
}
865+
EXPORT_SYMBOL_GPL(ishtp_wait_resume);
866+
852867
/**
853868
* ishtp_get_pci_device() - Return PCI device dev pointer
854869
* This interface is used to return PCI device pointer

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ int ishtp_register_event_cb(struct ishtp_cl_device *device,
8181

8282
/* Get the device * from ishtp device instance */
8383
struct device *ishtp_device(struct ishtp_cl_device *cl_device);
84+
/* wait for IPC resume */
85+
bool ishtp_wait_resume(struct ishtp_device *dev);
8486
/* Trace interface for clients */
8587
ishtp_print_log ishtp_trace_callback(struct ishtp_cl_device *cl_device);
8688
/* Get device pointer of PCI device for DMA acces */

0 commit comments

Comments
 (0)