Commit 097b0e1b authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

b43: fix crash with OpenFWWF

b43 with open firmware crashes mac80211 because
it changes the number of queues at runtime which,
while it was never really supported, now crashes
mac80211 due to the new hardware queue logic.

Fix this by detecting open vs. proprietary fw
earlier and registering with mac80211 with the
right number of queues.
Tested-by: default avatarStefan Lippers-Hollmann <s.l-h@gmx.de>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Cc: stable@vger.kernel.org (depends on commit a6f38ac3)
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent d369f7b2
...@@ -870,13 +870,6 @@ struct b43_wl { ...@@ -870,13 +870,6 @@ struct b43_wl {
* handler, only. This basically is just the IRQ mask register. */ * handler, only. This basically is just the IRQ mask register. */
spinlock_t hardirq_lock; spinlock_t hardirq_lock;
/* The number of queues that were registered with the mac80211 subsystem
* initially. This is a backup copy of hw->queues in case hw->queues has
* to be dynamically lowered at runtime (Firmware does not support QoS).
* hw->queues has to be restored to the original value before unregistering
* from the mac80211 subsystem. */
u16 mac80211_initially_registered_queues;
/* Set this if we call ieee80211_register_hw() and check if we call /* Set this if we call ieee80211_register_hw() and check if we call
* ieee80211_unregister_hw(). */ * ieee80211_unregister_hw(). */
bool hw_registred; bool hw_registred;
......
...@@ -2359,6 +2359,8 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) ...@@ -2359,6 +2359,8 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
if (err) if (err)
goto err_load; goto err_load;
fw->opensource = (ctx->req_type == B43_FWTYPE_OPENSOURCE);
return 0; return 0;
err_no_ucode: err_no_ucode:
...@@ -2434,6 +2436,10 @@ static void b43_request_firmware(struct work_struct *work) ...@@ -2434,6 +2436,10 @@ static void b43_request_firmware(struct work_struct *work)
goto out; goto out;
start_ieee80211: start_ieee80211:
wl->hw->queues = B43_QOS_QUEUE_NUM;
if (!modparam_qos || dev->fw.opensource)
wl->hw->queues = 1;
err = ieee80211_register_hw(wl->hw); err = ieee80211_register_hw(wl->hw);
if (err) if (err)
goto err_one_core_detach; goto err_one_core_detach;
...@@ -2537,11 +2543,9 @@ static int b43_upload_microcode(struct b43_wldev *dev) ...@@ -2537,11 +2543,9 @@ static int b43_upload_microcode(struct b43_wldev *dev)
dev->fw.hdr_format = B43_FW_HDR_410; dev->fw.hdr_format = B43_FW_HDR_410;
else else
dev->fw.hdr_format = B43_FW_HDR_351; dev->fw.hdr_format = B43_FW_HDR_351;
dev->fw.opensource = (fwdate == 0xFFFF); WARN_ON(dev->fw.opensource != (fwdate == 0xFFFF));
/* Default to use-all-queues. */ dev->qos_enabled = dev->wl->hw->queues > 1;
dev->wl->hw->queues = dev->wl->mac80211_initially_registered_queues;
dev->qos_enabled = !!modparam_qos;
/* Default to firmware/hardware crypto acceleration. */ /* Default to firmware/hardware crypto acceleration. */
dev->hwcrypto_enabled = true; dev->hwcrypto_enabled = true;
...@@ -2559,14 +2563,8 @@ static int b43_upload_microcode(struct b43_wldev *dev) ...@@ -2559,14 +2563,8 @@ static int b43_upload_microcode(struct b43_wldev *dev)
/* Disable hardware crypto and fall back to software crypto. */ /* Disable hardware crypto and fall back to software crypto. */
dev->hwcrypto_enabled = false; dev->hwcrypto_enabled = false;
} }
if (!(fwcapa & B43_FWCAPA_QOS)) { /* adding QoS support should use an offline discovery mechanism */
b43info(dev->wl, "QoS not supported by firmware\n"); WARN(fwcapa & B43_FWCAPA_QOS, "QoS in OpenFW not supported\n");
/* Disable QoS. Tweak hw->queues to 1. It will be restored before
* ieee80211_unregister to make sure the networking core can
* properly free possible resources. */
dev->wl->hw->queues = 1;
dev->qos_enabled = false;
}
} else { } else {
b43info(dev->wl, "Loading firmware version %u.%u " b43info(dev->wl, "Loading firmware version %u.%u "
"(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
...@@ -5298,8 +5296,6 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev) ...@@ -5298,8 +5296,6 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
hw->queues = modparam_qos ? B43_QOS_QUEUE_NUM : 1;
wl->mac80211_initially_registered_queues = hw->queues;
wl->hw_registred = false; wl->hw_registred = false;
hw->max_rates = 2; hw->max_rates = 2;
SET_IEEE80211_DEV(hw, dev->dev); SET_IEEE80211_DEV(hw, dev->dev);
...@@ -5374,10 +5370,6 @@ static void b43_bcma_remove(struct bcma_device *core) ...@@ -5374,10 +5370,6 @@ static void b43_bcma_remove(struct bcma_device *core)
B43_WARN_ON(!wl); B43_WARN_ON(!wl);
if (wl->current_dev == wldev && wl->hw_registred) { if (wl->current_dev == wldev && wl->hw_registred) {
/* Restore the queues count before unregistering, because firmware detect
* might have modified it. Restoring is important, so the networking
* stack can properly free resources. */
wl->hw->queues = wl->mac80211_initially_registered_queues;
b43_leds_stop(wldev); b43_leds_stop(wldev);
ieee80211_unregister_hw(wl->hw); ieee80211_unregister_hw(wl->hw);
} }
...@@ -5452,10 +5444,6 @@ static void b43_ssb_remove(struct ssb_device *sdev) ...@@ -5452,10 +5444,6 @@ static void b43_ssb_remove(struct ssb_device *sdev)
B43_WARN_ON(!wl); B43_WARN_ON(!wl);
if (wl->current_dev == wldev && wl->hw_registred) { if (wl->current_dev == wldev && wl->hw_registred) {
/* Restore the queues count before unregistering, because firmware detect
* might have modified it. Restoring is important, so the networking
* stack can properly free resources. */
wl->hw->queues = wl->mac80211_initially_registered_queues;
b43_leds_stop(wldev); b43_leds_stop(wldev);
ieee80211_unregister_hw(wl->hw); ieee80211_unregister_hw(wl->hw);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment