diff options
author | Larry Finger <Larry.Finger@lwfinger.net> | 2012-02-05 22:12:26 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-02-08 17:14:15 -0500 |
commit | 8c213fa59199f9673d66970d6940fa093186642f (patch) | |
tree | e7357cf1101a7b1451ab4b5c05245c34ad97436a | |
parent | 737912e11bf5bd4874acc771d8511a6eab891fc5 (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.h | 7 | ||||
-rw-r--r-- | drivers/staging/rtl8712/hal_init.c | 62 | ||||
-rw-r--r-- | drivers/staging/rtl8712/os_intfs.c | 14 | ||||
-rw-r--r-- | drivers/staging/rtl8712/rtl8712_hal.h | 1 | ||||
-rw-r--r-- | drivers/staging/rtl8712/usb_intf.c | 9 |
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 | ||
41 | enum _NIC_VERSION { | 43 | enum _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 | ||
189 | static inline u8 *myid(struct eeprom_priv *peepriv) | 196 | static 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 | ||
45 | static u32 rtl871x_open_fw(struct _adapter *padapter, void **pphfwfile_hdl, | 45 | static 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 | |||
65 | static const char firmware_file[] = "rtlwifi/rtl8712u.bin"; | ||
66 | |||
67 | int 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 | } | ||
81 | MODULE_FIRMWARE("rtlwifi/rtl8712u.bin"); | ||
82 | |||
83 | static 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 | } |
67 | MODULE_FIRMWARE("rtlwifi/rtl8712u.bin"); | ||
68 | 95 | ||
69 | static void fill_fwpriv(struct _adapter *padapter, struct fw_priv *pfwpriv) | 96 | static 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 | ||
298 | exit_fail: | 324 | exit_fail: |
299 | kfree(ptmpchar); | 325 | kfree(ptmpchar); |
300 | firmware_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) | |||
264 | void r8712_stop_drv_timers(struct _adapter *padapter) | 265 | void 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 | ||
275 | static u8 init_default_value(struct _adapter *padapter) | 276 | static 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; |
439 | netdev_open_error: | 443 | netdev_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 | ||
147 | uint rtl8712_hal_init(struct _adapter *padapter); | 147 | uint rtl8712_hal_init(struct _adapter *padapter); |
148 | int 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; |
604 | error: | 606 | error: |
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 | } |