Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/net/wireless/broadcom/b43/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 152 kB image not shown  

Quelle  main.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*

  Broadcom B43 wireless driver

  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
  Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it>
  Copyright (c) 2005-2009 Michael Buesch <m@bues.ch>
  Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
  Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
  Copyright (c) 2010-2011 Rafał Miłecki <zajec5@gmail.com>

  SDIO support
  Copyright (c) 2009 Albert Herranz <albert_herranz@yahoo.es>

  Some parts of the code in this file are derived from the ipw2200
  driver  Copyright(c) 2003 - 2004 Intel Corporation.


*/


#include <linux/delay.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
#include <linux/firmware.h>
#include <linux/workqueue.h>
#include <linux/skbuff.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/unaligned.h>

#include "b43.h"
#include "main.h"
#include "debugfs.h"
#include "phy_common.h"
#include "phy_g.h"
#include "phy_n.h"
#include "dma.h"
#include "pio.h"
#include "sysfs.h"
#include "xmit.h"
#include "lo.h"
#include "sdio.h"
#include <linux/mmc/sdio_func.h>

MODULE_DESCRIPTION("Broadcom B43 wireless driver");
MODULE_AUTHOR("Martin Langer");
MODULE_AUTHOR("Stefano Brivio");
MODULE_AUTHOR("Michael Buesch");
MODULE_AUTHOR("Gábor Stefanik");
MODULE_AUTHOR("Rafał Miłecki");
MODULE_LICENSE("GPL");

MODULE_FIRMWARE("b43/ucode11.fw");
MODULE_FIRMWARE("b43/ucode13.fw");
MODULE_FIRMWARE("b43/ucode14.fw");
MODULE_FIRMWARE("b43/ucode15.fw");
MODULE_FIRMWARE("b43/ucode16_lp.fw");
MODULE_FIRMWARE("b43/ucode16_mimo.fw");
MODULE_FIRMWARE("b43/ucode24_lcn.fw");
MODULE_FIRMWARE("b43/ucode25_lcn.fw");
MODULE_FIRMWARE("b43/ucode25_mimo.fw");
MODULE_FIRMWARE("b43/ucode26_mimo.fw");
MODULE_FIRMWARE("b43/ucode29_mimo.fw");
MODULE_FIRMWARE("b43/ucode33_lcn40.fw");
MODULE_FIRMWARE("b43/ucode30_mimo.fw");
MODULE_FIRMWARE("b43/ucode5.fw");
MODULE_FIRMWARE("b43/ucode40.fw");
MODULE_FIRMWARE("b43/ucode42.fw");
MODULE_FIRMWARE("b43/ucode9.fw");

static int modparam_bad_frames_preempt;
module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
MODULE_PARM_DESC(bad_frames_preempt,
   "enable(1) / disable(0) Bad Frames Preemption");

static char modparam_fwpostfix[16];
module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load.");

static int modparam_hwpctl;
module_param_named(hwpctl, modparam_hwpctl, int, 0444);
MODULE_PARM_DESC(hwpctl, "Enable hardware-side power control (default off)");

static int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");

static int modparam_hwtkip;
module_param_named(hwtkip, modparam_hwtkip, int, 0444);
MODULE_PARM_DESC(hwtkip, "Enable hardware tkip.");

static int modparam_qos = 1;
module_param_named(qos, modparam_qos, int, 0444);
MODULE_PARM_DESC(qos, "Enable QOS support (default on)");

static int modparam_btcoex = 1;
module_param_named(btcoex, modparam_btcoex, int, 0444);
MODULE_PARM_DESC(btcoex, "Enable Bluetooth coexistence (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 int b43_modparam_pio;
module_param_named(pio, b43_modparam_pio, int, 0644);
MODULE_PARM_DESC(pio, "Use PIO accesses by default: 0=DMA, 1=PIO");

static int modparam_allhwsupport = !IS_ENABLED(CONFIG_BRCMSMAC);
module_param_named(allhwsupport, modparam_allhwsupport, int, 0444);
MODULE_PARM_DESC(allhwsupport, "Enable support for all hardware (even it if overlaps with the brcmsmac driver)");

#ifdef CONFIG_B43_BCMA
static const struct bcma_device_id b43_bcma_tbl[] = {
 BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x11, BCMA_ANY_CLASS),
 BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x15, BCMA_ANY_CLASS),
 BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x17, BCMA_ANY_CLASS),
 BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x18, BCMA_ANY_CLASS),
 BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1C, BCMA_ANY_CLASS),
 BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1D, BCMA_ANY_CLASS),
 BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1E, BCMA_ANY_CLASS),
 BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x28, BCMA_ANY_CLASS),
 BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x2A, BCMA_ANY_CLASS),
 {},
};
MODULE_DEVICE_TABLE(bcma, b43_bcma_tbl);
#endif

#ifdef CONFIG_B43_SSB
static const struct ssb_device_id b43_ssb_tbl[] = {
 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6),
 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 7),
 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9),
 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10),
 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 11),
 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 12),
 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13),
 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 15),
 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 16),
 {},
};
MODULE_DEVICE_TABLE(ssb, b43_ssb_tbl);
#endif

/* Channel and ratetables are shared for all devices.
 * They can't be const, because ieee80211 puts some precalculated
 * data in there. This data is the same for all devices, so we don't
 * get concurrency issues */

#define RATETAB_ENT(_rateid, _flags) \
 {        \
  .bitrate = B43_RATE_TO_BASE100KBPS(_rateid), \
  .hw_value = (_rateid),    \
  .flags  = (_flags),    \
 }

/*
 * NOTE: When changing this, sync with xmit.c's
 *  b43_plcp_get_bitrate_idx_* functions!
 */

static struct ieee80211_rate __b43_ratetable[] = {
 RATETAB_ENT(B43_CCK_RATE_1MB, 0),
 RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_SHORT_PREAMBLE),
 RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_SHORT_PREAMBLE),
 RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_SHORT_PREAMBLE),
 RATETAB_ENT(B43_OFDM_RATE_6MB, 0),
 RATETAB_ENT(B43_OFDM_RATE_9MB, 0),
 RATETAB_ENT(B43_OFDM_RATE_12MB, 0),
 RATETAB_ENT(B43_OFDM_RATE_18MB, 0),
 RATETAB_ENT(B43_OFDM_RATE_24MB, 0),
 RATETAB_ENT(B43_OFDM_RATE_36MB, 0),
 RATETAB_ENT(B43_OFDM_RATE_48MB, 0),
 RATETAB_ENT(B43_OFDM_RATE_54MB, 0),
};

#define b43_a_ratetable  (__b43_ratetable + 4)
#define b43_a_ratetable_size 8
#define b43_b_ratetable  (__b43_ratetable + 0)
#define b43_b_ratetable_size 4
#define b43_g_ratetable  (__b43_ratetable + 0)
#define b43_g_ratetable_size 12

#define CHAN2G(_channel, _freq, _flags) {   \
 .band   = NL80211_BAND_2GHZ,  \
 .center_freq  = (_freq),   \
 .hw_value  = (_channel),   \
 .flags   = (_flags),   \
 .max_antenna_gain = 0,    \
 .max_power  = 30,    \
}
static struct ieee80211_channel b43_2ghz_chantable[] = {
 CHAN2G(1, 2412, 0),
 CHAN2G(2, 2417, 0),
 CHAN2G(3, 2422, 0),
 CHAN2G(4, 2427, 0),
 CHAN2G(5, 2432, 0),
 CHAN2G(6, 2437, 0),
 CHAN2G(7, 2442, 0),
 CHAN2G(8, 2447, 0),
 CHAN2G(9, 2452, 0),
 CHAN2G(10, 2457, 0),
 CHAN2G(11, 2462, 0),
 CHAN2G(12, 2467, 0),
 CHAN2G(13, 2472, 0),
 CHAN2G(14, 2484, 0),
};

/* No support for the last 3 channels (12, 13, 14) */
#define b43_2ghz_chantable_limited_size  11
#undef CHAN2G

#define CHAN4G(_channel, _flags) {    \
 .band   = NL80211_BAND_5GHZ,  \
 .center_freq  = 4000 + (5 * (_channel)), \
 .hw_value  = (_channel),   \
 .flags   = (_flags),   \
 .max_antenna_gain = 0,    \
 .max_power  = 30,    \
}
#define CHAN5G(_channel, _flags) {    \
 .band   = NL80211_BAND_5GHZ,  \
 .center_freq  = 5000 + (5 * (_channel)), \
 .hw_value  = (_channel),   \
 .flags   = (_flags),   \
 .max_antenna_gain = 0,    \
 .max_power  = 30,    \
}
static struct ieee80211_channel b43_5ghz_nphy_chantable[] = {
 CHAN4G(184, 0),  CHAN4G(186, 0),
 CHAN4G(188, 0),  CHAN4G(190, 0),
 CHAN4G(192, 0),  CHAN4G(194, 0),
 CHAN4G(196, 0),  CHAN4G(198, 0),
 CHAN4G(200, 0),  CHAN4G(202, 0),
 CHAN4G(204, 0),  CHAN4G(206, 0),
 CHAN4G(208, 0),  CHAN4G(210, 0),
 CHAN4G(212, 0),  CHAN4G(214, 0),
 CHAN4G(216, 0),  CHAN4G(218, 0),
 CHAN4G(220, 0),  CHAN4G(222, 0),
 CHAN4G(224, 0),  CHAN4G(226, 0),
 CHAN4G(228, 0),
 CHAN5G(32, 0),  CHAN5G(34, 0),
 CHAN5G(36, 0),  CHAN5G(38, 0),
 CHAN5G(40, 0),  CHAN5G(42, 0),
 CHAN5G(44, 0),  CHAN5G(46, 0),
 CHAN5G(48, 0),  CHAN5G(50, 0),
 CHAN5G(52, 0),  CHAN5G(54, 0),
 CHAN5G(56, 0),  CHAN5G(58, 0),
 CHAN5G(60, 0),  CHAN5G(62, 0),
 CHAN5G(64, 0),  CHAN5G(66, 0),
 CHAN5G(68, 0),  CHAN5G(70, 0),
 CHAN5G(72, 0),  CHAN5G(74, 0),
 CHAN5G(76, 0),  CHAN5G(78, 0),
 CHAN5G(80, 0),  CHAN5G(82, 0),
 CHAN5G(84, 0),  CHAN5G(86, 0),
 CHAN5G(88, 0),  CHAN5G(90, 0),
 CHAN5G(92, 0),  CHAN5G(94, 0),
 CHAN5G(96, 0),  CHAN5G(98, 0),
 CHAN5G(100, 0),  CHAN5G(102, 0),
 CHAN5G(104, 0),  CHAN5G(106, 0),
 CHAN5G(108, 0),  CHAN5G(110, 0),
 CHAN5G(112, 0),  CHAN5G(114, 0),
 CHAN5G(116, 0),  CHAN5G(118, 0),
 CHAN5G(120, 0),  CHAN5G(122, 0),
 CHAN5G(124, 0),  CHAN5G(126, 0),
 CHAN5G(128, 0),  CHAN5G(130, 0),
 CHAN5G(132, 0),  CHAN5G(134, 0),
 CHAN5G(136, 0),  CHAN5G(138, 0),
 CHAN5G(140, 0),  CHAN5G(142, 0),
 CHAN5G(144, 0),  CHAN5G(145, 0),
 CHAN5G(146, 0),  CHAN5G(147, 0),
 CHAN5G(148, 0),  CHAN5G(149, 0),
 CHAN5G(150, 0),  CHAN5G(151, 0),
 CHAN5G(152, 0),  CHAN5G(153, 0),
 CHAN5G(154, 0),  CHAN5G(155, 0),
 CHAN5G(156, 0),  CHAN5G(157, 0),
 CHAN5G(158, 0),  CHAN5G(159, 0),
 CHAN5G(160, 0),  CHAN5G(161, 0),
 CHAN5G(162, 0),  CHAN5G(163, 0),
 CHAN5G(164, 0),  CHAN5G(165, 0),
 CHAN5G(166, 0),  CHAN5G(168, 0),
 CHAN5G(170, 0),  CHAN5G(172, 0),
 CHAN5G(174, 0),  CHAN5G(176, 0),
 CHAN5G(178, 0),  CHAN5G(180, 0),
 CHAN5G(182, 0),
};

static struct ieee80211_channel b43_5ghz_nphy_chantable_limited[] = {
 CHAN5G(36, 0),  CHAN5G(40, 0),
 CHAN5G(44, 0),  CHAN5G(48, 0),
 CHAN5G(149, 0),  CHAN5G(153, 0),
 CHAN5G(157, 0),  CHAN5G(161, 0),
 CHAN5G(165, 0),
};

static struct ieee80211_channel b43_5ghz_aphy_chantable[] = {
 CHAN5G(34, 0),  CHAN5G(36, 0),
 CHAN5G(38, 0),  CHAN5G(40, 0),
 CHAN5G(42, 0),  CHAN5G(44, 0),
 CHAN5G(46, 0),  CHAN5G(48, 0),
 CHAN5G(52, 0),  CHAN5G(56, 0),
 CHAN5G(60, 0),  CHAN5G(64, 0),
 CHAN5G(100, 0),  CHAN5G(104, 0),
 CHAN5G(108, 0),  CHAN5G(112, 0),
 CHAN5G(116, 0),  CHAN5G(120, 0),
 CHAN5G(124, 0),  CHAN5G(128, 0),
 CHAN5G(132, 0),  CHAN5G(136, 0),
 CHAN5G(140, 0),  CHAN5G(149, 0),
 CHAN5G(153, 0),  CHAN5G(157, 0),
 CHAN5G(161, 0),  CHAN5G(165, 0),
 CHAN5G(184, 0),  CHAN5G(188, 0),
 CHAN5G(192, 0),  CHAN5G(196, 0),
 CHAN5G(200, 0),  CHAN5G(204, 0),
 CHAN5G(208, 0),  CHAN5G(212, 0),
 CHAN5G(216, 0),
};
#undef CHAN4G
#undef CHAN5G

static struct ieee80211_supported_band b43_band_5GHz_nphy = {
 .band  = NL80211_BAND_5GHZ,
 .channels = b43_5ghz_nphy_chantable,
 .n_channels = ARRAY_SIZE(b43_5ghz_nphy_chantable),
 .bitrates = b43_a_ratetable,
 .n_bitrates = b43_a_ratetable_size,
};

static struct ieee80211_supported_band b43_band_5GHz_nphy_limited = {
 .band  = NL80211_BAND_5GHZ,
 .channels = b43_5ghz_nphy_chantable_limited,
 .n_channels = ARRAY_SIZE(b43_5ghz_nphy_chantable_limited),
 .bitrates = b43_a_ratetable,
 .n_bitrates = b43_a_ratetable_size,
};

static struct ieee80211_supported_band b43_band_5GHz_aphy = {
 .band  = NL80211_BAND_5GHZ,
 .channels = b43_5ghz_aphy_chantable,
 .n_channels = ARRAY_SIZE(b43_5ghz_aphy_chantable),
 .bitrates = b43_a_ratetable,
 .n_bitrates = b43_a_ratetable_size,
};

static struct ieee80211_supported_band b43_band_2GHz = {
 .band  = NL80211_BAND_2GHZ,
 .channels = b43_2ghz_chantable,
 .n_channels = ARRAY_SIZE(b43_2ghz_chantable),
 .bitrates = b43_g_ratetable,
 .n_bitrates = b43_g_ratetable_size,
};

static struct ieee80211_supported_band b43_band_2ghz_limited = {
 .band  = NL80211_BAND_2GHZ,
 .channels = b43_2ghz_chantable,
 .n_channels = b43_2ghz_chantable_limited_size,
 .bitrates = b43_g_ratetable,
 .n_bitrates = b43_g_ratetable_size,
};

static void b43_wireless_core_exit(struct b43_wldev *dev);
static int b43_wireless_core_init(struct b43_wldev *dev);
static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev);
static int b43_wireless_core_start(struct b43_wldev *dev);
static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
        struct ieee80211_vif *vif,
        struct ieee80211_bss_conf *conf,
        u64 changed);

static int b43_ratelimit(struct b43_wl *wl)
{
 if (!wl || !wl->current_dev)
  return 1;
 if (b43_status(wl->current_dev) < B43_STAT_STARTED)
  return 1;
 /* We are up and running.
 * Ratelimit the messages to avoid DoS over the net. */

 return net_ratelimit();
}

void b43info(struct b43_wl *wl, const char *fmt, ...)
{
 struct va_format vaf;
 va_list args;

 if (b43_modparam_verbose < B43_VERBOSITY_INFO)
  return;
 if (!b43_ratelimit(wl))
  return;

 va_start(args, fmt);

 vaf.fmt = fmt;
 vaf.va = &args;

 printk(KERN_INFO "b43-%s: %pV",
        (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);

 va_end(args);
}

void b43err(struct b43_wl *wl, const char *fmt, ...)
{
 struct va_format vaf;
 va_list args;

 if (b43_modparam_verbose < B43_VERBOSITY_ERROR)
  return;
 if (!b43_ratelimit(wl))
  return;

 va_start(args, fmt);

 vaf.fmt = fmt;
 vaf.va = &args;

 printk(KERN_ERR "b43-%s ERROR: %pV",
        (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);

 va_end(args);
}

void b43warn(struct b43_wl *wl, const char *fmt, ...)
{
 struct va_format vaf;
 va_list args;

 if (b43_modparam_verbose < B43_VERBOSITY_WARN)
  return;
 if (!b43_ratelimit(wl))
  return;

 va_start(args, fmt);

 vaf.fmt = fmt;
 vaf.va = &args;

 printk(KERN_WARNING "b43-%s warning: %pV",
        (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);

 va_end(args);
}

void b43dbg(struct b43_wl *wl, const char *fmt, ...)
{
 struct va_format vaf;
 va_list args;

 if (b43_modparam_verbose < B43_VERBOSITY_DEBUG)
  return;

 va_start(args, fmt);

 vaf.fmt = fmt;
 vaf.va = &args;

 printk(KERN_DEBUG "b43-%s debug: %pV",
        (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan", &vaf);

 va_end(args);
}

static void b43_ram_write(struct b43_wldev *dev, u16 offset, u32 val)
{
 u32 macctl;

 B43_WARN_ON(offset % 4 != 0);

 macctl = b43_read32(dev, B43_MMIO_MACCTL);
 if (macctl & B43_MACCTL_BE)
  val = swab32(val);

 b43_write32(dev, B43_MMIO_RAM_CONTROL, offset);
 b43_write32(dev, B43_MMIO_RAM_DATA, val);
}

static inline void b43_shm_control_word(struct b43_wldev *dev,
     u16 routing, u16 offset)
{
 u32 control;

 /* "offset" is the WORD offset. */
 control = routing;
 control <<= 16;
 control |= offset;
 b43_write32(dev, B43_MMIO_SHM_CONTROL, control);
}

u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
{
 u32 ret;

 if (routing == B43_SHM_SHARED) {
  B43_WARN_ON(offset & 0x0001);
  if (offset & 0x0003) {
   /* Unaligned access */
   b43_shm_control_word(dev, routing, offset >> 2);
   ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
   b43_shm_control_word(dev, routing, (offset >> 2) + 1);
   ret |= ((u32)b43_read16(dev, B43_MMIO_SHM_DATA)) << 16;

   goto out;
  }
  offset >>= 2;
 }
 b43_shm_control_word(dev, routing, offset);
 ret = b43_read32(dev, B43_MMIO_SHM_DATA);
out:
 return ret;
}

u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset)
{
 u16 ret;

 if (routing == B43_SHM_SHARED) {
  B43_WARN_ON(offset & 0x0001);
  if (offset & 0x0003) {
   /* Unaligned access */
   b43_shm_control_word(dev, routing, offset >> 2);
   ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);

   goto out;
  }
  offset >>= 2;
 }
 b43_shm_control_word(dev, routing, offset);
 ret = b43_read16(dev, B43_MMIO_SHM_DATA);
out:
 return ret;
}

void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
{
 if (routing == B43_SHM_SHARED) {
  B43_WARN_ON(offset & 0x0001);
  if (offset & 0x0003) {
   /* Unaligned access */
   b43_shm_control_word(dev, routing, offset >> 2);
   b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED,
        value & 0xFFFF);
   b43_shm_control_word(dev, routing, (offset >> 2) + 1);
   b43_write16(dev, B43_MMIO_SHM_DATA,
        (value >> 16) & 0xFFFF);
   return;
  }
  offset >>= 2;
 }
 b43_shm_control_word(dev, routing, offset);
 b43_write32(dev, B43_MMIO_SHM_DATA, value);
}

void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
{
 if (routing == B43_SHM_SHARED) {
  B43_WARN_ON(offset & 0x0001);
  if (offset & 0x0003) {
   /* Unaligned access */
   b43_shm_control_word(dev, routing, offset >> 2);
   b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value);
   return;
  }
  offset >>= 2;
 }
 b43_shm_control_word(dev, routing, offset);
 b43_write16(dev, B43_MMIO_SHM_DATA, value);
}

/* Read HostFlags */
u64 b43_hf_read(struct b43_wldev *dev)
{
 u64 ret;

 ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF3);
 ret <<= 16;
 ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF2);
 ret <<= 16;
 ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF1);

 return ret;
}

/* Write HostFlags */
void b43_hf_write(struct b43_wldev *dev, u64 value)
{
 u16 lo, mi, hi;

 lo = (value & 0x00000000FFFFULL);
 mi = (value & 0x0000FFFF0000ULL) >> 16;
 hi = (value & 0xFFFF00000000ULL) >> 32;
 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF1, lo);
 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF2, mi);
 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF3, hi);
}

/* Read the firmware capabilities bitmask (Opensource firmware only) */
static u16 b43_fwcapa_read(struct b43_wldev *dev)
{
 B43_WARN_ON(!dev->fw.opensource);
 return b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_FWCAPA);
}

void b43_tsf_read(struct b43_wldev *dev, u64 *tsf)
{
 u32 low, high;

 B43_WARN_ON(dev->dev->core_rev < 3);

 /* The hardware guarantees us an atomic read, if we
 * read the low register first. */

 low = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_LOW);
 high = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_HIGH);

 *tsf = high;
 *tsf <<= 32;
 *tsf |= low;
}

static void b43_time_lock(struct b43_wldev *dev)
{
 b43_maskset32(dev, B43_MMIO_MACCTL, ~0, B43_MACCTL_TBTTHOLD);
 /* Commit the write */
 b43_read32(dev, B43_MMIO_MACCTL);
}

static void b43_time_unlock(struct b43_wldev *dev)
{
 b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_TBTTHOLD, 0);
 /* Commit the write */
 b43_read32(dev, B43_MMIO_MACCTL);
}

static void b43_tsf_write_locked(struct b43_wldev *dev, u64 tsf)
{
 u32 low, high;

 B43_WARN_ON(dev->dev->core_rev < 3);

 low = tsf;
 high = (tsf >> 32);
 /* The hardware guarantees us an atomic write, if we
 * write the low register first. */

 b43_write32(dev, B43_MMIO_REV3PLUS_TSF_LOW, low);
 b43_write32(dev, B43_MMIO_REV3PLUS_TSF_HIGH, high);
}

void b43_tsf_write(struct b43_wldev *dev, u64 tsf)
{
 b43_time_lock(dev);
 b43_tsf_write_locked(dev, tsf);
 b43_time_unlock(dev);
}

static
void b43_macfilter_set(struct b43_wldev *dev, u16 offset, const u8 *mac)
{
 static const u8 zero_addr[ETH_ALEN] = { 0 };
 u16 data;

 if (!mac)
  mac = zero_addr;

 offset |= 0x0020;
 b43_write16(dev, B43_MMIO_MACFILTER_CONTROL, offset);

 data = mac[0];
 data |= mac[1] << 8;
 b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
 data = mac[2];
 data |= mac[3] << 8;
 b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
 data = mac[4];
 data |= mac[5] << 8;
 b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
}

static void b43_write_mac_bssid_templates(struct b43_wldev *dev)
{
 const u8 *mac;
 const u8 *bssid;
 u8 mac_bssid[ETH_ALEN * 2];
 int i;
 u32 tmp;

 bssid = dev->wl->bssid;
 mac = dev->wl->mac_addr;

 b43_macfilter_set(dev, B43_MACFILTER_BSSID, bssid);

 memcpy(mac_bssid, mac, ETH_ALEN);
 memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);

 /* Write our MAC address and BSSID to template ram */
 for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) {
  tmp = (u32) (mac_bssid[i + 0]);
  tmp |= (u32) (mac_bssid[i + 1]) << 8;
  tmp |= (u32) (mac_bssid[i + 2]) << 16;
  tmp |= (u32) (mac_bssid[i + 3]) << 24;
  b43_ram_write(dev, 0x20 + i, tmp);
 }
}

static void b43_upload_card_macaddress(struct b43_wldev *dev)
{
 b43_write_mac_bssid_templates(dev);
 b43_macfilter_set(dev, B43_MACFILTER_SELF, dev->wl->mac_addr);
}

static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time)
{
 /* slot_time is in usec. */
 /* This test used to exit for all but a G PHY. */
 if (b43_current_band(dev->wl) == NL80211_BAND_5GHZ)
  return;
 b43_write16(dev, B43_MMIO_IFSSLOT, 510 + slot_time);
 /* Shared memory location 0x0010 is the slot time and should be
 * set to slot_time; however, this register is initially 0 and changing
 * the value adversely affects the transmit rate for BCM4311
 * devices. Until this behavior is unterstood, delete this step
 *
 * b43_shm_write16(dev, B43_SHM_SHARED, 0x0010, slot_time);
 */

}

static void b43_short_slot_timing_enable(struct b43_wldev *dev)
{
 b43_set_slot_time(dev, 9);
}

static void b43_short_slot_timing_disable(struct b43_wldev *dev)
{
 b43_set_slot_time(dev, 20);
}

/* DummyTransmission function, as documented on
 * https://bcm-v4.sipsolutions.net/802.11/DummyTransmission
 */

void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on)
{
 struct b43_phy *phy = &dev->phy;
 unsigned int i, max_loop;
 u16 value;
 u32 buffer[5] = {
  0x00000000,
  0x00D40000,
  0x00000000,
  0x01000000,
  0x00000000,
 };

 if (ofdm) {
  max_loop = 0x1E;
  buffer[0] = 0x000201CC;
 } else {
  max_loop = 0xFA;
  buffer[0] = 0x000B846E;
 }

 for (i = 0; i < 5; i++)
  b43_ram_write(dev, i * 4, buffer[i]);

 b43_write16(dev, B43_MMIO_XMTSEL, 0x0000);

 if (dev->dev->core_rev < 11)
  b43_write16(dev, B43_MMIO_WEPCTL, 0x0000);
 else
  b43_write16(dev, B43_MMIO_WEPCTL, 0x0100);

 value = (ofdm ? 0x41 : 0x40);
 b43_write16(dev, B43_MMIO_TXE0_PHYCTL, value);
 if (phy->type == B43_PHYTYPE_N || phy->type == B43_PHYTYPE_LP ||
     phy->type == B43_PHYTYPE_LCN)
  b43_write16(dev, B43_MMIO_TXE0_PHYCTL1, 0x1A02);

 b43_write16(dev, B43_MMIO_TXE0_WM_0, 0x0000);
 b43_write16(dev, B43_MMIO_TXE0_WM_1, 0x0000);

 b43_write16(dev, B43_MMIO_XMTTPLATETXPTR, 0x0000);
 b43_write16(dev, B43_MMIO_XMTTXCNT, 0x0014);
 b43_write16(dev, B43_MMIO_XMTSEL, 0x0826);
 b43_write16(dev, B43_MMIO_TXE0_CTL, 0x0000);

 if (!pa_on && phy->type == B43_PHYTYPE_N) {
  ; /*b43_nphy_pa_override(dev, false) */
 }

 switch (phy->type) {
 case B43_PHYTYPE_N:
 case B43_PHYTYPE_LCN:
  b43_write16(dev, B43_MMIO_TXE0_AUX, 0x00D0);
  break;
 case B43_PHYTYPE_LP:
  b43_write16(dev, B43_MMIO_TXE0_AUX, 0x0050);
  break;
 default:
  b43_write16(dev, B43_MMIO_TXE0_AUX, 0x0030);
 }
 b43_read16(dev, B43_MMIO_TXE0_AUX);

 if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
  b43_radio_write16(dev, 0x0051, 0x0017);
 for (i = 0x00; i < max_loop; i++) {
  value = b43_read16(dev, B43_MMIO_TXE0_STATUS);
  if (value & 0x0080)
   break;
  udelay(10);
 }
 for (i = 0x00; i < 0x0A; i++) {
  value = b43_read16(dev, B43_MMIO_TXE0_STATUS);
  if (value & 0x0400)
   break;
  udelay(10);
 }
 for (i = 0x00; i < 0x19; i++) {
  value = b43_read16(dev, B43_MMIO_IFSSTAT);
  if (!(value & 0x0100))
   break;
  udelay(10);
 }
 if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
  b43_radio_write16(dev, 0x0051, 0x0037);
}

static void key_write(struct b43_wldev *dev,
        u8 index, u8 algorithm, const u8 *key)
{
 unsigned int i;
 u32 offset;
 u16 value;
 u16 kidx;

 /* Key index/algo block */
 kidx = b43_kidx_to_fw(dev, index);
 value = ((kidx << 4) | algorithm);
 b43_shm_write16(dev, B43_SHM_SHARED,
   B43_SHM_SH_KEYIDXBLOCK + (kidx * 2), value);

 /* Write the key to the Key Table Pointer offset */
 offset = dev->ktp + (index * B43_SEC_KEYSIZE);
 for (i = 0; i < B43_SEC_KEYSIZE; i += 2) {
  value = key[i];
  value |= (u16) (key[i + 1]) << 8;
  b43_shm_write16(dev, B43_SHM_SHARED, offset + i, value);
 }
}

static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr)
{
 u32 addrtmp[2] = { 0, 0, };
 u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;

 if (b43_new_kidx_api(dev))
  pairwise_keys_start = B43_NR_GROUP_KEYS;

 B43_WARN_ON(index < pairwise_keys_start);
 /* We have four default TX keys and possibly four default RX keys.
 * Physical mac 0 is mapped to physical key 4 or 8, depending
 * on the firmware version.
 * So we must adjust the index here.
 */

 index -= pairwise_keys_start;
 B43_WARN_ON(index >= B43_NR_PAIRWISE_KEYS);

 if (addr) {
  addrtmp[0] = addr[0];
  addrtmp[0] |= ((u32) (addr[1]) << 8);
  addrtmp[0] |= ((u32) (addr[2]) << 16);
  addrtmp[0] |= ((u32) (addr[3]) << 24);
  addrtmp[1] = addr[4];
  addrtmp[1] |= ((u32) (addr[5]) << 8);
 }

 /* Receive match transmitter address (RCMTA) mechanism */
 b43_shm_write32(dev, B43_SHM_RCMTA,
   (index * 2) + 0, addrtmp[0]);
 b43_shm_write16(dev, B43_SHM_RCMTA,
   (index * 2) + 1, addrtmp[1]);
}

/* The ucode will use phase1 key with TEK key to decrypt rx packets.
 * When a packet is received, the iv32 is checked.
 * - if it doesn't the packet is returned without modification (and software
 *   decryption can be done). That's what happen when iv16 wrap.
 * - if it does, the rc4 key is computed, and decryption is tried.
 *   Either it will success and B43_RX_MAC_DEC is returned,
 *   either it fails and B43_RX_MAC_DEC|B43_RX_MAC_DECERR is returned
 *   and the packet is not usable (it got modified by the ucode).
 * So in order to never have B43_RX_MAC_DECERR, we should provide
 * a iv32 and phase1key that match. Because we drop packets in case of
 * B43_RX_MAC_DECERR, if we have a correct iv32 but a wrong phase1key, all
 * packets will be lost without higher layer knowing (ie no resync possible
 * until next wrap).
 *
 * NOTE : this should support 50 key like RCMTA because
 * (B43_SHM_SH_KEYIDXBLOCK - B43_SHM_SH_TKIPTSCTTAK)/14 = 50
 */

static void rx_tkip_phase1_write(struct b43_wldev *dev, u8 index, u32 iv32,
  u16 *phase1key)
{
 unsigned int i;
 u32 offset;
 u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;

 if (!modparam_hwtkip)
  return;

 if (b43_new_kidx_api(dev))
  pairwise_keys_start = B43_NR_GROUP_KEYS;

 B43_WARN_ON(index < pairwise_keys_start);
 /* We have four default TX keys and possibly four default RX keys.
 * Physical mac 0 is mapped to physical key 4 or 8, depending
 * on the firmware version.
 * So we must adjust the index here.
 */

 index -= pairwise_keys_start;
 B43_WARN_ON(index >= B43_NR_PAIRWISE_KEYS);

 if (b43_debug(dev, B43_DBG_KEYS)) {
  b43dbg(dev->wl, "rx_tkip_phase1_write : idx 0x%x, iv32 0x%x\n",
    index, iv32);
 }
 /* Write the key to the  RX tkip shared mem */
 offset = B43_SHM_SH_TKIPTSCTTAK + index * (10 + 4);
 for (i = 0; i < 10; i += 2) {
  b43_shm_write16(dev, B43_SHM_SHARED, offset + i,
    phase1key ? phase1key[i / 2] : 0);
 }
 b43_shm_write16(dev, B43_SHM_SHARED, offset + i, iv32);
 b43_shm_write16(dev, B43_SHM_SHARED, offset + i + 2, iv32 >> 16);
}

static void b43_op_update_tkip_key(struct ieee80211_hw *hw,
       struct ieee80211_vif *vif,
       struct ieee80211_key_conf *keyconf,
       struct ieee80211_sta *sta,
       u32 iv32, u16 *phase1key)
{
 struct b43_wl *wl = hw_to_b43_wl(hw);
 struct b43_wldev *dev;
 int index = keyconf->hw_key_idx;

 if (B43_WARN_ON(!modparam_hwtkip))
  return;

 /* This is only called from the RX path through mac80211, where
 * our mutex is already locked. */

 B43_WARN_ON(!mutex_is_locked(&wl->mutex));
 dev = wl->current_dev;
 B43_WARN_ON(!dev || b43_status(dev) < B43_STAT_INITIALIZED);

 keymac_write(dev, index, NULL); /* First zero out mac to avoid race */

 rx_tkip_phase1_write(dev, index, iv32, phase1key);
 /* only pairwise TKIP keys are supported right now */
 if (WARN_ON(!sta))
  return;
 keymac_write(dev, index, sta->addr);
}

static void do_key_write(struct b43_wldev *dev,
    u8 index, u8 algorithm,
    const u8 *key, size_t key_len, const u8 *mac_addr)
{
 u8 buf[B43_SEC_KEYSIZE] = { 0, };
 u8 pairwise_keys_start = B43_NR_GROUP_KEYS * 2;

 if (b43_new_kidx_api(dev))
  pairwise_keys_start = B43_NR_GROUP_KEYS;

 B43_WARN_ON(index >= ARRAY_SIZE(dev->key));
 B43_WARN_ON(key_len > B43_SEC_KEYSIZE);

 if (index >= pairwise_keys_start)
  keymac_write(dev, index, NULL); /* First zero out mac. */
 if (algorithm == B43_SEC_ALGO_TKIP) {
  /*
 * We should provide an initial iv32, phase1key pair.
 * We could start with iv32=0 and compute the corresponding
 * phase1key, but this means calling ieee80211_get_tkip_key
 * with a fake skb (or export other tkip function).
 * Because we are lazy we hope iv32 won't start with
 * 0xffffffff and let's b43_op_update_tkip_key provide a
 * correct pair.
 */

  rx_tkip_phase1_write(dev, index, 0xffffffff, (u16*)buf);
 } else if (index >= pairwise_keys_start) /* clear it */
  rx_tkip_phase1_write(dev, index, 0, NULL);
 if (key)
  memcpy(buf, key, key_len);
 key_write(dev, index, algorithm, buf);
 if (index >= pairwise_keys_start)
  keymac_write(dev, index, mac_addr);

 dev->key[index].algorithm = algorithm;
}

static int b43_key_write(struct b43_wldev *dev,
    int index, u8 algorithm,
    const u8 *key, size_t key_len,
    const u8 *mac_addr,
    struct ieee80211_key_conf *keyconf)
{
 int i;
 int pairwise_keys_start;

 /* For ALG_TKIP the key is encoded as a 256-bit (32 byte) data block:
 *  - Temporal Encryption Key (128 bits)
 *  - Temporal Authenticator Tx MIC Key (64 bits)
 *  - Temporal Authenticator Rx MIC Key (64 bits)
 *
 *  Hardware only store TEK
 */

 if (algorithm == B43_SEC_ALGO_TKIP && key_len == 32)
  key_len = 16;
 if (key_len > B43_SEC_KEYSIZE)
  return -EINVAL;
 for (i = 0; i < ARRAY_SIZE(dev->key); i++) {
  /* Check that we don't already have this key. */
  B43_WARN_ON(dev->key[i].keyconf == keyconf);
 }
 if (index < 0) {
  /* Pairwise key. Get an empty slot for the key. */
  if (b43_new_kidx_api(dev))
   pairwise_keys_start = B43_NR_GROUP_KEYS;
  else
   pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
  for (i = pairwise_keys_start;
       i < pairwise_keys_start + B43_NR_PAIRWISE_KEYS;
       i++) {
   B43_WARN_ON(i >= ARRAY_SIZE(dev->key));
   if (!dev->key[i].keyconf) {
    /* found empty */
    index = i;
    break;
   }
  }
  if (index < 0) {
   b43warn(dev->wl, "Out of hardware key memory\n");
   return -ENOSPC;
  }
 } else
  B43_WARN_ON(index > 3);

 do_key_write(dev, index, algorithm, key, key_len, mac_addr);
 if ((index <= 3) && !b43_new_kidx_api(dev)) {
  /* Default RX key */
  B43_WARN_ON(mac_addr);
  do_key_write(dev, index + 4, algorithm, key, key_len, NULL);
 }
 keyconf->hw_key_idx = index;
 dev->key[index].keyconf = keyconf;

 return 0;
}

static int b43_key_clear(struct b43_wldev *dev, int index)
{
 if (B43_WARN_ON((index < 0) || (index >= ARRAY_SIZE(dev->key))))
  return -EINVAL;
 do_key_write(dev, index, B43_SEC_ALGO_NONE,
       NULL, B43_SEC_KEYSIZE, NULL);
 if ((index <= 3) && !b43_new_kidx_api(dev)) {
  do_key_write(dev, index + 4, B43_SEC_ALGO_NONE,
        NULL, B43_SEC_KEYSIZE, NULL);
 }
 dev->key[index].keyconf = NULL;

 return 0;
}

static void b43_clear_keys(struct b43_wldev *dev)
{
 int i, count;

 if (b43_new_kidx_api(dev))
  count = B43_NR_GROUP_KEYS + B43_NR_PAIRWISE_KEYS;
 else
  count = B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS;
 for (i = 0; i < count; i++)
  b43_key_clear(dev, i);
}

static void b43_dump_keymemory(struct b43_wldev *dev)
{
 unsigned int i, index, count, offset, pairwise_keys_start;
 u8 mac[ETH_ALEN];
 u16 algo;
 u32 rcmta0;
 u16 rcmta1;
 u64 hf;
 struct b43_key *key;

 if (!b43_debug(dev, B43_DBG_KEYS))
  return;

 hf = b43_hf_read(dev);
 b43dbg(dev->wl, "Hardware key memory dump: USEDEFKEYS=%u\n",
        !!(hf & B43_HF_USEDEFKEYS));
 if (b43_new_kidx_api(dev)) {
  pairwise_keys_start = B43_NR_GROUP_KEYS;
  count = B43_NR_GROUP_KEYS + B43_NR_PAIRWISE_KEYS;
 } else {
  pairwise_keys_start = B43_NR_GROUP_KEYS * 2;
  count = B43_NR_GROUP_KEYS * 2 + B43_NR_PAIRWISE_KEYS;
 }
 for (index = 0; index < count; index++) {
  key = &(dev->key[index]);
  printk(KERN_DEBUG "Key slot %02u: %s",
         index, (key->keyconf == NULL) ? " " : "*");
  offset = dev->ktp + (index * B43_SEC_KEYSIZE);
  for (i = 0; i < B43_SEC_KEYSIZE; i += 2) {
   u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i);
   printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF));
  }

  algo = b43_shm_read16(dev, B43_SHM_SHARED,
          B43_SHM_SH_KEYIDXBLOCK + (index * 2));
  printk(" Algo: %04X/%02X", algo, key->algorithm);

  if (index >= pairwise_keys_start) {
   if (key->algorithm == B43_SEC_ALGO_TKIP) {
    printk(" TKIP: ");
    offset = B43_SHM_SH_TKIPTSCTTAK + (index - 4) * (10 + 4);
    for (i = 0; i < 14; i += 2) {
     u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i);
     printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF));
    }
   }
   rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA,
      ((index - pairwise_keys_start) * 2) + 0);
   rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA,
      ((index - pairwise_keys_start) * 2) + 1);
   *((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0);
   *((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1);
   printk(" MAC: %pM", mac);
  } else
   printk(" DEFAULT KEY");
  printk("\n");
 }
}

void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
{
 u32 macctl;
 u16 ucstat;
 bool hwps;
 bool awake;
 int i;

 B43_WARN_ON((ps_flags & B43_PS_ENABLED) &&
      (ps_flags & B43_PS_DISABLED));
 B43_WARN_ON((ps_flags & B43_PS_AWAKE) && (ps_flags & B43_PS_ASLEEP));

 if (ps_flags & B43_PS_ENABLED) {
  hwps = true;
 } else if (ps_flags & B43_PS_DISABLED) {
  hwps = false;
 } else {
  //TODO: If powersave is not off and FIXME is not set and we are not in adhoc
  //      and thus is not an AP and we are associated, set bit 25
 }
 if (ps_flags & B43_PS_AWAKE) {
  awake = true;
 } else if (ps_flags & B43_PS_ASLEEP) {
  awake = false;
 } else {
  //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME,
  //      or we are associated, or FIXME, or the latest PS-Poll packet sent was
  //      successful, set bit26
 }

/* FIXME: For now we force awake-on and hwps-off */
 hwps = false;
 awake = true;

 macctl = b43_read32(dev, B43_MMIO_MACCTL);
 if (hwps)
  macctl |= B43_MACCTL_HWPS;
 else
  macctl &= ~B43_MACCTL_HWPS;
 if (awake)
  macctl |= B43_MACCTL_AWAKE;
 else
  macctl &= ~B43_MACCTL_AWAKE;
 b43_write32(dev, B43_MMIO_MACCTL, macctl);
 /* Commit write */
 b43_read32(dev, B43_MMIO_MACCTL);
 if (awake && dev->dev->core_rev >= 5) {
  /* Wait for the microcode to wake up. */
  for (i = 0; i < 100; i++) {
   ucstat = b43_shm_read16(dev, B43_SHM_SHARED,
      B43_SHM_SH_UCODESTAT);
   if (ucstat != B43_SHM_SH_UCODESTAT_SLEEP)
    break;
   udelay(10);
  }
 }
}

/* https://bcm-v4.sipsolutions.net/802.11/PHY/BmacCorePllReset */
void b43_wireless_core_phy_pll_reset(struct b43_wldev *dev)
{
 struct bcma_drv_cc *bcma_cc __maybe_unused;
 struct ssb_chipcommon *ssb_cc __maybe_unused;

 switch (dev->dev->bus_type) {
#ifdef CONFIG_B43_BCMA
 case B43_BUS_BCMA:
  bcma_cc = &dev->dev->bdev->bus->drv_cc;

  bcma_cc_write32(bcma_cc, BCMA_CC_PMU_CHIPCTL_ADDR, 0);
  bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
  bcma_cc_set32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, 0x4);
  bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
  break;
#endif
#ifdef CONFIG_B43_SSB
 case B43_BUS_SSB:
  ssb_cc = &dev->dev->sdev->bus->chipco;

  chipco_write32(ssb_cc, SSB_CHIPCO_CHIPCTL_ADDR, 0);
  chipco_mask32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, ~0x4);
  chipco_set32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, 0x4);
  chipco_mask32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, ~0x4);
  break;
#endif
 }
}

#ifdef CONFIG_B43_BCMA
static void b43_bcma_phy_reset(struct b43_wldev *dev)
{
 u32 flags;

 /* Put PHY into reset */
 flags = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
 flags |= B43_BCMA_IOCTL_PHY_RESET;
 flags |= B43_BCMA_IOCTL_PHY_BW_20MHZ; /* Make 20 MHz def */
 bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, flags);
 udelay(2);

 b43_phy_take_out_of_reset(dev);
}

static void b43_bcma_wireless_core_reset(struct b43_wldev *dev, bool gmode)
{
 u32 req = B43_BCMA_CLKCTLST_80211_PLL_REQ |
    B43_BCMA_CLKCTLST_PHY_PLL_REQ;
 u32 status = B43_BCMA_CLKCTLST_80211_PLL_ST |
       B43_BCMA_CLKCTLST_PHY_PLL_ST;
 u32 flags;

 flags = B43_BCMA_IOCTL_PHY_CLKEN;
 if (gmode)
  flags |= B43_BCMA_IOCTL_GMODE;
 b43_device_enable(dev, flags);

 if (dev->phy.type == B43_PHYTYPE_AC) {
  u16 tmp;

  tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
  tmp &= ~B43_BCMA_IOCTL_DAC;
  tmp |= 0x100;
  bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);

  tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
  tmp &= ~B43_BCMA_IOCTL_PHY_CLKEN;
  bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);

  tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
  tmp |= B43_BCMA_IOCTL_PHY_CLKEN;
  bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
 }

 bcma_core_set_clockmode(dev->dev->bdev, BCMA_CLKMODE_FAST);
 b43_bcma_phy_reset(dev);
 bcma_core_pll_ctl(dev->dev->bdev, req, status, true);
}
#endif

#ifdef CONFIG_B43_SSB
static void b43_ssb_wireless_core_reset(struct b43_wldev *dev, bool gmode)
{
 u32 flags = 0;

 if (gmode)
  flags |= B43_TMSLOW_GMODE;
 flags |= B43_TMSLOW_PHYCLKEN;
 flags |= B43_TMSLOW_PHYRESET;
 if (dev->phy.type == B43_PHYTYPE_N)
  flags |= B43_TMSLOW_PHY_BANDWIDTH_20MHZ; /* Make 20 MHz def */
 b43_device_enable(dev, flags);
 msleep(2);  /* Wait for the PLL to turn on. */

 b43_phy_take_out_of_reset(dev);
}
#endif

void b43_wireless_core_reset(struct b43_wldev *dev, bool gmode)
{
 u32 macctl;

 switch (dev->dev->bus_type) {
#ifdef CONFIG_B43_BCMA
 case B43_BUS_BCMA:
  b43_bcma_wireless_core_reset(dev, gmode);
  break;
#endif
#ifdef CONFIG_B43_SSB
 case B43_BUS_SSB:
  b43_ssb_wireless_core_reset(dev, gmode);
  break;
#endif
 }

 /* Turn Analog ON, but only if we already know the PHY-type.
 * This protects against very early setup where we don't know the
 * PHY-type, yet. wireless_core_reset will be called once again later,
 * when we know the PHY-type. */

 if (dev->phy.ops)
  dev->phy.ops->switch_analog(dev, 1);

 macctl = b43_read32(dev, B43_MMIO_MACCTL);
 macctl &= ~B43_MACCTL_GMODE;
 if (gmode)
  macctl |= B43_MACCTL_GMODE;
 macctl |= B43_MACCTL_IHR_ENABLED;
 b43_write32(dev, B43_MMIO_MACCTL, macctl);
}

static void handle_irq_transmit_status(struct b43_wldev *dev)
{
 u32 v0, v1;
 u16 tmp;
 struct b43_txstatus stat;

 while (1) {
  v0 = b43_read32(dev, B43_MMIO_XMITSTAT_0);
  if (!(v0 & 0x00000001))
   break;
  v1 = b43_read32(dev, B43_MMIO_XMITSTAT_1);

  stat.cookie = (v0 >> 16);
  stat.seq = (v1 & 0x0000FFFF);
  stat.phy_stat = ((v1 & 0x00FF0000) >> 16);
  tmp = (v0 & 0x0000FFFF);
  stat.frame_count = ((tmp & 0xF000) >> 12);
  stat.rts_count = ((tmp & 0x0F00) >> 8);
  stat.supp_reason = ((tmp & 0x001C) >> 2);
  stat.pm_indicated = !!(tmp & 0x0080);
  stat.intermediate = !!(tmp & 0x0040);
  stat.for_ampdu = !!(tmp & 0x0020);
  stat.acked = !!(tmp & 0x0002);

  b43_handle_txstatus(dev, &stat);
 }
}

static void drain_txstatus_queue(struct b43_wldev *dev)
{
 u32 dummy;

 if (dev->dev->core_rev < 5)
  return;
 /* Read all entries from the microcode TXstatus FIFO
 * and throw them away.
 */

 while (1) {
  dummy = b43_read32(dev, B43_MMIO_XMITSTAT_0);
  if (!(dummy & 0x00000001))
   break;
  dummy = b43_read32(dev, B43_MMIO_XMITSTAT_1);
 }
}

static u32 b43_jssi_read(struct b43_wldev *dev)
{
 u32 val = 0;

 val = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_JSSI1);
 val <<= 16;
 val |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_JSSI0);

 return val;
}

static void b43_jssi_write(struct b43_wldev *dev, u32 jssi)
{
 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_JSSI0,
   (jssi & 0x0000FFFF));
 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_JSSI1,
   (jssi & 0xFFFF0000) >> 16);
}

static void b43_generate_noise_sample(struct b43_wldev *dev)
{
 b43_jssi_write(dev, 0x7F7F7F7F);
 b43_write32(dev, B43_MMIO_MACCMD,
      b43_read32(dev, B43_MMIO_MACCMD) | B43_MACCMD_BGNOISE);
}

static void b43_calculate_link_quality(struct b43_wldev *dev)
{
 /* Top half of Link Quality calculation. */

 if (dev->phy.type != B43_PHYTYPE_G)
  return;
 if (dev->noisecalc.calculation_running)
  return;
 dev->noisecalc.calculation_running = true;
 dev->noisecalc.nr_samples = 0;

 b43_generate_noise_sample(dev);
}

static void handle_irq_noise(struct b43_wldev *dev)
{
 struct b43_phy_g *phy = dev->phy.g;
 u16 tmp;
 u8 noise[4];
 u8 i, j;
 s32 average;

 /* Bottom half of Link Quality calculation. */

 if (dev->phy.type != B43_PHYTYPE_G)
  return;

 /* Possible race condition: It might be possible that the user
 * changed to a different channel in the meantime since we
 * started the calculation. We ignore that fact, since it's
 * not really that much of a problem. The background noise is
 * an estimation only anyway. Slightly wrong results will get damped
 * by the averaging of the 8 sample rounds. Additionally the
 * value is shortlived. So it will be replaced by the next noise
 * calculation round soon. */


 B43_WARN_ON(!dev->noisecalc.calculation_running);
 *((__le32 *)noise) = cpu_to_le32(b43_jssi_read(dev));
 if (noise[0] == 0x7F || noise[1] == 0x7F ||
     noise[2] == 0x7F || noise[3] == 0x7F)
  goto generate_new;

 /* Get the noise samples. */
 B43_WARN_ON(dev->noisecalc.nr_samples >= 8);
 i = dev->noisecalc.nr_samples;
 noise[0] = clamp_val(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
 noise[1] = clamp_val(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
 noise[2] = clamp_val(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
 noise[3] = clamp_val(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
 dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]];
 dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]];
 dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]];
 dev->noisecalc.samples[i][3] = phy->nrssi_lt[noise[3]];
 dev->noisecalc.nr_samples++;
 if (dev->noisecalc.nr_samples == 8) {
  /* Calculate the Link Quality by the noise samples. */
  average = 0;
  for (i = 0; i < 8; i++) {
   for (j = 0; j < 4; j++)
    average += dev->noisecalc.samples[i][j];
  }
  average /= (8 * 4);
  average *= 125;
  average += 64;
  average /= 128;
  tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x40C);
  tmp = (tmp / 128) & 0x1F;
  if (tmp >= 8)
   average += 2;
  else
   average -= 25;
  if (tmp == 8)
   average -= 72;
  else
   average -= 48;

  dev->stats.link_noise = average;
  dev->noisecalc.calculation_running = false;
  return;
 }
generate_new:
 b43_generate_noise_sample(dev);
}

static void handle_irq_tbtt_indication(struct b43_wldev *dev)
{
 if (b43_is_mode(dev->wl, NL80211_IFTYPE_AP)) {
  ///TODO: PS TBTT
 } else {
  if (1 /*FIXME: the last PSpoll frame was sent successfully */ )
   b43_power_saving_ctl_bits(dev, 0);
 }
 if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC))
  dev->dfq_valid = true;
}

static void handle_irq_atim_end(struct b43_wldev *dev)
{
 if (dev->dfq_valid) {
  b43_write32(dev, B43_MMIO_MACCMD,
       b43_read32(dev, B43_MMIO_MACCMD)
       | B43_MACCMD_DFQ_VALID);
  dev->dfq_valid = false;
 }
}

static void handle_irq_pmq(struct b43_wldev *dev)
{
 u32 tmp;

 //TODO: AP mode.

 while (1) {
  tmp = b43_read32(dev, B43_MMIO_PS_STATUS);
  if (!(tmp & 0x00000008))
   break;
 }
 /* 16bit write is odd, but correct. */
 b43_write16(dev, B43_MMIO_PS_STATUS, 0x0002);
}

static void b43_write_template_common(struct b43_wldev *dev,
          const u8 *data, u16 size,
          u16 ram_offset,
          u16 shm_size_offset, u8 rate)
{
 u32 i, tmp;
 struct b43_plcp_hdr4 plcp;

 plcp.data = 0;
 b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
 b43_ram_write(dev, ram_offset, le32_to_cpu(plcp.data));
 ram_offset += sizeof(u32);
 /* The PLCP is 6 bytes long, but we only wrote 4 bytes, yet.
 * So leave the first two bytes of the next write blank.
 */

 tmp = (u32) (data[0]) << 16;
 tmp |= (u32) (data[1]) << 24;
 b43_ram_write(dev, ram_offset, tmp);
 ram_offset += sizeof(u32);
 for (i = 2; i < size; i += sizeof(u32)) {
  tmp = (u32) (data[i + 0]);
  if (i + 1 < size)
   tmp |= (u32) (data[i + 1]) << 8;
  if (i + 2 < size)
   tmp |= (u32) (data[i + 2]) << 16;
  if (i + 3 < size)
   tmp |= (u32) (data[i + 3]) << 24;
  b43_ram_write(dev, ram_offset + i - 2, tmp);
 }
 b43_shm_write16(dev, B43_SHM_SHARED, shm_size_offset,
   size + sizeof(struct b43_plcp_hdr6));
}

/* Check if the use of the antenna that ieee80211 told us to
 * use is possible. This will fall back to DEFAULT.
 * "antenna_nr" is the antenna identifier we got from ieee80211. */

u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
      u8 antenna_nr)
{
 u8 antenna_mask;

 if (antenna_nr == 0) {
  /* Zero means "use default antenna". That's always OK. */
  return 0;
 }

 /* Get the mask of available antennas. */
 if (dev->phy.gmode)
  antenna_mask = dev->dev->bus_sprom->ant_available_bg;
 else
  antenna_mask = dev->dev->bus_sprom->ant_available_a;

 if (!(antenna_mask & (1 << (antenna_nr - 1)))) {
  /* This antenna is not available. Fall back to default. */
  return 0;
 }

 return antenna_nr;
}

/* Convert a b43 antenna number value to the PHY TX control value. */
static u16 b43_antenna_to_phyctl(int antenna)
{
 switch (antenna) {
 case B43_ANTENNA0:
  return B43_TXH_PHY_ANT0;
 case B43_ANTENNA1:
  return B43_TXH_PHY_ANT1;
 case B43_ANTENNA2:
  return B43_TXH_PHY_ANT2;
 case B43_ANTENNA3:
  return B43_TXH_PHY_ANT3;
 case B43_ANTENNA_AUTO0:
 case B43_ANTENNA_AUTO1:
  return B43_TXH_PHY_ANT01AUTO;
 }
 B43_WARN_ON(1);
 return 0;
}

static void b43_write_beacon_template(struct b43_wldev *dev,
          u16 ram_offset,
          u16 shm_size_offset)
{
 unsigned int i, len, variable_len;
 const struct ieee80211_mgmt *bcn;
 const u8 *ie;
 bool tim_found = false;
 unsigned int rate;
 u16 ctl;
 int antenna;
 struct ieee80211_tx_info *info;
 unsigned long flags;
 struct sk_buff *beacon_skb;

 spin_lock_irqsave(&dev->wl->beacon_lock, flags);
 info = IEEE80211_SKB_CB(dev->wl->current_beacon);
 rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
 /* Clone the beacon, so it cannot go away, while we write it to hw. */
 beacon_skb = skb_clone(dev->wl->current_beacon, GFP_ATOMIC);
 spin_unlock_irqrestore(&dev->wl->beacon_lock, flags);

 if (!beacon_skb) {
  b43dbg(dev->wl, "Could not upload beacon. "
         "Failed to clone beacon skb.");
  return;
 }

 bcn = (const struct ieee80211_mgmt *)(beacon_skb->data);
 len = min_t(size_t, beacon_skb->len,
      0x200 - sizeof(struct b43_plcp_hdr6));

 b43_write_template_common(dev, (const u8 *)bcn,
      len, ram_offset, shm_size_offset, rate);

 /* Write the PHY TX control parameters. */
 antenna = B43_ANTENNA_DEFAULT;
 antenna = b43_antenna_to_phyctl(antenna);
 ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
 /* We can't send beacons with short preamble. Would get PHY errors. */
 ctl &= ~B43_TXH_PHY_SHORTPRMBL;
 ctl &= ~B43_TXH_PHY_ANT;
 ctl &= ~B43_TXH_PHY_ENC;
 ctl |= antenna;
 if (b43_is_cck_rate(rate))
  ctl |= B43_TXH_PHY_ENC_CCK;
 else
  ctl |= B43_TXH_PHY_ENC_OFDM;
 b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, ctl);

 /* Find the position of the TIM and the DTIM_period value
 * and write them to SHM. */

 ie = bcn->u.beacon.variable;
 variable_len = len - offsetof(struct ieee80211_mgmt, u.beacon.variable);
 for (i = 0; i < variable_len - 2; ) {
  uint8_t ie_id, ie_len;

  ie_id = ie[i];
  ie_len = ie[i + 1];
  if (ie_id == 5) {
   u16 tim_position;
   u16 dtim_period;
   /* This is the TIM Information Element */

   /* Check whether the ie_len is in the beacon data range. */
   if (variable_len < ie_len + 2 + i)
    break;
   /* A valid TIM is at least 4 bytes long. */
   if (ie_len < 4)
    break;
   tim_found = true;

   tim_position = sizeof(struct b43_plcp_hdr6);
   tim_position += offsetof(struct ieee80211_mgmt, u.beacon.variable);
   tim_position += i;

   dtim_period = ie[i + 3];

   b43_shm_write16(dev, B43_SHM_SHARED,
     B43_SHM_SH_TIMBPOS, tim_position);
   b43_shm_write16(dev, B43_SHM_SHARED,
     B43_SHM_SH_DTIMPER, dtim_period);
   break;
  }
  i += ie_len + 2;
 }
 if (!tim_found) {
  /*
 * If ucode wants to modify TIM do it behind the beacon, this
 * will happen, for example, when doing mesh networking.
 */

  b43_shm_write16(dev, B43_SHM_SHARED,
    B43_SHM_SH_TIMBPOS,
    len + sizeof(struct b43_plcp_hdr6));
  b43_shm_write16(dev, B43_SHM_SHARED,
    B43_SHM_SH_DTIMPER, 0);
 }
 b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset);

 dev_kfree_skb_any(beacon_skb);
}

static void b43_upload_beacon0(struct b43_wldev *dev)
{
 struct b43_wl *wl = dev->wl;

 if (wl->beacon0_uploaded)
  return;
 b43_write_beacon_template(dev, B43_SHM_SH_BT_BASE0, B43_SHM_SH_BTL0);
 wl->beacon0_uploaded = true;
}

static void b43_upload_beacon1(struct b43_wldev *dev)
{
 struct b43_wl *wl = dev->wl;

 if (wl->beacon1_uploaded)
  return;
 b43_write_beacon_template(dev, B43_SHM_SH_BT_BASE1, B43_SHM_SH_BTL1);
 wl->beacon1_uploaded = true;
}

static void handle_irq_beacon(struct b43_wldev *dev)
{
 struct b43_wl *wl = dev->wl;
 u32 cmd, beacon0_valid, beacon1_valid;

 if (!b43_is_mode(wl, NL80211_IFTYPE_AP) &&
     !b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) &&
     !b43_is_mode(wl, NL80211_IFTYPE_ADHOC))
  return;

 /* This is the bottom half of the asynchronous beacon update. */

 /* Ignore interrupt in the future. */
 dev->irq_mask &= ~B43_IRQ_BEACON;

 cmd = b43_read32(dev, B43_MMIO_MACCMD);
 beacon0_valid = (cmd & B43_MACCMD_BEACON0_VALID);
 beacon1_valid = (cmd & B43_MACCMD_BEACON1_VALID);

 /* Schedule interrupt manually, if busy. */
 if (beacon0_valid && beacon1_valid) {
  b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON);
  dev->irq_mask |= B43_IRQ_BEACON;
  return;
 }

 if (unlikely(wl->beacon_templates_virgin)) {
  /* We never uploaded a beacon before.
 * Upload both templates now, but only mark one valid. */

  wl->beacon_templates_virgin = false;
  b43_upload_beacon0(dev);
  b43_upload_beacon1(dev);
  cmd = b43_read32(dev, B43_MMIO_MACCMD);
  cmd |= B43_MACCMD_BEACON0_VALID;
  b43_write32(dev, B43_MMIO_MACCMD, cmd);
 } else {
  if (!beacon0_valid) {
   b43_upload_beacon0(dev);
   cmd = b43_read32(dev, B43_MMIO_MACCMD);
   cmd |= B43_MACCMD_BEACON0_VALID;
   b43_write32(dev, B43_MMIO_MACCMD, cmd);
  } else if (!beacon1_valid) {
   b43_upload_beacon1(dev);
   cmd = b43_read32(dev, B43_MMIO_MACCMD);
   cmd |= B43_MACCMD_BEACON1_VALID;
   b43_write32(dev, B43_MMIO_MACCMD, cmd);
  }
 }
}

static void b43_do_beacon_update_trigger_work(struct b43_wldev *dev)
{
 u32 old_irq_mask = dev->irq_mask;

 /* update beacon right away or defer to irq */
 handle_irq_beacon(dev);
 if (old_irq_mask != dev->irq_mask) {
  /* The handler updated the IRQ mask. */
  B43_WARN_ON(!dev->irq_mask);
  if (b43_read32(dev, B43_MMIO_GEN_IRQ_MASK)) {
   b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
  } else {
   /* Device interrupts are currently disabled. That means
 * we just ran the hardirq handler and scheduled the
 * IRQ thread. The thread will write the IRQ mask when
 * it finished, so there's nothing to do here. Writing
 * the mask _here_ would incorrectly re-enable IRQs. */

  }
 }
}

static void b43_beacon_update_trigger_work(struct work_struct *work)
{
 struct b43_wl *wl = container_of(work, struct b43_wl,
      beacon_update_trigger);
 struct b43_wldev *dev;

 mutex_lock(&wl->mutex);
 dev = wl->current_dev;
 if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) {
  if (b43_bus_host_is_sdio(dev->dev)) {
   /* wl->mutex is enough. */
   b43_do_beacon_update_trigger_work(dev);
  } else {
   spin_lock_irq(&wl->hardirq_lock);
   b43_do_beacon_update_trigger_work(dev);
   spin_unlock_irq(&wl->hardirq_lock);
  }
 }
 mutex_unlock(&wl->mutex);
}

/* Asynchronously update the packet templates in template RAM. */
static void b43_update_templates(struct b43_wl *wl)
{
 struct sk_buff *beacon, *old_beacon;
 unsigned long flags;

 /* This is the top half of the asynchronous beacon update.
 * The bottom half is the beacon IRQ.
 * Beacon update must be asynchronous to avoid sending an
 * invalid beacon. This can happen for example, if the firmware
 * transmits a beacon while we are updating it. */


 /* We could modify the existing beacon and set the aid bit in
 * the TIM field, but that would probably require resizing and
 * moving of data within the beacon template.
 * Simply request a new beacon and let mac80211 do the hard work. */

 beacon = ieee80211_beacon_get(wl->hw, wl->vif, 0);
 if (unlikely(!beacon))
  return;

 spin_lock_irqsave(&wl->beacon_lock, flags);
 old_beacon = wl->current_beacon;
 wl->current_beacon = beacon;
 wl->beacon0_uploaded = false;
 wl->beacon1_uploaded = false;
 spin_unlock_irqrestore(&wl->beacon_lock, flags);

 ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger);

 if (old_beacon)
  dev_kfree_skb_any(old_beacon);
}

static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
{
 b43_time_lock(dev);
 if (dev->dev->core_rev >= 3) {
  b43_write32(dev, B43_MMIO_TSF_CFP_REP, (beacon_int << 16));
  b43_write32(dev, B43_MMIO_TSF_CFP_START, (beacon_int << 10));
 } else {
  b43_write16(dev, 0x606, (beacon_int >> 6));
  b43_write16(dev, 0x610, beacon_int);
 }
 b43_time_unlock(dev);
 b43dbg(dev->wl, "Set beacon interval to %u\n", beacon_int);
}

static void b43_handle_firmware_panic(struct b43_wldev *dev)
{
 u16 reason;

 /* Read the register that contains the reason code for the panic. */
 reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_FWPANIC_REASON_REG);
 b43err(dev->wl, "Whoopsy, firmware panic! Reason: %u\n", reason);

 switch (reason) {
 default:
  b43dbg(dev->wl, "The panic reason is unknown.\n");
  fallthrough;
 case B43_FWPANIC_DIE:
  /* Do not restart the controller or firmware.
 * The device is nonfunctional from now on.
 * Restarting would result in this panic to trigger again,
 * so we avoid that recursion. */

  break;
 case B43_FWPANIC_RESTART:
  b43_controller_restart(dev, "Microcode panic");
  break;
 }
}

static void handle_irq_ucode_debug(struct b43_wldev *dev)
{
 unsigned int i, cnt;
 u16 reason, marker_id, marker_line;
 __le16 *buf;

 /* The proprietary firmware doesn't have this IRQ. */
 if (!dev->fw.opensource)
  return;

 /* Read the register that contains the reason code for this IRQ. */
 reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_DEBUGIRQ_REASON_REG);

 switch (reason) {
 case B43_DEBUGIRQ_PANIC:
  b43_handle_firmware_panic(dev);
  break;
 case B43_DEBUGIRQ_DUMP_SHM:
  if (!B43_DEBUG)
   break/* Only with driver debugging enabled. */
  buf = kmalloc(4096, GFP_ATOMIC);
  if (!buf) {
   b43dbg(dev->wl, "SHM-dump: Failed to allocate memory\n");
   goto out;
  }
  for (i = 0; i < 4096; i += 2) {
   u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, i);
   buf[i / 2] = cpu_to_le16(tmp);
  }
  b43info(dev->wl, "Shared memory dump:\n");
  print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET,
          16, 2, buf, 4096, 1);
  kfree(buf);
  break;
 case B43_DEBUGIRQ_DUMP_REGS:
  if (!B43_DEBUG)
   break/* Only with driver debugging enabled. */
  b43info(dev->wl, "Microcode register dump:\n");
  for (i = 0, cnt = 0; i < 64; i++) {
   u16 tmp = b43_shm_read16(dev, B43_SHM_SCRATCH, i);
   if (cnt == 0)
    printk(KERN_INFO);
   printk("r%02u: 0x%04X ", i, tmp);
   cnt++;
   if (cnt == 6) {
    printk("\n");
    cnt = 0;
   }
  }
  printk("\n");
  break;
 case B43_DEBUGIRQ_MARKER:
  if (!B43_DEBUG)
   break/* Only with driver debugging enabled. */
  marker_id = b43_shm_read16(dev, B43_SHM_SCRATCH,
        B43_MARKER_ID_REG);
  marker_line = b43_shm_read16(dev, B43_SHM_SCRATCH,
          B43_MARKER_LINE_REG);
  b43info(dev->wl, "The firmware just executed the MARKER(%u) "
   "at line number %u\n",
   marker_id, marker_line);
  break;
 default:
  b43dbg(dev->wl, "Debug-IRQ triggered for unknown reason: %u\n",
         reason);
 }
out:
 /* Acknowledge the debug-IRQ, so the firmware can continue. */
 b43_shm_write16(dev, B43_SHM_SCRATCH,
   B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK);
}

static void b43_do_interrupt_thread(struct b43_wldev *dev)
{
 u32 reason;
 u32 dma_reason[ARRAY_SIZE(dev->dma_reason)];
 u32 merged_dma_reason = 0;
 int i;

 if (unlikely(b43_status(dev) != B43_STAT_STARTED))
  return;

 reason = dev->irq_reason;
 for (i = 0; i < ARRAY_SIZE(dma_reason); i++) {
  dma_reason[i] = dev->dma_reason[i];
  merged_dma_reason |= dma_reason[i];
 }

 if (unlikely(reason & B43_IRQ_MAC_TXERR))
  b43err(dev->wl, "MAC transmission error\n");

 if (unlikely(reason & B43_IRQ_PHY_TXERR)) {
  b43err(dev->wl, "PHY transmission error\n");
  rmb();
  if (unlikely(atomic_dec_and_test(&dev->phy.txerr_cnt))) {
   atomic_set(&dev->phy.txerr_cnt,
       B43_PHY_TX_BADNESS_LIMIT);
   b43err(dev->wl, "Too many PHY TX errors, "
     "restarting the controller\n");
   b43_controller_restart(dev, "PHY TX errors");
  }
 }

 if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK))) {
  b43err(dev->wl,
   "Fatal DMA error: 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
   dma_reason[0], dma_reason[1],
   dma_reason[2], dma_reason[3],
   dma_reason[4], dma_reason[5]);
  b43err(dev->wl, "This device does not support DMA "
          "on your system. It will now be switched to PIO.\n");
  /* Fall back to PIO transfers if we get fatal DMA errors! */
  dev->use_pio = true;
  b43_controller_restart(dev, "DMA error");
  return;
 }

 if (unlikely(reason & B43_IRQ_UCODE_DEBUG))
  handle_irq_ucode_debug(dev);
 if (reason & B43_IRQ_TBTT_INDI)
  handle_irq_tbtt_indication(dev);
 if (reason & B43_IRQ_ATIM_END)
  handle_irq_atim_end(dev);
 if (reason & B43_IRQ_BEACON)
  handle_irq_beacon(dev);
 if (reason & B43_IRQ_PMQ)
  handle_irq_pmq(dev);
 if (reason & B43_IRQ_TXFIFO_FLUSH_OK) {
  ;/* TODO */
 }
 if (reason & B43_IRQ_NOISESAMPLE_OK)
  handle_irq_noise(dev);

 /* Check the DMA reason registers for received data. */
 if (dma_reason[0] & B43_DMAIRQ_RDESC_UFLOW) {
  if (B43_DEBUG)
   b43warn(dev->wl, "RX descriptor underrun\n");
  b43_dma_handle_rx_overflow(dev->dma.rx_ring);
 }
 if (dma_reason[0] & B43_DMAIRQ_RX_DONE) {
  if (b43_using_pio_transfers(dev))
   b43_pio_rx(dev->pio.rx_queue);
  else
   b43_dma_rx(dev->dma.rx_ring);
 }
 B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE);
 B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE);
 B43_WARN_ON(dma_reason[3] & B43_DMAIRQ_RX_DONE);
 B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE);
 B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE);

 if (reason & B43_IRQ_TX_OK)
  handle_irq_transmit_status(dev);

 /* Re-enable interrupts on the device by restoring the current interrupt mask. */
 b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);

#if B43_DEBUG
 if (b43_debug(dev, B43_DBG_VERBOSESTATS)) {
  dev->irq_count++;
  for (i = 0; i < ARRAY_SIZE(dev->irq_bit_count); i++) {
   if (reason & (1 << i))
    dev->irq_bit_count[i]++;
  }
 }
#endif
}

/* Interrupt thread handler. Handles device interrupts in thread context. */
static irqreturn_t b43_interrupt_thread_handler(int irq, void *dev_id)
{
 struct b43_wldev *dev = dev_id;

 mutex_lock(&dev->wl->mutex);
 b43_do_interrupt_thread(dev);
 mutex_unlock(&dev->wl->mutex);

 return IRQ_HANDLED;
}

static irqreturn_t b43_do_interrupt(struct b43_wldev *dev)
{
 u32 reason;

 /* This code runs under wl->hardirq_lock, but _only_ on non-SDIO busses.
 * On SDIO, this runs under wl->mutex. */


 reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
 if (reason == 0xffffffff) /* shared IRQ */
  return IRQ_NONE;
 reason &= dev->irq_mask;
 if (!reason)
  return IRQ_NONE;

 dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON)
     & 0x0001FC00;
 dev->dma_reason[1] = b43_read32(dev, B43_MMIO_DMA1_REASON)
     & 0x0000DC00;
 dev->dma_reason[2] = b43_read32(dev, B43_MMIO_DMA2_REASON)
     & 0x0000DC00;
 dev->dma_reason[3] = b43_read32(dev, B43_MMIO_DMA3_REASON)
     & 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;
*/


 /* ACK the interrupt. */
 b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason);
 b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]);
 b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]);
 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]);
*/


 /* Disable IRQs on the device. The IRQ thread handler will re-enable them. */
 b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
 /* Save the reason bitmasks for the IRQ thread handler. */
 dev->irq_reason = reason;

 return IRQ_WAKE_THREAD;
}

/* Interrupt handler top-half. This runs with interrupts disabled. */
static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
{
 struct b43_wldev *dev = dev_id;
 irqreturn_t ret;

 if (unlikely(b43_status(dev) < B43_STAT_STARTED))
  return IRQ_NONE;

 spin_lock(&dev->wl->hardirq_lock);
 ret = b43_do_interrupt(dev);
 spin_unlock(&dev->wl->hardirq_lock);

 return ret;
}

/* SDIO interrupt handler. This runs in process context. */
static void b43_sdio_interrupt_handler(struct b43_wldev *dev)
{
 struct b43_wl *wl = dev->wl;
 irqreturn_t ret;

 mutex_lock(&wl->mutex);

 ret = b43_do_interrupt(dev);
 if (ret == IRQ_WAKE_THREAD)
  b43_do_interrupt_thread(dev);

 mutex_unlock(&wl->mutex);
}

void b43_do_release_fw(struct b43_firmware_file *fw)
{
 release_firmware(fw->data);
 fw->data = NULL;
 fw->filename = NULL;
}

static void b43_release_firmware(struct b43_wldev *dev)
{
 complete(&dev->fw_load_complete);
 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[] =
  "You must go to " \
  "https://wireless.docs.kernel.org/en/latest/en/users/drivers/b43/developers.html#list-of-firmware " \
  "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 void b43_fw_cb(const struct firmware *firmware, void *context)
{
 struct b43_request_fw_context *ctx = context;

 ctx->blob = firmware;
 complete(&ctx->dev->fw_load_complete);
}

int b43_do_request_fw(struct b43_request_fw_context *ctx,
        const char *name,
        struct b43_firmware_file *fw, bool async)
{
 struct b43_fw_header *hdr;
 u32 size;
 int err;

 if (!name) {
  /* Don't fetch anything. Free possibly cached firmware. */
  /* 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 ((fw->type == ctx->req_type) &&
      (strcmp(fw->filename, name) == 0))
   return 0; /* Already have this fw. */
  /* Free the cached firmware first. */
  /* 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;
 }
 if (async) {
  /* do this part asynchronously */
  init_completion(&ctx->dev->fw_load_complete);
  err = request_firmware_nowait(THIS_MODULE, 1, ctx->fwname,
           ctx->dev->dev->dev, GFP_KERNEL,
           ctx, b43_fw_cb);
  if (err < 0) {
   pr_err("Unable to load firmware\n");
   return err;
  }
  wait_for_completion(&ctx->dev->fw_load_complete);
  if (ctx->blob)
   goto fw_ready;
 /* On some ARM systems, the async request will fail, but the next sync
 * request works. For this reason, we fall through here
 */

 }
 err = request_firmware(&ctx->blob, ctx->fwname,
          ctx->dev->dev->dev);
 if (err == -ENOENT) {
  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) {
  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;
 }
fw_ready:
 if (ctx->blob->size < sizeof(struct b43_fw_header))
  goto err_format;
 hdr = (struct b43_fw_header *)(ctx->blob->data);
 switch (hdr->type) {
 case B43_FW_TYPE_UCODE:
 case B43_FW_TYPE_PCM:
  size = be32_to_cpu(hdr->size);
  if (size != ctx->blob->size - sizeof(struct b43_fw_header))
   goto err_format;
  fallthrough;
 case B43_FW_TYPE_IV:
  if (hdr->ver != 1)
   goto err_format;
  break;
 default:
  goto err_format;
 }

 fw->data = ctx->blob;
 fw->filename = name;
 fw->type = ctx->req_type;

 return 0;

err_format:
 snprintf(ctx->errors[ctx->req_type],
   sizeof(ctx->errors[ctx->req_type]),
   "Firmware file \"%s\" format error.\n", ctx->fwname);
 release_firmware(ctx->blob);

 return -EPROTO;
}

/* https://bcm-v4.sipsolutions.net/802.11/Init/Firmware */
static int b43_try_request_fw(struct b43_request_fw_context *ctx)
{
 struct b43_wldev *dev = ctx->dev;
 struct b43_firmware *fw = &ctx->dev->fw;
 struct b43_phy *phy = &dev->phy;
 const u8 rev = ctx->dev->dev->core_rev;
 const char *filename;
 int err;

 /* Get microcode */
 filename = NULL;
 switch (rev) {
 case 42:
  if (phy->type == B43_PHYTYPE_AC)
   filename = "ucode42";
  break;
 case 40:
  if (phy->type == B43_PHYTYPE_AC)
   filename = "ucode40";
  break;
 case 33:
  if (phy->type == B43_PHYTYPE_LCN40)
   filename = "ucode33_lcn40";
  break;
 case 30:
  if (phy->type == B43_PHYTYPE_N)
   filename = "ucode30_mimo";
  break;
 case 29:
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=95 H=93 G=93

¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.