Commit 8c213fa5 authored by Larry Finger's avatar Larry Finger Committed by Greg Kroah-Hartman

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: default avatarLarry Finger <Larry.Finger@lwfinger.net>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 737912e1
...@@ -37,6 +37,8 @@ struct _adapter; ...@@ -37,6 +37,8 @@ struct _adapter;
#include "wlan_bssdef.h" #include "wlan_bssdef.h"
#include "rtl8712_spec.h" #include "rtl8712_spec.h"
#include "rtl8712_hal.h" #include "rtl8712_hal.h"
#include <linux/mutex.h>
#include <linux/completion.h>
enum _NIC_VERSION { enum _NIC_VERSION {
RTL8711_NIC, RTL8711_NIC,
...@@ -168,6 +170,7 @@ struct _adapter { ...@@ -168,6 +170,7 @@ struct _adapter {
s32 bSurpriseRemoved; s32 bSurpriseRemoved;
u32 IsrContent; u32 IsrContent;
u32 ImrContent; u32 ImrContent;
bool fw_found;
u8 EepromAddressSize; u8 EepromAddressSize;
u8 hw_init_completed; u8 hw_init_completed;
struct task_struct *cmdThread; struct task_struct *cmdThread;
...@@ -184,6 +187,10 @@ struct _adapter { ...@@ -184,6 +187,10 @@ struct _adapter {
_workitem wkFilterRxFF0; _workitem wkFilterRxFF0;
u8 blnEnableRxFF0Filter; u8 blnEnableRxFF0Filter;
spinlock_t lockRxFF0Filter; spinlock_t lockRxFF0Filter;
const struct firmware *fw;
struct usb_interface *pusb_intf;
struct mutex mutex_start;
struct completion rtl8712_fw_ready;
}; };
static inline u8 *myid(struct eeprom_priv *peepriv) static inline u8 *myid(struct eeprom_priv *peepriv)
......
...@@ -42,29 +42,56 @@ ...@@ -42,29 +42,56 @@
#define FWBUFF_ALIGN_SZ 512 #define FWBUFF_ALIGN_SZ 512
#define MAX_DUMP_FWSZ 49152 /*default = 49152 (48k)*/ #define MAX_DUMP_FWSZ 49152 /*default = 49152 (48k)*/
static u32 rtl871x_open_fw(struct _adapter *padapter, void **pphfwfile_hdl, static void rtl871x_load_fw_cb(const struct firmware *firmware, void *context)
const u8 **ppmappedfw)
{ {
struct _adapter *padapter = context;
complete(&padapter->rtl8712_fw_ready);
if (!firmware) {
struct usb_device *udev = padapter->dvobjpriv.pusbdev;
struct usb_interface *pusb_intf = padapter->pusb_intf;
printk(KERN_ERR "r8712u: Firmware request failed\n");
padapter->fw_found = false;
usb_put_dev(udev);
usb_set_intfdata(pusb_intf, NULL);
return;
}
padapter->fw = firmware;
padapter->fw_found = true;
/* firmware available - start netdev */
register_netdev(padapter->pnetdev);
}
static const char firmware_file[] = "rtlwifi/rtl8712u.bin";
int rtl871x_load_fw(struct _adapter *padapter)
{
struct device *dev = &padapter->dvobjpriv.pusbdev->dev;
int rc; int rc;
const char firmware_file[] = "rtlwifi/rtl8712u.bin";
const struct firmware **praw = (const struct firmware **)
(pphfwfile_hdl);
struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)
(&padapter->dvobjpriv);
struct usb_device *pusbdev = pdvobjpriv->pusbdev;
init_completion(&padapter->rtl8712_fw_ready);
printk(KERN_INFO "r8712u: Loading firmware from \"%s\"\n", printk(KERN_INFO "r8712u: Loading firmware from \"%s\"\n",
firmware_file); firmware_file);
rc = request_firmware(praw, firmware_file, &pusbdev->dev); rc = request_firmware_nowait(THIS_MODULE, 1, firmware_file, dev,
if (rc < 0) { GFP_KERNEL, padapter, rtl871x_load_fw_cb);
printk(KERN_ERR "r8712u: Unable to load firmware\n"); if (rc)
printk(KERN_ERR "r8712u: Install latest linux-firmware\n"); printk(KERN_ERR "r8712u: Firmware request error %d\n", rc);
return rc;
}
MODULE_FIRMWARE("rtlwifi/rtl8712u.bin");
static u32 rtl871x_open_fw(struct _adapter *padapter, const u8 **ppmappedfw)
{
const struct firmware **praw = &padapter->fw;
if (padapter->fw->size > 200000) {
printk(KERN_ERR "r8172u: Badfw->size of %d\n",
(int)padapter->fw->size);
return 0; return 0;
} }
*ppmappedfw = (u8 *)((*praw)->data); *ppmappedfw = (u8 *)((*praw)->data);
return (*praw)->size; return (*praw)->size;
} }
MODULE_FIRMWARE("rtlwifi/rtl8712u.bin");
static void fill_fwpriv(struct _adapter *padapter, struct fw_priv *pfwpriv) static void fill_fwpriv(struct _adapter *padapter, struct fw_priv *pfwpriv)
{ {
...@@ -142,18 +169,17 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter) ...@@ -142,18 +169,17 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter)
uint dump_imem_sz, imem_sz, dump_emem_sz, emem_sz; /* max = 49152; */ uint dump_imem_sz, imem_sz, dump_emem_sz, emem_sz; /* max = 49152; */
struct fw_hdr fwhdr; struct fw_hdr fwhdr;
u32 ulfilelength; /* FW file size */ u32 ulfilelength; /* FW file size */
void *phfwfile_hdl = NULL;
const u8 *pmappedfw = NULL; const u8 *pmappedfw = NULL;
u8 *ptmpchar = NULL, *ppayload, *ptr; u8 *ptmpchar = NULL, *ppayload, *ptr;
struct tx_desc *ptx_desc; struct tx_desc *ptx_desc;
u32 txdscp_sz = sizeof(struct tx_desc); u32 txdscp_sz = sizeof(struct tx_desc);
u8 ret = _FAIL; u8 ret = _FAIL;
ulfilelength = rtl871x_open_fw(padapter, &phfwfile_hdl, &pmappedfw); ulfilelength = rtl871x_open_fw(padapter, &pmappedfw);
if (pmappedfw && (ulfilelength > 0)) { if (pmappedfw && (ulfilelength > 0)) {
update_fwhdr(&fwhdr, pmappedfw); update_fwhdr(&fwhdr, pmappedfw);
if (chk_fwhdr(&fwhdr, ulfilelength) == _FAIL) if (chk_fwhdr(&fwhdr, ulfilelength) == _FAIL)
goto firmware_rel; return ret;
fill_fwpriv(padapter, &fwhdr.fwpriv); fill_fwpriv(padapter, &fwhdr.fwpriv);
/* firmware check ok */ /* firmware check ok */
maxlen = (fwhdr.img_IMEM_size > fwhdr.img_SRAM_size) ? maxlen = (fwhdr.img_IMEM_size > fwhdr.img_SRAM_size) ?
...@@ -161,7 +187,7 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter) ...@@ -161,7 +187,7 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter)
maxlen += txdscp_sz; maxlen += txdscp_sz;
ptmpchar = _malloc(maxlen + FWBUFF_ALIGN_SZ); ptmpchar = _malloc(maxlen + FWBUFF_ALIGN_SZ);
if (ptmpchar == NULL) if (ptmpchar == NULL)
goto firmware_rel; return ret;
ptx_desc = (struct tx_desc *)(ptmpchar + FWBUFF_ALIGN_SZ - ptx_desc = (struct tx_desc *)(ptmpchar + FWBUFF_ALIGN_SZ -
((addr_t)(ptmpchar) & (FWBUFF_ALIGN_SZ - 1))); ((addr_t)(ptmpchar) & (FWBUFF_ALIGN_SZ - 1)));
...@@ -297,8 +323,6 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter) ...@@ -297,8 +323,6 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter)
exit_fail: exit_fail:
kfree(ptmpchar); kfree(ptmpchar);
firmware_rel:
release_firmware((struct firmware *)phfwfile_hdl);
return ret; return ret;
} }
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/firmware.h>
#include "osdep_service.h" #include "osdep_service.h"
#include "drv_types.h" #include "drv_types.h"
#include "xmit_osdep.h" #include "xmit_osdep.h"
...@@ -264,12 +265,12 @@ static void start_drv_timers(struct _adapter *padapter) ...@@ -264,12 +265,12 @@ static void start_drv_timers(struct _adapter *padapter)
void r8712_stop_drv_timers(struct _adapter *padapter) void r8712_stop_drv_timers(struct _adapter *padapter)
{ {
_cancel_timer_ex(&padapter->mlmepriv.assoc_timer); _cancel_timer_ex(&padapter->mlmepriv.assoc_timer);
_cancel_timer_ex(&padapter->mlmepriv.sitesurveyctrl.
sitesurvey_ctrl_timer);
_cancel_timer_ex(&padapter->securitypriv.tkip_timer); _cancel_timer_ex(&padapter->securitypriv.tkip_timer);
_cancel_timer_ex(&padapter->mlmepriv.scan_to_timer); _cancel_timer_ex(&padapter->mlmepriv.scan_to_timer);
_cancel_timer_ex(&padapter->mlmepriv.dhcp_timer); _cancel_timer_ex(&padapter->mlmepriv.dhcp_timer);
_cancel_timer_ex(&padapter->mlmepriv.wdg_timer); _cancel_timer_ex(&padapter->mlmepriv.wdg_timer);
_cancel_timer_ex(&padapter->mlmepriv.sitesurveyctrl.
sitesurvey_ctrl_timer);
} }
static u8 init_default_value(struct _adapter *padapter) static u8 init_default_value(struct _adapter *padapter)
...@@ -347,6 +348,7 @@ u8 r8712_free_drv_sw(struct _adapter *padapter) ...@@ -347,6 +348,7 @@ u8 r8712_free_drv_sw(struct _adapter *padapter)
r8712_free_mlme_priv(&padapter->mlmepriv); r8712_free_mlme_priv(&padapter->mlmepriv);
r8712_free_io_queue(padapter); r8712_free_io_queue(padapter);
_free_xmit_priv(&padapter->xmitpriv); _free_xmit_priv(&padapter->xmitpriv);
if (padapter->fw_found)
_r8712_free_sta_priv(&padapter->stapriv); _r8712_free_sta_priv(&padapter->stapriv);
_r8712_free_recv_priv(&padapter->recvpriv); _r8712_free_recv_priv(&padapter->recvpriv);
mp871xdeinit(padapter); mp871xdeinit(padapter);
...@@ -388,6 +390,7 @@ static int netdev_open(struct net_device *pnetdev) ...@@ -388,6 +390,7 @@ static int netdev_open(struct net_device *pnetdev)
{ {
struct _adapter *padapter = (struct _adapter *)netdev_priv(pnetdev); struct _adapter *padapter = (struct _adapter *)netdev_priv(pnetdev);
mutex_lock(&padapter->mutex_start);
if (padapter->bup == false) { if (padapter->bup == false) {
padapter->bDriverStopped = false; padapter->bDriverStopped = false;
padapter->bSurpriseRemoved = false; padapter->bSurpriseRemoved = false;
...@@ -435,11 +438,13 @@ static int netdev_open(struct net_device *pnetdev) ...@@ -435,11 +438,13 @@ static int netdev_open(struct net_device *pnetdev)
/* start driver mlme relation timer */ /* start driver mlme relation timer */
start_drv_timers(padapter); start_drv_timers(padapter);
padapter->ledpriv.LedControlHandler(padapter, LED_CTL_NO_LINK); padapter->ledpriv.LedControlHandler(padapter, LED_CTL_NO_LINK);
mutex_unlock(&padapter->mutex_start);
return 0; return 0;
netdev_open_error: netdev_open_error:
padapter->bup = false; padapter->bup = false;
netif_carrier_off(pnetdev); netif_carrier_off(pnetdev);
netif_stop_queue(pnetdev); netif_stop_queue(pnetdev);
mutex_unlock(&padapter->mutex_start);
return -1; return -1;
} }
...@@ -473,6 +478,9 @@ static int netdev_close(struct net_device *pnetdev) ...@@ -473,6 +478,9 @@ static int netdev_close(struct net_device *pnetdev)
r8712_free_network_queue(padapter); r8712_free_network_queue(padapter);
/* The interface is no longer Up: */ /* The interface is no longer Up: */
padapter->bup = false; padapter->bup = false;
release_firmware(padapter->fw);
/* never exit with a firmware callback pending */
wait_for_completion(&padapter->rtl8712_fw_ready);
return 0; return 0;
} }
......
...@@ -145,5 +145,6 @@ struct hal_priv { ...@@ -145,5 +145,6 @@ struct hal_priv {
}; };
uint rtl8712_hal_init(struct _adapter *padapter); uint rtl8712_hal_init(struct _adapter *padapter);
int rtl871x_load_fw(struct _adapter *padapter);
#endif #endif
...@@ -390,6 +390,7 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf, ...@@ -390,6 +390,7 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf,
pdvobjpriv = &padapter->dvobjpriv; pdvobjpriv = &padapter->dvobjpriv;
pdvobjpriv->padapter = padapter; pdvobjpriv->padapter = padapter;
padapter->dvobjpriv.pusbdev = udev; padapter->dvobjpriv.pusbdev = udev;
padapter->pusb_intf = pusb_intf;
usb_set_intfdata(pusb_intf, pnetdev); usb_set_intfdata(pusb_intf, pnetdev);
SET_NETDEV_DEV(pnetdev, &pusb_intf->dev); SET_NETDEV_DEV(pnetdev, &pusb_intf->dev);
/* step 2. */ /* step 2. */
...@@ -596,10 +597,11 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf, ...@@ -596,10 +597,11 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf,
"%pM\n", mac); "%pM\n", mac);
memcpy(pnetdev->dev_addr, mac, ETH_ALEN); memcpy(pnetdev->dev_addr, mac, ETH_ALEN);
} }
/* step 6. Tell the network stack we exist */ /* step 6. Load the firmware asynchronously */
if (register_netdev(pnetdev) != 0) if (rtl871x_load_fw(padapter))
goto error; goto error;
spin_lock_init(&padapter->lockRxFF0Filter); spin_lock_init(&padapter->lockRxFF0Filter);
mutex_init(&padapter->mutex_start);
return 0; return 0;
error: error:
usb_put_dev(udev); usb_put_dev(udev);
...@@ -630,6 +632,7 @@ static void r871xu_dev_remove(struct usb_interface *pusb_intf) ...@@ -630,6 +632,7 @@ static void r871xu_dev_remove(struct usb_interface *pusb_intf)
flush_scheduled_work(); flush_scheduled_work();
udelay(1); udelay(1);
/*Stop driver mlme relation timer */ /*Stop driver mlme relation timer */
if (padapter->fw_found)
r8712_stop_drv_timers(padapter); r8712_stop_drv_timers(padapter);
r871x_dev_unload(padapter); r871x_dev_unload(padapter);
r8712_free_drv_sw(padapter); r8712_free_drv_sw(padapter);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment