aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLarry Finger <Larry.Finger@lwfinger.net>2012-02-05 22:12:26 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-02-08 17:14:15 -0500
commit8c213fa59199f9673d66970d6940fa093186642f (patch)
treee7357cf1101a7b1451ab4b5c05245c34ad97436a
parent737912e11bf5bd4874acc771d8511a6eab891fc5 (diff)
staging: r8712u: Use asynchronous firmware loading
In https://bugs.archlinux.org/task/27996, failure of driver r8712u is reported, with a timeout during module loading due to synchronous loading of the firmware. The code now uses request_firmware_nowait(). Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/staging/rtl8712/drv_types.h7
-rw-r--r--drivers/staging/rtl8712/hal_init.c62
-rw-r--r--drivers/staging/rtl8712/os_intfs.c14
-rw-r--r--drivers/staging/rtl8712/rtl8712_hal.h1
-rw-r--r--drivers/staging/rtl8712/usb_intf.c9
5 files changed, 68 insertions, 25 deletions
diff --git a/drivers/staging/rtl8712/drv_types.h b/drivers/staging/rtl8712/drv_types.h
index 9b5d771e650c..ed85b4415207 100644
--- a/drivers/staging/rtl8712/drv_types.h
+++ b/drivers/staging/rtl8712/drv_types.h
@@ -37,6 +37,8 @@ struct _adapter;
37#include "wlan_bssdef.h" 37#include "wlan_bssdef.h"
38#include "rtl8712_spec.h" 38#include "rtl8712_spec.h"
39#include "rtl8712_hal.h" 39#include "rtl8712_hal.h"
40#include <linux/mutex.h>
41#include <linux/completion.h>
40 42
41enum _NIC_VERSION { 43enum _NIC_VERSION {
42 RTL8711_NIC, 44 RTL8711_NIC,
@@ -168,6 +170,7 @@ struct _adapter {
168 s32 bSurpriseRemoved; 170 s32 bSurpriseRemoved;
169 u32 IsrContent; 171 u32 IsrContent;
170 u32 ImrContent; 172 u32 ImrContent;
173 bool fw_found;
171 u8 EepromAddressSize; 174 u8 EepromAddressSize;
172 u8 hw_init_completed; 175 u8 hw_init_completed;
173 struct task_struct *cmdThread; 176 struct task_struct *cmdThread;
@@ -184,6 +187,10 @@ struct _adapter {
184 _workitem wkFilterRxFF0; 187 _workitem wkFilterRxFF0;
185 u8 blnEnableRxFF0Filter; 188 u8 blnEnableRxFF0Filter;
186 spinlock_t lockRxFF0Filter; 189 spinlock_t lockRxFF0Filter;
190 const struct firmware *fw;
191 struct usb_interface *pusb_intf;
192 struct mutex mutex_start;
193 struct completion rtl8712_fw_ready;
187}; 194};
188 195
189static inline u8 *myid(struct eeprom_priv *peepriv) 196static inline u8 *myid(struct eeprom_priv *peepriv)
diff --git a/drivers/staging/rtl8712/hal_init.c b/drivers/staging/rtl8712/hal_init.c
index d0029aa4cd3c..cc893c0f5ad3 100644
--- a/drivers/staging/rtl8712/hal_init.c
+++ b/drivers/staging/rtl8712/hal_init.c
@@ -42,29 +42,56 @@
42#define FWBUFF_ALIGN_SZ 512 42#define FWBUFF_ALIGN_SZ 512
43#define MAX_DUMP_FWSZ 49152 /*default = 49152 (48k)*/ 43#define MAX_DUMP_FWSZ 49152 /*default = 49152 (48k)*/
44 44
45static u32 rtl871x_open_fw(struct _adapter *padapter, void **pphfwfile_hdl, 45static void rtl871x_load_fw_cb(const struct firmware *firmware, void *context)
46 const u8 **ppmappedfw)
47{ 46{
47 struct _adapter *padapter = context;
48
49 complete(&padapter->rtl8712_fw_ready);
50 if (!firmware) {
51 struct usb_device *udev = padapter->dvobjpriv.pusbdev;
52 struct usb_interface *pusb_intf = padapter->pusb_intf;
53 printk(KERN_ERR "r8712u: Firmware request failed\n");
54 padapter->fw_found = false;
55 usb_put_dev(udev);
56 usb_set_intfdata(pusb_intf, NULL);
57 return;
58 }
59 padapter->fw = firmware;
60 padapter->fw_found = true;
61 /* firmware available - start netdev */
62 register_netdev(padapter->pnetdev);
63}
64
65static const char firmware_file[] = "rtlwifi/rtl8712u.bin";
66
67int rtl871x_load_fw(struct _adapter *padapter)
68{
69 struct device *dev = &padapter->dvobjpriv.pusbdev->dev;
48 int rc; 70 int rc;
49 const char firmware_file[] = "rtlwifi/rtl8712u.bin";
50 const struct firmware **praw = (const struct firmware **)
51 (pphfwfile_hdl);
52 struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)
53 (&padapter->dvobjpriv);
54 struct usb_device *pusbdev = pdvobjpriv->pusbdev;
55 71
72 init_completion(&padapter->rtl8712_fw_ready);
56 printk(KERN_INFO "r8712u: Loading firmware from \"%s\"\n", 73 printk(KERN_INFO "r8712u: Loading firmware from \"%s\"\n",
57 firmware_file); 74 firmware_file);
58 rc = request_firmware(praw, firmware_file, &pusbdev->dev); 75 rc = request_firmware_nowait(THIS_MODULE, 1, firmware_file, dev,
59 if (rc < 0) { 76 GFP_KERNEL, padapter, rtl871x_load_fw_cb);
60 printk(KERN_ERR "r8712u: Unable to load firmware\n"); 77 if (rc)
61 printk(KERN_ERR "r8712u: Install latest linux-firmware\n"); 78 printk(KERN_ERR "r8712u: Firmware request error %d\n", rc);
79 return rc;
80}
81MODULE_FIRMWARE("rtlwifi/rtl8712u.bin");
82
83static u32 rtl871x_open_fw(struct _adapter *padapter, const u8 **ppmappedfw)
84{
85 const struct firmware **praw = &padapter->fw;
86
87 if (padapter->fw->size > 200000) {
88 printk(KERN_ERR "r8172u: Badfw->size of %d\n",
89 (int)padapter->fw->size);
62 return 0; 90 return 0;
63 } 91 }
64 *ppmappedfw = (u8 *)((*praw)->data); 92 *ppmappedfw = (u8 *)((*praw)->data);
65 return (*praw)->size; 93 return (*praw)->size;
66} 94}
67MODULE_FIRMWARE("rtlwifi/rtl8712u.bin");
68 95
69static void fill_fwpriv(struct _adapter *padapter, struct fw_priv *pfwpriv) 96static void fill_fwpriv(struct _adapter *padapter, struct fw_priv *pfwpriv)
70{ 97{
@@ -142,18 +169,17 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter)
142 uint dump_imem_sz, imem_sz, dump_emem_sz, emem_sz; /* max = 49152; */ 169 uint dump_imem_sz, imem_sz, dump_emem_sz, emem_sz; /* max = 49152; */
143 struct fw_hdr fwhdr; 170 struct fw_hdr fwhdr;
144 u32 ulfilelength; /* FW file size */ 171 u32 ulfilelength; /* FW file size */
145 void *phfwfile_hdl = NULL;
146 const u8 *pmappedfw = NULL; 172 const u8 *pmappedfw = NULL;
147 u8 *ptmpchar = NULL, *ppayload, *ptr; 173 u8 *ptmpchar = NULL, *ppayload, *ptr;
148 struct tx_desc *ptx_desc; 174 struct tx_desc *ptx_desc;
149 u32 txdscp_sz = sizeof(struct tx_desc); 175 u32 txdscp_sz = sizeof(struct tx_desc);
150 u8 ret = _FAIL; 176 u8 ret = _FAIL;
151 177
152 ulfilelength = rtl871x_open_fw(padapter, &phfwfile_hdl, &pmappedfw); 178 ulfilelength = rtl871x_open_fw(padapter, &pmappedfw);
153 if (pmappedfw && (ulfilelength > 0)) { 179 if (pmappedfw && (ulfilelength > 0)) {
154 update_fwhdr(&fwhdr, pmappedfw); 180 update_fwhdr(&fwhdr, pmappedfw);
155 if (chk_fwhdr(&fwhdr, ulfilelength) == _FAIL) 181 if (chk_fwhdr(&fwhdr, ulfilelength) == _FAIL)
156 goto firmware_rel; 182 return ret;
157 fill_fwpriv(padapter, &fwhdr.fwpriv); 183 fill_fwpriv(padapter, &fwhdr.fwpriv);
158 /* firmware check ok */ 184 /* firmware check ok */
159 maxlen = (fwhdr.img_IMEM_size > fwhdr.img_SRAM_size) ? 185 maxlen = (fwhdr.img_IMEM_size > fwhdr.img_SRAM_size) ?
@@ -161,7 +187,7 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter)
161 maxlen += txdscp_sz; 187 maxlen += txdscp_sz;
162 ptmpchar = _malloc(maxlen + FWBUFF_ALIGN_SZ); 188 ptmpchar = _malloc(maxlen + FWBUFF_ALIGN_SZ);
163 if (ptmpchar == NULL) 189 if (ptmpchar == NULL)
164 goto firmware_rel; 190 return ret;
165 191
166 ptx_desc = (struct tx_desc *)(ptmpchar + FWBUFF_ALIGN_SZ - 192 ptx_desc = (struct tx_desc *)(ptmpchar + FWBUFF_ALIGN_SZ -
167 ((addr_t)(ptmpchar) & (FWBUFF_ALIGN_SZ - 1))); 193 ((addr_t)(ptmpchar) & (FWBUFF_ALIGN_SZ - 1)));
@@ -297,8 +323,6 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter)
297 323
298exit_fail: 324exit_fail:
299 kfree(ptmpchar); 325 kfree(ptmpchar);
300firmware_rel:
301 release_firmware((struct firmware *)phfwfile_hdl);
302 return ret; 326 return ret;
303} 327}
304 328
diff --git a/drivers/staging/rtl8712/os_intfs.c b/drivers/staging/rtl8712/os_intfs.c
index 9a75c6dbe505..98a3d684f9b2 100644
--- a/drivers/staging/rtl8712/os_intfs.c
+++ b/drivers/staging/rtl8712/os_intfs.c
@@ -31,6 +31,7 @@
31#include <linux/module.h> 31#include <linux/module.h>
32#include <linux/init.h> 32#include <linux/init.h>
33#include <linux/kthread.h> 33#include <linux/kthread.h>
34#include <linux/firmware.h>
34#include "osdep_service.h" 35#include "osdep_service.h"
35#include "drv_types.h" 36#include "drv_types.h"
36#include "xmit_osdep.h" 37#include "xmit_osdep.h"
@@ -264,12 +265,12 @@ static void start_drv_timers(struct _adapter *padapter)
264void r8712_stop_drv_timers(struct _adapter *padapter) 265void r8712_stop_drv_timers(struct _adapter *padapter)
265{ 266{
266 _cancel_timer_ex(&padapter->mlmepriv.assoc_timer); 267 _cancel_timer_ex(&padapter->mlmepriv.assoc_timer);
267 _cancel_timer_ex(&padapter->mlmepriv.sitesurveyctrl.
268 sitesurvey_ctrl_timer);
269 _cancel_timer_ex(&padapter->securitypriv.tkip_timer); 268 _cancel_timer_ex(&padapter->securitypriv.tkip_timer);
270 _cancel_timer_ex(&padapter->mlmepriv.scan_to_timer); 269 _cancel_timer_ex(&padapter->mlmepriv.scan_to_timer);
271 _cancel_timer_ex(&padapter->mlmepriv.dhcp_timer); 270 _cancel_timer_ex(&padapter->mlmepriv.dhcp_timer);
272 _cancel_timer_ex(&padapter->mlmepriv.wdg_timer); 271 _cancel_timer_ex(&padapter->mlmepriv.wdg_timer);
272 _cancel_timer_ex(&padapter->mlmepriv.sitesurveyctrl.
273 sitesurvey_ctrl_timer);
273} 274}
274 275
275static u8 init_default_value(struct _adapter *padapter) 276static u8 init_default_value(struct _adapter *padapter)
@@ -347,7 +348,8 @@ u8 r8712_free_drv_sw(struct _adapter *padapter)
347 r8712_free_mlme_priv(&padapter->mlmepriv); 348 r8712_free_mlme_priv(&padapter->mlmepriv);
348 r8712_free_io_queue(padapter); 349 r8712_free_io_queue(padapter);
349 _free_xmit_priv(&padapter->xmitpriv); 350 _free_xmit_priv(&padapter->xmitpriv);
350 _r8712_free_sta_priv(&padapter->stapriv); 351 if (padapter->fw_found)
352 _r8712_free_sta_priv(&padapter->stapriv);
351 _r8712_free_recv_priv(&padapter->recvpriv); 353 _r8712_free_recv_priv(&padapter->recvpriv);
352 mp871xdeinit(padapter); 354 mp871xdeinit(padapter);
353 if (pnetdev) 355 if (pnetdev)
@@ -388,6 +390,7 @@ static int netdev_open(struct net_device *pnetdev)
388{ 390{
389 struct _adapter *padapter = (struct _adapter *)netdev_priv(pnetdev); 391 struct _adapter *padapter = (struct _adapter *)netdev_priv(pnetdev);
390 392
393 mutex_lock(&padapter->mutex_start);
391 if (padapter->bup == false) { 394 if (padapter->bup == false) {
392 padapter->bDriverStopped = false; 395 padapter->bDriverStopped = false;
393 padapter->bSurpriseRemoved = false; 396 padapter->bSurpriseRemoved = false;
@@ -435,11 +438,13 @@ static int netdev_open(struct net_device *pnetdev)
435 /* start driver mlme relation timer */ 438 /* start driver mlme relation timer */
436 start_drv_timers(padapter); 439 start_drv_timers(padapter);
437 padapter->ledpriv.LedControlHandler(padapter, LED_CTL_NO_LINK); 440 padapter->ledpriv.LedControlHandler(padapter, LED_CTL_NO_LINK);
441 mutex_unlock(&padapter->mutex_start);
438 return 0; 442 return 0;
439netdev_open_error: 443netdev_open_error:
440 padapter->bup = false; 444 padapter->bup = false;
441 netif_carrier_off(pnetdev); 445 netif_carrier_off(pnetdev);
442 netif_stop_queue(pnetdev); 446 netif_stop_queue(pnetdev);
447 mutex_unlock(&padapter->mutex_start);
443 return -1; 448 return -1;
444} 449}
445 450
@@ -473,6 +478,9 @@ static int netdev_close(struct net_device *pnetdev)
473 r8712_free_network_queue(padapter); 478 r8712_free_network_queue(padapter);
474 /* The interface is no longer Up: */ 479 /* The interface is no longer Up: */
475 padapter->bup = false; 480 padapter->bup = false;
481 release_firmware(padapter->fw);
482 /* never exit with a firmware callback pending */
483 wait_for_completion(&padapter->rtl8712_fw_ready);
476 return 0; 484 return 0;
477} 485}
478 486
diff --git a/drivers/staging/rtl8712/rtl8712_hal.h b/drivers/staging/rtl8712/rtl8712_hal.h
index 665e71838172..d19865a5a50c 100644
--- a/drivers/staging/rtl8712/rtl8712_hal.h
+++ b/drivers/staging/rtl8712/rtl8712_hal.h
@@ -145,5 +145,6 @@ struct hal_priv {
145}; 145};
146 146
147uint rtl8712_hal_init(struct _adapter *padapter); 147uint rtl8712_hal_init(struct _adapter *padapter);
148int rtl871x_load_fw(struct _adapter *padapter);
148 149
149#endif 150#endif
diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c
index 8de0c80ebf8a..9bade184883b 100644
--- a/drivers/staging/rtl8712/usb_intf.c
+++ b/drivers/staging/rtl8712/usb_intf.c
@@ -390,6 +390,7 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf,
390 pdvobjpriv = &padapter->dvobjpriv; 390 pdvobjpriv = &padapter->dvobjpriv;
391 pdvobjpriv->padapter = padapter; 391 pdvobjpriv->padapter = padapter;
392 padapter->dvobjpriv.pusbdev = udev; 392 padapter->dvobjpriv.pusbdev = udev;
393 padapter->pusb_intf = pusb_intf;
393 usb_set_intfdata(pusb_intf, pnetdev); 394 usb_set_intfdata(pusb_intf, pnetdev);
394 SET_NETDEV_DEV(pnetdev, &pusb_intf->dev); 395 SET_NETDEV_DEV(pnetdev, &pusb_intf->dev);
395 /* step 2. */ 396 /* step 2. */
@@ -596,10 +597,11 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf,
596 "%pM\n", mac); 597 "%pM\n", mac);
597 memcpy(pnetdev->dev_addr, mac, ETH_ALEN); 598 memcpy(pnetdev->dev_addr, mac, ETH_ALEN);
598 } 599 }
599 /* step 6. Tell the network stack we exist */ 600 /* step 6. Load the firmware asynchronously */
600 if (register_netdev(pnetdev) != 0) 601 if (rtl871x_load_fw(padapter))
601 goto error; 602 goto error;
602 spin_lock_init(&padapter->lockRxFF0Filter); 603 spin_lock_init(&padapter->lockRxFF0Filter);
604 mutex_init(&padapter->mutex_start);
603 return 0; 605 return 0;
604error: 606error:
605 usb_put_dev(udev); 607 usb_put_dev(udev);
@@ -630,7 +632,8 @@ static void r871xu_dev_remove(struct usb_interface *pusb_intf)
630 flush_scheduled_work(); 632 flush_scheduled_work();
631 udelay(1); 633 udelay(1);
632 /*Stop driver mlme relation timer */ 634 /*Stop driver mlme relation timer */
633 r8712_stop_drv_timers(padapter); 635 if (padapter->fw_found)
636 r8712_stop_drv_timers(padapter);
634 r871x_dev_unload(padapter); 637 r871x_dev_unload(padapter);
635 r8712_free_drv_sw(padapter); 638 r8712_free_drv_sw(padapter);
636 } 639 }