diff options
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c')
| -rw-r--r-- | drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | 264 | 
1 files changed, 132 insertions, 132 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index c6451c61407..e2340b231aa 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -274,6 +274,130 @@ static void brcms_set_basic_rate(struct brcm_rateset *rs, u16 rate, bool is_br)  	}  } +/** + * This function frees the WL per-device resources. + * + * This function frees resources owned by the WL device pointed to + * by the wl parameter. + * + * precondition: can both be called locked and unlocked + * + */ +static void brcms_free(struct brcms_info *wl) +{ +	struct brcms_timer *t, *next; + +	/* free ucode data */ +	if (wl->fw.fw_cnt) +		brcms_ucode_data_free(&wl->ucode); +	if (wl->irq) +		free_irq(wl->irq, wl); + +	/* kill dpc */ +	tasklet_kill(&wl->tasklet); + +	if (wl->pub) { +		brcms_debugfs_detach(wl->pub); +		brcms_c_module_unregister(wl->pub, "linux", wl); +	} + +	/* free common resources */ +	if (wl->wlc) { +		brcms_c_detach(wl->wlc); +		wl->wlc = NULL; +		wl->pub = NULL; +	} + +	/* virtual interface deletion is deferred so we cannot spinwait */ + +	/* wait for all pending callbacks to complete */ +	while (atomic_read(&wl->callbacks) > 0) +		schedule(); + +	/* free timers */ +	for (t = wl->timers; t; t = next) { +		next = t->next; +#ifdef DEBUG +		kfree(t->name); +#endif +		kfree(t); +	} +} + +/* +* called from both kernel as from this kernel module (error flow on attach) +* precondition: perimeter lock is not acquired. +*/ +static void brcms_remove(struct bcma_device *pdev) +{ +	struct ieee80211_hw *hw = bcma_get_drvdata(pdev); +	struct brcms_info *wl = hw->priv; + +	if (wl->wlc) { +		wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false); +		wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); +		ieee80211_unregister_hw(hw); +	} + +	brcms_free(wl); + +	bcma_set_drvdata(pdev, NULL); +	ieee80211_free_hw(hw); +} + +/* + * Precondition: Since this function is called in brcms_pci_probe() context, + * no locking is required. + */ +static void brcms_release_fw(struct brcms_info *wl) +{ +	int i; +	for (i = 0; i < MAX_FW_IMAGES; i++) { +		release_firmware(wl->fw.fw_bin[i]); +		release_firmware(wl->fw.fw_hdr[i]); +	} +} + +/* + * Precondition: Since this function is called in brcms_pci_probe() context, + * no locking is required. + */ +static int brcms_request_fw(struct brcms_info *wl, struct bcma_device *pdev) +{ +	int status; +	struct device *device = &pdev->dev; +	char fw_name[100]; +	int i; + +	memset(&wl->fw, 0, sizeof(struct brcms_firmware)); +	for (i = 0; i < MAX_FW_IMAGES; i++) { +		if (brcms_firmwares[i] == NULL) +			break; +		sprintf(fw_name, "%s-%d.fw", brcms_firmwares[i], +			UCODE_LOADER_API_VER); +		status = request_firmware(&wl->fw.fw_bin[i], fw_name, device); +		if (status) { +			wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n", +				  KBUILD_MODNAME, fw_name); +			return status; +		} +		sprintf(fw_name, "%s_hdr-%d.fw", brcms_firmwares[i], +			UCODE_LOADER_API_VER); +		status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device); +		if (status) { +			wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n", +				  KBUILD_MODNAME, fw_name); +			return status; +		} +		wl->fw.hdr_num_entries[i] = +		    wl->fw.fw_hdr[i]->size / (sizeof(struct firmware_hdr)); +	} +	wl->fw.fw_cnt = i; +	status = brcms_ucode_data_init(wl, &wl->ucode); +	brcms_release_fw(wl); +	return status; +} +  static void brcms_ops_tx(struct ieee80211_hw *hw,  			 struct ieee80211_tx_control *control,  			 struct sk_buff *skb) @@ -306,6 +430,14 @@ static int brcms_ops_start(struct ieee80211_hw *hw)  	if (!blocked)  		wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); +	if (!wl->ucode.bcm43xx_bomminor) { +		err = brcms_request_fw(wl, wl->wlc->hw->d11core); +		if (err) { +			brcms_remove(wl->wlc->hw->d11core); +			return -ENOENT; +		} +	} +  	spin_lock_bh(&wl->lock);  	/* avoid acknowledging frames before a non-monitor device is added */  	wl->mute_tx = true; @@ -793,128 +925,6 @@ void brcms_dpc(unsigned long data)  	wake_up(&wl->tx_flush_wq);  } -/* - * Precondition: Since this function is called in brcms_pci_probe() context, - * no locking is required. - */ -static int brcms_request_fw(struct brcms_info *wl, struct bcma_device *pdev) -{ -	int status; -	struct device *device = &pdev->dev; -	char fw_name[100]; -	int i; - -	memset(&wl->fw, 0, sizeof(struct brcms_firmware)); -	for (i = 0; i < MAX_FW_IMAGES; i++) { -		if (brcms_firmwares[i] == NULL) -			break; -		sprintf(fw_name, "%s-%d.fw", brcms_firmwares[i], -			UCODE_LOADER_API_VER); -		status = request_firmware(&wl->fw.fw_bin[i], fw_name, device); -		if (status) { -			wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n", -				  KBUILD_MODNAME, fw_name); -			return status; -		} -		sprintf(fw_name, "%s_hdr-%d.fw", brcms_firmwares[i], -			UCODE_LOADER_API_VER); -		status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device); -		if (status) { -			wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n", -				  KBUILD_MODNAME, fw_name); -			return status; -		} -		wl->fw.hdr_num_entries[i] = -		    wl->fw.fw_hdr[i]->size / (sizeof(struct firmware_hdr)); -	} -	wl->fw.fw_cnt = i; -	return brcms_ucode_data_init(wl, &wl->ucode); -} - -/* - * Precondition: Since this function is called in brcms_pci_probe() context, - * no locking is required. - */ -static void brcms_release_fw(struct brcms_info *wl) -{ -	int i; -	for (i = 0; i < MAX_FW_IMAGES; i++) { -		release_firmware(wl->fw.fw_bin[i]); -		release_firmware(wl->fw.fw_hdr[i]); -	} -} - -/** - * This function frees the WL per-device resources. - * - * This function frees resources owned by the WL device pointed to - * by the wl parameter. - * - * precondition: can both be called locked and unlocked - * - */ -static void brcms_free(struct brcms_info *wl) -{ -	struct brcms_timer *t, *next; - -	/* free ucode data */ -	if (wl->fw.fw_cnt) -		brcms_ucode_data_free(&wl->ucode); -	if (wl->irq) -		free_irq(wl->irq, wl); - -	/* kill dpc */ -	tasklet_kill(&wl->tasklet); - -	if (wl->pub) { -		brcms_debugfs_detach(wl->pub); -		brcms_c_module_unregister(wl->pub, "linux", wl); -	} - -	/* free common resources */ -	if (wl->wlc) { -		brcms_c_detach(wl->wlc); -		wl->wlc = NULL; -		wl->pub = NULL; -	} - -	/* virtual interface deletion is deferred so we cannot spinwait */ - -	/* wait for all pending callbacks to complete */ -	while (atomic_read(&wl->callbacks) > 0) -		schedule(); - -	/* free timers */ -	for (t = wl->timers; t; t = next) { -		next = t->next; -#ifdef DEBUG -		kfree(t->name); -#endif -		kfree(t); -	} -} - -/* -* called from both kernel as from this kernel module (error flow on attach) -* precondition: perimeter lock is not acquired. -*/ -static void brcms_remove(struct bcma_device *pdev) -{ -	struct ieee80211_hw *hw = bcma_get_drvdata(pdev); -	struct brcms_info *wl = hw->priv; - -	if (wl->wlc) { -		wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false); -		wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); -		ieee80211_unregister_hw(hw); -	} - -	brcms_free(wl); - -	bcma_set_drvdata(pdev, NULL); -	ieee80211_free_hw(hw); -} -  static irqreturn_t brcms_isr(int irq, void *dev_id)  {  	struct brcms_info *wl; @@ -1047,18 +1057,8 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)  	spin_lock_init(&wl->lock);  	spin_lock_init(&wl->isr_lock); -	/* prepare ucode */ -	if (brcms_request_fw(wl, pdev) < 0) { -		wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in " -			  "%s\n", KBUILD_MODNAME, "/lib/firmware/brcm"); -		brcms_release_fw(wl); -		brcms_remove(pdev); -		return NULL; -	} -  	/* common load-time initialization */  	wl->wlc = brcms_c_attach((void *)wl, pdev, unit, false, &err); -	brcms_release_fw(wl);  	if (!wl->wlc) {  		wiphy_err(wl->wiphy, "%s: attach() failed with code %d\n",  			  KBUILD_MODNAME, err);  |