From: Kalle Valo <kvalo@kernel.org>
To: mhi@lists.linux.dev
Cc: ath11k@lists.infradead.org, linux-wireless@vger.kernel.org
Subject: [PATCH RFC 1/8] bus: mhi: host: add mhi_power_down_no_destroy()
Date: Fri, 10 Nov 2023 12:21:55 +0200 [thread overview]
Message-ID: <20231110102202.3168243-2-kvalo@kernel.org> (raw)
In-Reply-To: <20231110102202.3168243-1-kvalo@kernel.org>
From: Baochen Qiang <quic_bqiang@quicinc.com>
If ath11k tries to call mhi_power_up() during resume it fails:
ath11k_pci 0000:06:00.0: timeout while waiting for restart complete
This happens because when calling mhi_power_up() the MHI subsystem eventually
calls device_add() from mhi_create_devices() but the device creation is
deferred:
mhi mhi0_IPCR: Driver qcom_mhi_qrtr force probe deferral
The reason for deferring device creation is explained in dpm_prepare():
/*
* It is unsafe if probing of devices will happen during suspend or
* hibernation and system behavior will be unpredictable in this case.
* So, let's prohibit device's probing here and defer their probes
* instead. The normal behavior will be restored in dpm_complete().
*/
Because the device probe is deferred, the qcom_mhi_qrtr_probe() is not called and
qcom_mhi_qrtr_dl_callback() fails silently as qdev is zero:
static void qcom_mhi_qrtr_dl_callback(struct mhi_device *mhi_dev,
struct mhi_result *mhi_res)
{
struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev);
int rc;
if (!qdev || mhi_res->transaction_status)
return;
So what this means that QRTR is not delivering messages and the QMI connection
is not working between ath11k and the firmware, resulting a failure in firmware
initialisation.
To fix this add new function mhi_power_down_no_destroy() which does not destroy
the devices during power down. This way mhi_power_up() can be called during
resume and we can get ath11k hibernation working with the following patches.
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
---
drivers/bus/mhi/host/internal.h | 1 +
drivers/bus/mhi/host/pm.c | 26 +++++++++++++++++++-------
include/linux/mhi.h | 29 +++++++++++++++++++++++++++--
3 files changed, 47 insertions(+), 9 deletions(-)
diff --git a/drivers/bus/mhi/host/internal.h b/drivers/bus/mhi/host/internal.h
index 2e139e76de4c..d1033af285e2 100644
--- a/drivers/bus/mhi/host/internal.h
+++ b/drivers/bus/mhi/host/internal.h
@@ -69,6 +69,7 @@ enum dev_st_transition {
DEV_ST_TRANSITION_FP,
DEV_ST_TRANSITION_SYS_ERR,
DEV_ST_TRANSITION_DISABLE,
+ DEV_ST_TRANSITION_DISABLE_DESTROY_DEVICE,
DEV_ST_TRANSITION_MAX,
};
diff --git a/drivers/bus/mhi/host/pm.c b/drivers/bus/mhi/host/pm.c
index 8a4362d75fc4..e0e429adbda6 100644
--- a/drivers/bus/mhi/host/pm.c
+++ b/drivers/bus/mhi/host/pm.c
@@ -453,7 +453,8 @@ static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl)
}
/* Handle shutdown transitions */
-static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl)
+static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl,
+ bool destroy_device)
{
enum mhi_pm_state cur_state;
struct mhi_event *mhi_event;
@@ -515,8 +516,10 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl)
dev_dbg(dev, "Waiting for all pending threads to complete\n");
wake_up_all(&mhi_cntrl->state_event);
- dev_dbg(dev, "Reset all active channels and remove MHI devices\n");
- device_for_each_child(&mhi_cntrl->mhi_dev->dev, NULL, mhi_destroy_device);
+ if (destroy_device) {
+ dev_dbg(dev, "Reset all active channels and remove MHI devices\n");
+ device_for_each_child(&mhi_cntrl->mhi_dev->dev, NULL, mhi_destroy_device);
+ }
mutex_lock(&mhi_cntrl->pm_mutex);
@@ -801,7 +804,10 @@ void mhi_pm_st_worker(struct work_struct *work)
mhi_pm_sys_error_transition(mhi_cntrl);
break;
case DEV_ST_TRANSITION_DISABLE:
- mhi_pm_disable_transition(mhi_cntrl);
+ mhi_pm_disable_transition(mhi_cntrl, false);
+ break;
+ case DEV_ST_TRANSITION_DISABLE_DESTROY_DEVICE:
+ mhi_pm_disable_transition(mhi_cntrl, true);
break;
default:
break;
@@ -1154,7 +1160,8 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl)
}
EXPORT_SYMBOL_GPL(mhi_async_power_up);
-void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful)
+void __mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful,
+ bool destroy_device)
{
enum mhi_pm_state cur_state, transition_state;
struct device *dev = &mhi_cntrl->mhi_dev->dev;
@@ -1190,14 +1197,19 @@ void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful)
write_unlock_irq(&mhi_cntrl->pm_lock);
mutex_unlock(&mhi_cntrl->pm_mutex);
- mhi_queue_state_transition(mhi_cntrl, DEV_ST_TRANSITION_DISABLE);
+ if (destroy_device)
+ mhi_queue_state_transition(mhi_cntrl,
+ DEV_ST_TRANSITION_DISABLE_DESTROY_DEVICE);
+ else
+ mhi_queue_state_transition(mhi_cntrl,
+ DEV_ST_TRANSITION_DISABLE);
/* Wait for shutdown to complete */
flush_work(&mhi_cntrl->st_worker);
disable_irq(mhi_cntrl->irq[0]);
}
-EXPORT_SYMBOL_GPL(mhi_power_down);
+EXPORT_SYMBOL_GPL(__mhi_power_down);
int mhi_sync_power_up(struct mhi_controller *mhi_cntrl)
{
diff --git a/include/linux/mhi.h b/include/linux/mhi.h
index 039943ec4d4e..85edc9c5df88 100644
--- a/include/linux/mhi.h
+++ b/include/linux/mhi.h
@@ -644,12 +644,37 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl);
*/
int mhi_sync_power_up(struct mhi_controller *mhi_cntrl);
+void __mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful,
+ bool destroy_device);
+
/**
- * mhi_power_down - Start MHI power down sequence
+ * mhi_power_down - Start MHI power down sequence. See also
+ * mhi_power_down_no_destroy() which is a variant of this for suspend.
+ *
* @mhi_cntrl: MHI controller
* @graceful: Link is still accessible, so do a graceful shutdown process
*/
-void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful);
+static inline void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful)
+{
+ __mhi_power_down(mhi_cntrl, graceful, true);
+}
+
+/**
+ * mhi_power_down_no_destroy - Start MHI power down sequence but don't
+ * destroy struct devices. This is a variant for mhi_power_down() and is a
+ * workaround to make it possible to use mhi_power_up() in a resume
+ * handler. When using this variant the caller must also call
+ * mhi_prepare_all_for_transfer_autoqueue() and
+ * mhi_unprepare_all_from_transfer().
+ *
+ * @mhi_cntrl: MHI controller
+ * @graceful: Link is still accessible, so do a graceful shutdown process
+ */
+static inline void mhi_power_down_no_destroy(struct mhi_controller *mhi_cntrl,
+ bool graceful)
+{
+ __mhi_power_down(mhi_cntrl, graceful, false);
+}
/**
* mhi_unprepare_after_power_down - Free any allocated memory after power down
--
2.39.2
--
ath11k mailing list
ath11k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath11k
WARNING: multiple messages have this Message-ID (diff)
From: Kalle Valo <kvalo@kernel.org>
To: mhi@lists.linux.dev
Cc: ath11k@lists.infradead.org, linux-wireless@vger.kernel.org
Subject: [PATCH RFC 1/8] bus: mhi: host: add mhi_power_down_no_destroy()
Date: Fri, 10 Nov 2023 12:21:55 +0200 [thread overview]
Message-ID: <20231110102202.3168243-2-kvalo@kernel.org> (raw)
In-Reply-To: <20231110102202.3168243-1-kvalo@kernel.org>
From: Baochen Qiang <quic_bqiang@quicinc.com>
If ath11k tries to call mhi_power_up() during resume it fails:
ath11k_pci 0000:06:00.0: timeout while waiting for restart complete
This happens because when calling mhi_power_up() the MHI subsystem eventually
calls device_add() from mhi_create_devices() but the device creation is
deferred:
mhi mhi0_IPCR: Driver qcom_mhi_qrtr force probe deferral
The reason for deferring device creation is explained in dpm_prepare():
/*
* It is unsafe if probing of devices will happen during suspend or
* hibernation and system behavior will be unpredictable in this case.
* So, let's prohibit device's probing here and defer their probes
* instead. The normal behavior will be restored in dpm_complete().
*/
Because the device probe is deferred, the qcom_mhi_qrtr_probe() is not called and
qcom_mhi_qrtr_dl_callback() fails silently as qdev is zero:
static void qcom_mhi_qrtr_dl_callback(struct mhi_device *mhi_dev,
struct mhi_result *mhi_res)
{
struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev);
int rc;
if (!qdev || mhi_res->transaction_status)
return;
So what this means that QRTR is not delivering messages and the QMI connection
is not working between ath11k and the firmware, resulting a failure in firmware
initialisation.
To fix this add new function mhi_power_down_no_destroy() which does not destroy
the devices during power down. This way mhi_power_up() can be called during
resume and we can get ath11k hibernation working with the following patches.
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
---
drivers/bus/mhi/host/internal.h | 1 +
drivers/bus/mhi/host/pm.c | 26 +++++++++++++++++++-------
include/linux/mhi.h | 29 +++++++++++++++++++++++++++--
3 files changed, 47 insertions(+), 9 deletions(-)
diff --git a/drivers/bus/mhi/host/internal.h b/drivers/bus/mhi/host/internal.h
index 2e139e76de4c..d1033af285e2 100644
--- a/drivers/bus/mhi/host/internal.h
+++ b/drivers/bus/mhi/host/internal.h
@@ -69,6 +69,7 @@ enum dev_st_transition {
DEV_ST_TRANSITION_FP,
DEV_ST_TRANSITION_SYS_ERR,
DEV_ST_TRANSITION_DISABLE,
+ DEV_ST_TRANSITION_DISABLE_DESTROY_DEVICE,
DEV_ST_TRANSITION_MAX,
};
diff --git a/drivers/bus/mhi/host/pm.c b/drivers/bus/mhi/host/pm.c
index 8a4362d75fc4..e0e429adbda6 100644
--- a/drivers/bus/mhi/host/pm.c
+++ b/drivers/bus/mhi/host/pm.c
@@ -453,7 +453,8 @@ static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl)
}
/* Handle shutdown transitions */
-static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl)
+static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl,
+ bool destroy_device)
{
enum mhi_pm_state cur_state;
struct mhi_event *mhi_event;
@@ -515,8 +516,10 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl)
dev_dbg(dev, "Waiting for all pending threads to complete\n");
wake_up_all(&mhi_cntrl->state_event);
- dev_dbg(dev, "Reset all active channels and remove MHI devices\n");
- device_for_each_child(&mhi_cntrl->mhi_dev->dev, NULL, mhi_destroy_device);
+ if (destroy_device) {
+ dev_dbg(dev, "Reset all active channels and remove MHI devices\n");
+ device_for_each_child(&mhi_cntrl->mhi_dev->dev, NULL, mhi_destroy_device);
+ }
mutex_lock(&mhi_cntrl->pm_mutex);
@@ -801,7 +804,10 @@ void mhi_pm_st_worker(struct work_struct *work)
mhi_pm_sys_error_transition(mhi_cntrl);
break;
case DEV_ST_TRANSITION_DISABLE:
- mhi_pm_disable_transition(mhi_cntrl);
+ mhi_pm_disable_transition(mhi_cntrl, false);
+ break;
+ case DEV_ST_TRANSITION_DISABLE_DESTROY_DEVICE:
+ mhi_pm_disable_transition(mhi_cntrl, true);
break;
default:
break;
@@ -1154,7 +1160,8 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl)
}
EXPORT_SYMBOL_GPL(mhi_async_power_up);
-void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful)
+void __mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful,
+ bool destroy_device)
{
enum mhi_pm_state cur_state, transition_state;
struct device *dev = &mhi_cntrl->mhi_dev->dev;
@@ -1190,14 +1197,19 @@ void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful)
write_unlock_irq(&mhi_cntrl->pm_lock);
mutex_unlock(&mhi_cntrl->pm_mutex);
- mhi_queue_state_transition(mhi_cntrl, DEV_ST_TRANSITION_DISABLE);
+ if (destroy_device)
+ mhi_queue_state_transition(mhi_cntrl,
+ DEV_ST_TRANSITION_DISABLE_DESTROY_DEVICE);
+ else
+ mhi_queue_state_transition(mhi_cntrl,
+ DEV_ST_TRANSITION_DISABLE);
/* Wait for shutdown to complete */
flush_work(&mhi_cntrl->st_worker);
disable_irq(mhi_cntrl->irq[0]);
}
-EXPORT_SYMBOL_GPL(mhi_power_down);
+EXPORT_SYMBOL_GPL(__mhi_power_down);
int mhi_sync_power_up(struct mhi_controller *mhi_cntrl)
{
diff --git a/include/linux/mhi.h b/include/linux/mhi.h
index 039943ec4d4e..85edc9c5df88 100644
--- a/include/linux/mhi.h
+++ b/include/linux/mhi.h
@@ -644,12 +644,37 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl);
*/
int mhi_sync_power_up(struct mhi_controller *mhi_cntrl);
+void __mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful,
+ bool destroy_device);
+
/**
- * mhi_power_down - Start MHI power down sequence
+ * mhi_power_down - Start MHI power down sequence. See also
+ * mhi_power_down_no_destroy() which is a variant of this for suspend.
+ *
* @mhi_cntrl: MHI controller
* @graceful: Link is still accessible, so do a graceful shutdown process
*/
-void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful);
+static inline void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful)
+{
+ __mhi_power_down(mhi_cntrl, graceful, true);
+}
+
+/**
+ * mhi_power_down_no_destroy - Start MHI power down sequence but don't
+ * destroy struct devices. This is a variant for mhi_power_down() and is a
+ * workaround to make it possible to use mhi_power_up() in a resume
+ * handler. When using this variant the caller must also call
+ * mhi_prepare_all_for_transfer_autoqueue() and
+ * mhi_unprepare_all_from_transfer().
+ *
+ * @mhi_cntrl: MHI controller
+ * @graceful: Link is still accessible, so do a graceful shutdown process
+ */
+static inline void mhi_power_down_no_destroy(struct mhi_controller *mhi_cntrl,
+ bool graceful)
+{
+ __mhi_power_down(mhi_cntrl, graceful, false);
+}
/**
* mhi_unprepare_after_power_down - Free any allocated memory after power down
--
2.39.2
next prev parent reply other threads:[~2023-11-10 10:22 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-11-10 10:21 [PATCH RFC 0/8] wifi: ath11k: hibernation support Kalle Valo
2023-11-10 10:21 ` Kalle Valo
2023-11-10 10:21 ` Kalle Valo [this message]
2023-11-10 10:21 ` [PATCH RFC 1/8] bus: mhi: host: add mhi_power_down_no_destroy() Kalle Valo
2023-11-14 1:26 ` Mayank Rana
2023-11-14 1:26 ` Mayank Rana
2023-11-10 10:21 ` [PATCH RFC 2/8] bus: mhi: host: add new interfaces to handle MHI channels directly Kalle Valo
2023-11-10 10:21 ` Kalle Valo
2023-11-10 17:14 ` Jeffrey Hugo
2023-11-10 17:14 ` Jeffrey Hugo
2023-11-12 3:59 ` Baochen Qiang
2023-11-12 3:59 ` Baochen Qiang
2023-11-12 16:18 ` Jeffrey Hugo
2023-11-12 16:18 ` Jeffrey Hugo
2023-11-13 0:32 ` Baochen Qiang
2023-11-13 0:32 ` Baochen Qiang
2023-11-10 10:21 ` [PATCH RFC 3/8] wifi: ath11k: handle irq enable/disable in several code path Kalle Valo
2023-11-10 10:21 ` Kalle Valo
2023-11-10 10:21 ` [PATCH RFC 4/8] wifi: ath11k: remove MHI LOOPBACK channels Kalle Valo
2023-11-10 10:21 ` Kalle Valo
2023-11-10 16:54 ` Jeffrey Hugo
2023-11-10 16:54 ` Jeffrey Hugo
2023-11-12 4:24 ` Baochen Qiang
2023-11-12 4:24 ` Baochen Qiang
2023-11-12 16:15 ` Jeffrey Hugo
2023-11-12 16:15 ` Jeffrey Hugo
2023-11-13 0:30 ` Baochen Qiang
2023-11-13 0:30 ` Baochen Qiang
2023-11-13 14:15 ` Kalle Valo
2023-11-13 14:15 ` Kalle Valo
2023-11-13 14:26 ` Jeffrey Hugo
2023-11-13 14:26 ` Jeffrey Hugo
2023-11-13 15:04 ` Kalle Valo
2023-11-13 15:04 ` Kalle Valo
2023-11-10 10:21 ` [PATCH RFC 5/8] wifi: ath11k: do not dump SRNG statistics during resume Kalle Valo
2023-11-10 10:21 ` Kalle Valo
2023-11-10 10:22 ` [PATCH RFC 6/8] wifi: ath11k: fix warning on DMA ring capabilities event Kalle Valo
2023-11-10 10:22 ` Kalle Valo
2023-11-10 10:22 ` [PATCH RFC 7/8] wifi: ath11k: thermal: don't try to register multiple times Kalle Valo
2023-11-10 10:22 ` Kalle Valo
2023-11-10 10:22 ` [PATCH RFC 8/8] wifi: ath11k: support hibernation Kalle Valo
2023-11-10 10:22 ` Kalle Valo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20231110102202.3168243-2-kvalo@kernel.org \
--to=kvalo@kernel.org \
--cc=ath11k@lists.infradead.org \
--cc=linux-wireless@vger.kernel.org \
--cc=mhi@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.