aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjoern A. Zeeb <bz@FreeBSD.org>2022-11-22 17:29:41 +0000
committerBjoern A. Zeeb <bz@FreeBSD.org>2022-11-22 17:29:41 +0000
commitbee60c98974593d25aa18743f9413a78e0d57dc9 (patch)
tree47f5ebe1693fad911720e5be0a7dabdd01e72a1e
parent8576f84bc1d75c2bae0a41ccb6ebe5de08479a06 (diff)
downloadsrc-bee60c98974593d25aa18743f9413a78e0d57dc9.tar.gz
src-bee60c98974593d25aa18743f9413a78e0d57dc9.zip
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 MFC after: 3 days
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-drv.c11
1 files changed, 11 insertions, 0 deletions
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);