mirror of
https://github.com/torvalds/linux.git
synced 2024-12-26 21:02:19 +00:00
brcmsmac: request firmware in .start() callback
The firmware is requested from user-space. To assure the request is handled it is recommended to do the request upon IFF_UP. For a mac80211 driver the .start() callback can be considered the equivalent. Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Reviewed-by: Piotr Haber <phaber@broadcom.com> Reviewed-by: Hante Meuleman <meuleman@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
1527c343c1
commit
25b5632fb3
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user