Skip to content

Commit 8c213fa

Browse files
lwfingergregkh
authored andcommitted
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 <[email protected]> Cc: stable <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 737912e commit 8c213fa

File tree

5 files changed

+68
-25
lines changed

5 files changed

+68
-25
lines changed

drivers/staging/rtl8712/drv_types.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ struct _adapter;
3737
#include "wlan_bssdef.h"
3838
#include "rtl8712_spec.h"
3939
#include "rtl8712_hal.h"
40+
#include <linux/mutex.h>
41+
#include <linux/completion.h>
4042

4143
enum _NIC_VERSION {
4244
RTL8711_NIC,
@@ -168,6 +170,7 @@ struct _adapter {
168170
s32 bSurpriseRemoved;
169171
u32 IsrContent;
170172
u32 ImrContent;
173+
bool fw_found;
171174
u8 EepromAddressSize;
172175
u8 hw_init_completed;
173176
struct task_struct *cmdThread;
@@ -184,6 +187,10 @@ struct _adapter {
184187
_workitem wkFilterRxFF0;
185188
u8 blnEnableRxFF0Filter;
186189
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;
187194
};
188195

189196
static inline u8 *myid(struct eeprom_priv *peepriv)

drivers/staging/rtl8712/hal_init.c

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -42,29 +42,56 @@
4242
#define FWBUFF_ALIGN_SZ 512
4343
#define MAX_DUMP_FWSZ 49152 /*default = 49152 (48k)*/
4444

45-
static u32 rtl871x_open_fw(struct _adapter *padapter, void **pphfwfile_hdl,
46-
const u8 **ppmappedfw)
45+
static void rtl871x_load_fw_cb(const struct firmware *firmware, void *context)
4746
{
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;
4870
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;
5571

72+
init_completion(&padapter->rtl8712_fw_ready);
5673
printk(KERN_INFO "r8712u: Loading firmware from \"%s\"\n",
5774
firmware_file);
58-
rc = request_firmware(praw, firmware_file, &pusbdev->dev);
59-
if (rc < 0) {
60-
printk(KERN_ERR "r8712u: Unable to load firmware\n");
61-
printk(KERN_ERR "r8712u: Install latest linux-firmware\n");
75+
rc = request_firmware_nowait(THIS_MODULE, 1, firmware_file, dev,
76+
GFP_KERNEL, padapter, rtl871x_load_fw_cb);
77+
if (rc)
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);
6290
return 0;
6391
}
6492
*ppmappedfw = (u8 *)((*praw)->data);
6593
return (*praw)->size;
6694
}
67-
MODULE_FIRMWARE("rtlwifi/rtl8712u.bin");
6895

6996
static void fill_fwpriv(struct _adapter *padapter, struct fw_priv *pfwpriv)
7097
{
@@ -142,26 +169,25 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter)
142169
uint dump_imem_sz, imem_sz, dump_emem_sz, emem_sz; /* max = 49152; */
143170
struct fw_hdr fwhdr;
144171
u32 ulfilelength; /* FW file size */
145-
void *phfwfile_hdl = NULL;
146172
const u8 *pmappedfw = NULL;
147173
u8 *ptmpchar = NULL, *ppayload, *ptr;
148174
struct tx_desc *ptx_desc;
149175
u32 txdscp_sz = sizeof(struct tx_desc);
150176
u8 ret = _FAIL;
151177

152-
ulfilelength = rtl871x_open_fw(padapter, &phfwfile_hdl, &pmappedfw);
178+
ulfilelength = rtl871x_open_fw(padapter, &pmappedfw);
153179
if (pmappedfw && (ulfilelength > 0)) {
154180
update_fwhdr(&fwhdr, pmappedfw);
155181
if (chk_fwhdr(&fwhdr, ulfilelength) == _FAIL)
156-
goto firmware_rel;
182+
return ret;
157183
fill_fwpriv(padapter, &fwhdr.fwpriv);
158184
/* firmware check ok */
159185
maxlen = (fwhdr.img_IMEM_size > fwhdr.img_SRAM_size) ?
160186
fwhdr.img_IMEM_size : fwhdr.img_SRAM_size;
161187
maxlen += txdscp_sz;
162188
ptmpchar = _malloc(maxlen + FWBUFF_ALIGN_SZ);
163189
if (ptmpchar == NULL)
164-
goto firmware_rel;
190+
return ret;
165191

166192
ptx_desc = (struct tx_desc *)(ptmpchar + FWBUFF_ALIGN_SZ -
167193
((addr_t)(ptmpchar) & (FWBUFF_ALIGN_SZ - 1)));
@@ -297,8 +323,6 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter)
297323

298324
exit_fail:
299325
kfree(ptmpchar);
300-
firmware_rel:
301-
release_firmware((struct firmware *)phfwfile_hdl);
302326
return ret;
303327
}
304328

drivers/staging/rtl8712/os_intfs.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <linux/module.h>
3232
#include <linux/init.h>
3333
#include <linux/kthread.h>
34+
#include <linux/firmware.h>
3435
#include "osdep_service.h"
3536
#include "drv_types.h"
3637
#include "xmit_osdep.h"
@@ -264,12 +265,12 @@ static void start_drv_timers(struct _adapter *padapter)
264265
void r8712_stop_drv_timers(struct _adapter *padapter)
265266
{
266267
_cancel_timer_ex(&padapter->mlmepriv.assoc_timer);
267-
_cancel_timer_ex(&padapter->mlmepriv.sitesurveyctrl.
268-
sitesurvey_ctrl_timer);
269268
_cancel_timer_ex(&padapter->securitypriv.tkip_timer);
270269
_cancel_timer_ex(&padapter->mlmepriv.scan_to_timer);
271270
_cancel_timer_ex(&padapter->mlmepriv.dhcp_timer);
272271
_cancel_timer_ex(&padapter->mlmepriv.wdg_timer);
272+
_cancel_timer_ex(&padapter->mlmepriv.sitesurveyctrl.
273+
sitesurvey_ctrl_timer);
273274
}
274275

275276
static u8 init_default_value(struct _adapter *padapter)
@@ -347,7 +348,8 @@ u8 r8712_free_drv_sw(struct _adapter *padapter)
347348
r8712_free_mlme_priv(&padapter->mlmepriv);
348349
r8712_free_io_queue(padapter);
349350
_free_xmit_priv(&padapter->xmitpriv);
350-
_r8712_free_sta_priv(&padapter->stapriv);
351+
if (padapter->fw_found)
352+
_r8712_free_sta_priv(&padapter->stapriv);
351353
_r8712_free_recv_priv(&padapter->recvpriv);
352354
mp871xdeinit(padapter);
353355
if (pnetdev)
@@ -388,6 +390,7 @@ static int netdev_open(struct net_device *pnetdev)
388390
{
389391
struct _adapter *padapter = (struct _adapter *)netdev_priv(pnetdev);
390392

393+
mutex_lock(&padapter->mutex_start);
391394
if (padapter->bup == false) {
392395
padapter->bDriverStopped = false;
393396
padapter->bSurpriseRemoved = false;
@@ -435,11 +438,13 @@ static int netdev_open(struct net_device *pnetdev)
435438
/* start driver mlme relation timer */
436439
start_drv_timers(padapter);
437440
padapter->ledpriv.LedControlHandler(padapter, LED_CTL_NO_LINK);
441+
mutex_unlock(&padapter->mutex_start);
438442
return 0;
439443
netdev_open_error:
440444
padapter->bup = false;
441445
netif_carrier_off(pnetdev);
442446
netif_stop_queue(pnetdev);
447+
mutex_unlock(&padapter->mutex_start);
443448
return -1;
444449
}
445450

@@ -473,6 +478,9 @@ static int netdev_close(struct net_device *pnetdev)
473478
r8712_free_network_queue(padapter);
474479
/* The interface is no longer Up: */
475480
padapter->bup = false;
481+
release_firmware(padapter->fw);
482+
/* never exit with a firmware callback pending */
483+
wait_for_completion(&padapter->rtl8712_fw_ready);
476484
return 0;
477485
}
478486

drivers/staging/rtl8712/rtl8712_hal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,5 +145,6 @@ struct hal_priv {
145145
};
146146

147147
uint rtl8712_hal_init(struct _adapter *padapter);
148+
int rtl871x_load_fw(struct _adapter *padapter);
148149

149150
#endif

drivers/staging/rtl8712/usb_intf.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf,
390390
pdvobjpriv = &padapter->dvobjpriv;
391391
pdvobjpriv->padapter = padapter;
392392
padapter->dvobjpriv.pusbdev = udev;
393+
padapter->pusb_intf = pusb_intf;
393394
usb_set_intfdata(pusb_intf, pnetdev);
394395
SET_NETDEV_DEV(pnetdev, &pusb_intf->dev);
395396
/* step 2. */
@@ -596,10 +597,11 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf,
596597
"%pM\n", mac);
597598
memcpy(pnetdev->dev_addr, mac, ETH_ALEN);
598599
}
599-
/* step 6. Tell the network stack we exist */
600-
if (register_netdev(pnetdev) != 0)
600+
/* step 6. Load the firmware asynchronously */
601+
if (rtl871x_load_fw(padapter))
601602
goto error;
602603
spin_lock_init(&padapter->lockRxFF0Filter);
604+
mutex_init(&padapter->mutex_start);
603605
return 0;
604606
error:
605607
usb_put_dev(udev);
@@ -630,7 +632,8 @@ static void r871xu_dev_remove(struct usb_interface *pusb_intf)
630632
flush_scheduled_work();
631633
udelay(1);
632634
/*Stop driver mlme relation timer */
633-
r8712_stop_drv_timers(padapter);
635+
if (padapter->fw_found)
636+
r8712_stop_drv_timers(padapter);
634637
r871x_dev_unload(padapter);
635638
r8712_free_drv_sw(padapter);
636639
}

0 commit comments

Comments
 (0)