wifi: ath11k: hibernation support
Subsystems (2)
cover wifi: ath11k: hibernation support
From: Kalle Valo <[email protected]>
Currently in ath11k we keep the firmware running on the WLAN device when the network interface (wlan0) is down. The problem is that this will break hibernation, obviously the firmware can't be running after the whole system is powered off. To power down the ath11k firmware for suspend/hibernation some changes both in MHI subsystem and ath11k is needed.
This patchset fixes a longstanding bug report about broken hibernation support:
https://bugzilla.kernel.org/show_bug.cgi?id=214649
This patchset is marked as RFC as it requires changes in MHI subsystem. Also this has been tested only on WCN6855, need to test also on more AP based chipsets like IPQ8074 and QCN9074.
The patches are also available at:
https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git/log/?h=ath11k-hibernation-support
Earlier versions of this patchset have been tested by multiple users with positive results. Takashi also tested this latest version:
Baochen Qiang (7):
bus: mhi: host: add mhi_power_down_no_destroy()
bus: mhi: host: add new interfaces to handle MHI channels directly
wifi: ath11k: handle irq enable/disable in several code path
wifi: ath11k: remove MHI LOOPBACK channels
wifi: ath11k: do not dump SRNG statistics during resume
wifi: ath11k: fix warning on DMA ring capabilities event
wifi: ath11k: support hibernation
Kalle Valo (1):
wifi: ath11k: thermal: don't try to register multiple times
drivers/bus/mhi/host/internal.h | 1 + drivers/bus/mhi/host/main.c | 91 +++++++++++++++++++++++ drivers/bus/mhi/host/pm.c | 26 +++++-- drivers/net/wireless/ath/ath11k/ahb.c | 8 +- drivers/net/wireless/ath/ath11k/core.c | 44 ++++++----- drivers/net/wireless/ath/ath11k/core.h | 2 + drivers/net/wireless/ath/ath11k/hif.h | 12 +-- drivers/net/wireless/ath/ath11k/mhi.c | 49 +++++------- drivers/net/wireless/ath/ath11k/mhi.h | 4 +- drivers/net/wireless/ath/ath11k/pci.c | 55 ++++++++++++-- drivers/net/wireless/ath/ath11k/qmi.c | 7 +- drivers/net/wireless/ath/ath11k/thermal.c | 3 + drivers/net/wireless/ath/ath11k/wmi.c | 1 + include/linux/mhi.h | 47 +++++++++++- 14 files changed, 268 insertions(+), 82 deletions(-)
base-commit: f24dee89bb8a7ef33c28e31632b1f3dd4e196413
Signature · 1 line
2.39.2
RFC PATCH 1/8 bus: mhi: host: add mhi_power_down_no_destroy()
From: Baochen Qiang <[email protected]>
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
--- 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(-)
drivers/bus/mhi/host/internal.h +1 -0
@@ -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, };
drivers/bus/mhi/host/pm.c +19 -7
@@ -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) {
include/linux/mhi.h +27 -2
@@ -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
Signature · 1 line
2.39.2
Re: [PATCH RFC 1/8] bus: mhi: host: add mhi_power_down_no_destroy()
Quoted 12 lines · Kalle Valo
From: Baochen Qiang <[email protected]>
If ath11k tries to call
mhi_power_up()during resume it fails:
ath11k_pci0000:06:00.0: timeout while waiting for restart completeThis happens because when calling
mhi_power_up()the MHI subsystem eventually callsdevice_add()frommhi_create_devices()but the device creation is deferred:mhi
mhi0_IPCR: Driverqcom_mhi_qrtrforce probe deferral
Quoted 8 lines
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 indpm_complete(). */
have you consider registering for pm_notifier callback specifically for PM_POST_HIBERNATION (Documentation/power/notifiers.txt), and then making decision of calling MHI power up sequence which would make sure that created device based driver probe() is completed.
Quoted 158 lines
Because the device probe is deferred, the
qcom_mhi_qrtr_probe()is not called andqcom_mhi_qrtr_dl_callback()fails silently as qdev is zero:static void qcom_mhi_qrtr_dl_callback(struct
mhi_device*mhi_dev,
structmhi_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 waymhi_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 <[email protected]>Signed-off-by Kalle Valo <[email protected]>--- 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(-)drivers/bus/mhi/host/internal.h +1
-0@@ -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, };drivers/bus/mhi/host/pm.c +19
-7@@ -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) {include/linux/mhi.h +27
-2@@ -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
Signature · 3 lines
ath11k mailing list [email protected] http://lists.infradead.org/mailman/listinfo/ath11k
RFC PATCH 2/8 bus: mhi: host: add new interfaces to handle MHI channels directly
In reply to Kalle ValoFrom: Baochen Qiang <[email protected]>
When using mhi_power_down_no_destroy() MHI hosts need to unprepare MHI channels by themselves. Similarly, MHI stack will also not create new MHI device since old devices were not destroyed, so MHI hosts need to prepare channels as well. Hence add these two interfaces to make that possible.
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
--- drivers/bus/mhi/host/main.c | 91 +++++++++++++++++++++++++++++++++++++ include/linux/mhi.h | 18 ++++++++ 2 files changed, 109 insertions(+)
drivers/bus/mhi/host/main.c +91 -0
@@ -1667,6 +1667,49 @@ int mhi_prepare_for_transfer_autoqueue(struct mhi_device *mhi_dev) }EXPORT_SYMBOL_GPL (mhi_prepare_for_transfer_autoqueue); +static int __mhi_prepare_for_transfer_autoqueue (struct device *dev,void *data) +{ +struct mhi_device *mhi_dev; +struct mhi_chan *ul_chan, *dl_chan; +enum mhi_ee_type ee =MHI_EE_MAX ; + +if (dev->bus != &mhi_bus_type) +return 0 ; + + mhi_dev =to_mhi_device (dev); + +/* Only prepare virtual devices thats attached to bus */ +if (mhi_dev->dev_type ==MHI_DEVICE_CONTROLLER ) +return 0 ; + + ul_chan = mhi_dev->ul_chan; + dl_chan = mhi_dev->dl_chan; + +/* +* If execution environment is specified, remove only those devices that +* started in them based on ee_mask for the channels as we move on to a +* different execution environment +*/ +if (data) + ee = *(enum mhi_ee_type *)data; + +if (ul_chan && ee !=MHI_EE_MAX && !(ul_chan->ee_mask &BIT (ee))) +return 0 ; + + +if (dl_chan && ee !=MHI_EE_MAX && !(dl_chan->ee_mask &BIT (ee))) +return 0 ; + +return mhi_prepare_for_transfer_autoqueue (mhi_dev); +} + +int mhi_prepare_all_for_transfer_autoqueue (struct mhi_controller *mhi_cntrl) +{ +return device_for_each_child (&mhi_cntrl->mhi_dev->dev,NULL , + __mhi_prepare_for_transfer_autoqueue); +} +EXPORT_SYMBOL_GPL (mhi_prepare_all_for_transfer_autoqueue); +void mhi_unprepare_from_transfer (struct mhi_device *mhi_dev) {struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
@@ -1682,3 +1725,51 @@ void mhi_unprepare_from_transfer(struct mhi_device *mhi_dev) } }EXPORT_SYMBOL_GPL (mhi_unprepare_from_transfer); + +static int __mhi_unprepare_from_transfer (struct device *dev,void *data) +{ +struct mhi_device *mhi_dev; +struct mhi_chan *ul_chan, *dl_chan; +enum mhi_ee_type ee =MHI_EE_MAX ; + +if (dev->bus != &mhi_bus_type) +return 0 ; + + mhi_dev =to_mhi_device (dev); + +/* Only unprepare virtual devices thats attached to bus */ +if (mhi_dev->dev_type ==MHI_DEVICE_CONTROLLER ) +return 0 ; + + ul_chan = mhi_dev->ul_chan; + dl_chan = mhi_dev->dl_chan; + +/* +* If execution environment is specified, remove only those devices that +* started in them based on ee_mask for the channels as we move on to a +* different execution environment +*/ +if (data) + ee = *(enum mhi_ee_type *)data; + +if (ul_chan) { +if (ee !=MHI_EE_MAX && !(ul_chan->ee_mask &BIT (ee))) +return 0 ; + } + +if (dl_chan) { +if (ee !=MHI_EE_MAX && !(dl_chan->ee_mask &BIT (ee))) +return 0 ; + } + +mhi_unprepare_from_transfer (mhi_dev); + +return 0 ; +} + +int mhi_unprepare_all_from_transfer (struct mhi_controller *mhi_cntrl) +{ +return device_for_each_child (&mhi_cntrl->mhi_dev->dev,NULL , + __mhi_unprepare_from_transfer); +} +EXPORT_SYMBOL_GPL (mhi_unprepare_all_from_transfer);
include/linux/mhi.h +18 -0
@@ -838,4 +838,22 @@ int mhi_queue_skb(struct mhi_device *mhi_dev, enum dma_data_direction dir,*/ bool mhi_queue_is_full (struct mhi_device *mhi_dev,enum dma_data_direction dir); +/** +* mhi_prepare_all_for_transfer_autoqueue - if you are using +* mhi_power_down_no_destroy() variant this needs to be called after +* calling mhi_power_up(). +* +* @mhi_cntrl: MHI controller +*/ +int mhi_prepare_all_for_transfer_autoqueue (struct mhi_controller *mhi_cntrl); + +/** +* mhi_unprepare_all_from_transfer - if you are using +* mhi_power_down_no_destroy() variant this function needs to be called +* before calling mhi_power_down_no_destroy(). +* +* @mhi_cntrl: MHI controller +*/ +int mhi_unprepare_all_from_transfer (struct mhi_controller *mhi_cntrl); +#endif /* _MHI_H_ */
Signature · 1 line
2.39.2
Re: [PATCH RFC 2/8] bus: mhi: host: add new interfaces to handle MHI channels directly
Quoted 26 lines · Kalle Valo
From: Baochen Qiang <[email protected]>
When using
mhi_power_down_no_destroy()MHI hosts need to unprepare MHI channels by themselves. Similarly, MHI stack will also not create new MHI device since old devices were not destroyed, so MHI hosts need to prepare channels as well. Hence add these two interfaces to make that possible.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]>Signed-off-by Kalle Valo <[email protected]>--- drivers/bus/mhi/host/main.c | 91 +++++++++++++++++++++++++++++++++++++ include/linux/mhi.h | 18 ++++++++ 2 files changed, 109 insertions(+)drivers/bus/mhi/host/main.c +2
-0@@ -1667,6 +1667,49 @@ int mhi_prepare_for_transfer_autoqueue(struct mhi_device *mhi_dev) }EXPORT_SYMBOL_GPL (mhi_prepare_for_transfer_autoqueue); +static int __mhi_prepare_for_transfer_autoqueue (struct device *dev,void *data) +{
drivers/bus/mhi/host/main.c int mhi_prepare_for_transfer_autoqueue(struct mhi_device *mhi_dev) · line 1681
Quoted 10 lines
drivers/bus/mhi/host/main.c +10
-0+struct mhi_device *mhi_dev; +struct mhi_chan *ul_chan, *dl_chan; +enum mhi_ee_type ee =MHI_EE_MAX ; + +if (dev->bus != &mhi_bus_type) +return 0 ; + + mhi_dev =to_mhi_device (dev); + +/* Only prepare virtual devices thats attached to bus */
"that are"?
Quoted 20 lines
drivers/bus/mhi/host/main.c +20
-0+if (mhi_dev->dev_type ==MHI_DEVICE_CONTROLLER ) +return 0 ; + + ul_chan = mhi_dev->ul_chan; + dl_chan = mhi_dev->dl_chan; + +/* +* If execution environment is specified, remove only those devices that +* started in them based on ee_mask for the channels as we move on to a +* different execution environment +*/ +if (data) + ee = *(enum mhi_ee_type *)data; + +if (ul_chan && ee !=MHI_EE_MAX && !(ul_chan->ee_mask &BIT (ee))) +return 0 ; + + +if (dl_chan && ee !=MHI_EE_MAX && !(dl_chan->ee_mask &BIT (ee))) +return 0 ;
drivers/bus/mhi/host/main.c int mhi_prepare_for_transfer_autoqueue(struct mhi_device *mhi_dev) · line 1711
Quoted 10 lines
drivers/bus/mhi/host/main.c +10
-0+ +return mhi_prepare_for_transfer_autoqueue (mhi_dev); +} + +int mhi_prepare_all_for_transfer_autoqueue (struct mhi_controller *mhi_cntrl) +{ +return device_for_each_child (&mhi_cntrl->mhi_dev->dev,NULL , + __mhi_prepare_for_transfer_autoqueue); +} +EXPORT_SYMBOL_GPL (mhi_prepare_all_for_transfer_autoqueue);
This seems broken. It appears to configure all channels as autoqueue, regardless of how the controller initially configured them. This would only be safe to use if all channels were configured for autoqueue, but would silently cause issues otherwise.
Re: [PATCH RFC 2/8] bus: mhi: host: add new interfaces to handle MHI channels directly
Quoted 31 lines · Jeffrey Hugo
Quoted 30 lines · Kalle Valo
From: Baochen Qiang <[email protected]>
When using
mhi_power_down_no_destroy()MHI hosts need to unprepare MHI channels by themselves. Similarly, MHI stack will also not create new MHI device since old devices were not destroyed, so MHI hosts need to prepare channels as well. Hence add these two interfaces to make that possible.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]>Signed-off-by Kalle Valo <[email protected]>---
drivers/bus/mhi/host/main.c| 91 +++++++++++++++++++++++++++++++++++++ include/linux/mhi.h | 18 ++++++++2 files changed, 109 insertions(+)drivers/bus/mhi/host/main.c +5
-0@@ -1667,6 +1667,49 @@ int mhi_prepare_for_transfer_autoqueue(struct mhi_device *mhi_dev) } EXPORT_SYMBOL_GPL(mhi_prepare_for_transfer_autoqueue); +static int __mhi_prepare_for_transfer_autoqueue(struct device *dev, void *data) +{ + struct mhi_device *mhi_dev; + struct mhi_chan *ul_chan, *dl_chan; + enum mhi_ee_type ee = MHI_EE_MAX; +
Quoted 9 lines
drivers/bus/mhi/host/main.c int mhi_prepare_for_transfer_autoqueue(struct mhi_device *mhi_dev) · line 1681
Quoted 6 lines
drivers/bus/mhi/host/main.c +6
-0+ if (dev->bus != &mhi_bus_type) + return 0; + + mhi_dev = to_mhi_device(dev); + + /* Only prepare virtual devices thats attached to bus */"that are"?
It means MHI devices with a type of MHI_DEVICE_XFER. See also mhi_destroy_device();
Quoted 27 lines
Quoted 27 lines
drivers/bus/mhi/host/main.c +8
-0+ if (mhi_dev->dev_type == MHI_DEVICE_CONTROLLER) + return 0; + + ul_chan = mhi_dev->ul_chan; + dl_chan = mhi_dev->dl_chan; + + /* +* If execution environment is specified, remove only those devices that
+ * started in them based onee_maskfor the channels as we move on to a
+ * different execution environment
+ */
+ if (data)
+ ee = *(enummhi_ee_type*)data;drivers/bus/mhi/host/main.c +12
-0+ + if (ul_chan && ee != MHI_EE_MAX && !(ul_chan->ee_mask & BIT(ee))) + return 0; + + + if (dl_chan && ee != MHI_EE_MAX && !(dl_chan->ee_mask & BIT(ee))) + return 0; + + return mhi_prepare_for_transfer_autoqueue(mhi_dev); +} + +int mhi_prepare_all_for_transfer_autoqueue(struct mhi_controller
Quoted 8 lines
drivers/bus/mhi/host/main.c int mhi_prepare_for_transfer_autoqueue(struct mhi_device *mhi_dev) · line 1711
Quoted 6 lines
*mhi_cntrl)drivers/bus/mhi/host/main.c +5
-0+{ + return device_for_each_child(&mhi_cntrl->mhi_dev->dev, NULL, + __mhi_prepare_for_transfer_autoqueue); +} +EXPORT_SYMBOL_GPL (mhi_prepare_all_for_transfer_autoqueue);This seems broken. It appears to configure all channels as autoqueue, regardless of how the controller initially configured them. This would only be safe to use if all channels were configured for autoqueue, but would silently cause issues otherwise.
Thanks for pointing that. Yes, it is not correct to treat all channels as autoqueue regardless of its initial configuration. So how about change as below:
/* The difference between mhi_prepare_for_transfer_autoqueue() and mhi_prepare_for_transfer() comes from how to treat downlink channel */
mhi_prepare_for_transfer_dev(struct device *dev, ...)
{
...
dl_chan = mhi_dev->dl_chan;
...
if (dl_chan->pre_alloc)
mhi_prepare_for_transfer_autoqueue(dev);
else
mhi_prepare_for_transfer(dev);
}
/* And then iterate all devices and call mhi_prepare_for_transfer_dev() for each. */
int mhi_prepare_all_for_transfer(struct mhi_controller *mhi_cntrl) {
return device_for_each_child(&mhi_cntrl->mhi_dev->dev, NULL, mhi_prepare_for_transfer_dev);
}EXPORT_SYMBOL_GPL(mhi_prepare_all_for_transfer);
Signature · 3 lines
ath11k mailing list [email protected] http://lists.infradead.org/mailman/listinfo/ath11k
Re: [PATCH RFC 2/8] bus: mhi: host: add new interfaces to handle MHI channels directly
Quoted 42 lines · Baochen Qiang
Quoted 31 lines · Jeffrey Hugo
Quoted 30 lines · Kalle Valo
From: Baochen Qiang <[email protected]>
When using
mhi_power_down_no_destroy()MHI hosts need to unprepare MHI channels by themselves. Similarly, MHI stack will also not create new MHI device since old devices were not destroyed, so MHI hosts need to prepare channels as well. Hence add these two interfaces to make that possible.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]>Signed-off-by Kalle Valo <[email protected]>---
drivers/bus/mhi/host/main.c| 91 +++++++++++++++++++++++++++++++++++++ include/linux/mhi.h | 18 ++++++++2 files changed, 109 insertions(+)drivers/bus/mhi/host/main.c +5
-0@@ -1667,6 +1667,49 @@ int mhi_prepare_for_transfer_autoqueue(struct mhi_device *mhi_dev) } EXPORT_SYMBOL_GPL(mhi_prepare_for_transfer_autoqueue); +static int __mhi_prepare_for_transfer_autoqueue(struct device *dev, void *data) +{ + struct mhi_device *mhi_dev; + struct mhi_chan *ul_chan, *dl_chan; + enum mhi_ee_type ee = MHI_EE_MAX; +Quoted 9 lines
drivers/bus/mhi/host/main.c int mhi_prepare_for_transfer_autoqueue(struct mhi_device *mhi_dev) · line 1681
Quoted 6 lines
drivers/bus/mhi/host/main.c +6
-0+ if (dev->bus != &mhi_bus_type) + return 0; + + mhi_dev = to_mhi_device(dev); + + /* Only prepare virtual devices thats attached to bus */"that are"?
Quoted 1 line
It means MHI devices with a type of
MHI_DEVICE_XFER. See alsomhi_destroy_device();
I think you are confused about my comment. "thats" is not correct English. I was suggesting you replace it with "that are", but there are many ways to reword the comment.
Quoted 38 lines
Quoted 29 lines
Quoted 29 lines
drivers/bus/mhi/host/main.c +8
-0+ if (mhi_dev->dev_type == MHI_DEVICE_CONTROLLER) + return 0; + + ul_chan = mhi_dev->ul_chan; + dl_chan = mhi_dev->dl_chan; + + /* +* If execution environment is specified, remove only those devices that
+ * started in them based onee_maskfor the channels as we move on to a
+ * different execution environment
+ */
+ if (data)
+ ee = *(enummhi_ee_type*)data;drivers/bus/mhi/host/main.c +12
-0+ + if (ul_chan && ee != MHI_EE_MAX && !(ul_chan->ee_mask & BIT(ee))) + return 0; + + + if (dl_chan && ee != MHI_EE_MAX && !(dl_chan->ee_mask & BIT(ee))) + return 0; + + return mhi_prepare_for_transfer_autoqueue(mhi_dev); +} + +int mhi_prepare_all_for_transfer_autoqueue(struct mhi_controllerQuoted 8 lines
drivers/bus/mhi/host/main.c int mhi_prepare_for_transfer_autoqueue(struct mhi_device *mhi_dev) · line 1711
Quoted 6 lines
*mhi_cntrl)drivers/bus/mhi/host/main.c +5
-0+{ + return device_for_each_child(&mhi_cntrl->mhi_dev->dev, NULL, + __mhi_prepare_for_transfer_autoqueue); +} +EXPORT_SYMBOL_GPL (mhi_prepare_all_for_transfer_autoqueue);This seems broken. It appears to configure all channels as autoqueue, regardless of how the controller initially configured them. This would only be safe to use if all channels were configured for autoqueue, but would silently cause issues otherwise.
Quoted 1 line
Thanks for pointing that. Yes, it is not correct to treat all channels as autoqueue regardless of its initial configuration. So how about change as below:
Seems ok.
Quoted 32 lines
/* The difference between
mhi_prepare_for_transfer_autoqueue()andmhi_prepare_for_transfer()comes from how to treat downlink channel */
mhi_prepare_for_transfer_dev(struct device *dev, ...){
...
dl_chan=mhi_dev->dl_chan;...
if (
dl_chan->pre_alloc)
mhi_prepare_for_transfer_autoqueue(dev);else
mhi_prepare_for_transfer(dev);}
/* And then iterate all devices and call
mhi_prepare_for_transfer_dev()for each. */int
mhi_prepare_all_for_transfer(struct mhi_controller *mhi_cntrl){
returndevice_for_each_child(&mhi_cntrl->mhi_dev->dev, NULL, mhi_prepare_for_transfer_dev);
}EXPORT_SYMBOL_GPL(mhi_prepare_all_for_transfer);
Re: [PATCH RFC 2/8] bus: mhi: host: add new interfaces to handle MHI channels directly
Quoted 44 lines · Jeffrey Hugo
Quoted 43 lines · Baochen Qiang
Quoted 41 lines · Jeffrey Hugo
Quoted 27 lines · Kalle Valo
From: Baochen Qiang <[email protected]>
When using
mhi_power_down_no_destroy()MHI hosts need to unprepare MHI channels by themselves. Similarly, MHI stack will also not create new MHI device since old devices were not destroyed, so MHI hosts need to prepare channels as well. Hence add these two interfaces to make that possible.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]>Signed-off-by Kalle Valo <[email protected]>---
drivers/bus/mhi/host/main.c| 91
+++++++++++++++++++++++++++++++++++++
include/linux/mhi.h | 18 ++++++++2 files changed, 109 insertions(+)drivers/bus/mhi/host/main.c +1
-0@@ -1667,6 +1667,49 @@ int mhi_prepare_for_transfer_autoqueue(struct mhi_device *mhi_dev) } EXPORT_SYMBOL_GPL(mhi_prepare_for_transfer_autoqueue); +static int __mhi_prepare_for_transfer_autoqueue(struct device *dev, void *data) +{drivers/bus/mhi/host/main.c int · line 1681
Quoted 10 lines
drivers/bus/mhi/host/main.c +10
-0+ struct mhi_device *mhi_dev; + struct mhi_chan *ul_chan, *dl_chan; + enum mhi_ee_type ee = MHI_EE_MAX; + + if (dev->bus != &mhi_bus_type) + return 0; + + mhi_dev = to_mhi_device(dev); + + /* Only prepare virtual devices thats attached to bus */"that are"?
Quoted 3 lines
Quoted 1 line
It means MHI devices with a type of
MHI_DEVICE_XFER. See alsomhi_destroy_device();I think you are confused about my comment. "thats" is not correct English. I was suggesting you replace it with "that are", but there are many ways to reword the comment.
Sorry for misunderstood your comment. Will refine it in next version.
Quoted 76 lines
Quoted 39 lines
Quoted 30 lines
Quoted 30 lines
drivers/bus/mhi/host/main.c +8
-0+ if (mhi_dev->dev_type == MHI_DEVICE_CONTROLLER) + return 0; + + ul_chan = mhi_dev->ul_chan; + dl_chan = mhi_dev->dl_chan; + + /* +* If execution environment is specified, remove only those devices that
+ * started in them based onee_maskfor the channels as we move on to a
+ * different execution environment
+ */
+ if (data)
+ ee = *(enummhi_ee_type*)data;drivers/bus/mhi/host/main.c +12
-0+ + if (ul_chan && ee != MHI_EE_MAX && !(ul_chan->ee_mask & BIT(ee))) + return 0; + + + if (dl_chan && ee != MHI_EE_MAX && !(dl_chan->ee_mask & BIT(ee))) + return 0; + + return mhi_prepare_for_transfer_autoqueue(mhi_dev); +} + +int mhi_prepare_all_for_transfer_autoqueue(struct mhi_controllerQuoted 8 lines
drivers/bus/mhi/host/main.c int mhi_prepare_for_transfer_autoqueue(struct mhi_device *mhi_dev) · line 1711
Quoted 6 lines
*mhi_cntrl)drivers/bus/mhi/host/main.c +5
-0+{ + return device_for_each_child(&mhi_cntrl->mhi_dev->dev, NULL, + __mhi_prepare_for_transfer_autoqueue); +} +EXPORT_SYMBOL_GPL (mhi_prepare_all_for_transfer_autoqueue);This seems broken. It appears to configure all channels as autoqueue, regardless of how the controller initially configured them. This would only be safe to use if all channels were configured for autoqueue, but would silently cause issues otherwise.
Quoted 1 line
Thanks for pointing that. Yes, it is not correct to treat all channels as autoqueue regardless of its initial configuration. So how about change as below:
Seems ok.
Quoted 32 lines
/* The difference between
mhi_prepare_for_transfer_autoqueue()andmhi_prepare_for_transfer()comes from how to treat downlink channel */
mhi_prepare_for_transfer_dev(struct device *dev, ...){
...
dl_chan=mhi_dev->dl_chan;...
if (
dl_chan->pre_alloc)
mhi_prepare_for_transfer_autoqueue(dev);else
mhi_prepare_for_transfer(dev);}
/* And then iterate all devices and call
mhi_prepare_for_transfer_dev()for each. */int
mhi_prepare_all_for_transfer(struct mhi_controller *mhi_cntrl){
returndevice_for_each_child(&mhi_cntrl->mhi_dev->dev, NULL, mhi_prepare_for_transfer_dev);
}EXPORT_SYMBOL_GPL(mhi_prepare_all_for_transfer);
RFC PATCH 3/8 wifi: ath11k: handle irq enable/disable in several code path
In reply to Kalle ValoFrom: Baochen Qiang <[email protected]>
For non WoW suspend/resume, ath11k host powers down whole hardware when suspend and power up it when resume, the code path it goes through is very like the ath11k reset logic.
In order to reuse that logic, do some IRQ management work to make it work.
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
--- drivers/net/wireless/ath/ath11k/core.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-)
drivers/net/wireless/ath/ath11k/core.c +3 -7
@@ -852,9 +852,6 @@ int ath11k_core_resume(struct ath11k_base *ab)return ret; } -ath11k_hif_ce_irq_enable (ab); -ath11k_hif_irq_enable (ab); - ret =ath11k_dp_rx_pktlog_start (ab);if (ret) { ath11k_warn(ab, "failed to start rx pktlog during resume: %d\n",
@@ -1775,10 +1772,9 @@ static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab)mutex_lock (&ab->core_lock);ath11k_thermal_unregister (ab); -ath11k_hif_irq_disable (ab);ath11k_dp_pdev_free (ab);ath11k_spectral_deinit (ab); -ath11k_hif_stop (ab); +ath11k_ce_cleanup_pipes (ab);ath11k_wmi_detach (ab);ath11k_dp_pdev_reo_cleanup (ab);mutex_unlock (&ab->core_lock);
@@ -2033,8 +2029,8 @@ static void ath11k_core_reset(struct work_struct *work) time_left =wait_for_completion_timeout (&ab->recovery_start,ATH11K_RECOVER_START_TIMEOUT_HZ ); -ath11k_hif_power_down (ab); -ath11k_hif_power_up (ab); +ath11k_hif_irq_disable (ab); +ath11k_hif_ce_irq_disable (ab);ath11k_dbg (ab,ATH11K_DBG_BOOT ,"reset started\n" ); }
Signature · 1 line
2.39.2
RFC PATCH 4/8 wifi: ath11k: remove MHI LOOPBACK channels
In reply to Kalle ValoFrom: Baochen Qiang <[email protected]>
There is no driver to match these two channels, so remove them. This fixes warnings from MHI subsystem during suspend:
mhi mhi0_LOOPBACK: 1: Failed to reset channel, still resetting mhi mhi0_LOOPBACK: 0: Failed to reset channel, still resetting
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
--- drivers/net/wireless/ath/ath11k/mhi.c | 28 --------------------------- 1 file changed, 28 deletions(-)
drivers/net/wireless/ath/ath11k/mhi.c +0 -28
@@ -21,34 +21,6 @@#define RDDM_DUMP_SIZE 0x420000static struct mhi_channel_config ath11k_mhi_channels_qca6390[] = { - { - .num =0 , - .name ="LOOPBACK" , - .num_elements =32 , - .event_ring =0 , - .dir =DMA_TO_DEVICE , - .ee_mask =0x4 , - .pollcfg =0 , - .doorbell =MHI_DB_BRST_DISABLE , - .lpm_notify = false, - .offload_channel = false, - .doorbell_mode_switch = false, - .auto_queue = false, - }, - { - .num =1 , - .name ="LOOPBACK" , - .num_elements =32 , - .event_ring =0 , - .dir =DMA_FROM_DEVICE , - .ee_mask =0x4 , - .pollcfg =0 , - .doorbell =MHI_DB_BRST_DISABLE , - .lpm_notify = false, - .offload_channel = false, - .doorbell_mode_switch = false, - .auto_queue = false, - }, { .num =20 , .name ="IPCR" ,
Signature · 1 line
2.39.2
Re: [PATCH RFC 4/8] wifi: ath11k: remove MHI LOOPBACK channels
Quoted 7 lines · Kalle Valo
From: Baochen Qiang <[email protected]>
There is no driver to match these two channels, so remove them. This fixes warnings from MHI subsystem during suspend:
mhi
mhi0_LOOPBACK: 1: Failed to reset channel, still resetting mhimhi0_LOOPBACK: 0: Failed to reset channel, still resetting
This feels like just masking a real issue.
If LOOPBACK is not being consumed, then the channel should never go into the start state. Why would we be trying to transition to the reset state then?
-Jeff
Signature · 3 lines
ath11k mailing list [email protected] http://lists.infradead.org/mailman/listinfo/ath11k
Re: [PATCH RFC 4/8] wifi: ath11k: remove MHI LOOPBACK channels
Quoted 6 lines · Jeffrey Hugo
Quoted 5 lines · Kalle Valo
From: Baochen Qiang <[email protected]>
There is no driver to match these two channels, so remove them. This fixes warnings from MHI subsystem during suspend:
Quoted 8 lines
Quoted 2 lines
mhi
mhi0_LOOPBACK: 1: Failed to reset channel, still resetting mhimhi0_LOOPBACK: 0: Failed to reset channel, still resettingThis feels like just masking a real issue.
If LOOPBACK is not being consumed, then the channel should never go into the start state. Why would we be trying to transition to the reset state then?
-Jeff
That is because, with patch 'bus: mhi: host: add new interfaces to handle MHI channels directly' in this patch set, ath11k is able to call mhi_unprepare_all_from_transfer(), which will reset all channels.
Re: [PATCH RFC 4/8] wifi: ath11k: remove MHI LOOPBACK channels
Quoted 11 lines · Baochen Qiang
Quoted 9 lines · Jeffrey Hugo
Quoted 7 lines · Kalle Valo
From: Baochen Qiang <[email protected]>
There is no driver to match these two channels, so remove them. This fixes warnings from MHI subsystem during suspend:
mhi
mhi0_LOOPBACK: 1: Failed to reset channel, still resetting mhimhi0_LOOPBACK: 0: Failed to reset channel, still resetting
Quoted 6 lines
Quoted 5 lines
This feels like just masking a real issue.
If LOOPBACK is not being consumed, then the channel should never go into the start state. Why would we be trying to transition to the reset state then?
-Jeff
That is because, with patch 'bus: mhi: host: add new interfaces to handle MHI channels directly' in this patch set, ath11k is able to call
mhi_unprepare_all_from_transfer(), which will reset all channels.
that implementation is flawed if it is causing this. Looks like you never check to see if the channel was prepared in the first place.
If you go fix that, then it looks like this change is not needed.
Re: [PATCH RFC 4/8] wifi: ath11k: remove MHI LOOPBACK channels
Quoted 14 lines · Jeffrey Hugo
Quoted 13 lines · Baochen Qiang
Quoted 11 lines · Jeffrey Hugo
Quoted 7 lines · Kalle Valo
From: Baochen Qiang <[email protected]>
There is no driver to match these two channels, so remove them. This fixes warnings from MHI subsystem during suspend:
mhi
mhi0_LOOPBACK: 1: Failed to reset channel, still resetting mhimhi0_LOOPBACK: 0: Failed to reset channel, still resettingThis feels like just masking a real issue.
Quoted 8 lines
Quoted 4 lines
Quoted 3 lines
If LOOPBACK is not being consumed, then the channel should never go into the start state. Why would we be trying to transition to the reset state then?
-Jeff
That is because, with patch 'bus: mhi: host: add new interfaces to handle MHI channels directly' in this patch set, ath11k is able to call
mhi_unprepare_all_from_transfer(), which will reset all channels.that implementation is flawed if it is causing this. Looks like you never check to see if the channel was prepared in the first place.
If you go fix that, then it looks like this change is not needed.
Sure, will check whether channel is in MHI_CH_STATE_ENABLED state in next version.
Re: [PATCH RFC 4/8] wifi: ath11k: remove MHI LOOPBACK channels
In reply to Jeffrey HugoQuoted 24 lines · Jeffrey Hugo
Quoted 16 lines · Baochen Qiang
Quoted 15 lines · Jeffrey Hugo
Quoted 7 lines · Kalle Valo
From: Baochen Qiang <[email protected]>
There is no driver to match these two channels, so remove them. This fixes warnings from MHI subsystem during suspend:
mhi
mhi0_LOOPBACK: 1: Failed to reset channel, still resetting mhimhi0_LOOPBACK: 0: Failed to reset channel, still resettingThis feels like just masking a real issue.
If LOOPBACK is not being consumed, then the channel should never go into the start state. Why would we be trying to transition to the reset state then?
Quoted 5 lines
Quoted 1 line
-Jeff
That is because, with patch 'bus: mhi: host: add new interfaces to handle MHI channels directly' in this patch set, ath11k is able to call
mhi_unprepare_all_from_transfer(), which will reset all channels.
Quoted 4 lines
that implementation is flawed if it is causing this. Looks like you never check to see if the channel was prepared in the first place.
If you go fix that, then it looks like this change is not needed.
BTW what do these loopback channels do? I didn't notice any difference in the functionality so I'm wondering the reason for these.
Signature · 3 lines
https://patchwork.kernel.org/project/linux-wireless/list/ https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
Re: [PATCH RFC 4/8] wifi: ath11k: remove MHI LOOPBACK channels
Quoted 26 lines · Kalle Valo
Quoted 24 lines · Jeffrey Hugo
Quoted 21 lines · Baochen Qiang
Quoted 9 lines · Jeffrey Hugo
Quoted 7 lines · Kalle Valo
From: Baochen Qiang <[email protected]>
There is no driver to match these two channels, so remove them. This fixes warnings from MHI subsystem during suspend:
mhi
mhi0_LOOPBACK: 1: Failed to reset channel, still resetting mhimhi0_LOOPBACK: 0: Failed to reset channel, still resettingQuoted 7 lines
This feels like just masking a real issue.
If LOOPBACK is not being consumed, then the channel should never go into the start state. Why would we be trying to transition to the reset state then?
-Jeff
That is because, with patch 'bus: mhi: host: add new interfaces to handle MHI channels directly' in this patch set, ath11k is able to call
mhi_unprepare_all_from_transfer(), which will reset all channels.
Quoted 8 lines
Quoted 4 lines
that implementation is flawed if it is causing this. Looks like you never check to see if the channel was prepared in the first place.
If you go fix that, then it looks like this change is not needed.
BTW what do these loopback channels do? I didn't notice any difference in the functionality so I'm wondering the reason for these.
The loopback channel is defined as a service where any data the host sends to the device is immediately sent back to the host, unmodified. The typical usecase is smoke test and performance profiling.
I do not object to the removal of the channel from the atheros devices, assuming suitable justification. Not having a use for the channel seems like good justification. Working around a bug seem more like a hack than proper justification.
Re: [PATCH RFC 4/8] wifi: ath11k: remove MHI LOOPBACK channels
Quoted 32 lines · Jeffrey Hugo
Quoted 30 lines · Kalle Valo
Quoted 28 lines · Jeffrey Hugo
Quoted 16 lines · Baochen Qiang
Quoted 15 lines · Jeffrey Hugo
Quoted 7 lines · Kalle Valo
From: Baochen Qiang <[email protected]>
There is no driver to match these two channels, so remove them. This fixes warnings from MHI subsystem during suspend:
mhi
mhi0_LOOPBACK: 1: Failed to reset channel, still resetting mhimhi0_LOOPBACK: 0: Failed to reset channel, still resettingThis feels like just masking a real issue.
If LOOPBACK is not being consumed, then the channel should never go into the start state. Why would we be trying to transition to the reset state then?
Quoted 5 lines
Quoted 1 line
-Jeff
That is because, with patch 'bus: mhi: host: add new interfaces to handle MHI channels directly' in this patch set, ath11k is able to call
mhi_unprepare_all_from_transfer(), which will reset all channels.that implementation is flawed if it is causing this. Looks like you never check to see if the channel was prepared in the first place.
If you go fix that, then it looks like this change is not needed.
Quoted 8 lines
Quoted 4 lines
BTW what do these loopback channels do? I didn't notice any difference
in the functionality so I'm wondering the reason for these.The loopback channel is defined as a service where any data the host sends to the device is immediately sent back to the host, unmodified. The typical usecase is smoke test and performance profiling.
Thanks, good to know. We don't have any such functionality in ath11k right now and if we ever do we can always add the channels back.
Signature · 3 lines
https://patchwork.kernel.org/project/linux-wireless/list/ https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
RFC PATCH 5/8 wifi: ath11k: do not dump SRNG statistics during resume
In reply to Kalle ValoFrom: Baochen Qiang <[email protected]>
Both the firmware reset feature and the power management suspend/resume feature share common power-down and power-up functionality. One aspect of the power-up functionality is the handling of the ATH11K_QMI_EVENT_FW_INIT_DONE event. When this event is received, a call is made to ath11k_hal_dump_srng_stats(), with the purpose to collect information that may be useful in debugging the cause of a firmware reset.
Unfortunately, since this functionality is shared between both the firmware reset path and the power management resume path, the kernel log is flooded with messages during resume. Since these messages are not useful during resume, and in fact can be confusing and can increase the time it takes to resume, update the logic to only call ath11k_hal_dump_srng_stats() during firmware reset.
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
--- drivers/net/wireless/ath/ath11k/qmi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/wireless/ath/ath11k/qmi.c +2 -1
@@ -3249,7 +3249,8 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work)case ATH11K_QMI_EVENT_FW_INIT_DONE :clear_bit (ATH11K_FLAG_QMI_FAIL , &ab->dev_flags);if (test_bit (ATH11K_FLAG_REGISTERED , &ab->dev_flags)) { -ath11k_hal_dump_srng_stats (ab); +if (ab->is_reset) +ath11k_hal_dump_srng_stats (ab);queue_work (ab->workqueue, &ab->restart_work);break ; }
Signature · 1 line
2.39.2
RFC PATCH 6/8 wifi: ath11k: fix warning on DMA ring capabilities event
In reply to Kalle ValoFrom: Baochen Qiang <[email protected]>
We are seeing below warning in both reset and suspend/resume scenarios:
[69663.691847] ath11k_pci 0000:02:00.0: Already processed, so ignoring dma ring caps
This is because ab->num_db_cap is not cleared in ath11k_wmi_free_dbring_caps(), so clear it to avoid such warnings.
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
--- drivers/net/wireless/ath/ath11k/wmi.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/wireless/ath/ath11k/wmi.c +1 -0
@@ -4786,6 +4786,7 @@ static void ath11k_wmi_free_dbring_caps(struct ath11k_base *ab) {kfree (ab->db_caps); ab->db_caps =NULL ; + ab->num_db_cap =0 ; } static int ath11k_wmi_tlv_dma_ring_caps(struct ath11k_base *ab,
Signature · 1 line
2.39.2
RFC PATCH 7/8 wifi: ath11k: thermal: don't try to register multiple times
In reply to Kalle ValoFrom: Kalle Valo <[email protected]>
Every time the firmware boots we call ath11k_core_qmi_firmware_ready() which ends up calling ath11k_thermal_register(). So we try to register thermal devices multiple times. And when we power off the firmware during suspend/hibernation (implemented in the next patch) we get a warning in resume:
hwmon hwmon4: PM: parent phy0 should not be sleeping
Workaround this similarly like ath11k_mac_register() does by testing ATH11K_FLAG_REGISTERED.
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
--- drivers/net/wireless/ath/ath11k/thermal.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/wireless/ath/ath11k/thermal.c +3 -0
@@ -162,6 +162,9 @@ int ath11k_thermal_register(struct ath11k_base *ab)struct ath11k_pdev *pdev;int i, ret; +if (test_bit (ATH11K_FLAG_REGISTERED , &ab->dev_flags)) +return 0 ; +for (i =0 ; i < ab->num_radios; i++) { pdev = &ab->pdevs[i]; ar = pdev->ar;
Signature · 1 line
2.39.2
RFC PATCH 8/8 wifi: ath11k: support hibernation
In reply to Kalle ValoFrom: Baochen Qiang <[email protected]>
Now that all infrastructure is in place and ath11k is fixed to handle all the corner cases, power down the ath11k firmware during suspend and power it back up during resume. This fixes the problem when using hibernation with ath11k PCI devices.
Change to use ath11k_hif_power_down() instead of ath11k_hif_suspend() in suspend callback and to use ath11k_hif_power_up() instead of ath11k_hif_resume() in resume callback.
In ath11k_hif_power_down(), we reset MHI channels to keep from unexpected activities, and last we go PCI power down path to completely reset whole hardware. Most importantly in power down path, we tell mhi_power_down() to not to destroy MHI devices, making us get rid of the probe-defer issue when resume.
In ath11k_hif_power_up(), we go normal PCI power up path to download firmware etc. Since MHI channels are not activated automatically, we do it manually as the last part.
Also change related code due to interface changes.
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
--- drivers/net/wireless/ath/ath11k/ahb.c | 8 ++-- drivers/net/wireless/ath/ath11k/core.c | 34 ++++++++-------- drivers/net/wireless/ath/ath11k/core.h | 2 + drivers/net/wireless/ath/ath11k/hif.h | 12 +++--- drivers/net/wireless/ath/ath11k/mhi.c | 21 +++++++++- drivers/net/wireless/ath/ath11k/mhi.h | 4 +- drivers/net/wireless/ath/ath11k/pci.c | 55 +++++++++++++++++++++++--- drivers/net/wireless/ath/ath11k/qmi.c | 4 +- 8 files changed, 103 insertions(+), 37 deletions(-)
drivers/net/wireless/ath/ath11k/ahb.c +4 -4
@@ -401,7 +401,7 @@ static void ath11k_ahb_stop(struct ath11k_base *ab)ath11k_ce_cleanup_pipes (ab); } -static int ath11k_ahb_power_up (struct ath11k_base *ab) +static int ath11k_ahb_power_up (struct ath11k_base *ab,bool is_resume) {struct ath11k_ahb *ab_ahb =ath11k_ahb_priv (ab);int ret;
@@ -413,11 +413,11 @@ static int ath11k_ahb_power_up(struct ath11k_base *ab)return ret; } -static void ath11k_ahb_power_down (struct ath11k_base *ab) +static int ath11k_ahb_power_down (struct ath11k_base *ab,bool is_suspend) {struct ath11k_ahb *ab_ahb =ath11k_ahb_priv (ab); -rproc_shutdown (ab_ahb->tgt_rproc); +return rproc_shutdown (ab_ahb->tgt_rproc); }static void ath11k_ahb_init_qmi_ce_config (struct ath11k_base *ab)
@@ -1256,7 +1256,7 @@ static int ath11k_ahb_remove(struct platform_device *pdev)struct ath11k_base *ab =platform_get_drvdata (pdev);if (test_bit (ATH11K_FLAG_QMI_FAIL , &ab->dev_flags)) { -ath11k_ahb_power_down (ab); +ath11k_ahb_power_down (ab, false);ath11k_debugfs_soc_destroy (ab);ath11k_qmi_deinit_service (ab); goto qmi_fail;
drivers/net/wireless/ath/ath11k/core.c +18 -16
@@ -800,12 +800,6 @@ int ath11k_core_suspend(struct ath11k_base *ab)return ret; } - ret =ath11k_wow_enable (ab); -if (ret) { -ath11k_warn (ab,"failed to enable wow during suspend: %d\n" , ret); -return ret; - } - ret =ath11k_dp_rx_pktlog_stop (ab, false);if (ret) { ath11k_warn(ab, "failed to stop dp rx pktlog during suspend: %d\n",
@@ -819,7 +813,7 @@ int ath11k_core_suspend(struct ath11k_base *ab)ath11k_hif_irq_disable (ab);ath11k_hif_ce_irq_disable (ab); - ret =ath11k_hif_suspend (ab); + ret =ath11k_hif_power_down (ab, true);if (ret) {ath11k_warn (ab,"failed to suspend hif: %d\n" , ret);return ret;
@@ -834,6 +828,7 @@ int ath11k_core_resume(struct ath11k_base *ab)int ret;struct ath11k_pdev *pdev;struct ath11k *ar; +long time_left;if (!ab->hw_params.supports_suspend)return -EOPNOTSUPP ;
@@ -846,11 +841,18 @@ int ath11k_core_resume(struct ath11k_base *ab)if (!ar || ar->state !=ATH11K_STATE_OFF )return 0 ; - ret =ath11k_hif_resume (ab); +reinit_completion (&ab->restart_completed); + ret =ath11k_hif_power_up (ab, true);if (ret) {ath11k_warn (ab,"failed to resume hif during resume: %d\n" , ret);return ret; } + time_left =wait_for_completion_timeout (&ab->restart_completed, +ATH11K_RESET_TIMEOUT_HZ ); +if (time_left ==0 ) { +ath11k_warn (ab,"timeout while waiting for restart complete" ); +return -ETIMEDOUT ; + } ret =ath11k_dp_rx_pktlog_start (ab);if (ret) {
@@ -859,12 +861,6 @@ int ath11k_core_resume(struct ath11k_base *ab)return ret; } - ret =ath11k_wow_wakeup (ab); -if (ret) { -ath11k_warn (ab,"failed to wakeup wow during resume: %d\n" , ret); -return ret; - } -return 0 ; }EXPORT_SYMBOL (ath11k_core_resume);
@@ -1488,7 +1484,7 @@ static int ath11k_core_soc_create(struct ath11k_base *ab) goto err_qmi_deinit; } - ret =ath11k_hif_power_up (ab); + ret =ath11k_hif_power_up (ab, false);if (ret) {ath11k_err (ab,"failed to power up :%d\n" , ret); goto err_debugfs_reg;
@@ -1963,6 +1959,8 @@ static void ath11k_core_restart(struct work_struct *work)if (!ab->is_reset)ath11k_core_post_reconfigure_recovery (ab); + +complete (&ab->restart_completed); }static void ath11k_core_reset (struct work_struct *work)
@@ -2032,6 +2030,9 @@ static void ath11k_core_reset(struct work_struct *work)ath11k_hif_irq_disable (ab);ath11k_hif_ce_irq_disable (ab); +ath11k_hif_power_down (ab, false); +ath11k_hif_power_up (ab, false); +ath11k_dbg (ab,ATH11K_DBG_BOOT ,"reset started\n" ); }
@@ -2102,7 +2103,7 @@ void ath11k_core_deinit(struct ath11k_base *ab)mutex_unlock (&ab->core_lock); -ath11k_hif_power_down (ab); +ath11k_hif_power_down (ab, false);ath11k_mac_destroy (ab);ath11k_core_soc_destroy (ab);ath11k_fw_destroy (ab);
@@ -2155,6 +2156,7 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size,timer_setup (&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry,0 );init_completion (&ab->htc_suspend);init_completion (&ab->wow.wakeup_completed); +init_completion (&ab->restart_completed); ab->dev = dev; ab->hif.bus = bus;
drivers/net/wireless/ath/ath11k/core.h +2 -0
@@ -996,6 +996,8 @@ struct ath11k_base {DECLARE_BITMAP (fw_features,ATH11K_FW_FEATURE_COUNT ); } fw; +struct completion restart_completed; + #ifdef CONFIG_NL80211_TESTMODE struct { u32 data_pos;
drivers/net/wireless/ath/ath11k/hif.h +6 -6
@@ -16,8 +16,8 @@ struct ath11k_hif_ops {void (*irq_disable)(struct ath11k_base *ab);int (*start)(struct ath11k_base *ab);void (*stop)(struct ath11k_base *ab); -int (*power_up)(struct ath11k_base *ab); -void (*power_down)(struct ath11k_base *ab); +int (*power_up)(struct ath11k_base *ab,bool is_resume); +int (*power_down)(struct ath11k_base *ab,bool is_suspend);int (*suspend)(struct ath11k_base *ab);int (*resume)(struct ath11k_base *ab); int (*map_service_to_pipe)(struct ath11k_base *ab, u16 service_id,
@@ -64,14 +64,14 @@ static inline void ath11k_hif_irq_disable(struct ath11k_base *ab) ab->hif.ops->irq_disable (ab); } -static inline int ath11k_hif_power_up (struct ath11k_base *ab) +static inline int ath11k_hif_power_up (struct ath11k_base *ab,bool is_resume) { -return ab->hif.ops->power_up (ab); +return ab->hif.ops->power_up (ab, is_resume); } -static inline void ath11k_hif_power_down (struct ath11k_base *ab) +static inline int ath11k_hif_power_down (struct ath11k_base *ab,bool is_resume) { - ab->hif.ops->power_down (ab); +return ab->hif.ops->power_down (ab, is_resume); }static inline int ath11k_hif_suspend (struct ath11k_base *ab)
drivers/net/wireless/ath/ath11k/mhi.c +19 -2
@@ -469,9 +469,16 @@ int ath11k_mhi_start(struct ath11k_pci *ab_pci)return 0 ; } -void ath11k_mhi_stop (struct ath11k_pci *ab_pci) +void ath11k_mhi_stop (struct ath11k_pci *ab_pci,bool is_suspend) { -mhi_power_down (ab_pci->mhi_ctrl, true); +/* During suspend we need to use mhi_power_down_no_destroy() +* workaround, otherwise mhi_power_up() will fail during resume. +*/ +if (is_suspend) +mhi_power_down_no_destroy (ab_pci->mhi_ctrl, true); +else +mhi_power_down (ab_pci->mhi_ctrl, true); +mhi_unprepare_after_power_down (ab_pci->mhi_ctrl); }
@@ -506,3 +513,13 @@ int ath11k_mhi_resume(struct ath11k_pci *ab_pci)return 0 ; } + +int ath11k_mhi_prepare_for_transfer (struct ath11k_pci *ab_pci) +{ +return mhi_prepare_all_for_transfer_autoqueue (ab_pci->mhi_ctrl); +} + +int ath11k_mhi_unprepare_from_transfer (struct ath11k_pci *ab_pci) +{ +return mhi_unprepare_all_from_transfer (ab_pci->mhi_ctrl); +}
drivers/net/wireless/ath/ath11k/mhi.h +3 -1
@@ -17,7 +17,7 @@#define MHICTRL_RESET_MASK 0x2int ath11k_mhi_start (struct ath11k_pci *ar_pci); -void ath11k_mhi_stop (struct ath11k_pci *ar_pci); +void ath11k_mhi_stop (struct ath11k_pci *ar_pci,bool is_suspend);int ath11k_mhi_register (struct ath11k_pci *ar_pci);void ath11k_mhi_unregister (struct ath11k_pci *ar_pci);void ath11k_mhi_set_mhictrl_reset (struct ath11k_base *ab);
@@ -26,4 +26,6 @@ void ath11k_mhi_clear_vector(struct ath11k_base *ab);int ath11k_mhi_suspend (struct ath11k_pci *ar_pci);int ath11k_mhi_resume (struct ath11k_pci *ar_pci); +int ath11k_mhi_prepare_for_transfer (struct ath11k_pci *ar_pci); +int ath11k_mhi_unprepare_from_transfer (struct ath11k_pci *ar_pci);#endif
drivers/net/wireless/ath/ath11k/pci.c +49 -6
89 lines not on this page · raw message
drivers/net/wireless/ath/ath11k/qmi.c +2 -2
@@ -2877,8 +2877,8 @@ int ath11k_qmi_fwreset_from_cold_boot(struct ath11k_base *ab) }/* reset the firmware */ -ath11k_hif_power_down (ab); -ath11k_hif_power_up (ab); +ath11k_hif_power_down (ab, false); +ath11k_hif_power_up (ab, false);ath11k_dbg (ab,ATH11K_DBG_QMI ,"exit wait for cold boot done\n" );return 0 ; }
Signature · 1 line
2.39.2