staging: brcm80211: Fix some initialisation failure paths
Initialise wl_info::tasklet early so that it's safe to tasklet_kill() it in wl_free(). Remove assertions from wl_free() that may not be true in case of initialisation failure. Call wl_release_fw() in case of failure after wl_request_fw(). Don't rely on wl_firmware::fw_cnt in wl_release_fw(). Signed-off-by: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: Henry Ptasinski <henryp@broadcom.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
6b5e073663
commit
eb4764c300
@@ -25,7 +25,6 @@ Bugs
|
|||||||
- Various occasional asserts/hangs
|
- Various occasional asserts/hangs
|
||||||
- Scanning during data transfer sometimes causes major slowdowns. Sometimes
|
- Scanning during data transfer sometimes causes major slowdowns. Sometimes
|
||||||
revcovers when scan is done, other times not.
|
revcovers when scan is done, other times not.
|
||||||
- Driver does not handle missing firmware gracefully.
|
|
||||||
- Mac80211 API not completely implemented (ie ops_bss_info_changed,
|
- Mac80211 API not completely implemented (ie ops_bss_info_changed,
|
||||||
ops_get_stats, etc)
|
ops_get_stats, etc)
|
||||||
|
|
||||||
|
@@ -837,6 +837,9 @@ static wl_info_t *wl_attach(uint16 vendor, uint16 device, ulong regs,
|
|||||||
wl->osh = osh;
|
wl->osh = osh;
|
||||||
atomic_set(&wl->callbacks, 0);
|
atomic_set(&wl->callbacks, 0);
|
||||||
|
|
||||||
|
/* setup the bottom half handler */
|
||||||
|
tasklet_init(&wl->tasklet, wl_dpc, (ulong) wl);
|
||||||
|
|
||||||
#ifdef WLC_HIGH_ONLY
|
#ifdef WLC_HIGH_ONLY
|
||||||
wl->rpc_th = bcm_rpc_tp_attach(osh, NULL);
|
wl->rpc_th = bcm_rpc_tp_attach(osh, NULL);
|
||||||
if (wl->rpc_th == NULL) {
|
if (wl->rpc_th == NULL) {
|
||||||
@@ -905,17 +908,16 @@ static wl_info_t *wl_attach(uint16 vendor, uint16 device, ulong regs,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* common load-time initialization */
|
/* common load-time initialization */
|
||||||
if (!
|
wl->wlc = wlc_attach((void *)wl, vendor, device, unit, wl->piomode, osh,
|
||||||
(wl->wlc =
|
wl->regsva, wl->bcm_bustype, btparam, &err);
|
||||||
wlc_attach((void *)wl, vendor, device, unit, wl->piomode, osh,
|
#ifndef WLC_HIGH_ONLY
|
||||||
wl->regsva, wl->bcm_bustype, btparam, &err))) {
|
wl_release_fw(wl);
|
||||||
|
#endif
|
||||||
|
if (!wl->wlc) {
|
||||||
printf("%s: %s driver failed with code %d\n", KBUILD_MODNAME,
|
printf("%s: %s driver failed with code %d\n", KBUILD_MODNAME,
|
||||||
EPI_VERSION_STR, err);
|
EPI_VERSION_STR, err);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
#ifndef WLC_HIGH_ONLY
|
|
||||||
wl_release_fw(wl);
|
|
||||||
#endif
|
|
||||||
wl->pub = wlc_pub(wl->wlc);
|
wl->pub = wlc_pub(wl->wlc);
|
||||||
|
|
||||||
wl->pub->ieee_hw = hw;
|
wl->pub->ieee_hw = hw;
|
||||||
@@ -942,9 +944,6 @@ static wl_info_t *wl_attach(uint16 vendor, uint16 device, ulong regs,
|
|||||||
wlc_iovar_setint(wl->wlc, "sd_drivestrength", sd_drivestrength);
|
wlc_iovar_setint(wl->wlc, "sd_drivestrength", sd_drivestrength);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* setup the bottom half handler */
|
|
||||||
tasklet_init(&wl->tasklet, wl_dpc, (ulong) wl);
|
|
||||||
|
|
||||||
#ifdef WLC_LOW
|
#ifdef WLC_LOW
|
||||||
/* register our interrupt handler */
|
/* register our interrupt handler */
|
||||||
if (request_irq(irq, wl_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) {
|
if (request_irq(irq, wl_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) {
|
||||||
@@ -1710,11 +1709,9 @@ void wl_free(wl_info_t * wl)
|
|||||||
|
|
||||||
ASSERT(wl);
|
ASSERT(wl);
|
||||||
#ifndef WLC_HIGH_ONLY
|
#ifndef WLC_HIGH_ONLY
|
||||||
ASSERT(wl->irq); /* bmac does not use direct interrupt */
|
|
||||||
/* free ucode data */
|
/* free ucode data */
|
||||||
if (wl->fw.fw_cnt)
|
if (wl->fw.fw_cnt)
|
||||||
wl_ucode_data_free();
|
wl_ucode_data_free();
|
||||||
ASSERT(wl->wlc);
|
|
||||||
if (wl->irq)
|
if (wl->irq)
|
||||||
free_irq(wl->irq, wl);
|
free_irq(wl->irq, wl);
|
||||||
#endif
|
#endif
|
||||||
@@ -2509,6 +2506,7 @@ static int wl_request_fw(wl_info_t * wl, struct pci_dev *pdev)
|
|||||||
status = request_firmware(&wl->fw.fw_bin[i], fw_name, device);
|
status = request_firmware(&wl->fw.fw_bin[i], fw_name, device);
|
||||||
if (status) {
|
if (status) {
|
||||||
printf("fail to request firmware %s\n", fw_name);
|
printf("fail to request firmware %s\n", fw_name);
|
||||||
|
wl_release_fw(wl);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
WL_NONE(("request fw %s\n", fw_name));
|
WL_NONE(("request fw %s\n", fw_name));
|
||||||
@@ -2517,6 +2515,7 @@ static int wl_request_fw(wl_info_t * wl, struct pci_dev *pdev)
|
|||||||
status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device);
|
status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device);
|
||||||
if (status) {
|
if (status) {
|
||||||
printf("fail to request firmware %s\n", fw_name);
|
printf("fail to request firmware %s\n", fw_name);
|
||||||
|
wl_release_fw(wl);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
wl->fw.hdr_num_entries[i] =
|
wl->fw.hdr_num_entries[i] =
|
||||||
@@ -2539,7 +2538,7 @@ void wl_ucode_free_buf(void *p)
|
|||||||
static void wl_release_fw(wl_info_t * wl)
|
static void wl_release_fw(wl_info_t * wl)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < wl->fw.fw_cnt; i++) {
|
for (i = 0; i < WL_MAX_FW; i++) {
|
||||||
release_firmware(wl->fw.fw_bin[i]);
|
release_firmware(wl->fw.fw_bin[i]);
|
||||||
release_firmware(wl->fw.fw_hdr[i]);
|
release_firmware(wl->fw.fw_hdr[i]);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user