aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/mwl8k.c207
1 files changed, 178 insertions, 29 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index e5b062c3bd56..081bb6c848d9 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -224,6 +224,12 @@ struct mwl8k_priv {
224 * the firmware image is swapped. 224 * the firmware image is swapped.
225 */ 225 */
226 struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_QUEUES]; 226 struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_QUEUES];
227
228 /* async firmware loading state */
229 unsigned fw_state;
230 char *fw_pref;
231 char *fw_alt;
232 struct completion firmware_loading_complete;
227}; 233};
228 234
229/* Per interface specific private data */ 235/* Per interface specific private data */
@@ -403,34 +409,66 @@ static void mwl8k_release_firmware(struct mwl8k_priv *priv)
403 mwl8k_release_fw(&priv->fw_helper); 409 mwl8k_release_fw(&priv->fw_helper);
404} 410}
405 411
412/* states for asynchronous f/w loading */
413static void mwl8k_fw_state_machine(const struct firmware *fw, void *context);
414enum {
415 FW_STATE_INIT = 0,
416 FW_STATE_LOADING_PREF,
417 FW_STATE_LOADING_ALT,
418 FW_STATE_ERROR,
419};
420
406/* Request fw image */ 421/* Request fw image */
407static int mwl8k_request_fw(struct mwl8k_priv *priv, 422static int mwl8k_request_fw(struct mwl8k_priv *priv,
408 const char *fname, struct firmware **fw) 423 const char *fname, struct firmware **fw,
424 bool nowait)
409{ 425{
410 /* release current image */ 426 /* release current image */
411 if (*fw != NULL) 427 if (*fw != NULL)
412 mwl8k_release_fw(fw); 428 mwl8k_release_fw(fw);
413 429
414 return request_firmware((const struct firmware **)fw, 430 if (nowait)
415 fname, &priv->pdev->dev); 431 return request_firmware_nowait(THIS_MODULE, 1, fname,
432 &priv->pdev->dev, GFP_KERNEL,
433 priv, mwl8k_fw_state_machine);
434 else
435 return request_firmware((const struct firmware **)fw,
436 fname, &priv->pdev->dev);
416} 437}
417 438
418static int mwl8k_request_firmware(struct mwl8k_priv *priv, char *fw_image) 439static int mwl8k_request_firmware(struct mwl8k_priv *priv, char *fw_image,
440 bool nowait)
419{ 441{
420 struct mwl8k_device_info *di = priv->device_info; 442 struct mwl8k_device_info *di = priv->device_info;
421 int rc; 443 int rc;
422 444
423 if (di->helper_image != NULL) { 445 if (di->helper_image != NULL) {
424 rc = mwl8k_request_fw(priv, di->helper_image, &priv->fw_helper); 446 if (nowait)
425 if (rc) { 447 rc = mwl8k_request_fw(priv, di->helper_image,
426 printk(KERN_ERR "%s: Error requesting helper " 448 &priv->fw_helper, true);
427 "firmware file %s\n", pci_name(priv->pdev), 449 else
428 di->helper_image); 450 rc = mwl8k_request_fw(priv, di->helper_image,
451 &priv->fw_helper, false);
452 if (rc)
453 printk(KERN_ERR "%s: Error requesting helper fw %s\n",
454 pci_name(priv->pdev), di->helper_image);
455
456 if (rc || nowait)
429 return rc; 457 return rc;
430 }
431 } 458 }
432 459
433 rc = mwl8k_request_fw(priv, fw_image, &priv->fw_ucode); 460 if (nowait) {
461 /*
462 * if we get here, no helper image is needed. Skip the
463 * FW_STATE_INIT state.
464 */
465 priv->fw_state = FW_STATE_LOADING_PREF;
466 rc = mwl8k_request_fw(priv, fw_image,
467 &priv->fw_ucode,
468 true);
469 } else
470 rc = mwl8k_request_fw(priv, fw_image,
471 &priv->fw_ucode, false);
434 if (rc) { 472 if (rc) {
435 printk(KERN_ERR "%s: Error requesting firmware file %s\n", 473 printk(KERN_ERR "%s: Error requesting firmware file %s\n",
436 pci_name(priv->pdev), fw_image); 474 pci_name(priv->pdev), fw_image);
@@ -3998,7 +4036,99 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
3998}; 4036};
3999MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table); 4037MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table);
4000 4038
4001static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image) 4039static int mwl8k_request_alt_fw(struct mwl8k_priv *priv)
4040{
4041 int rc;
4042 printk(KERN_ERR "%s: Error requesting preferred fw %s.\n"
4043 "Trying alternative firmware %s\n", pci_name(priv->pdev),
4044 priv->fw_pref, priv->fw_alt);
4045 rc = mwl8k_request_fw(priv, priv->fw_alt, &priv->fw_ucode, true);
4046 if (rc) {
4047 printk(KERN_ERR "%s: Error requesting alt fw %s\n",
4048 pci_name(priv->pdev), priv->fw_alt);
4049 return rc;
4050 }
4051 return 0;
4052}
4053
4054static int mwl8k_firmware_load_success(struct mwl8k_priv *priv);
4055static void mwl8k_fw_state_machine(const struct firmware *fw, void *context)
4056{
4057 struct mwl8k_priv *priv = context;
4058 struct mwl8k_device_info *di = priv->device_info;
4059 int rc;
4060
4061 switch (priv->fw_state) {
4062 case FW_STATE_INIT:
4063 if (!fw) {
4064 printk(KERN_ERR "%s: Error requesting helper fw %s\n",
4065 pci_name(priv->pdev), di->helper_image);
4066 goto fail;
4067 }
4068 priv->fw_helper = fw;
4069 rc = mwl8k_request_fw(priv, priv->fw_pref, &priv->fw_ucode,
4070 true);
4071 if (rc && priv->fw_alt) {
4072 rc = mwl8k_request_alt_fw(priv);
4073 if (rc)
4074 goto fail;
4075 priv->fw_state = FW_STATE_LOADING_ALT;
4076 } else if (rc)
4077 goto fail;
4078 else
4079 priv->fw_state = FW_STATE_LOADING_PREF;
4080 break;
4081
4082 case FW_STATE_LOADING_PREF:
4083 if (!fw) {
4084 if (priv->fw_alt) {
4085 rc = mwl8k_request_alt_fw(priv);
4086 if (rc)
4087 goto fail;
4088 priv->fw_state = FW_STATE_LOADING_ALT;
4089 } else
4090 goto fail;
4091 } else {
4092 priv->fw_ucode = fw;
4093 rc = mwl8k_firmware_load_success(priv);
4094 if (rc)
4095 goto fail;
4096 else
4097 complete(&priv->firmware_loading_complete);
4098 }
4099 break;
4100
4101 case FW_STATE_LOADING_ALT:
4102 if (!fw) {
4103 printk(KERN_ERR "%s: Error requesting alt fw %s\n",
4104 pci_name(priv->pdev), di->helper_image);
4105 goto fail;
4106 }
4107 priv->fw_ucode = fw;
4108 rc = mwl8k_firmware_load_success(priv);
4109 if (rc)
4110 goto fail;
4111 else
4112 complete(&priv->firmware_loading_complete);
4113 break;
4114
4115 default:
4116 printk(KERN_ERR "%s: Unexpected firmware loading state: %d\n",
4117 MWL8K_NAME, priv->fw_state);
4118 BUG_ON(1);
4119 }
4120
4121 return;
4122
4123fail:
4124 priv->fw_state = FW_STATE_ERROR;
4125 complete(&priv->firmware_loading_complete);
4126 device_release_driver(&priv->pdev->dev);
4127 mwl8k_release_firmware(priv);
4128}
4129
4130static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image,
4131 bool nowait)
4002{ 4132{
4003 struct mwl8k_priv *priv = hw->priv; 4133 struct mwl8k_priv *priv = hw->priv;
4004 int rc; 4134 int rc;
@@ -4007,12 +4137,15 @@ static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image)
4007 mwl8k_hw_reset(priv); 4137 mwl8k_hw_reset(priv);
4008 4138
4009 /* Ask userland hotplug daemon for the device firmware */ 4139 /* Ask userland hotplug daemon for the device firmware */
4010 rc = mwl8k_request_firmware(priv, fw_image); 4140 rc = mwl8k_request_firmware(priv, fw_image, nowait);
4011 if (rc) { 4141 if (rc) {
4012 wiphy_err(hw->wiphy, "Firmware files not found\n"); 4142 wiphy_err(hw->wiphy, "Firmware files not found\n");
4013 return rc; 4143 return rc;
4014 } 4144 }
4015 4145
4146 if (nowait)
4147 return rc;
4148
4016 /* Load firmware into hardware */ 4149 /* Load firmware into hardware */
4017 rc = mwl8k_load_firmware(hw); 4150 rc = mwl8k_load_firmware(hw);
4018 if (rc) 4151 if (rc)
@@ -4147,7 +4280,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image)
4147 for (i = 0; i < MWL8K_TX_QUEUES; i++) 4280 for (i = 0; i < MWL8K_TX_QUEUES; i++)
4148 mwl8k_txq_deinit(hw, i); 4281 mwl8k_txq_deinit(hw, i);
4149 4282
4150 rc = mwl8k_init_firmware(hw, fw_image); 4283 rc = mwl8k_init_firmware(hw, fw_image, false);
4151 if (rc) 4284 if (rc)
4152 goto fail; 4285 goto fail;
4153 4286
@@ -4181,6 +4314,13 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
4181 struct ieee80211_hw *hw = priv->hw; 4314 struct ieee80211_hw *hw = priv->hw;
4182 int i, rc; 4315 int i, rc;
4183 4316
4317 rc = mwl8k_load_firmware(hw);
4318 mwl8k_release_firmware(priv);
4319 if (rc) {
4320 wiphy_err(hw->wiphy, "Cannot start firmware\n");
4321 return rc;
4322 }
4323
4184 /* 4324 /*
4185 * Extra headroom is the size of the required DMA header 4325 * Extra headroom is the size of the required DMA header
4186 * minus the size of the smallest 802.11 frame (CTS frame). 4326 * minus the size of the smallest 802.11 frame (CTS frame).
@@ -4325,28 +4465,29 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
4325 } 4465 }
4326 4466
4327 /* 4467 /*
4328 * Choose the initial fw image depending on user input and availability 4468 * Choose the initial fw image depending on user input. If a second
4329 * of images. 4469 * image is available, make it the alternative image that will be
4470 * loaded if the first one fails.
4330 */ 4471 */
4472 init_completion(&priv->firmware_loading_complete);
4331 di = priv->device_info; 4473 di = priv->device_info;
4332 if (ap_mode_default && di->fw_image_ap) 4474 if (ap_mode_default && di->fw_image_ap) {
4333 rc = mwl8k_init_firmware(hw, di->fw_image_ap); 4475 priv->fw_pref = di->fw_image_ap;
4334 else if (!ap_mode_default && di->fw_image_sta) 4476 priv->fw_alt = di->fw_image_sta;
4335 rc = mwl8k_init_firmware(hw, di->fw_image_sta); 4477 } else if (!ap_mode_default && di->fw_image_sta) {
4336 else if (ap_mode_default && !di->fw_image_ap && di->fw_image_sta) { 4478 priv->fw_pref = di->fw_image_sta;
4479 priv->fw_alt = di->fw_image_ap;
4480 } else if (ap_mode_default && !di->fw_image_ap && di->fw_image_sta) {
4337 printk(KERN_WARNING "AP fw is unavailable. Using STA fw."); 4481 printk(KERN_WARNING "AP fw is unavailable. Using STA fw.");
4338 rc = mwl8k_init_firmware(hw, di->fw_image_sta); 4482 priv->fw_pref = di->fw_image_sta;
4339 } else if (!ap_mode_default && !di->fw_image_sta && di->fw_image_ap) { 4483 } else if (!ap_mode_default && !di->fw_image_sta && di->fw_image_ap) {
4340 printk(KERN_WARNING "STA fw is unavailable. Using AP fw."); 4484 printk(KERN_WARNING "STA fw is unavailable. Using AP fw.");
4341 rc = mwl8k_init_firmware(hw, di->fw_image_ap); 4485 priv->fw_pref = di->fw_image_ap;
4342 } else 4486 }
4343 rc = mwl8k_init_firmware(hw, di->fw_image_sta); 4487 rc = mwl8k_init_firmware(hw, priv->fw_pref, true);
4344 if (rc) 4488 if (rc)
4345 goto err_stop_firmware; 4489 goto err_stop_firmware;
4346 4490 return rc;
4347 rc = mwl8k_firmware_load_success(priv);
4348 if (!rc)
4349 return rc;
4350 4491
4351err_stop_firmware: 4492err_stop_firmware:
4352 mwl8k_hw_reset(priv); 4493 mwl8k_hw_reset(priv);
@@ -4385,6 +4526,13 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev)
4385 return; 4526 return;
4386 priv = hw->priv; 4527 priv = hw->priv;
4387 4528
4529 wait_for_completion(&priv->firmware_loading_complete);
4530
4531 if (priv->fw_state == FW_STATE_ERROR) {
4532 mwl8k_hw_reset(priv);
4533 goto unmap;
4534 }
4535
4388 ieee80211_stop_queues(hw); 4536 ieee80211_stop_queues(hw);
4389 4537
4390 ieee80211_unregister_hw(hw); 4538 ieee80211_unregister_hw(hw);
@@ -4407,6 +4555,7 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev)
4407 4555
4408 pci_free_consistent(priv->pdev, 4, priv->cookie, priv->cookie_dma); 4556 pci_free_consistent(priv->pdev, 4, priv->cookie, priv->cookie_dma);
4409 4557
4558unmap:
4410 pci_iounmap(pdev, priv->regs); 4559 pci_iounmap(pdev, priv->regs);
4411 pci_iounmap(pdev, priv->sram); 4560 pci_iounmap(pdev, priv->sram);
4412 pci_set_drvdata(pdev, NULL); 4561 pci_set_drvdata(pdev, NULL);