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 | } |
