#include <linux/moduleparam.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
-#include <linux/version.h>
#include <linux/firmware.h>
#include <linux/wireless.h>
#include <linux/workqueue.h>
#include "b43.h"
#include "main.h"
#include "debugfs.h"
-#include "phy.h"
-#include "nphy.h"
+#include "phy_common.h"
+#include "phy_g.h"
+#include "phy_n.h"
#include "dma.h"
#include "pio.h"
#include "sysfs.h"
break;
udelay(10);
}
- for (i = 0x00; i < 0x0A; i++) {
+ for (i = 0x00; i < 0x19; i++) {
value = b43_read16(dev, 0x0690);
if (!(value & 0x0100))
break;
}
}
-/* Turn the Analog ON/OFF */
-static void b43_switch_analog(struct b43_wldev *dev, int on)
-{
- switch (dev->phy.type) {
- case B43_PHYTYPE_A:
- case B43_PHYTYPE_G:
- b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4);
- break;
- case B43_PHYTYPE_N:
- b43_phy_write(dev, B43_NPHY_AFECTL_OVER,
- on ? 0 : 0x7FFF);
- break;
- default:
- B43_WARN_ON(1);
- }
-}
-
void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
{
u32 tmslow;
ssb_read32(dev->dev, SSB_TMSLOW); /* flush */
msleep(1);
- /* Turn Analog ON */
- b43_switch_analog(dev, 1);
+ /* 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;
{
/* Top half of Link Quality calculation. */
+ if (dev->phy.type != B43_PHYTYPE_G)
+ return;
if (dev->noisecalc.calculation_running)
return;
dev->noisecalc.calculation_running = 1;
static void handle_irq_noise(struct b43_wldev *dev)
{
- struct b43_phy *phy = &dev->phy;
+ struct b43_phy_g *phy = dev->phy.g;
u16 tmp;
u8 noise[4];
u8 i, j;
/* 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
static void handle_irq_tbtt_indication(struct b43_wldev *dev)
{
- if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) {
+ 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, IEEE80211_IF_TYPE_IBSS))
+ if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC))
dev->dfq_valid = 1;
}
struct b43_wl *wl = dev->wl;
u32 cmd, beacon0_valid, beacon1_valid;
- if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP) &&
- !b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
+ if (!b43_is_mode(wl, NL80211_IFTYPE_AP) &&
+ !b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT))
return;
/* This is the bottom half of the asynchronous beacon update. */
/* Asynchronously update the packet templates in template RAM.
* Locking: Requires wl->irq_lock to be locked. */
-static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon)
+static void b43_update_templates(struct b43_wl *wl)
{
+ struct sk_buff *beacon;
+
/* This is the top half of the ansynchronous 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);
+ if (unlikely(!beacon))
+ return;
+
if (wl->current_beacon)
dev_kfree_skb_any(wl->current_beacon);
wl->current_beacon = beacon;
/* http://bcm-specs.sipsolutions.net/EnableMac */
void b43_mac_enable(struct b43_wldev *dev)
{
+ if (b43_debug(dev, B43_DBG_FIRMWARE)) {
+ u16 fwstate;
+
+ fwstate = b43_shm_read16(dev, B43_SHM_SHARED,
+ B43_SHM_SH_UCODESTAT);
+ if ((fwstate != B43_SHM_SH_UCODESTAT_SUSP) &&
+ (fwstate != B43_SHM_SH_UCODESTAT_SLEEP)) {
+ b43err(dev->wl, "b43_mac_enable(): The firmware "
+ "should be suspended, but current state is %u\n",
+ fwstate);
+ }
+ }
+
dev->mac_suspended--;
B43_WARN_ON(dev->mac_suspended < 0);
if (dev->mac_suspended == 0) {
ctl &= ~B43_MACCTL_BEACPROMISC;
ctl |= B43_MACCTL_INFRA;
- if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
- b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
+ if (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
+ b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT))
ctl |= B43_MACCTL_AP;
- else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS))
+ else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC))
ctl &= ~B43_MACCTL_INFRA;
if (wl->filter_flags & FIF_CONTROL)
/* This is the opposite of b43_chip_init() */
static void b43_chip_exit(struct b43_wldev *dev)
{
- b43_radio_turn_off(dev, 1);
+ b43_phy_exit(dev);
b43_gpio_cleanup(dev);
- b43_lo_g_cleanup(dev);
/* firmware is released later */
}
static int b43_chip_init(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
- int err, tmp;
+ int err;
u32 value32, macctl;
u16 value16;
err = b43_upload_initvals(dev);
if (err)
goto err_gpio_clean;
- b43_radio_turn_on(dev);
- b43_write16(dev, 0x03E6, 0x0000);
+ /* Turn the Analog on and initialize the PHY. */
+ phy->ops->switch_analog(dev, 1);
err = b43_phy_init(dev);
if (err)
- goto err_radio_off;
+ goto err_gpio_clean;
- /* Select initial Interference Mitigation. */
- tmp = phy->interfmode;
- phy->interfmode = B43_INTERFMODE_NONE;
- b43_radio_set_interference_mitigation(dev, tmp);
+ /* Disable Interference Mitigation. */
+ if (phy->ops->interf_mitigation)
+ phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE);
- b43_set_rx_antenna(dev, B43_ANTENNA_DEFAULT);
+ /* Select the antennae */
+ if (phy->ops->set_rx_antenna)
+ phy->ops->set_rx_antenna(dev, B43_ANTENNA_DEFAULT);
b43_mgmtframe_txantenna(dev, B43_ANTENNA_DEFAULT);
if (phy->type == B43_PHYTYPE_B) {
out:
return err;
-err_radio_off:
- b43_radio_turn_off(dev, 1);
err_gpio_clean:
b43_gpio_cleanup(dev);
return err;
static void b43_periodic_every60sec(struct b43_wldev *dev)
{
- struct b43_phy *phy = &dev->phy;
+ const struct b43_phy_operations *ops = dev->phy.ops;
- if (phy->type != B43_PHYTYPE_G)
- return;
- if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
- b43_mac_suspend(dev);
- b43_calc_nrssi_slope(dev);
- if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) {
- u8 old_chan = phy->channel;
-
- /* VCO Calibration */
- if (old_chan >= 8)
- b43_radio_selectchannel(dev, 1, 0);
- else
- b43_radio_selectchannel(dev, 13, 0);
- b43_radio_selectchannel(dev, old_chan, 0);
- }
- b43_mac_enable(dev);
- }
+ if (ops->pwork_60sec)
+ ops->pwork_60sec(dev);
+
+ /* Force check the TX power emission now. */
+ b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME);
}
static void b43_periodic_every30sec(struct b43_wldev *dev)
}
}
- if (phy->type == B43_PHYTYPE_G) {
- //TODO: update_aci_moving_average
- if (phy->aci_enable && phy->aci_wlan_automatic) {
- b43_mac_suspend(dev);
- if (!phy->aci_enable && 1 /*TODO: not scanning? */ ) {
- if (0 /*TODO: bunch of conditions */ ) {
- b43_radio_set_interference_mitigation
- (dev, B43_INTERFMODE_MANUALWLAN);
- }
- } else if (1 /*TODO*/) {
- /*
- if ((aci_average > 1000) && !(b43_radio_aci_scan(dev))) {
- b43_radio_set_interference_mitigation(dev,
- B43_INTERFMODE_NONE);
- }
- */
- }
- b43_mac_enable(dev);
- } else if (phy->interfmode == B43_INTERFMODE_NONWLAN &&
- phy->rev == 1) {
- //TODO: implement rev1 workaround
- }
- }
- b43_phy_xmitpower(dev); //FIXME: unless scanning?
- b43_lo_g_maintanance_work(dev);
- //TODO for APHY (temperature?)
+ if (phy->ops->pwork_15sec)
+ phy->ops->pwork_15sec(dev);
atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
wmb();
if (unlikely(skb->len < 2 + 2 + 6)) {
/* Too short, this can't be a valid frame. */
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
+ goto drop_packet;
}
B43_WARN_ON(skb_shinfo(skb)->nr_frags);
if (unlikely(!dev))
- return NETDEV_TX_BUSY;
+ goto drop_packet;
/* Transmissions on seperate queues can run concurrently. */
read_lock_irqsave(&wl->tx_lock, flags);
read_unlock_irqrestore(&wl->tx_lock, flags);
if (unlikely(err))
- return NETDEV_TX_BUSY;
+ goto drop_packet;
+ return NETDEV_TX_OK;
+
+drop_packet:
+ /* We can not transmit this packet. Drop it. */
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
u16 shm_offset)
{
u16 params[B43_NR_QOSPARAMS];
- int cw_min, cw_max, aifs, bslots, tmp;
+ int bslots, tmp;
unsigned int i;
- const u16 aCWmin = 0x0001;
- const u16 aCWmax = 0x03FF;
-
- /* Calculate the default values for the parameters, if needed. */
- switch (shm_offset) {
- case B43_QOS_VOICE:
- aifs = (p->aifs == -1) ? 2 : p->aifs;
- cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 4 - 1) : p->cw_min;
- cw_max = (p->cw_max == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_max;
- break;
- case B43_QOS_VIDEO:
- aifs = (p->aifs == -1) ? 2 : p->aifs;
- cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_min;
- cw_max = (p->cw_max == 0) ? aCWmin : p->cw_max;
- break;
- case B43_QOS_BESTEFFORT:
- aifs = (p->aifs == -1) ? 3 : p->aifs;
- cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min;
- cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max;
- break;
- case B43_QOS_BACKGROUND:
- aifs = (p->aifs == -1) ? 7 : p->aifs;
- cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min;
- cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max;
- break;
- default:
- B43_WARN_ON(1);
- return;
- }
- if (cw_min <= 0)
- cw_min = aCWmin;
- if (cw_max <= 0)
- cw_max = aCWmin;
- bslots = b43_read16(dev, B43_MMIO_RNG) % cw_min;
+ bslots = b43_read16(dev, B43_MMIO_RNG) & p->cw_min;
memset(¶ms, 0, sizeof(params));
params[B43_QOSPARAM_TXOP] = p->txop * 32;
- params[B43_QOSPARAM_CWMIN] = cw_min;
- params[B43_QOSPARAM_CWMAX] = cw_max;
- params[B43_QOSPARAM_CWCUR] = cw_min;
- params[B43_QOSPARAM_AIFS] = aifs;
+ params[B43_QOSPARAM_CWMIN] = p->cw_min;
+ params[B43_QOSPARAM_CWMAX] = p->cw_max;
+ params[B43_QOSPARAM_CWCUR] = p->cw_min;
+ params[B43_QOSPARAM_AIFS] = p->aifs;
params[B43_QOSPARAM_BSLOTS] = bslots;
- params[B43_QOSPARAM_REGGAP] = bslots + aifs;
+ params[B43_QOSPARAM_REGGAP] = bslots + p->aifs;
for (i = 0; i < ARRAY_SIZE(params); i++) {
if (i == B43_QOSPARAM_STATUS) {
}
}
-/* Update the QOS parameters in hardware. */
-static void b43_qos_update(struct b43_wldev *dev)
+/* Mapping of mac80211 queue numbers to b43 QoS SHM offsets. */
+static const u16 b43_qos_shm_offsets[] = {
+ /* [mac80211-queue-nr] = SHM_OFFSET, */
+ [0] = B43_QOS_VOICE,
+ [1] = B43_QOS_VIDEO,
+ [2] = B43_QOS_BESTEFFORT,
+ [3] = B43_QOS_BACKGROUND,
+};
+
+/* Update all QOS parameters in hardware. */
+static void b43_qos_upload_all(struct b43_wldev *dev)
{
struct b43_wl *wl = dev->wl;
struct b43_qos_params *params;
- unsigned long flags;
unsigned int i;
- /* Mapping of mac80211 queues to b43 SHM offsets. */
- static const u16 qos_shm_offsets[] = {
- [0] = B43_QOS_VOICE,
- [1] = B43_QOS_VIDEO,
- [2] = B43_QOS_BESTEFFORT,
- [3] = B43_QOS_BACKGROUND,
- };
- BUILD_BUG_ON(ARRAY_SIZE(qos_shm_offsets) != ARRAY_SIZE(wl->qos_params));
+ BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) !=
+ ARRAY_SIZE(wl->qos_params));
b43_mac_suspend(dev);
- spin_lock_irqsave(&wl->irq_lock, flags);
-
for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) {
params = &(wl->qos_params[i]);
- if (params->need_hw_update) {
- b43_qos_params_upload(dev, &(params->p),
- qos_shm_offsets[i]);
- params->need_hw_update = 0;
- }
+ b43_qos_params_upload(dev, &(params->p),
+ b43_qos_shm_offsets[i]);
}
-
- spin_unlock_irqrestore(&wl->irq_lock, flags);
b43_mac_enable(dev);
}
struct b43_qos_params *params;
unsigned int i;
+ /* Initialize QoS parameters to sane defaults. */
+
+ BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) !=
+ ARRAY_SIZE(wl->qos_params));
+
for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) {
params = &(wl->qos_params[i]);
- memset(&(params->p), 0, sizeof(params->p));
- params->p.aifs = -1;
- params->need_hw_update = 1;
+ switch (b43_qos_shm_offsets[i]) {
+ case B43_QOS_VOICE:
+ params->p.txop = 0;
+ params->p.aifs = 2;
+ params->p.cw_min = 0x0001;
+ params->p.cw_max = 0x0001;
+ break;
+ case B43_QOS_VIDEO:
+ params->p.txop = 0;
+ params->p.aifs = 2;
+ params->p.cw_min = 0x0001;
+ params->p.cw_max = 0x0001;
+ break;
+ case B43_QOS_BESTEFFORT:
+ params->p.txop = 0;
+ params->p.aifs = 3;
+ params->p.cw_min = 0x0001;
+ params->p.cw_max = 0x03FF;
+ break;
+ case B43_QOS_BACKGROUND:
+ params->p.txop = 0;
+ params->p.aifs = 7;
+ params->p.cw_min = 0x0001;
+ params->p.cw_max = 0x03FF;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
}
}
/* Initialize the core's QOS capabilities */
static void b43_qos_init(struct b43_wldev *dev)
{
- struct b43_wl *wl = dev->wl;
- unsigned int i;
-
/* Upload the current QOS parameters. */
- for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++)
- wl->qos_params[i].need_hw_update = 1;
- b43_qos_update(dev);
+ b43_qos_upload_all(dev);
/* Enable QOS support. */
b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF);
| B43_MMIO_IFSCTL_USE_EDCF);
}
-static void b43_qos_update_work(struct work_struct *work)
-{
- struct b43_wl *wl = container_of(work, struct b43_wl, qos_update_work);
- struct b43_wldev *dev;
-
- mutex_lock(&wl->mutex);
- dev = wl->current_dev;
- if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED)))
- b43_qos_update(dev);
- mutex_unlock(&wl->mutex);
-}
-
static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue,
const struct ieee80211_tx_queue_params *params)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
- unsigned long flags;
+ struct b43_wldev *dev;
unsigned int queue = (unsigned int)_queue;
- struct b43_qos_params *p;
+ int err = -ENODEV;
if (queue >= ARRAY_SIZE(wl->qos_params)) {
/* Queue not available or don't support setting
* confuse mac80211. */
return 0;
}
+ BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) !=
+ ARRAY_SIZE(wl->qos_params));
- spin_lock_irqsave(&wl->irq_lock, flags);
- p = &(wl->qos_params[queue]);
- memcpy(&(p->p), params, sizeof(p->p));
- p->need_hw_update = 1;
- spin_unlock_irqrestore(&wl->irq_lock, flags);
+ mutex_lock(&wl->mutex);
+ dev = wl->current_dev;
+ if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED)))
+ goto out_unlock;
- queue_work(hw->workqueue, &wl->qos_update_work);
+ memcpy(&(wl->qos_params[queue].p), params, sizeof(*params));
+ b43_mac_suspend(dev);
+ b43_qos_params_upload(dev, &(wl->qos_params[queue].p),
+ b43_qos_shm_offsets[queue]);
+ b43_mac_enable(dev);
+ err = 0;
- return 0;
+out_unlock:
+ mutex_unlock(&wl->mutex);
+
+ return err;
}
static int b43_op_get_tx_stats(struct ieee80211_hw *hw,
/* Switch to the requested channel.
* The firmware takes care of races with the TX handler. */
if (conf->channel->hw_value != phy->channel)
- b43_radio_selectchannel(dev, conf->channel->hw_value, 0);
+ b43_switch_channel(dev, conf->channel->hw_value);
/* Enable/Disable ShortSlot timing. */
if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) !=
/* Adjust the desired TX power level. */
if (conf->power_level != 0) {
- if (conf->power_level != phy->power_level) {
- phy->power_level = conf->power_level;
- b43_phy_xmitpower(dev);
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ if (conf->power_level != phy->desired_txpower) {
+ phy->desired_txpower = conf->power_level;
+ b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME |
+ B43_TXPWR_IGNORE_TSSI);
}
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
}
/* Antennas for RX and management frame TX. */
antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx);
b43_mgmtframe_txantenna(dev, antenna);
antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx);
- b43_set_rx_antenna(dev, antenna);
+ if (phy->ops->set_rx_antenna)
+ phy->ops->set_rx_antenna(dev, antenna);
/* Update templates for AP/mesh mode. */
- if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
- b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
+ 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_radio_turn_on(dev);
+ b43_software_rfkill(dev, RFKILL_STATE_UNBLOCKED);
b43info(dev->wl, "Radio turned on by software\n");
if (!dev->radio_hw_enable) {
b43info(dev->wl, "The hardware RF-kill button "
"Press the button to turn it on.\n");
}
} else {
- b43_radio_turn_off(dev, 0);
+ b43_software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
b43info(dev->wl, "Radio turned off by software\n");
}
}
u8 algorithm;
u8 index;
int err;
- DECLARE_MAC_BUF(mac);
if (modparam_nohwcrypt)
return -ENOSPC; /* User disabled HW-crypto */
mutex_unlock(&wl->mutex);
if (!err) {
b43dbg(wl, "%s hardware based encryption for keyidx: %d, "
- "mac: %s\n",
+ "mac: %pM\n",
cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
- print_mac(mac, addr));
+ addr);
}
return err;
}
else
memset(wl->bssid, 0, ETH_ALEN);
if (b43_status(dev) >= B43_STAT_INITIALIZED) {
- if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
- b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) {
- B43_WARN_ON(conf->type != wl->if_type);
- b43_set_ssid(dev, conf->ssid, conf->ssid_len);
- if (conf->beacon)
- b43_update_templates(wl, conf->beacon);
+ 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_SSID)
+ b43_set_ssid(dev, conf->ssid, conf->ssid_len);
+ 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);
}
static void setup_struct_phy_for_init(struct b43_wldev *dev,
struct b43_phy *phy)
{
- struct b43_txpower_lo_control *lo;
- int i;
-
- memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
- memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
-
- phy->aci_enable = 0;
- phy->aci_wlan_automatic = 0;
- phy->aci_hw_rssi = 0;
-
- phy->radio_off_context.valid = 0;
-
- lo = phy->lo_control;
- if (lo) {
- memset(lo, 0, sizeof(*(phy->lo_control)));
- lo->tx_bias = 0xFF;
- INIT_LIST_HEAD(&lo->calib_list);
- }
- phy->max_lb_gain = 0;
- phy->trsw_rx_gain = 0;
- phy->txpwr_offset = 0;
-
- /* NRSSI */
- phy->nrssislope = 0;
- for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++)
- phy->nrssi[i] = -1000;
- for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++)
- phy->nrssi_lt[i] = i;
-
- phy->lofcal = 0xFFFF;
- phy->initval = 0xFFFF;
-
- phy->interfmode = B43_INTERFMODE_NONE;
- phy->channel = 0xFF;
-
phy->hardware_power_control = !!modparam_hwpctl;
-
+ phy->next_txpwr_check_time = jiffies;
/* PHY TX errors counter. */
atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
-
- /* OFDM-table address caching. */
- phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN;
}
static void setup_struct_wldev_for_init(struct b43_wldev *dev)
pu_delay = 3700;
else
pu_delay = 1050;
- if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS) || idle)
+ if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC) || idle)
pu_delay = 500;
if ((dev->phy.radio_ver == 0x2050) && (dev->phy.radio_rev == 8))
pu_delay = max(pu_delay, (u16)2400);
u16 pretbtt;
/* The time value is in microseconds. */
- if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) {
+ if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC)) {
pretbtt = 2;
} else {
if (dev->phy.type == B43_PHYTYPE_A)
/* Locking: wl->mutex */
static void b43_wireless_core_exit(struct b43_wldev *dev)
{
- struct b43_phy *phy = &dev->phy;
u32 macctl;
B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED);
b43_dma_free(dev);
b43_pio_free(dev);
b43_chip_exit(dev);
- b43_radio_turn_off(dev, 1);
- b43_switch_analog(dev, 0);
- if (phy->dyn_tssi_tbl)
- kfree(phy->tssi2dbm);
- kfree(phy->lo_control);
- phy->lo_control = NULL;
+ dev->phy.ops->switch_analog(dev, 0);
if (dev->wl->current_beacon) {
dev_kfree_skb_any(dev->wl->current_beacon);
dev->wl->current_beacon = NULL;
b43_wireless_core_reset(dev, tmp);
}
- if ((phy->type == B43_PHYTYPE_B) || (phy->type == B43_PHYTYPE_G)) {
- phy->lo_control =
- kzalloc(sizeof(*(phy->lo_control)), GFP_KERNEL);
- if (!phy->lo_control) {
- err = -ENOMEM;
- goto err_busdown;
- }
- }
+ /* Reset all data structures. */
setup_struct_wldev_for_init(dev);
-
- err = b43_phy_init_tssi2dbm_table(dev);
- if (err)
- goto err_kfree_lo_control;
+ phy->ops->prepare_structs(dev);
/* Enable IRQ routing to this device. */
ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev);
b43_imcfglo_timeouts_workaround(dev);
b43_bluetooth_coext_disable(dev);
- b43_phy_early_init(dev);
+ if (phy->ops->prepare_hardware) {
+ err = phy->ops->prepare_hardware(dev);
+ if (err)
+ goto err_busdown;
+ }
err = b43_chip_init(dev);
if (err)
- goto err_kfree_tssitbl;
+ goto err_busdown;
b43_shm_write16(dev, B43_SHM_SHARED,
B43_SHM_SH_WLCOREREV, dev->dev->id.revision);
hf = b43_hf_read(dev);
out:
return err;
- err_chip_exit:
+err_chip_exit:
b43_chip_exit(dev);
- err_kfree_tssitbl:
- if (phy->dyn_tssi_tbl)
- kfree(phy->tssi2dbm);
- err_kfree_lo_control:
- kfree(phy->lo_control);
- phy->lo_control = NULL;
- err_busdown:
+err_busdown:
ssb_bus_may_powerdown(bus);
B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
return err;
/* TODO: allow WDS/AP devices to coexist */
- if (conf->type != IEEE80211_IF_TYPE_AP &&
- conf->type != IEEE80211_IF_TYPE_MESH_POINT &&
- conf->type != IEEE80211_IF_TYPE_STA &&
- conf->type != IEEE80211_IF_TYPE_WDS &&
- conf->type != IEEE80211_IF_TYPE_IBSS)
+ if (conf->type != NL80211_IFTYPE_AP &&
+ conf->type != NL80211_IFTYPE_MESH_POINT &&
+ conf->type != NL80211_IFTYPE_STATION &&
+ conf->type != NL80211_IFTYPE_WDS &&
+ conf->type != NL80211_IFTYPE_ADHOC)
return -EOPNOTSUPP;
mutex_lock(&wl->mutex);
struct b43_wldev *dev = wl->current_dev;
b43_rfkill_exit(dev);
- cancel_work_sync(&(wl->qos_update_work));
cancel_work_sync(&(wl->beacon_update_trigger));
mutex_lock(&wl->mutex);
b43_wireless_core_stop(dev);
b43_wireless_core_exit(dev);
mutex_unlock(&wl->mutex);
+
+ cancel_work_sync(&(wl->txpower_adjust_work));
}
static int b43_op_set_retry_limit(struct ieee80211_hw *hw,
return err;
}
-static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set)
-{
- struct b43_wl *wl = hw_to_b43_wl(hw);
- struct sk_buff *beacon;
- unsigned long flags;
-
- /* 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(hw, wl->vif);
- if (unlikely(!beacon))
- return -ENOMEM;
- spin_lock_irqsave(&wl->irq_lock, flags);
- b43_update_templates(wl, beacon);
- spin_unlock_irqrestore(&wl->irq_lock, flags);
-
- return 0;
-}
-
-static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw,
- struct sk_buff *beacon)
+static int b43_op_beacon_set_tim(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, bool set)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
unsigned long flags;
spin_lock_irqsave(&wl->irq_lock, flags);
- b43_update_templates(wl, beacon);
+ b43_update_templates(wl);
spin_unlock_irqrestore(&wl->irq_lock, flags);
return 0;
static void b43_op_sta_notify(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum sta_notify_cmd notify_cmd,
- const u8 *addr)
+ struct ieee80211_sta *sta)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
.stop = b43_op_stop,
.set_retry_limit = b43_op_set_retry_limit,
.set_tim = b43_op_beacon_set_tim,
- .beacon_update = b43_op_ibss_beacon_update,
.sta_notify = b43_op_sta_notify,
};
/* We release firmware that late to not be required to re-request
* is all the time when we reinit the core. */
b43_release_firmware(dev);
+ b43_phy_free(dev);
}
static int b43_wireless_core_attach(struct b43_wldev *dev)
}
}
+ err = b43_phy_allocate(dev);
+ if (err)
+ goto err_powerdown;
+
dev->phy.gmode = have_2ghz_phy;
tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
b43_wireless_core_reset(dev, tmp);
err = b43_validate_chipaccess(dev);
if (err)
- goto err_powerdown;
+ goto err_phy_free;
err = b43_setup_bands(dev, have_2ghz_phy, have_5ghz_phy);
if (err)
- goto err_powerdown;
+ goto err_phy_free;
/* Now set some default "current_dev" */
if (!wl->current_dev)
wl->current_dev = dev;
INIT_WORK(&dev->restart_work, b43_chip_reset);
- b43_radio_turn_off(dev, 1);
- b43_switch_analog(dev, 0);
+ dev->phy.ops->switch_analog(dev, 0);
ssb_device_disable(dev->dev, 0);
ssb_bus_may_powerdown(bus);
out:
return err;
+err_phy_free:
+ b43_phy_free(dev);
err_powerdown:
ssb_bus_may_powerdown(bus);
return err;
if (bus->bustype == SSB_BUSTYPE_PCI) {
pdev = bus->host_pci;
if (IS_PDEV(pdev, BROADCOM, 0x4318, ASUSTEK, 0x100F) ||
+ IS_PDEV(pdev, BROADCOM, 0x4320, DELL, 0x0003) ||
+ IS_PDEV(pdev, BROADCOM, 0x4320, HP, 0x12f8) ||
IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0015) ||
- IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0013))
+ IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0014) ||
+ IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0013) ||
+ IS_PDEV(pdev, BROADCOM, 0x4320, MOTOROLA, 0x7010))
bus->sprom.boardflags_lo &= ~B43_BFL_BTCOEXIST;
}
}
}
/* fill hw info */
- hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
- IEEE80211_HW_RX_INCLUDES_FCS |
+ hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM;
+ hw->wiphy->interface_modes =
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+ BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_WDS) |
+ BIT(NL80211_IFTYPE_ADHOC);
+
hw->queues = b43_modparam_qos ? 4 : 1;
+ hw->max_altrates = 1;
SET_IEEE80211_DEV(hw, dev->dev);
if (is_valid_ether_addr(sprom->et1mac))
SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
spin_lock_init(&wl->shm_lock);
mutex_init(&wl->mutex);
INIT_LIST_HEAD(&wl->devlist);
- INIT_WORK(&wl->qos_update_work, b43_qos_update_work);
INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work);
+ 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);