Skip to content

Commit e0cd118

Browse files
Baochen Qiangkvalo
authored andcommitted
net: qrtr: support suspend/hibernation
MHI devices may not be destroyed during suspend/hibernation, so need to unprepare/prepare MHI channels throughout the transition, this is done by adding suspend/resume callbacks. The suspend callback is called in the late suspend stage, this means MHI channels are still alive at suspend stage, and that makes it possible for an MHI controller driver to communicate with others over those channels at suspend stage. While the resume callback is called in the early resume stage, for a similar reason. Also note that we won't do unprepare/prepare when MHI device is in suspend state because it's pointless if MHI is only meant to go through a suspend/resume transition, instead of a complete power cycle. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30 Signed-off-by: Baochen Qiang <[email protected]> Reviewed-by: Manivannan Sadhasivam <[email protected]> Reviewed-by: Jeff Johnson <[email protected]> Signed-off-by: Kalle Valo <[email protected]> Link: https://msgid.link/[email protected]
1 parent b34389c commit e0cd118

File tree

1 file changed

+46
-0
lines changed

1 file changed

+46
-0
lines changed

net/qrtr/mhi.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,51 @@ static const struct mhi_device_id qcom_mhi_qrtr_id_table[] = {
118118
};
119119
MODULE_DEVICE_TABLE(mhi, qcom_mhi_qrtr_id_table);
120120

121+
static int __maybe_unused qcom_mhi_qrtr_pm_suspend_late(struct device *dev)
122+
{
123+
struct mhi_device *mhi_dev = container_of(dev, struct mhi_device, dev);
124+
enum mhi_state state;
125+
126+
state = mhi_get_mhi_state(mhi_dev->mhi_cntrl);
127+
/*
128+
* If the device is in suspend state, then no need for the
129+
* client driver to unprepare the channels.
130+
*/
131+
if (state == MHI_STATE_M3)
132+
return 0;
133+
134+
mhi_unprepare_from_transfer(mhi_dev);
135+
136+
return 0;
137+
}
138+
139+
static int __maybe_unused qcom_mhi_qrtr_pm_resume_early(struct device *dev)
140+
{
141+
struct mhi_device *mhi_dev = container_of(dev, struct mhi_device, dev);
142+
enum mhi_state state;
143+
int rc;
144+
145+
state = mhi_get_mhi_state(mhi_dev->mhi_cntrl);
146+
/*
147+
* If the device is in suspend state, we won't unprepare channels
148+
* in suspend callback, therefore no need to prepare channels when
149+
* resume.
150+
*/
151+
if (state == MHI_STATE_M3)
152+
return 0;
153+
154+
rc = mhi_prepare_for_transfer_autoqueue(mhi_dev);
155+
if (rc)
156+
dev_err(dev, "failed to prepare for autoqueue transfer %d\n", rc);
157+
158+
return rc;
159+
}
160+
161+
static const struct dev_pm_ops qcom_mhi_qrtr_pm_ops = {
162+
SET_LATE_SYSTEM_SLEEP_PM_OPS(qcom_mhi_qrtr_pm_suspend_late,
163+
qcom_mhi_qrtr_pm_resume_early)
164+
};
165+
121166
static struct mhi_driver qcom_mhi_qrtr_driver = {
122167
.probe = qcom_mhi_qrtr_probe,
123168
.remove = qcom_mhi_qrtr_remove,
@@ -126,6 +171,7 @@ static struct mhi_driver qcom_mhi_qrtr_driver = {
126171
.id_table = qcom_mhi_qrtr_id_table,
127172
.driver = {
128173
.name = "qcom_mhi_qrtr",
174+
.pm = &qcom_mhi_qrtr_pm_ops,
129175
},
130176
};
131177

0 commit comments

Comments
 (0)