diff options
Diffstat (limited to 'drivers/net/wireless/b43/main.c')
-rw-r--r-- | drivers/net/wireless/b43/main.c | 83 |
1 files changed, 53 insertions, 30 deletions
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 1d3e40095ada..6456afebdba1 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -80,8 +80,8 @@ static int modparam_nohwcrypt; | |||
80 | module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); | 80 | module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); |
81 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); | 81 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); |
82 | 82 | ||
83 | int b43_modparam_qos = 1; | 83 | static int modparam_qos = 1; |
84 | module_param_named(qos, b43_modparam_qos, int, 0444); | 84 | module_param_named(qos, modparam_qos, int, 0444); |
85 | MODULE_PARM_DESC(qos, "Enable QOS support (default on)"); | 85 | MODULE_PARM_DESC(qos, "Enable QOS support (default on)"); |
86 | 86 | ||
87 | static int modparam_btcoex = 1; | 87 | static int modparam_btcoex = 1; |
@@ -538,6 +538,13 @@ void b43_hf_write(struct b43_wldev *dev, u64 value) | |||
538 | b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI, hi); | 538 | b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI, hi); |
539 | } | 539 | } |
540 | 540 | ||
541 | /* Read the firmware capabilities bitmask (Opensource firmware only) */ | ||
542 | static u16 b43_fwcapa_read(struct b43_wldev *dev) | ||
543 | { | ||
544 | B43_WARN_ON(!dev->fw.opensource); | ||
545 | return b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_FWCAPA); | ||
546 | } | ||
547 | |||
541 | void b43_tsf_read(struct b43_wldev *dev, u64 *tsf) | 548 | void b43_tsf_read(struct b43_wldev *dev, u64 *tsf) |
542 | { | 549 | { |
543 | u32 low, high; | 550 | u32 low, high; |
@@ -2307,12 +2314,34 @@ static int b43_upload_microcode(struct b43_wldev *dev) | |||
2307 | dev->fw.patch = fwpatch; | 2314 | dev->fw.patch = fwpatch; |
2308 | dev->fw.opensource = (fwdate == 0xFFFF); | 2315 | dev->fw.opensource = (fwdate == 0xFFFF); |
2309 | 2316 | ||
2317 | /* Default to use-all-queues. */ | ||
2318 | dev->wl->hw->queues = dev->wl->mac80211_initially_registered_queues; | ||
2319 | dev->qos_enabled = !!modparam_qos; | ||
2320 | /* Default to firmware/hardware crypto acceleration. */ | ||
2321 | dev->hwcrypto_enabled = 1; | ||
2322 | |||
2310 | if (dev->fw.opensource) { | 2323 | if (dev->fw.opensource) { |
2324 | u16 fwcapa; | ||
2325 | |||
2311 | /* Patchlevel info is encoded in the "time" field. */ | 2326 | /* Patchlevel info is encoded in the "time" field. */ |
2312 | dev->fw.patch = fwtime; | 2327 | dev->fw.patch = fwtime; |
2313 | b43info(dev->wl, "Loading OpenSource firmware version %u.%u%s\n", | 2328 | b43info(dev->wl, "Loading OpenSource firmware version %u.%u\n", |
2314 | dev->fw.rev, dev->fw.patch, | 2329 | dev->fw.rev, dev->fw.patch); |
2315 | dev->fw.pcm_request_failed ? " (Hardware crypto not supported)" : ""); | 2330 | |
2331 | fwcapa = b43_fwcapa_read(dev); | ||
2332 | if (!(fwcapa & B43_FWCAPA_HWCRYPTO) || dev->fw.pcm_request_failed) { | ||
2333 | b43info(dev->wl, "Hardware crypto acceleration not supported by firmware\n"); | ||
2334 | /* Disable hardware crypto and fall back to software crypto. */ | ||
2335 | dev->hwcrypto_enabled = 0; | ||
2336 | } | ||
2337 | if (!(fwcapa & B43_FWCAPA_QOS)) { | ||
2338 | b43info(dev->wl, "QoS not supported by firmware\n"); | ||
2339 | /* Disable QoS. Tweak hw->queues to 1. It will be restored before | ||
2340 | * ieee80211_unregister to make sure the networking core can | ||
2341 | * properly free possible resources. */ | ||
2342 | dev->wl->hw->queues = 1; | ||
2343 | dev->qos_enabled = 0; | ||
2344 | } | ||
2316 | } else { | 2345 | } else { |
2317 | b43info(dev->wl, "Loading firmware version %u.%u " | 2346 | b43info(dev->wl, "Loading firmware version %u.%u " |
2318 | "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", | 2347 | "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", |
@@ -3627,7 +3656,7 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
3627 | if (!dev || b43_status(dev) < B43_STAT_INITIALIZED) | 3656 | if (!dev || b43_status(dev) < B43_STAT_INITIALIZED) |
3628 | goto out_unlock; | 3657 | goto out_unlock; |
3629 | 3658 | ||
3630 | if (dev->fw.pcm_request_failed) { | 3659 | if (dev->fw.pcm_request_failed || !dev->hwcrypto_enabled) { |
3631 | /* We don't have firmware for the crypto engine. | 3660 | /* We don't have firmware for the crypto engine. |
3632 | * Must use software-crypto. */ | 3661 | * Must use software-crypto. */ |
3633 | err = -EOPNOTSUPP; | 3662 | err = -EOPNOTSUPP; |
@@ -4298,7 +4327,6 @@ static int b43_op_start(struct ieee80211_hw *hw) | |||
4298 | struct b43_wldev *dev = wl->current_dev; | 4327 | struct b43_wldev *dev = wl->current_dev; |
4299 | int did_init = 0; | 4328 | int did_init = 0; |
4300 | int err = 0; | 4329 | int err = 0; |
4301 | bool do_rfkill_exit = 0; | ||
4302 | 4330 | ||
4303 | /* Kill all old instance specific information to make sure | 4331 | /* Kill all old instance specific information to make sure |
4304 | * the card won't use it in the short timeframe between start | 4332 | * the card won't use it in the short timeframe between start |
@@ -4312,18 +4340,12 @@ static int b43_op_start(struct ieee80211_hw *hw) | |||
4312 | wl->beacon1_uploaded = 0; | 4340 | wl->beacon1_uploaded = 0; |
4313 | wl->beacon_templates_virgin = 1; | 4341 | wl->beacon_templates_virgin = 1; |
4314 | 4342 | ||
4315 | /* First register RFkill. | ||
4316 | * LEDs that are registered later depend on it. */ | ||
4317 | b43_rfkill_init(dev); | ||
4318 | |||
4319 | mutex_lock(&wl->mutex); | 4343 | mutex_lock(&wl->mutex); |
4320 | 4344 | ||
4321 | if (b43_status(dev) < B43_STAT_INITIALIZED) { | 4345 | if (b43_status(dev) < B43_STAT_INITIALIZED) { |
4322 | err = b43_wireless_core_init(dev); | 4346 | err = b43_wireless_core_init(dev); |
4323 | if (err) { | 4347 | if (err) |
4324 | do_rfkill_exit = 1; | ||
4325 | goto out_mutex_unlock; | 4348 | goto out_mutex_unlock; |
4326 | } | ||
4327 | did_init = 1; | 4349 | did_init = 1; |
4328 | } | 4350 | } |
4329 | 4351 | ||
@@ -4332,17 +4354,16 @@ static int b43_op_start(struct ieee80211_hw *hw) | |||
4332 | if (err) { | 4354 | if (err) { |
4333 | if (did_init) | 4355 | if (did_init) |
4334 | b43_wireless_core_exit(dev); | 4356 | b43_wireless_core_exit(dev); |
4335 | do_rfkill_exit = 1; | ||
4336 | goto out_mutex_unlock; | 4357 | goto out_mutex_unlock; |
4337 | } | 4358 | } |
4338 | } | 4359 | } |
4339 | 4360 | ||
4361 | /* XXX: only do if device doesn't support rfkill irq */ | ||
4362 | wiphy_rfkill_start_polling(hw->wiphy); | ||
4363 | |||
4340 | out_mutex_unlock: | 4364 | out_mutex_unlock: |
4341 | mutex_unlock(&wl->mutex); | 4365 | mutex_unlock(&wl->mutex); |
4342 | 4366 | ||
4343 | if (do_rfkill_exit) | ||
4344 | b43_rfkill_exit(dev); | ||
4345 | |||
4346 | return err; | 4367 | return err; |
4347 | } | 4368 | } |
4348 | 4369 | ||
@@ -4351,7 +4372,6 @@ static void b43_op_stop(struct ieee80211_hw *hw) | |||
4351 | struct b43_wl *wl = hw_to_b43_wl(hw); | 4372 | struct b43_wl *wl = hw_to_b43_wl(hw); |
4352 | struct b43_wldev *dev = wl->current_dev; | 4373 | struct b43_wldev *dev = wl->current_dev; |
4353 | 4374 | ||
4354 | b43_rfkill_exit(dev); | ||
4355 | cancel_work_sync(&(wl->beacon_update_trigger)); | 4375 | cancel_work_sync(&(wl->beacon_update_trigger)); |
4356 | 4376 | ||
4357 | mutex_lock(&wl->mutex); | 4377 | mutex_lock(&wl->mutex); |
@@ -4433,6 +4453,7 @@ static const struct ieee80211_ops b43_hw_ops = { | |||
4433 | .sta_notify = b43_op_sta_notify, | 4453 | .sta_notify = b43_op_sta_notify, |
4434 | .sw_scan_start = b43_op_sw_scan_start_notifier, | 4454 | .sw_scan_start = b43_op_sw_scan_start_notifier, |
4435 | .sw_scan_complete = b43_op_sw_scan_complete_notifier, | 4455 | .sw_scan_complete = b43_op_sw_scan_complete_notifier, |
4456 | .rfkill_poll = b43_rfkill_poll, | ||
4436 | }; | 4457 | }; |
4437 | 4458 | ||
4438 | /* Hard-reset the chip. Do not call this directly. | 4459 | /* Hard-reset the chip. Do not call this directly. |
@@ -4735,6 +4756,7 @@ static int b43_wireless_init(struct ssb_device *dev) | |||
4735 | b43err(NULL, "Could not allocate ieee80211 device\n"); | 4756 | b43err(NULL, "Could not allocate ieee80211 device\n"); |
4736 | goto out; | 4757 | goto out; |
4737 | } | 4758 | } |
4759 | wl = hw_to_b43_wl(hw); | ||
4738 | 4760 | ||
4739 | /* fill hw info */ | 4761 | /* fill hw info */ |
4740 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | | 4762 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | |
@@ -4748,7 +4770,8 @@ static int b43_wireless_init(struct ssb_device *dev) | |||
4748 | BIT(NL80211_IFTYPE_WDS) | | 4770 | BIT(NL80211_IFTYPE_WDS) | |
4749 | BIT(NL80211_IFTYPE_ADHOC); | 4771 | BIT(NL80211_IFTYPE_ADHOC); |
4750 | 4772 | ||
4751 | hw->queues = b43_modparam_qos ? 4 : 1; | 4773 | hw->queues = modparam_qos ? 4 : 1; |
4774 | wl->mac80211_initially_registered_queues = hw->queues; | ||
4752 | hw->max_rates = 2; | 4775 | hw->max_rates = 2; |
4753 | SET_IEEE80211_DEV(hw, dev->dev); | 4776 | SET_IEEE80211_DEV(hw, dev->dev); |
4754 | if (is_valid_ether_addr(sprom->et1mac)) | 4777 | if (is_valid_ether_addr(sprom->et1mac)) |
@@ -4756,9 +4779,7 @@ static int b43_wireless_init(struct ssb_device *dev) | |||
4756 | else | 4779 | else |
4757 | SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac); | 4780 | SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac); |
4758 | 4781 | ||
4759 | /* Get and initialize struct b43_wl */ | 4782 | /* Initialize struct b43_wl */ |
4760 | wl = hw_to_b43_wl(hw); | ||
4761 | memset(wl, 0, sizeof(*wl)); | ||
4762 | wl->hw = hw; | 4783 | wl->hw = hw; |
4763 | spin_lock_init(&wl->irq_lock); | 4784 | spin_lock_init(&wl->irq_lock); |
4764 | rwlock_init(&wl->tx_lock); | 4785 | rwlock_init(&wl->tx_lock); |
@@ -4824,8 +4845,13 @@ static void b43_remove(struct ssb_device *dev) | |||
4824 | cancel_work_sync(&wldev->restart_work); | 4845 | cancel_work_sync(&wldev->restart_work); |
4825 | 4846 | ||
4826 | B43_WARN_ON(!wl); | 4847 | B43_WARN_ON(!wl); |
4827 | if (wl->current_dev == wldev) | 4848 | if (wl->current_dev == wldev) { |
4849 | /* Restore the queues count before unregistering, because firmware detect | ||
4850 | * might have modified it. Restoring is important, so the networking | ||
4851 | * stack can properly free resources. */ | ||
4852 | wl->hw->queues = wl->mac80211_initially_registered_queues; | ||
4828 | ieee80211_unregister_hw(wl->hw); | 4853 | ieee80211_unregister_hw(wl->hw); |
4854 | } | ||
4829 | 4855 | ||
4830 | b43_one_core_detach(dev); | 4856 | b43_one_core_detach(dev); |
4831 | 4857 | ||
@@ -4920,7 +4946,7 @@ static struct ssb_driver b43_ssb_driver = { | |||
4920 | static void b43_print_driverinfo(void) | 4946 | static void b43_print_driverinfo(void) |
4921 | { | 4947 | { |
4922 | const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "", | 4948 | const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "", |
4923 | *feat_leds = "", *feat_rfkill = ""; | 4949 | *feat_leds = ""; |
4924 | 4950 | ||
4925 | #ifdef CONFIG_B43_PCI_AUTOSELECT | 4951 | #ifdef CONFIG_B43_PCI_AUTOSELECT |
4926 | feat_pci = "P"; | 4952 | feat_pci = "P"; |
@@ -4934,14 +4960,11 @@ static void b43_print_driverinfo(void) | |||
4934 | #ifdef CONFIG_B43_LEDS | 4960 | #ifdef CONFIG_B43_LEDS |
4935 | feat_leds = "L"; | 4961 | feat_leds = "L"; |
4936 | #endif | 4962 | #endif |
4937 | #ifdef CONFIG_B43_RFKILL | ||
4938 | feat_rfkill = "R"; | ||
4939 | #endif | ||
4940 | printk(KERN_INFO "Broadcom 43xx driver loaded " | 4963 | printk(KERN_INFO "Broadcom 43xx driver loaded " |
4941 | "[ Features: %s%s%s%s%s, Firmware-ID: " | 4964 | "[ Features: %s%s%s%s, Firmware-ID: " |
4942 | B43_SUPPORTED_FIRMWARE_ID " ]\n", | 4965 | B43_SUPPORTED_FIRMWARE_ID " ]\n", |
4943 | feat_pci, feat_pcmcia, feat_nphy, | 4966 | feat_pci, feat_pcmcia, feat_nphy, |
4944 | feat_leds, feat_rfkill); | 4967 | feat_leds); |
4945 | } | 4968 | } |
4946 | 4969 | ||
4947 | static int __init b43_init(void) | 4970 | static int __init b43_init(void) |