aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBrian Cavagnolo <brian@cozybit.com>2010-11-12 20:23:50 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-11-16 16:37:03 -0500
commit0863ade8d6bde1d151f75720d999ff27f9fe3533 (patch)
tree46ce01dce308c20be66f3abbc79d3ae7d96d0b0d /drivers
parent3cc7772c0a3cc193fa9873816168bd34d4f16837 (diff)
mwl8k: choose proper firmware image as directed by user
The mwl8k can operate in AP or STA mode, depending on the firmware image that is loaded. By default, STA firmware is loaded. Allow the user to override this default mode at module load time. This saves an unnecessary firmware reload for users only interested in AP mode. Also, the firmware image can be swapped to meet the user's add_interface request. For example, suppose the STA firmware is loaded, no STA interface has been added, and the user adds an AP interface. In this case, the AP firmware will be loaded to meet the request. Based on contributions from Pradeep Nemavat <pnemavat@marvell.com>, Yogesh Powar <yogeshp@marvell.com>, and Lennert Buytenhek <buytenh@wantstofly.org>. Signed-off-by: Brian Cavagnolo <brian@cozybit.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/mwl8k.c78
1 files changed, 66 insertions, 12 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 7bd861586983..cbf72714e74d 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -29,6 +29,12 @@
29#define MWL8K_NAME KBUILD_MODNAME 29#define MWL8K_NAME KBUILD_MODNAME
30#define MWL8K_VERSION "0.12" 30#define MWL8K_VERSION "0.12"
31 31
32/* Module parameters */
33static unsigned ap_mode_default;
34module_param(ap_mode_default, bool, 0);
35MODULE_PARM_DESC(ap_mode_default,
36 "Set to 1 to make ap mode the default instead of sta mode");
37
32/* Register definitions */ 38/* Register definitions */
33#define MWL8K_HIU_GEN_PTR 0x00000c10 39#define MWL8K_HIU_GEN_PTR 0x00000c10
34#define MWL8K_MODE_STA 0x0000005a 40#define MWL8K_MODE_STA 0x0000005a
@@ -92,7 +98,8 @@ struct rxd_ops {
92struct mwl8k_device_info { 98struct mwl8k_device_info {
93 char *part_name; 99 char *part_name;
94 char *helper_image; 100 char *helper_image;
95 char *fw_image; 101 char *fw_image_sta;
102 char *fw_image_ap;
96 struct rxd_ops *ap_rxd_ops; 103 struct rxd_ops *ap_rxd_ops;
97}; 104};
98 105
@@ -210,6 +217,12 @@ struct mwl8k_priv {
210 217
211 /* Most recently reported noise in dBm */ 218 /* Most recently reported noise in dBm */
212 s8 noise; 219 s8 noise;
220
221 /*
222 * preserve the queue configurations so they can be restored if/when
223 * the firmware image is swapped.
224 */
225 struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_QUEUES];
213}; 226};
214 227
215/* Per interface specific private data */ 228/* Per interface specific private data */
@@ -401,7 +414,7 @@ static int mwl8k_request_fw(struct mwl8k_priv *priv,
401 fname, &priv->pdev->dev); 414 fname, &priv->pdev->dev);
402} 415}
403 416
404static int mwl8k_request_firmware(struct mwl8k_priv *priv) 417static int mwl8k_request_firmware(struct mwl8k_priv *priv, char *fw_image)
405{ 418{
406 struct mwl8k_device_info *di = priv->device_info; 419 struct mwl8k_device_info *di = priv->device_info;
407 int rc; 420 int rc;
@@ -416,10 +429,10 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv)
416 } 429 }
417 } 430 }
418 431
419 rc = mwl8k_request_fw(priv, di->fw_image, &priv->fw_ucode); 432 rc = mwl8k_request_fw(priv, fw_image, &priv->fw_ucode);
420 if (rc) { 433 if (rc) {
421 printk(KERN_ERR "%s: Error requesting firmware file %s\n", 434 printk(KERN_ERR "%s: Error requesting firmware file %s\n",
422 pci_name(priv->pdev), di->fw_image); 435 pci_name(priv->pdev), fw_image);
423 mwl8k_release_fw(&priv->fw_helper); 436 mwl8k_release_fw(&priv->fw_helper);
424 return rc; 437 return rc;
425 } 438 }
@@ -3345,13 +3358,16 @@ static void mwl8k_stop(struct ieee80211_hw *hw)
3345 mwl8k_txq_reclaim(hw, i, INT_MAX, 1); 3358 mwl8k_txq_reclaim(hw, i, INT_MAX, 1);
3346} 3359}
3347 3360
3361static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image);
3362
3348static int mwl8k_add_interface(struct ieee80211_hw *hw, 3363static int mwl8k_add_interface(struct ieee80211_hw *hw,
3349 struct ieee80211_vif *vif) 3364 struct ieee80211_vif *vif)
3350{ 3365{
3351 struct mwl8k_priv *priv = hw->priv; 3366 struct mwl8k_priv *priv = hw->priv;
3352 struct mwl8k_vif *mwl8k_vif; 3367 struct mwl8k_vif *mwl8k_vif;
3353 u32 macids_supported; 3368 u32 macids_supported;
3354 int macid; 3369 int macid, rc;
3370 struct mwl8k_device_info *di;
3355 3371
3356 /* 3372 /*
3357 * Reject interface creation if sniffer mode is active, as 3373 * Reject interface creation if sniffer mode is active, as
@@ -3364,12 +3380,28 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
3364 return -EINVAL; 3380 return -EINVAL;
3365 } 3381 }
3366 3382
3367 3383 di = priv->device_info;
3368 switch (vif->type) { 3384 switch (vif->type) {
3369 case NL80211_IFTYPE_AP: 3385 case NL80211_IFTYPE_AP:
3386 if (!priv->ap_fw && di->fw_image_ap) {
3387 /* we must load the ap fw to meet this request */
3388 if (!list_empty(&priv->vif_list))
3389 return -EBUSY;
3390 rc = mwl8k_reload_firmware(hw, di->fw_image_ap);
3391 if (rc)
3392 return rc;
3393 }
3370 macids_supported = priv->ap_macids_supported; 3394 macids_supported = priv->ap_macids_supported;
3371 break; 3395 break;
3372 case NL80211_IFTYPE_STATION: 3396 case NL80211_IFTYPE_STATION:
3397 if (priv->ap_fw && di->fw_image_sta) {
3398 /* we must load the sta fw to meet this request */
3399 if (!list_empty(&priv->vif_list))
3400 return -EBUSY;
3401 rc = mwl8k_reload_firmware(hw, di->fw_image_sta);
3402 if (rc)
3403 return rc;
3404 }
3373 macids_supported = priv->sta_macids_supported; 3405 macids_supported = priv->sta_macids_supported;
3374 break; 3406 break;
3375 default: 3407 default:
@@ -3805,6 +3837,9 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
3805 3837
3806 rc = mwl8k_fw_lock(hw); 3838 rc = mwl8k_fw_lock(hw);
3807 if (!rc) { 3839 if (!rc) {
3840 BUG_ON(queue > MWL8K_TX_QUEUES - 1);
3841 memcpy(&priv->wmm_params[queue], params, sizeof(*params));
3842
3808 if (!priv->wmm_enabled) 3843 if (!priv->wmm_enabled)
3809 rc = mwl8k_cmd_set_wmm_mode(hw, 1); 3844 rc = mwl8k_cmd_set_wmm_mode(hw, 1);
3810 3845
@@ -3908,17 +3943,18 @@ static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = {
3908 [MWL8363] = { 3943 [MWL8363] = {
3909 .part_name = "88w8363", 3944 .part_name = "88w8363",
3910 .helper_image = "mwl8k/helper_8363.fw", 3945 .helper_image = "mwl8k/helper_8363.fw",
3911 .fw_image = "mwl8k/fmimage_8363.fw", 3946 .fw_image_sta = "mwl8k/fmimage_8363.fw",
3912 }, 3947 },
3913 [MWL8687] = { 3948 [MWL8687] = {
3914 .part_name = "88w8687", 3949 .part_name = "88w8687",
3915 .helper_image = "mwl8k/helper_8687.fw", 3950 .helper_image = "mwl8k/helper_8687.fw",
3916 .fw_image = "mwl8k/fmimage_8687.fw", 3951 .fw_image_sta = "mwl8k/fmimage_8687.fw",
3917 }, 3952 },
3918 [MWL8366] = { 3953 [MWL8366] = {
3919 .part_name = "88w8366", 3954 .part_name = "88w8366",
3920 .helper_image = "mwl8k/helper_8366.fw", 3955 .helper_image = "mwl8k/helper_8366.fw",
3921 .fw_image = "mwl8k/fmimage_8366.fw", 3956 .fw_image_sta = "mwl8k/fmimage_8366.fw",
3957 .fw_image_ap = "mwl8k/fmimage_8366_ap-1.fw",
3922 .ap_rxd_ops = &rxd_8366_ap_ops, 3958 .ap_rxd_ops = &rxd_8366_ap_ops,
3923 }, 3959 },
3924}; 3960};
@@ -3929,6 +3965,7 @@ MODULE_FIRMWARE("mwl8k/helper_8687.fw");
3929MODULE_FIRMWARE("mwl8k/fmimage_8687.fw"); 3965MODULE_FIRMWARE("mwl8k/fmimage_8687.fw");
3930MODULE_FIRMWARE("mwl8k/helper_8366.fw"); 3966MODULE_FIRMWARE("mwl8k/helper_8366.fw");
3931MODULE_FIRMWARE("mwl8k/fmimage_8366.fw"); 3967MODULE_FIRMWARE("mwl8k/fmimage_8366.fw");
3968MODULE_FIRMWARE("mwl8k/fmimage_8366_ap-1.fw");
3932 3969
3933static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { 3970static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
3934 { PCI_VDEVICE(MARVELL, 0x2a0a), .driver_data = MWL8363, }, 3971 { PCI_VDEVICE(MARVELL, 0x2a0a), .driver_data = MWL8363, },
@@ -3942,7 +3979,7 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
3942}; 3979};
3943MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table); 3980MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table);
3944 3981
3945static int mwl8k_init_firmware(struct ieee80211_hw *hw) 3982static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image)
3946{ 3983{
3947 struct mwl8k_priv *priv = hw->priv; 3984 struct mwl8k_priv *priv = hw->priv;
3948 int rc; 3985 int rc;
@@ -3951,7 +3988,7 @@ static int mwl8k_init_firmware(struct ieee80211_hw *hw)
3951 mwl8k_hw_reset(priv); 3988 mwl8k_hw_reset(priv);
3952 3989
3953 /* Ask userland hotplug daemon for the device firmware */ 3990 /* Ask userland hotplug daemon for the device firmware */
3954 rc = mwl8k_request_firmware(priv); 3991 rc = mwl8k_request_firmware(priv, fw_image);
3955 if (rc) { 3992 if (rc) {
3956 wiphy_err(hw->wiphy, "Firmware files not found\n"); 3993 wiphy_err(hw->wiphy, "Firmware files not found\n");
3957 return rc; 3994 return rc;
@@ -4207,6 +4244,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
4207 static int printed_version; 4244 static int printed_version;
4208 struct ieee80211_hw *hw; 4245 struct ieee80211_hw *hw;
4209 struct mwl8k_priv *priv; 4246 struct mwl8k_priv *priv;
4247 struct mwl8k_device_info *di;
4210 int rc; 4248 int rc;
4211 4249
4212 if (!printed_version) { 4250 if (!printed_version) {
@@ -4267,7 +4305,23 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
4267 } 4305 }
4268 } 4306 }
4269 4307
4270 rc = mwl8k_init_firmware(hw); 4308 /*
4309 * Choose the initial fw image depending on user input and availability
4310 * of images.
4311 */
4312 di = priv->device_info;
4313 if (ap_mode_default && di->fw_image_ap)
4314 rc = mwl8k_init_firmware(hw, di->fw_image_ap);
4315 else if (!ap_mode_default && di->fw_image_sta)
4316 rc = mwl8k_init_firmware(hw, di->fw_image_sta);
4317 else if (ap_mode_default && !di->fw_image_ap && di->fw_image_sta) {
4318 printk(KERN_WARNING "AP fw is unavailable. Using STA fw.");
4319 rc = mwl8k_init_firmware(hw, di->fw_image_sta);
4320 } else if (!ap_mode_default && !di->fw_image_sta && di->fw_image_ap) {
4321 printk(KERN_WARNING "STA fw is unavailable. Using AP fw.");
4322 rc = mwl8k_init_firmware(hw, di->fw_image_ap);
4323 } else
4324 rc = mwl8k_init_firmware(hw, di->fw_image_sta);
4271 if (rc) 4325 if (rc)
4272 goto err_stop_firmware; 4326 goto err_stop_firmware;
4273 4327