Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 224552
b: refs/heads/master
c: 9902047
h: refs/heads/master
v: v3
  • Loading branch information
Brian Cavagnolo authored and John W. Linville committed Nov 16, 2010
1 parent 6d16413 commit eb25b0b
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 30 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 952a0e963fb02e50f4afbf502f7d468a8fe2b0fa
refs/heads/master: 99020471001dbbd6edf61f105368cb6667cc683d
207 changes: 178 additions & 29 deletions trunk/drivers/net/wireless/mwl8k.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,12 @@ struct mwl8k_priv {
* the firmware image is swapped.
*/
struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_QUEUES];

/* async firmware loading state */
unsigned fw_state;
char *fw_pref;
char *fw_alt;
struct completion firmware_loading_complete;
};

/* Per interface specific private data */
Expand Down Expand Up @@ -403,34 +409,66 @@ static void mwl8k_release_firmware(struct mwl8k_priv *priv)
mwl8k_release_fw(&priv->fw_helper);
}

/* states for asynchronous f/w loading */
static void mwl8k_fw_state_machine(const struct firmware *fw, void *context);
enum {
FW_STATE_INIT = 0,
FW_STATE_LOADING_PREF,
FW_STATE_LOADING_ALT,
FW_STATE_ERROR,
};

/* Request fw image */
static int mwl8k_request_fw(struct mwl8k_priv *priv,
const char *fname, struct firmware **fw)
const char *fname, struct firmware **fw,
bool nowait)
{
/* release current image */
if (*fw != NULL)
mwl8k_release_fw(fw);

return request_firmware((const struct firmware **)fw,
fname, &priv->pdev->dev);
if (nowait)
return request_firmware_nowait(THIS_MODULE, 1, fname,
&priv->pdev->dev, GFP_KERNEL,
priv, mwl8k_fw_state_machine);
else
return request_firmware((const struct firmware **)fw,
fname, &priv->pdev->dev);
}

static int mwl8k_request_firmware(struct mwl8k_priv *priv, char *fw_image)
static int mwl8k_request_firmware(struct mwl8k_priv *priv, char *fw_image,
bool nowait)
{
struct mwl8k_device_info *di = priv->device_info;
int rc;

if (di->helper_image != NULL) {
rc = mwl8k_request_fw(priv, di->helper_image, &priv->fw_helper);
if (rc) {
printk(KERN_ERR "%s: Error requesting helper "
"firmware file %s\n", pci_name(priv->pdev),
di->helper_image);
if (nowait)
rc = mwl8k_request_fw(priv, di->helper_image,
&priv->fw_helper, true);
else
rc = mwl8k_request_fw(priv, di->helper_image,
&priv->fw_helper, false);
if (rc)
printk(KERN_ERR "%s: Error requesting helper fw %s\n",
pci_name(priv->pdev), di->helper_image);

if (rc || nowait)
return rc;
}
}

rc = mwl8k_request_fw(priv, fw_image, &priv->fw_ucode);
if (nowait) {
/*
* if we get here, no helper image is needed. Skip the
* FW_STATE_INIT state.
*/
priv->fw_state = FW_STATE_LOADING_PREF;
rc = mwl8k_request_fw(priv, fw_image,
&priv->fw_ucode,
true);
} else
rc = mwl8k_request_fw(priv, fw_image,
&priv->fw_ucode, false);
if (rc) {
printk(KERN_ERR "%s: Error requesting firmware file %s\n",
pci_name(priv->pdev), fw_image);
Expand Down Expand Up @@ -3998,7 +4036,99 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
};
MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table);

static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image)
static int mwl8k_request_alt_fw(struct mwl8k_priv *priv)
{
int rc;
printk(KERN_ERR "%s: Error requesting preferred fw %s.\n"
"Trying alternative firmware %s\n", pci_name(priv->pdev),
priv->fw_pref, priv->fw_alt);
rc = mwl8k_request_fw(priv, priv->fw_alt, &priv->fw_ucode, true);
if (rc) {
printk(KERN_ERR "%s: Error requesting alt fw %s\n",
pci_name(priv->pdev), priv->fw_alt);
return rc;
}
return 0;
}

static int mwl8k_firmware_load_success(struct mwl8k_priv *priv);
static void mwl8k_fw_state_machine(const struct firmware *fw, void *context)
{
struct mwl8k_priv *priv = context;
struct mwl8k_device_info *di = priv->device_info;
int rc;

switch (priv->fw_state) {
case FW_STATE_INIT:
if (!fw) {
printk(KERN_ERR "%s: Error requesting helper fw %s\n",
pci_name(priv->pdev), di->helper_image);
goto fail;
}
priv->fw_helper = fw;
rc = mwl8k_request_fw(priv, priv->fw_pref, &priv->fw_ucode,
true);
if (rc && priv->fw_alt) {
rc = mwl8k_request_alt_fw(priv);
if (rc)
goto fail;
priv->fw_state = FW_STATE_LOADING_ALT;
} else if (rc)
goto fail;
else
priv->fw_state = FW_STATE_LOADING_PREF;
break;

case FW_STATE_LOADING_PREF:
if (!fw) {
if (priv->fw_alt) {
rc = mwl8k_request_alt_fw(priv);
if (rc)
goto fail;
priv->fw_state = FW_STATE_LOADING_ALT;
} else
goto fail;
} else {
priv->fw_ucode = fw;
rc = mwl8k_firmware_load_success(priv);
if (rc)
goto fail;
else
complete(&priv->firmware_loading_complete);
}
break;

case FW_STATE_LOADING_ALT:
if (!fw) {
printk(KERN_ERR "%s: Error requesting alt fw %s\n",
pci_name(priv->pdev), di->helper_image);
goto fail;
}
priv->fw_ucode = fw;
rc = mwl8k_firmware_load_success(priv);
if (rc)
goto fail;
else
complete(&priv->firmware_loading_complete);
break;

default:
printk(KERN_ERR "%s: Unexpected firmware loading state: %d\n",
MWL8K_NAME, priv->fw_state);
BUG_ON(1);
}

return;

fail:
priv->fw_state = FW_STATE_ERROR;
complete(&priv->firmware_loading_complete);
device_release_driver(&priv->pdev->dev);
mwl8k_release_firmware(priv);
}

static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image,
bool nowait)
{
struct mwl8k_priv *priv = hw->priv;
int rc;
Expand All @@ -4007,12 +4137,15 @@ static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image)
mwl8k_hw_reset(priv);

/* Ask userland hotplug daemon for the device firmware */
rc = mwl8k_request_firmware(priv, fw_image);
rc = mwl8k_request_firmware(priv, fw_image, nowait);
if (rc) {
wiphy_err(hw->wiphy, "Firmware files not found\n");
return rc;
}

if (nowait)
return rc;

/* Load firmware into hardware */
rc = mwl8k_load_firmware(hw);
if (rc)
Expand Down Expand Up @@ -4147,7 +4280,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image)
for (i = 0; i < MWL8K_TX_QUEUES; i++)
mwl8k_txq_deinit(hw, i);

rc = mwl8k_init_firmware(hw, fw_image);
rc = mwl8k_init_firmware(hw, fw_image, false);
if (rc)
goto fail;

Expand Down Expand Up @@ -4181,6 +4314,13 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
struct ieee80211_hw *hw = priv->hw;
int i, rc;

rc = mwl8k_load_firmware(hw);
mwl8k_release_firmware(priv);
if (rc) {
wiphy_err(hw->wiphy, "Cannot start firmware\n");
return rc;
}

/*
* Extra headroom is the size of the required DMA header
* minus the size of the smallest 802.11 frame (CTS frame).
Expand Down Expand Up @@ -4325,28 +4465,29 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
}

/*
* Choose the initial fw image depending on user input and availability
* of images.
* Choose the initial fw image depending on user input. If a second
* image is available, make it the alternative image that will be
* loaded if the first one fails.
*/
init_completion(&priv->firmware_loading_complete);
di = priv->device_info;
if (ap_mode_default && di->fw_image_ap)
rc = mwl8k_init_firmware(hw, di->fw_image_ap);
else if (!ap_mode_default && di->fw_image_sta)
rc = mwl8k_init_firmware(hw, di->fw_image_sta);
else if (ap_mode_default && !di->fw_image_ap && di->fw_image_sta) {
if (ap_mode_default && di->fw_image_ap) {
priv->fw_pref = di->fw_image_ap;
priv->fw_alt = di->fw_image_sta;
} else if (!ap_mode_default && di->fw_image_sta) {
priv->fw_pref = di->fw_image_sta;
priv->fw_alt = di->fw_image_ap;
} else if (ap_mode_default && !di->fw_image_ap && di->fw_image_sta) {
printk(KERN_WARNING "AP fw is unavailable. Using STA fw.");
rc = mwl8k_init_firmware(hw, di->fw_image_sta);
priv->fw_pref = di->fw_image_sta;
} else if (!ap_mode_default && !di->fw_image_sta && di->fw_image_ap) {
printk(KERN_WARNING "STA fw is unavailable. Using AP fw.");
rc = mwl8k_init_firmware(hw, di->fw_image_ap);
} else
rc = mwl8k_init_firmware(hw, di->fw_image_sta);
priv->fw_pref = di->fw_image_ap;
}
rc = mwl8k_init_firmware(hw, priv->fw_pref, true);
if (rc)
goto err_stop_firmware;

rc = mwl8k_firmware_load_success(priv);
if (!rc)
return rc;
return rc;

err_stop_firmware:
mwl8k_hw_reset(priv);
Expand Down Expand Up @@ -4385,6 +4526,13 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev)
return;
priv = hw->priv;

wait_for_completion(&priv->firmware_loading_complete);

if (priv->fw_state == FW_STATE_ERROR) {
mwl8k_hw_reset(priv);
goto unmap;
}

ieee80211_stop_queues(hw);

ieee80211_unregister_hw(hw);
Expand All @@ -4407,6 +4555,7 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev)

pci_free_consistent(priv->pdev, 4, priv->cookie, priv->cookie_dma);

unmap:
pci_iounmap(pdev, priv->regs);
pci_iounmap(pdev, priv->sram);
pci_set_drvdata(pdev, NULL);
Expand Down

0 comments on commit eb25b0b

Please sign in to comment.