diff options
author | Bjoern A. Zeeb <bz@FreeBSD.org> | 2022-11-22 17:29:41 +0000 |
---|---|---|
committer | Bjoern A. Zeeb <bz@FreeBSD.org> | 2022-11-22 17:29:41 +0000 |
commit | bee60c98974593d25aa18743f9413a78e0d57dc9 (patch) | |
tree | 47f5ebe1693fad911720e5be0a7dabdd01e72a1e | |
parent | 8576f84bc1d75c2bae0a41ccb6ebe5de08479a06 (diff) | |
download | src-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.c | 11 |
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); |