From 160b82420ab41f1e67fbf2e56dc587837ef39ce0 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Thu, 29 Apr 2010 17:53:33 +0200 Subject: ar9170: wait for asynchronous firmware loading This patch fixes a regression introduced by the following patch: "ar9170: load firmware asynchronously" When we kick off a firmware loading request and then unbind, or disconnect the usb device right away, we get into trouble: > ------------[ cut here ]------------ > WARNING: at lib/kref.c:44 kref_get+0x1c/0x20() > Hardware name: 18666GU > Modules linked in: ar9170usb [...] > Pid: 6588, comm: firmware/ar9170 Not tainted 2.6.34-rc5-wl #43 > Call Trace: > [] ? warn_slowpath_common+0x6e/0xb0 > [] ? kref_get+0x1c/0x20 > [] ? warn_slowpath_null+0x13/0x20 > [] ? kref_get+0x1c/0x20 > [] ? kobject_get+0xf/0x20 > [] ? get_device+0x10/0x20 > [] ? device_add+0x60/0x530 > [] ? kobject_init+0x25/0xa0 > [] ? _request_firmware+0x139/0x3e0 > [] ? request_firmware_work_func+0x20/0x70 > [] ? request_firmware_work_func+0x0/0x70 > [] ? kthread+0x74/0x80 > [] ? kthread+0x0/0x80 > [] ? kernel_thread_helper+0x6/0x10 >---[ end trace 2d50bd818f64a1b7 ]--- - followed by a random Oops - Avoid that by waiting for the firmware loading to finish (whether successfully or not) before the unbind in ar9170_usb_disconnect. Reported-by: Johannes Berg Bug-fixed-by: Johannes Berg Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/usb.c | 11 +++++++++++ drivers/net/wireless/ath/ar9170/usb.h | 1 + 2 files changed, 12 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index 6b1cb706e41..24dc555f5ff 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -726,12 +726,16 @@ static void ar9170_usb_firmware_failed(struct ar9170_usb *aru) { struct device *parent = aru->udev->dev.parent; + complete(&aru->firmware_loading_complete); + /* unbind anything failed */ if (parent) down(&parent->sem); device_release_driver(&aru->udev->dev); if (parent) up(&parent->sem); + + usb_put_dev(aru->udev); } static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context) @@ -760,6 +764,8 @@ static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context) if (err) goto err_unrx; + complete(&aru->firmware_loading_complete); + usb_put_dev(aru->udev); return; err_unrx: @@ -857,6 +863,7 @@ static int ar9170_usb_probe(struct usb_interface *intf, init_usb_anchor(&aru->tx_pending); init_usb_anchor(&aru->tx_submitted); init_completion(&aru->cmd_wait); + init_completion(&aru->firmware_loading_complete); spin_lock_init(&aru->tx_urb_lock); aru->tx_pending_urbs = 0; @@ -876,6 +883,7 @@ static int ar9170_usb_probe(struct usb_interface *intf, if (err) goto err_freehw; + usb_get_dev(aru->udev); return request_firmware_nowait(THIS_MODULE, 1, "ar9170.fw", &aru->udev->dev, GFP_KERNEL, aru, ar9170_usb_firmware_step2); @@ -895,6 +903,9 @@ static void ar9170_usb_disconnect(struct usb_interface *intf) return; aru->common.state = AR9170_IDLE; + + wait_for_completion(&aru->firmware_loading_complete); + ar9170_unregister(&aru->common); ar9170_usb_cancel_urbs(aru); diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h index a2ce3b169ce..919b06046eb 100644 --- a/drivers/net/wireless/ath/ar9170/usb.h +++ b/drivers/net/wireless/ath/ar9170/usb.h @@ -71,6 +71,7 @@ struct ar9170_usb { unsigned int tx_pending_urbs; struct completion cmd_wait; + struct completion firmware_loading_complete; int readlen; u8 *readbuf; -- cgit v1.2.3-70-g09d2 From 562db532760827f6ce30801a08e6b568848bc9f2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 29 Apr 2010 07:41:53 -0700 Subject: iwlagn: wait for asynchronous firmware loading When we kick off a firmware loading process, and then unbind from the pci device right away, we get into trouble. Avoid that by waiting for the firmware loading to finish (whether successfully or not) before the unbind in iwl_pci_remove. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre --- drivers/net/wireless/iwlwifi/iwl-agn.c | 6 ++++++ drivers/net/wireless/iwlwifi/iwl-dev.h | 2 ++ 2 files changed, 8 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ba0fdba602c..ae8eb09f801 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1741,6 +1741,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) /* We have our copies now, allow OS release its copies */ release_firmware(ucode_raw); + complete(&priv->firmware_loading_complete); return; try_again: @@ -1754,6 +1755,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) IWL_ERR(priv, "failed to allocate pci memory\n"); iwl_dealloc_ucode_pci(priv); out_unbind: + complete(&priv->firmware_loading_complete); device_release_driver(&priv->pci_dev->dev); release_firmware(ucode_raw); } @@ -3671,6 +3673,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iwl_power_initialize(priv); iwl_tt_initialize(priv); + init_completion(&priv->firmware_loading_complete); + err = iwl_request_firmware(priv, true); if (err) goto out_remove_sysfs; @@ -3711,6 +3715,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) if (!priv) return; + wait_for_completion(&priv->firmware_loading_complete); + IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n"); iwl_dbgfs_unregister(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index ef1720a852e..4d4c6516430 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1304,6 +1304,8 @@ struct iwl_priv { struct delayed_work alive_start; struct delayed_work scan_check; + struct completion firmware_loading_complete; + /*For 3945 only*/ struct delayed_work thermal_periodic; struct delayed_work rfkill_poll; -- cgit v1.2.3-70-g09d2