Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it>
- Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+ Copyright (c) 2005-2009 Michael Buesch <mb@bu3sch.de>
Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
module_param_named(btcoex, modparam_btcoex, int, 0444);
MODULE_PARM_DESC(btcoex, "Enable Bluetooth coexistance (default on)");
+int b43_modparam_verbose = B43_VERBOSITY_DEFAULT;
+module_param_named(verbose, b43_modparam_verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "Log message verbosity: 0=error, 1=warn, 2=info(default), 3=debug");
+
static const struct ssb_device_id b43_ssb_tbl[] = {
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
{
va_list args;
+ if (b43_modparam_verbose < B43_VERBOSITY_INFO)
+ return;
if (!b43_ratelimit(wl))
return;
va_start(args, fmt);
{
va_list args;
+ if (b43_modparam_verbose < B43_VERBOSITY_ERROR)
+ return;
if (!b43_ratelimit(wl))
return;
va_start(args, fmt);
{
va_list args;
+ if (b43_modparam_verbose < B43_VERBOSITY_WARN)
+ return;
if (!b43_ratelimit(wl))
return;
va_start(args, fmt);
va_end(args);
}
-#if B43_DEBUG
void b43dbg(struct b43_wl *wl, const char *fmt, ...)
{
va_list args;
+ if (b43_modparam_verbose < B43_VERBOSITY_DEBUG)
+ return;
va_start(args, fmt);
printk(KERN_DEBUG "b43-%s debug: ",
(wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
vprintk(fmt, args);
va_end(args);
}
-#endif /* DEBUG */
static void b43_ram_write(struct b43_wldev *dev, u16 offset, u32 val)
{
}
/* Read HostFlags */
-u64 b43_hf_read(struct b43_wldev * dev)
+u64 b43_hf_read(struct b43_wldev *dev)
{
u64 ret;
}
static
-void b43_macfilter_set(struct b43_wldev *dev, u16 offset, const u8 * mac)
+void b43_macfilter_set(struct b43_wldev *dev, u16 offset, const u8 *mac)
{
static const u8 zero_addr[ETH_ALEN] = { 0 };
u16 data;
b43_set_slot_time(dev, 20);
}
-/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
- * Returns the _previously_ enabled IRQ mask.
- */
-static inline u32 b43_interrupt_enable(struct b43_wldev *dev, u32 mask)
-{
- u32 old_mask;
-
- old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
- b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask | mask);
-
- return old_mask;
-}
-
-/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
- * Returns the _previously_ enabled IRQ mask.
- */
-static inline u32 b43_interrupt_disable(struct b43_wldev *dev, u32 mask)
-{
- u32 old_mask;
-
- old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
- b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
-
- return old_mask;
-}
-
/* Synchronize IRQ top- and bottom-half.
* IRQs must be masked before calling this.
* This must not be called with the irq_lock held.
}
static void key_write(struct b43_wldev *dev,
- u8 index, u8 algorithm, const u8 * key)
+ u8 index, u8 algorithm, const u8 *key)
{
unsigned int i;
u32 offset;
}
}
-static void keymac_write(struct b43_wldev *dev, u8 index, const u8 * addr)
+static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr)
{
u32 addrtmp[2] = { 0, 0, };
u8 per_sta_keys_start = 8;
static void do_key_write(struct b43_wldev *dev,
u8 index, u8 algorithm,
- const u8 * key, size_t key_len, const u8 * mac_addr)
+ const u8 *key, size_t key_len, const u8 *mac_addr)
{
u8 buf[B43_SEC_KEYSIZE] = { 0, };
u8 per_sta_keys_start = 8;
static int b43_key_write(struct b43_wldev *dev,
int index, u8 algorithm,
- const u8 * key, size_t key_len,
- const u8 * mac_addr,
+ const u8 *key, size_t key_len,
+ const u8 *mac_addr,
struct ieee80211_key_conf *keyconf)
{
int i;
}
static void b43_write_template_common(struct b43_wldev *dev,
- const u8 * data, u16 size,
+ const u8 *data, u16 size,
u16 ram_offset,
u16 shm_size_offset, u8 rate)
{
* 2) Patching duration field
* 3) Stripping TIM
*/
-static const u8 * b43_generate_probe_resp(struct b43_wldev *dev,
- u16 *dest_size,
- struct ieee80211_rate *rate)
+static const u8 *b43_generate_probe_resp(struct b43_wldev *dev,
+ u16 *dest_size,
+ struct ieee80211_rate *rate)
{
const u8 *src_data;
u8 *dest_data;
/* This is the bottom half of the asynchronous beacon update. */
/* Ignore interrupt in the future. */
- dev->irq_savedstate &= ~B43_IRQ_BEACON;
+ dev->irq_mask &= ~B43_IRQ_BEACON;
cmd = b43_read32(dev, B43_MMIO_MACCMD);
beacon0_valid = (cmd & B43_MACCMD_BEACON0_VALID);
/* Schedule interrupt manually, if busy. */
if (beacon0_valid && beacon1_valid) {
b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON);
- dev->irq_savedstate |= B43_IRQ_BEACON;
+ dev->irq_mask |= B43_IRQ_BEACON;
return;
}
if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) {
spin_lock_irq(&wl->irq_lock);
/* update beacon right away or defer to irq */
- dev->irq_savedstate = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
handle_irq_beacon(dev);
/* The handler might have updated the IRQ mask. */
- b43_write32(dev, B43_MMIO_GEN_IRQ_MASK,
- dev->irq_savedstate);
+ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
mmiowb();
spin_unlock_irq(&wl->irq_lock);
}
if (reason & B43_IRQ_TX_OK)
handle_irq_transmit_status(dev);
- b43_interrupt_enable(dev, dev->irq_savedstate);
+ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
mmiowb();
spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
}
b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]);
b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]);
b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]);
+/* Unused ring
b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]);
+*/
}
/* Interrupt handler top-half */
struct b43_wldev *dev = dev_id;
u32 reason;
- if (!dev)
- return IRQ_NONE;
+ B43_WARN_ON(!dev);
spin_lock(&dev->wl->irq_lock);
- if (b43_status(dev) < B43_STAT_STARTED)
+ if (unlikely(b43_status(dev) < B43_STAT_STARTED)) {
+ /* This can only happen on shared IRQ lines. */
goto out;
+ }
reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
if (reason == 0xffffffff) /* shared IRQ */
goto out;
ret = IRQ_HANDLED;
- reason &= b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
+ reason &= dev->irq_mask;
if (!reason)
goto out;
& 0x0001DC00;
dev->dma_reason[4] = b43_read32(dev, B43_MMIO_DMA4_REASON)
& 0x0000DC00;
+/* Unused ring
dev->dma_reason[5] = b43_read32(dev, B43_MMIO_DMA5_REASON)
& 0x0000DC00;
+*/
b43_interrupt_ack(dev, reason);
/* disable all IRQs. They are enabled again in the bottom half. */
- dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
+ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
/* save the reason code and call our bottom half. */
dev->irq_reason = reason;
tasklet_schedule(&dev->isr_tasklet);
- out:
+out:
mmiowb();
spin_unlock(&dev->wl->irq_lock);
return ret;
}
-static void do_release_fw(struct b43_firmware_file *fw)
+void b43_do_release_fw(struct b43_firmware_file *fw)
{
release_firmware(fw->data);
fw->data = NULL;
static void b43_release_firmware(struct b43_wldev *dev)
{
- do_release_fw(&dev->fw.ucode);
- do_release_fw(&dev->fw.pcm);
- do_release_fw(&dev->fw.initvals);
- do_release_fw(&dev->fw.initvals_band);
+ b43_do_release_fw(&dev->fw.ucode);
+ b43_do_release_fw(&dev->fw.pcm);
+ b43_do_release_fw(&dev->fw.initvals);
+ b43_do_release_fw(&dev->fw.initvals_band);
}
static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
{
- const char *text;
+ const char text[] =
+ "You must go to " \
+ "http://wireless.kernel.org/en/users/Drivers/b43#devicefirmware " \
+ "and download the correct firmware for this driver version. " \
+ "Please carefully read all instructions on this website.\n";
- text = "You must go to "
- "http://wireless.kernel.org/en/users/Drivers/b43#devicefirmware "
- "and download the correct firmware for this driver version. "
- "Please carefully read all instructions on this website.\n";
if (error)
b43err(wl, text);
else
b43warn(wl, text);
}
-static int do_request_fw(struct b43_wldev *dev,
- const char *name,
- struct b43_firmware_file *fw,
- bool silent)
+int b43_do_request_fw(struct b43_request_fw_context *ctx,
+ const char *name,
+ struct b43_firmware_file *fw)
{
- char path[sizeof(modparam_fwpostfix) + 32];
const struct firmware *blob;
struct b43_fw_header *hdr;
u32 size;
if (!name) {
/* Don't fetch anything. Free possibly cached firmware. */
- do_release_fw(fw);
+ /* FIXME: We should probably keep it anyway, to save some headache
+ * on suspend/resume with multiband devices. */
+ b43_do_release_fw(fw);
return 0;
}
if (fw->filename) {
- if (strcmp(fw->filename, name) == 0)
+ if ((fw->type == ctx->req_type) &&
+ (strcmp(fw->filename, name) == 0))
return 0; /* Already have this fw. */
/* Free the cached firmware first. */
- do_release_fw(fw);
+ /* FIXME: We should probably do this later after we successfully
+ * got the new fw. This could reduce headache with multiband devices.
+ * We could also redesign this to cache the firmware for all possible
+ * bands all the time. */
+ b43_do_release_fw(fw);
+ }
+
+ switch (ctx->req_type) {
+ case B43_FWTYPE_PROPRIETARY:
+ snprintf(ctx->fwname, sizeof(ctx->fwname),
+ "b43%s/%s.fw",
+ modparam_fwpostfix, name);
+ break;
+ case B43_FWTYPE_OPENSOURCE:
+ snprintf(ctx->fwname, sizeof(ctx->fwname),
+ "b43-open%s/%s.fw",
+ modparam_fwpostfix, name);
+ break;
+ default:
+ B43_WARN_ON(1);
+ return -ENOSYS;
}
-
- snprintf(path, ARRAY_SIZE(path),
- "b43%s/%s.fw",
- modparam_fwpostfix, name);
- err = request_firmware(&blob, path, dev->dev->dev);
+ err = request_firmware(&blob, ctx->fwname, ctx->dev->dev->dev);
if (err == -ENOENT) {
- if (!silent) {
- b43err(dev->wl, "Firmware file \"%s\" not found\n",
- path);
- }
+ snprintf(ctx->errors[ctx->req_type],
+ sizeof(ctx->errors[ctx->req_type]),
+ "Firmware file \"%s\" not found\n", ctx->fwname);
return err;
} else if (err) {
- b43err(dev->wl, "Firmware file \"%s\" request failed (err=%d)\n",
- path, err);
+ snprintf(ctx->errors[ctx->req_type],
+ sizeof(ctx->errors[ctx->req_type]),
+ "Firmware file \"%s\" request failed (err=%d)\n",
+ ctx->fwname, err);
return err;
}
if (blob->size < sizeof(struct b43_fw_header))
fw->data = blob;
fw->filename = name;
+ fw->type = ctx->req_type;
return 0;
err_format:
- b43err(dev->wl, "Firmware file \"%s\" format error.\n", path);
+ snprintf(ctx->errors[ctx->req_type],
+ sizeof(ctx->errors[ctx->req_type]),
+ "Firmware file \"%s\" format error.\n", ctx->fwname);
release_firmware(blob);
return -EPROTO;
}
-static int b43_request_firmware(struct b43_wldev *dev)
+static int b43_try_request_fw(struct b43_request_fw_context *ctx)
{
- struct b43_firmware *fw = &dev->fw;
- const u8 rev = dev->dev->id.revision;
+ struct b43_wldev *dev = ctx->dev;
+ struct b43_firmware *fw = &ctx->dev->fw;
+ const u8 rev = ctx->dev->dev->id.revision;
const char *filename;
u32 tmshigh;
int err;
filename = "ucode13";
else
goto err_no_ucode;
- err = do_request_fw(dev, filename, &fw->ucode, 0);
+ err = b43_do_request_fw(ctx, filename, &fw->ucode);
if (err)
goto err_load;
else
goto err_no_pcm;
fw->pcm_request_failed = 0;
- err = do_request_fw(dev, filename, &fw->pcm, 1);
+ err = b43_do_request_fw(ctx, filename, &fw->pcm);
if (err == -ENOENT) {
/* We did not find a PCM file? Not fatal, but
* core rev <= 10 must do without hwcrypto then. */
default:
goto err_no_initvals;
}
- err = do_request_fw(dev, filename, &fw->initvals, 0);
+ err = b43_do_request_fw(ctx, filename, &fw->initvals);
if (err)
goto err_load;
default:
goto err_no_initvals;
}
- err = do_request_fw(dev, filename, &fw->initvals_band, 0);
+ err = b43_do_request_fw(ctx, filename, &fw->initvals_band);
if (err)
goto err_load;
return 0;
-err_load:
- b43_print_fw_helptext(dev->wl, 1);
- goto error;
-
err_no_ucode:
- err = -ENODEV;
- b43err(dev->wl, "No microcode available for core rev %u\n", rev);
+ err = ctx->fatal_failure = -EOPNOTSUPP;
+ b43err(dev->wl, "The driver does not know which firmware (ucode) "
+ "is required for your device (wl-core rev %u)\n", rev);
goto error;
err_no_pcm:
- err = -ENODEV;
- b43err(dev->wl, "No PCM available for core rev %u\n", rev);
+ err = ctx->fatal_failure = -EOPNOTSUPP;
+ b43err(dev->wl, "The driver does not know which firmware (PCM) "
+ "is required for your device (wl-core rev %u)\n", rev);
goto error;
err_no_initvals:
- err = -ENODEV;
- b43err(dev->wl, "No Initial Values firmware file for PHY %u, "
- "core rev %u\n", dev->phy.type, rev);
+ err = ctx->fatal_failure = -EOPNOTSUPP;
+ b43err(dev->wl, "The driver does not know which firmware (initvals) "
+ "is required for your device (wl-core rev %u)\n", rev);
+ goto error;
+
+err_load:
+ /* We failed to load this firmware image. The error message
+ * already is in ctx->errors. Return and let our caller decide
+ * what to do. */
goto error;
error:
return err;
}
+static int b43_request_firmware(struct b43_wldev *dev)
+{
+ struct b43_request_fw_context *ctx;
+ unsigned int i;
+ int err;
+ const char *errmsg;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+ ctx->dev = dev;
+
+ ctx->req_type = B43_FWTYPE_PROPRIETARY;
+ err = b43_try_request_fw(ctx);
+ if (!err)
+ goto out; /* Successfully loaded it. */
+ err = ctx->fatal_failure;
+ if (err)
+ goto out;
+
+ ctx->req_type = B43_FWTYPE_OPENSOURCE;
+ err = b43_try_request_fw(ctx);
+ if (!err)
+ goto out; /* Successfully loaded it. */
+ err = ctx->fatal_failure;
+ if (err)
+ goto out;
+
+ /* Could not find a usable firmware. Print the errors. */
+ for (i = 0; i < B43_NR_FWTYPES; i++) {
+ errmsg = ctx->errors[i];
+ if (strlen(errmsg))
+ b43err(dev->wl, errmsg);
+ }
+ b43_print_fw_helptext(dev->wl, 1);
+ err = -ENOENT;
+
+out:
+ kfree(ctx);
+ return err;
+}
+
static int b43_upload_microcode(struct b43_wldev *dev)
{
const size_t hdr_len = sizeof(struct b43_fw_header);
b43_clear_keys(dev);
}
-static int b43_rng_read(struct hwrng *rng, u32 * data)
+#ifdef CONFIG_B43_HWRNG
+static int b43_rng_read(struct hwrng *rng, u32 *data)
{
struct b43_wl *wl = (struct b43_wl *)rng->priv;
unsigned long flags;
return (sizeof(u16));
}
+#endif /* CONFIG_B43_HWRNG */
static void b43_rng_exit(struct b43_wl *wl)
{
+#ifdef CONFIG_B43_HWRNG
if (wl->rng_initialized)
hwrng_unregister(&wl->rng);
+#endif /* CONFIG_B43_HWRNG */
}
static int b43_rng_init(struct b43_wl *wl)
{
- int err;
+ int err = 0;
+#ifdef CONFIG_B43_HWRNG
snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name),
"%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy));
wl->rng.name = wl->rng_name;
b43err(wl, "Failed to register the random "
"number generator (%d)\n", err);
}
+#endif /* CONFIG_B43_HWRNG */
return err;
}
return 0;
}
+static u64 b43_op_get_tsf(struct ieee80211_hw *hw)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev;
+ u64 tsf;
+
+ mutex_lock(&wl->mutex);
+ spin_lock_irq(&wl->irq_lock);
+ dev = wl->current_dev;
+
+ if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED))
+ b43_tsf_read(dev, &tsf);
+ else
+ tsf = 0;
+
+ spin_unlock_irq(&wl->irq_lock);
+ mutex_unlock(&wl->mutex);
+
+ return tsf;
+}
+
+static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev;
+
+ mutex_lock(&wl->mutex);
+ spin_lock_irq(&wl->irq_lock);
+ dev = wl->current_dev;
+
+ if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED))
+ b43_tsf_write(dev, tsf);
+
+ spin_unlock_irq(&wl->irq_lock);
+ mutex_unlock(&wl->mutex);
+}
+
static void b43_put_phy_into_reset(struct b43_wldev *dev)
{
struct ssb_device *sdev = dev->dev;
msleep(1);
}
-static const char * band_to_string(enum ieee80211_band band)
+static const char *band_to_string(enum ieee80211_band band)
{
switch (band) {
case IEEE80211_BAND_5GHZ:
if (phy->ops->set_rx_antenna)
phy->ops->set_rx_antenna(dev, antenna);
- /* Update templates for AP/mesh mode. */
- if (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
- b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT))
- b43_set_beacon_int(dev, conf->beacon_int);
-
if (!!conf->radio_enabled != phy->radio_on) {
if (conf->radio_enabled) {
b43_software_rfkill(dev, RFKILL_STATE_UNBLOCKED);
return err;
}
-static void b43_update_basic_rates(struct b43_wldev *dev, u64 brates)
+static void b43_update_basic_rates(struct b43_wldev *dev, u32 brates)
{
struct ieee80211_supported_band *sband =
dev->wl->hw->wiphy->bands[b43_current_band(dev->wl)];
{
struct b43_wl *wl = hw_to_b43_wl(hw);
struct b43_wldev *dev;
+ unsigned long flags;
mutex_lock(&wl->mutex);
dev = wl->current_dev;
if (!dev || b43_status(dev) < B43_STAT_STARTED)
goto out_unlock_mutex;
+
+ B43_WARN_ON(wl->vif != vif);
+
+ if (changed & BSS_CHANGED_BSSID) {
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ if (conf->bssid)
+ memcpy(wl->bssid, conf->bssid, ETH_ALEN);
+ else
+ memset(wl->bssid, 0, ETH_ALEN);
+
+ if (b43_status(dev) >= B43_STAT_INITIALIZED) {
+ if (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
+ b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) {
+ B43_WARN_ON(vif->type != wl->if_type);
+ if (changed & BSS_CHANGED_BEACON)
+ b43_update_templates(wl);
+ } else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) {
+ if (changed & BSS_CHANGED_BEACON)
+ b43_update_templates(wl);
+ }
+ b43_write_mac_bssid_templates(dev);
+ }
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ }
+
b43_mac_suspend(dev);
+ /* Update templates for AP/mesh mode. */
+ if (changed & BSS_CHANGED_BEACON_INT &&
+ (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
+ b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) ||
+ b43_is_mode(wl, NL80211_IFTYPE_ADHOC)))
+ b43_set_beacon_int(dev, conf->beacon_int);
+
if (changed & BSS_CHANGED_BASIC_RATES)
b43_update_basic_rates(dev, conf->basic_rates);
b43_mac_enable(dev);
out_unlock_mutex:
mutex_unlock(&wl->mutex);
-
- return;
}
static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
u8 algorithm;
u8 index;
int err;
+ static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
if (modparam_nohwcrypt)
return -ENOSPC; /* User disabled HW-crypto */
b43dbg(wl, "%s hardware based encryption for keyidx: %d, "
"mac: %pM\n",
cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
- sta ? sta->addr : "<group key>");
+ sta ? sta->addr : bcast_addr);
b43_dump_keymemory(dev);
}
write_unlock(&wl->tx_lock);
spin_unlock_irqrestore(&wl->irq_lock, flags);
}
-static int b43_op_config_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_if_conf *conf)
-{
- struct b43_wl *wl = hw_to_b43_wl(hw);
- struct b43_wldev *dev = wl->current_dev;
- unsigned long flags;
-
- if (!dev)
- return -ENODEV;
- mutex_lock(&wl->mutex);
- spin_lock_irqsave(&wl->irq_lock, flags);
- B43_WARN_ON(wl->vif != vif);
- if (conf->bssid)
- memcpy(wl->bssid, conf->bssid, ETH_ALEN);
- else
- memset(wl->bssid, 0, ETH_ALEN);
- if (b43_status(dev) >= B43_STAT_INITIALIZED) {
- if (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
- b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) {
- B43_WARN_ON(vif->type != wl->if_type);
- if (conf->changed & IEEE80211_IFCC_BEACON)
- b43_update_templates(wl);
- } else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) {
- if (conf->changed & IEEE80211_IFCC_BEACON)
- b43_update_templates(wl);
- }
- b43_write_mac_bssid_templates(dev);
- }
- spin_unlock_irqrestore(&wl->irq_lock, flags);
- mutex_unlock(&wl->mutex);
-
- return 0;
-}
-
/* Locking: wl->mutex */
static void b43_wireless_core_stop(struct b43_wldev *dev)
{
* setting the status to INITIALIZED, as the interrupt handler
* won't care about IRQs then. */
spin_lock_irqsave(&wl->irq_lock, flags);
- dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
+ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */
spin_unlock_irqrestore(&wl->irq_lock, flags);
b43_synchronize_irq(dev);
/* Start data flow (TX/RX). */
b43_mac_enable(dev);
- b43_interrupt_enable(dev, dev->irq_savedstate);
+ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
/* Start maintainance work */
b43_periodic_tasks_setup(dev);
phy->next_txpwr_check_time = jiffies;
/* PHY TX errors counter. */
atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
+
+#if B43_DEBUG
+ phy->phy_locked = 0;
+ phy->radio_locked = 0;
+#endif
}
static void setup_struct_wldev_for_init(struct b43_wldev *dev)
/* IRQ related flags */
dev->irq_reason = 0;
memset(dev->dma_reason, 0, sizeof(dev->dma_reason));
- dev->irq_savedstate = B43_IRQ_MASKTEMPLATE;
+ dev->irq_mask = B43_IRQ_MASKTEMPLATE;
+ if (b43_modparam_verbose < B43_VERBOSITY_DEBUG)
+ dev->irq_mask &= ~B43_IRQ_PHY_TXERR;
dev->mac_suspended = 1;
hf |= B43_HF_GDCW;
if (sprom->boardflags_lo & B43_BFL_PACTRL)
hf |= B43_HF_OFDMPABOOST;
- } else if (phy->type == B43_PHYTYPE_B) {
- hf |= B43_HF_SYMW;
- if (phy->rev >= 2 && phy->radio_ver == 0x2050)
- hf &= ~B43_HF_GDCW;
}
+ if (phy->radio_ver == 0x2050) {
+ if (phy->radio_rev == 6)
+ hf |= B43_HF_4318TSSI;
+ if (phy->radio_rev < 6)
+ hf |= B43_HF_VCORECALC;
+ }
+ if (sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW)
+ hf |= B43_HF_DSCRQ; /* Disable slowclock requests from ucode. */
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ if ((bus->bustype == SSB_BUSTYPE_PCI) &&
+ (bus->pcicore.dev->id.revision <= 10))
+ hf |= B43_HF_PCISCW; /* PCI slow clock workaround. */
+#endif
+ hf &= ~B43_HF_SKCFPUP;
b43_hf_write(dev, hf);
b43_set_retry_limits(dev, B43_DEFAULT_SHORT_RETRY_LIMIT,
b43_set_synth_pu_delay(dev, 1);
b43_bluetooth_coext_enable(dev);
- ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */
+ ssb_bus_powerup(bus, !(sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW));
b43_upload_card_macaddress(dev);
b43_security_init(dev);
if (!dev->suspend_in_progress)
B43_WARN_ON(!vif || wl->vif != vif);
}
+static void b43_op_sw_scan_start_notifier(struct ieee80211_hw *hw)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev;
+
+ mutex_lock(&wl->mutex);
+ dev = wl->current_dev;
+ if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) {
+ /* Disable CFP update during scan on other channels. */
+ b43_hf_write(dev, b43_hf_read(dev) | B43_HF_SKCFPUP);
+ }
+ mutex_unlock(&wl->mutex);
+}
+
+static void b43_op_sw_scan_complete_notifier(struct ieee80211_hw *hw)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev;
+
+ mutex_lock(&wl->mutex);
+ dev = wl->current_dev;
+ if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) {
+ /* Re-enable CFP update. */
+ b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_SKCFPUP);
+ }
+ mutex_unlock(&wl->mutex);
+}
+
static const struct ieee80211_ops b43_hw_ops = {
.tx = b43_op_tx,
.conf_tx = b43_op_conf_tx,
.remove_interface = b43_op_remove_interface,
.config = b43_op_config,
.bss_info_changed = b43_op_bss_info_changed,
- .config_interface = b43_op_config_interface,
.configure_filter = b43_op_configure_filter,
.set_key = b43_op_set_key,
.get_stats = b43_op_get_stats,
.get_tx_stats = b43_op_get_tx_stats,
+ .get_tsf = b43_op_get_tsf,
+ .set_tsf = b43_op_set_tsf,
.start = b43_op_start,
.stop = b43_op_stop,
.set_tim = b43_op_beacon_set_tim,
.sta_notify = b43_op_sta_notify,
+ .sw_scan_start = b43_op_sw_scan_start_notifier,
+ .sw_scan_complete = b43_op_sw_scan_complete_notifier,
};
/* Hard-reset the chip. Do not call this directly.
INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work);
ssb_set_devtypedata(dev, wl);
- b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id);
+ b43info(wl, "Broadcom %04X WLAN found (core revision %u)\n",
+ dev->bus->chip_id, dev->id.revision);
err = 0;
- out:
+out:
return err;
}