git: 46c09d766d26 - stable/13 - iwlwifi: fix hang on unloading driver

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Mon, 28 Nov 2022 17:27:11 UTC
The branch stable/13 has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=46c09d766d265a886a7fd11ee5dd88bb17e9a0af

commit 46c09d766d265a886a7fd11ee5dd88bb17e9a0af
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2022-11-22 17:29:41 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2022-11-28 16:34:46 +0000

    iwlwifi: fix hang on unloading driver
    
    f808c43ad9234670770601ba32a7426b00bbf528 introduced a FreeBSD specific
    behaviour to wait for firmware load completion before returning from
    loading the driver.  This does no longer allow iwl_drv_stop to detect
    that startup has completed and it will wait indefinitely for a
    completion event that will not happen.
    We could change the complete() call to a complete_all() but to avoid
    confusion, future side effects, and for simplicity daisy-chain two
    complete events in FreeBSD.
    
    PR:             267869
    Reported by:    Peter Much (pmc citylink.dinoex.sub.org)
    Tested by:      Peter Much (pmc citylink.dinoex.sub.org)
    Sponsored by:   The FreeBSD Foundation
    
    (cherry picked from commit bee60c98974593d25aa18743f9413a78e0d57dc9)
---
 sys/contrib/dev/iwlwifi/iwl-drv.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/sys/contrib/dev/iwlwifi/iwl-drv.c b/sys/contrib/dev/iwlwifi/iwl-drv.c
index 6daba537262b..cecbacbe62c2 100644
--- a/sys/contrib/dev/iwlwifi/iwl-drv.c
+++ b/sys/contrib/dev/iwlwifi/iwl-drv.c
@@ -77,6 +77,9 @@ struct iwl_drv {
 	char firmware_name[64];         /* name of firmware file to load */
 
 	struct completion request_firmware_complete;
+#if defined(__FreeBSD__)
+	struct completion drv_start_complete;
+#endif
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 	struct dentry *dbgfs_drv;
@@ -1736,6 +1739,9 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans)
 	drv->dev = trans->dev;
 
 	init_completion(&drv->request_firmware_complete);
+#if defined(__FreeBSD__)
+	init_completion(&drv->drv_start_complete);
+#endif
 	INIT_LIST_HEAD(&drv->list);
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -1763,6 +1769,7 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans)
 	 * returned before it was all done that is what could happen.
 	 */
 	wait_for_completion(&drv->request_firmware_complete);
+	complete(&drv->drv_start_complete);
 #endif
 
 	return drv;
@@ -1779,7 +1786,11 @@ err:
 
 void iwl_drv_stop(struct iwl_drv *drv)
 {
+#if defined(__linux__)
 	wait_for_completion(&drv->request_firmware_complete);
+#elif defined(__FreeBSD__)
+	wait_for_completion(&drv->drv_start_complete);
+#endif
 
 	_iwl_op_mode_stop(drv);