Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index 2232232..d032bba 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -65,6 +65,32 @@
EXPORT_SYMBOL_GPL(rndis_status);
/*
+ * RNDIS indicate messages.
+ */
+static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg,
+ int buflen)
+{
+ struct cdc_state *info = (void *)&dev->data;
+ struct device *udev = &info->control->dev;
+
+ if (dev->driver_info->indication) {
+ dev->driver_info->indication(dev, msg, buflen);
+ } else {
+ switch (msg->status) {
+ case RNDIS_STATUS_MEDIA_CONNECT:
+ dev_info(udev, "rndis media connect\n");
+ break;
+ case RNDIS_STATUS_MEDIA_DISCONNECT:
+ dev_info(udev, "rndis media disconnect\n");
+ break;
+ default:
+ dev_info(udev, "rndis indication: 0x%08x\n",
+ le32_to_cpu(msg->status));
+ }
+ }
+}
+
+/*
* RPC done RNDIS-style. Caller guarantees:
* - message is properly byteswapped
* - there's no other request pending
@@ -143,27 +169,9 @@
request_id, xid);
/* then likely retry */
} else switch (buf->msg_type) {
- case RNDIS_MSG_INDICATE: { /* fault/event */
- struct rndis_indicate *msg = (void *)buf;
- int state = 0;
+ case RNDIS_MSG_INDICATE: /* fault/event */
+ rndis_msg_indicate(dev, (void *)buf, buflen);
- switch (msg->status) {
- case RNDIS_STATUS_MEDIA_CONNECT:
- state = 1;
- case RNDIS_STATUS_MEDIA_DISCONNECT:
- dev_info(&info->control->dev,
- "rndis media %sconnect\n",
- !state?"dis":"");
- if (dev->driver_info->link_change)
- dev->driver_info->link_change(
- dev, state);
- break;
- default:
- dev_info(&info->control->dev,
- "rndis indication: 0x%08x\n",
- le32_to_cpu(msg->status));
- }
- }
break;
case RNDIS_MSG_KEEPALIVE: { /* ping */
struct rndis_keepalive_c *msg = (void *)buf;
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 25e435c..af1fe46 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -601,21 +601,25 @@
info->description);
}
- // ensure there are no more active urbs
- add_wait_queue (&unlink_wakeup, &wait);
- dev->wait = &unlink_wakeup;
- temp = unlink_urbs (dev, &dev->txq) + unlink_urbs (dev, &dev->rxq);
+ if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) {
+ /* ensure there are no more active urbs */
+ add_wait_queue(&unlink_wakeup, &wait);
+ dev->wait = &unlink_wakeup;
+ temp = unlink_urbs(dev, &dev->txq) +
+ unlink_urbs(dev, &dev->rxq);
- // maybe wait for deletions to finish.
- while (!skb_queue_empty(&dev->rxq)
- && !skb_queue_empty(&dev->txq)
- && !skb_queue_empty(&dev->done)) {
- msleep(UNLINK_TIMEOUT_MS);
- if (netif_msg_ifdown (dev))
- devdbg (dev, "waited for %d urb completions", temp);
+ /* maybe wait for deletions to finish. */
+ while (!skb_queue_empty(&dev->rxq)
+ && !skb_queue_empty(&dev->txq)
+ && !skb_queue_empty(&dev->done)) {
+ msleep(UNLINK_TIMEOUT_MS);
+ if (netif_msg_ifdown(dev))
+ devdbg(dev, "waited for %d urb completions",
+ temp);
+ }
+ dev->wait = NULL;
+ remove_wait_queue(&unlink_wakeup, &wait);
}
- dev->wait = NULL;
- remove_wait_queue (&unlink_wakeup, &wait);
usb_kill_urb(dev->interrupt);
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index ca7a8a3..dda7cc2 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -5,7 +5,7 @@
menu "Wireless LAN"
depends on !S390
-config WLAN_PRE80211
+menuconfig WLAN_PRE80211
bool "Wireless LAN (pre-802.11)"
depends on NETDEVICES
---help---
@@ -101,7 +101,7 @@
called netwave_cs. If unsure, say N.
-config WLAN_80211
+menuconfig WLAN_80211
bool "Wireless LAN (IEEE 802.11)"
depends on NETDEVICES
---help---
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 13303fa..7218dba 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -1773,6 +1773,9 @@
at76_dbg(DBG_MAC80211, "%s()", __func__);
+ cancel_delayed_work(&priv->dwork_hw_scan);
+ cancel_work_sync(&priv->work_set_promisc);
+
mutex_lock(&priv->mtx);
if (!priv->device_unplugged) {
@@ -1872,8 +1875,8 @@
/* FIXME: add maximum time for scan to complete */
if (ret != CMD_STATUS_COMPLETE) {
- queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan,
- SCAN_POLL_INTERVAL);
+ ieee80211_queue_delayed_work(priv->hw, &priv->dwork_hw_scan,
+ SCAN_POLL_INTERVAL);
mutex_unlock(&priv->mtx);
return;
}
@@ -1934,8 +1937,8 @@
goto exit;
}
- queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan,
- SCAN_POLL_INTERVAL);
+ ieee80211_queue_delayed_work(priv->hw, &priv->dwork_hw_scan,
+ SCAN_POLL_INTERVAL);
exit:
mutex_unlock(&priv->mtx);
@@ -2024,7 +2027,7 @@
} else
return;
- queue_work(hw->workqueue, &priv->work_set_promisc);
+ ieee80211_queue_work(hw, &priv->work_set_promisc);
}
static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
@@ -2295,11 +2298,8 @@
tasklet_kill(&priv->rx_tasklet);
- if (priv->mac80211_registered) {
- cancel_delayed_work(&priv->dwork_hw_scan);
- flush_workqueue(priv->hw->workqueue);
+ if (priv->mac80211_registered)
ieee80211_unregister_hw(priv->hw);
- }
if (priv->tx_urb) {
usb_kill_urb(priv->tx_urb);
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig
index eb0337c..253b95a 100644
--- a/drivers/net/wireless/ath/Kconfig
+++ b/drivers/net/wireless/ath/Kconfig
@@ -1,9 +1,24 @@
-config ATH_COMMON
+menuconfig ATH_COMMON
tristate "Atheros Wireless Cards"
depends on WLAN_80211
- depends on ATH5K || ATH9K || AR9170_USB
+ depends on CFG80211
+ ---help---
+ This will enable the support for the Atheros wireless drivers.
+ ath5k, ath9k and ar9170 drivers share some common code, this option
+ enables the common ath.ko module which currently shares just common
+ regulatory EEPROM helpers but will likely be extended later to share
+ more between modules.
+ For more information and documentation on this module you can visit:
+
+ http://wireless.kernel.org/en/users/Drivers/ath
+
+ For information on all Atheros wireless drivers visit:
+
+ http://wireless.kernel.org/en/users/Drivers/Atheros
+
+if ATH_COMMON
source "drivers/net/wireless/ath/ath5k/Kconfig"
source "drivers/net/wireless/ath/ath9k/Kconfig"
source "drivers/net/wireless/ath/ar9170/Kconfig"
-
+endif
diff --git a/drivers/net/wireless/ath/ar9170/Kconfig b/drivers/net/wireless/ath/ar9170/Kconfig
index b99e326..05918f1 100644
--- a/drivers/net/wireless/ath/ar9170/Kconfig
+++ b/drivers/net/wireless/ath/ar9170/Kconfig
@@ -1,13 +1,13 @@
config AR9170_USB
tristate "Atheros AR9170 802.11n USB support"
- depends on USB && MAC80211 && WLAN_80211 && EXPERIMENTAL
+ depends on USB && MAC80211 && WLAN_80211
select FW_LOADER
- select ATH_COMMON
help
This is a driver for the Atheros "otus" 802.11n USB devices.
These devices require additional firmware (2 files).
For now, these files can be downloaded from here:
+
http://wireless.kernel.org/en/users/Drivers/ar9170
If you choose to build a module, it'll be called ar9170usb.
diff --git a/drivers/net/wireless/ath/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c
index 63fda6c..86c4e79 100644
--- a/drivers/net/wireless/ath/ar9170/led.c
+++ b/drivers/net/wireless/ath/ar9170/led.c
@@ -90,9 +90,12 @@
ar9170_set_leds_state(ar, led_val);
mutex_unlock(&ar->mutex);
- if (rerun)
- queue_delayed_work(ar->hw->workqueue, &ar->led_work,
- msecs_to_jiffies(blink_delay));
+ if (!rerun)
+ return;
+
+ ieee80211_queue_delayed_work(ar->hw,
+ &ar->led_work,
+ msecs_to_jiffies(blink_delay));
}
static void ar9170_led_brightness_set(struct led_classdev *led,
@@ -110,7 +113,7 @@
}
if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled))
- queue_delayed_work(ar->hw->workqueue, &ar->led_work, HZ/10);
+ ieee80211_queue_delayed_work(ar->hw, &ar->led_work, HZ/10);
}
static int ar9170_register_led(struct ar9170 *ar, int i, char *name,
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index 85a1452..4fc389a 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -595,10 +595,12 @@
ar9170_tx_fake_ampdu_status(ar);
- if (resched)
- queue_delayed_work(ar->hw->workqueue,
- &ar->tx_janitor,
- msecs_to_jiffies(AR9170_JANITOR_DELAY));
+ if (!resched)
+ return;
+
+ ieee80211_queue_delayed_work(ar->hw,
+ &ar->tx_janitor,
+ msecs_to_jiffies(AR9170_JANITOR_DELAY));
}
void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
@@ -648,7 +650,7 @@
* pre-TBTT event
*/
if (ar->vif && ar->vif->type == NL80211_IFTYPE_AP)
- queue_work(ar->hw->workqueue, &ar->beacon_work);
+ ieee80211_queue_work(ar->hw, &ar->beacon_work);
break;
case 0xc2:
@@ -1290,14 +1292,13 @@
if (IS_STARTED(ar))
ar->state = AR9170_IDLE;
- flush_workqueue(ar->hw->workqueue);
-
cancel_delayed_work_sync(&ar->tx_janitor);
#ifdef CONFIG_AR9170_LEDS
cancel_delayed_work_sync(&ar->led_work);
#endif
cancel_work_sync(&ar->filter_config_work);
cancel_work_sync(&ar->beacon_work);
+
mutex_lock(&ar->mutex);
if (IS_ACCEPTING_CMD(ar)) {
@@ -1826,10 +1827,12 @@
}
}
- if (schedule_garbagecollector)
- queue_delayed_work(ar->hw->workqueue,
- &ar->tx_janitor,
- msecs_to_jiffies(AR9170_JANITOR_DELAY));
+ if (!schedule_garbagecollector)
+ return;
+
+ ieee80211_queue_delayed_work(ar->hw,
+ &ar->tx_janitor,
+ msecs_to_jiffies(AR9170_JANITOR_DELAY));
}
static bool ar9170_tx_ampdu_queue(struct ar9170 *ar, struct sk_buff *skb)
@@ -2158,7 +2161,7 @@
}
if (likely(IS_STARTED(ar)))
- queue_work(ar->hw->workqueue, &ar->filter_config_work);
+ ieee80211_queue_work(ar->hw, &ar->filter_config_work);
}
static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
@@ -2416,7 +2419,7 @@
}
if (IS_STARTED(ar) && ar->filter_changed)
- queue_work(ar->hw->workqueue, &ar->filter_config_work);
+ ieee80211_queue_work(ar->hw, &ar->filter_config_work);
}
static int ar9170_get_stats(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig
index daf0c83..06d0066 100644
--- a/drivers/net/wireless/ath/ath5k/Kconfig
+++ b/drivers/net/wireless/ath/ath5k/Kconfig
@@ -1,7 +1,6 @@
config ATH5K
tristate "Atheros 5xxx wireless cards support"
- depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
- select ATH_COMMON
+ depends on PCI && MAC80211 && WLAN_80211
select MAC80211_LEDS
select LEDS_CLASS
select NEW_LEDS
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 7db32ce..3a1c156d 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -1117,6 +1117,8 @@
struct ath5k_hw *ah = sc->ah;
u32 rfilt;
+ ah->ah_op_mode = sc->opmode;
+
/* configure rx filter */
rfilt = sc->filter_flags;
ath5k_hw_set_rx_filter(ah, rfilt);
@@ -1998,9 +2000,12 @@
static void
ath5k_tasklet_tx(unsigned long data)
{
+ int i;
struct ath5k_softc *sc = (void *)data;
- ath5k_tx_processq(sc, sc->txq);
+ for (i=0; i < AR5K_NUM_TX_QUEUES; i++)
+ if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i)))
+ ath5k_tx_processq(sc, &sc->txqs[i]);
}
@@ -2768,6 +2773,7 @@
}
ath5k_hw_set_lladdr(sc->ah, conf->mac_addr);
+ ath5k_mode_setup(sc);
ret = 0;
end:
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index 0f4a6d8..2cb72f8 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -1,7 +1,6 @@
config ATH9K
tristate "Atheros 802.11n wireless cards support"
depends on PCI && MAC80211 && WLAN_80211
- select ATH_COMMON
select MAC80211_LEDS
select LEDS_CLASS
select NEW_LEDS
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 0e65c51..5618fc2 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -119,7 +119,7 @@
sc->bus_ops = &ath_ahb_bus_ops;
sc->irq = irq;
- ret = ath_attach(AR5416_AR9100_DEVID, sc);
+ ret = ath_init_device(AR5416_AR9100_DEVID, sc);
if (ret != 0) {
dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret);
ret = -ENODEV;
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index aad259b..b709312 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -777,7 +777,7 @@
}
}
-void ath9k_hw_ani_attach(struct ath_hw *ah)
+void ath9k_hw_ani_init(struct ath_hw *ah)
{
int i;
@@ -822,9 +822,9 @@
ah->proc_phyerr |= HAL_PROCESS_ANI;
}
-void ath9k_hw_ani_detach(struct ath_hw *ah)
+void ath9k_hw_ani_disable(struct ath_hw *ah)
{
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n");
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disabling ANI\n");
if (ah->has_hw_phycounters) {
ath9k_hw_disable_mib_counters(ah);
diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h
index 08b4e7e..a36b7bb 100644
--- a/drivers/net/wireless/ath/ath9k/ani.h
+++ b/drivers/net/wireless/ath/ath9k/ani.h
@@ -132,7 +132,7 @@
void ath9k_hw_procmibevent(struct ath_hw *ah,
const struct ath9k_node_stats *stats);
void ath9k_hw_ani_setup(struct ath_hw *ah);
-void ath9k_hw_ani_attach(struct ath_hw *ah);
-void ath9k_hw_ani_detach(struct ath_hw *ah);
+void ath9k_hw_ani_init(struct ath_hw *ah);
+void ath9k_hw_ani_disable(struct ath_hw *ah);
#endif /* ANI_H */
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index bda0f30..7a5a157 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -642,7 +642,7 @@
irqreturn_t ath_isr(int irq, void *dev);
void ath_cleanup(struct ath_softc *sc);
-int ath_attach(u16 devid, struct ath_softc *sc);
+int ath_init_device(u16 devid, struct ath_softc *sc);
void ath_detach(struct ath_softc *sc);
const char *ath_mac_bb_name(u32 mac_bb_version);
const char *ath_rf_name(u16 rf_version);
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index d1bbb02..26d8752 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -753,6 +753,98 @@
}
}
+static void ath9k_hw_9271_pa_cal(struct ath_hw *ah)
+{
+ u32 regVal;
+ unsigned int i;
+ u32 regList [][2] = {
+ { 0x786c, 0 },
+ { 0x7854, 0 },
+ { 0x7820, 0 },
+ { 0x7824, 0 },
+ { 0x7868, 0 },
+ { 0x783c, 0 },
+ { 0x7838, 0 } ,
+ { 0x7828, 0 } ,
+ };
+
+ for (i = 0; i < ARRAY_SIZE(regList); i++)
+ regList[i][1] = REG_READ(ah, regList[i][0]);
+
+ regVal = REG_READ(ah, 0x7834);
+ regVal &= (~(0x1));
+ REG_WRITE(ah, 0x7834, regVal);
+ regVal = REG_READ(ah, 0x9808);
+ regVal |= (0x1 << 27);
+ REG_WRITE(ah, 0x9808, regVal);
+
+ /* 786c,b23,1, pwddac=1 */
+ REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
+ /* 7854, b5,1, pdrxtxbb=1 */
+ REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
+ /* 7854, b7,1, pdv2i=1 */
+ REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
+ /* 7854, b8,1, pddacinterface=1 */
+ REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
+ /* 7824,b12,0, offcal=0 */
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
+ /* 7838, b1,0, pwddb=0 */
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
+ /* 7820,b11,0, enpacal=0 */
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
+ /* 7820,b25,1, pdpadrv1=0 */
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
+ /* 7820,b24,0, pdpadrv2=0 */
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G1,AR9285_AN_RF2G1_PDPADRV2,0);
+ /* 7820,b23,0, pdpaout=0 */
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
+ /* 783c,b14-16,7, padrvgn2tab_0=7 */
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G8,AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
+ /*
+ * 7838,b29-31,0, padrvgn1tab_0=0
+ * does not matter since we turn it off
+ */
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G7,AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
+
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff);
+
+ /* Set:
+ * localmode=1,bmode=1,bmoderxtx=1,synthon=1,
+ * txon=1,paon=1,oscon=1,synthon_force=1
+ */
+ REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
+ udelay(30);
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0);
+
+ /* find off_6_1; */
+ for (i = 6; i >= 0; i--) {
+ regVal = REG_READ(ah, 0x7834);
+ regVal |= (1 << (20 + i));
+ REG_WRITE(ah, 0x7834, regVal);
+ udelay(1);
+ //regVal = REG_READ(ah, 0x7834);
+ regVal &= (~(0x1 << (20 + i)));
+ regVal |= (MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9)
+ << (20 + i));
+ REG_WRITE(ah, 0x7834, regVal);
+ }
+
+ /* Empirical offset correction */
+#if 0
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0x20);
+#endif
+
+ regVal = REG_READ(ah, 0x7834);
+ regVal |= 0x1;
+ REG_WRITE(ah, 0x7834, regVal);
+ regVal = REG_READ(ah, 0x9808);
+ regVal &= (~(0x1 << 27));
+ REG_WRITE(ah, 0x9808, regVal);
+
+ for (i = 0; i < ARRAY_SIZE(regList); i++)
+ REG_WRITE(ah, regList[i][0], regList[i][1]);
+}
+
static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
{
@@ -869,14 +961,26 @@
}
}
+ /* Do NF cal only at longer intervals */
if (longcal) {
- if (AR_SREV_9285_11_OR_LATER(ah))
+ /* Do periodic PAOffset Cal */
+ if (AR_SREV_9271(ah))
+ ath9k_hw_9271_pa_cal(ah);
+ else if (AR_SREV_9285_11_OR_LATER(ah))
ath9k_hw_9285_pa_cal(ah);
if (OLC_FOR_AR9280_20_LATER || OLC_FOR_AR9287_10_LATER)
ath9k_olc_temp_compensation(ah);
+
+ /* Get the value from the previous NF cal and update history buffer */
ath9k_hw_getnf(ah, chan);
+
+ /*
+ * Load the NF from history buffer of the current channel.
+ * NF is slow time-variant, so it is OK to use a historical value.
+ */
ath9k_hw_loadnf(ah, ah->curchan);
+
ath9k_hw_start_nfcal(ah);
}
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index 6fb1a80..4cb64a0 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -1237,6 +1237,10 @@
REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
}
+/*
+ * Read EEPROM header info and program the device for correct operation
+ * given the channel value.
+ */
static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
struct ath9k_channel *chan)
{
@@ -1313,38 +1317,110 @@
}
}
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
- AR9285_AN_RF2G3_OB_0, AR9285_AN_RF2G3_OB_0_S, ob[0]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
- AR9285_AN_RF2G3_OB_1, AR9285_AN_RF2G3_OB_1_S, ob[1]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
- AR9285_AN_RF2G3_OB_2, AR9285_AN_RF2G3_OB_2_S, ob[2]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
- AR9285_AN_RF2G3_OB_3, AR9285_AN_RF2G3_OB_3_S, ob[3]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
- AR9285_AN_RF2G3_OB_4, AR9285_AN_RF2G3_OB_4_S, ob[4]);
+ if (AR_SREV_9271(ah)) {
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9271_AN_RF2G3_OB_cck,
+ AR9271_AN_RF2G3_OB_cck_S,
+ ob[0]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9271_AN_RF2G3_OB_psk,
+ AR9271_AN_RF2G3_OB_psk_S,
+ ob[1]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9271_AN_RF2G3_OB_qam,
+ AR9271_AN_RF2G3_OB_qam_S,
+ ob[2]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9271_AN_RF2G3_DB_1,
+ AR9271_AN_RF2G3_DB_1_S,
+ db1[0]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G4,
+ AR9271_AN_RF2G4_DB_2,
+ AR9271_AN_RF2G4_DB_2_S,
+ db2[0]);
+ } else {
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_OB_0,
+ AR9285_AN_RF2G3_OB_0_S,
+ ob[0]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_OB_1,
+ AR9285_AN_RF2G3_OB_1_S,
+ ob[1]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_OB_2,
+ AR9285_AN_RF2G3_OB_2_S,
+ ob[2]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_OB_3,
+ AR9285_AN_RF2G3_OB_3_S,
+ ob[3]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_OB_4,
+ AR9285_AN_RF2G3_OB_4_S,
+ ob[4]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
- AR9285_AN_RF2G3_DB1_0, AR9285_AN_RF2G3_DB1_0_S, db1[0]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
- AR9285_AN_RF2G3_DB1_1, AR9285_AN_RF2G3_DB1_1_S, db1[1]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3,
- AR9285_AN_RF2G3_DB1_2, AR9285_AN_RF2G3_DB1_2_S, db1[2]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
- AR9285_AN_RF2G4_DB1_3, AR9285_AN_RF2G4_DB1_3_S, db1[3]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
- AR9285_AN_RF2G4_DB1_4, AR9285_AN_RF2G4_DB1_4_S, db1[4]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_DB1_0,
+ AR9285_AN_RF2G3_DB1_0_S,
+ db1[0]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_DB1_1,
+ AR9285_AN_RF2G3_DB1_1_S,
+ db1[1]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G3,
+ AR9285_AN_RF2G3_DB1_2,
+ AR9285_AN_RF2G3_DB1_2_S,
+ db1[2]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB1_3,
+ AR9285_AN_RF2G4_DB1_3_S,
+ db1[3]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB1_4,
+ AR9285_AN_RF2G4_DB1_4_S, db1[4]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
- AR9285_AN_RF2G4_DB2_0, AR9285_AN_RF2G4_DB2_0_S, db2[0]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
- AR9285_AN_RF2G4_DB2_1, AR9285_AN_RF2G4_DB2_1_S, db2[1]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
- AR9285_AN_RF2G4_DB2_2, AR9285_AN_RF2G4_DB2_2_S, db2[2]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
- AR9285_AN_RF2G4_DB2_3, AR9285_AN_RF2G4_DB2_3_S, db2[3]);
- ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4,
- AR9285_AN_RF2G4_DB2_4, AR9285_AN_RF2G4_DB2_4_S, db2[4]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB2_0,
+ AR9285_AN_RF2G4_DB2_0_S,
+ db2[0]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB2_1,
+ AR9285_AN_RF2G4_DB2_1_S,
+ db2[1]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB2_2,
+ AR9285_AN_RF2G4_DB2_2_S,
+ db2[2]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB2_3,
+ AR9285_AN_RF2G4_DB2_3_S,
+ db2[3]);
+ ath9k_hw_analog_shift_rmw(ah,
+ AR9285_AN_RF2G4,
+ AR9285_AN_RF2G4_DB2_4,
+ AR9285_AN_RF2G4_DB2_4_S,
+ db2[4]);
+ }
if (AR_SREV_9285_11(ah))
@@ -2794,7 +2870,7 @@
static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah)
{
- struct ar9287_eeprom_t *eep = &ah->eeprom.map9287;
+ struct ar9287_eeprom *eep = &ah->eeprom.map9287;
u16 *eep_data;
int addr, eep_start_loc = AR9287_EEP_START_LOC;
eep_data = (u16 *)eep;
@@ -2803,7 +2879,7 @@
"Reading from EEPROM, not flash\n");
}
- for (addr = 0; addr < sizeof(struct ar9287_eeprom_t) / sizeof(u16);
+ for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16);
addr++) {
if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) {
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
@@ -2816,12 +2892,11 @@
}
static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
{
-#define SIZE_EEPROM_87 (sizeof(struct ar9287_eeprom_t) / sizeof(u16))
u32 sum = 0, el, integer;
u16 temp, word, magic, magic2, *eepdata;
int i, addr;
bool need_swap = false;
- struct ar9287_eeprom_t *eep = &ah->eeprom.map9287;
+ struct ar9287_eeprom *eep = &ah->eeprom.map9287;
if (!ath9k_hw_use_flash(ah)) {
if (!ath9k_hw_nvram_read
@@ -2842,7 +2917,9 @@
need_swap = true;
eepdata = (u16 *)(&ah->eeprom);
- for (addr = 0; addr < SIZE_EEPROM_87; addr++) {
+ for (addr = 0;
+ addr < sizeof(struct ar9287_eeprom) / sizeof(u16);
+ addr++) {
temp = swab16(*eepdata);
*eepdata = temp;
eepdata++;
@@ -2862,8 +2939,13 @@
else
el = ah->eeprom.map9287.baseEepHeader.length;
+ if (el > sizeof(struct ar9287_eeprom))
+ el = sizeof(struct ar9287_eeprom) / sizeof(u16);
+ else
+ el = el / sizeof(u16);
+
eepdata = (u16 *)(&ah->eeprom);
- for (i = 0; i < min(el, SIZE_EEPROM_87); i++)
+ for (i = 0; i < el; i++)
sum ^= *eepdata++;
if (need_swap) {
@@ -2914,13 +2996,12 @@
}
return 0;
-#undef SIZE_EEPROM_87
}
static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah,
enum eeprom_param param)
{
- struct ar9287_eeprom_t *eep = &ah->eeprom.map9287;
+ struct ar9287_eeprom *eep = &ah->eeprom.map9287;
struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
struct base_eep_ar9287_header *pBase = &eep->baseEepHeader;
u16 ver_minor;
@@ -3210,7 +3291,7 @@
u16 xpdGainValues[AR9287_NUM_PD_GAINS] = {0, 0, 0, 0};
u32 reg32, regOffset, regChainOffset;
int16_t modalIdx, diff = 0;
- struct ar9287_eeprom_t *pEepData = &ah->eeprom.map9287;
+ struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
xpdMask = pEepData->modalHeader.xpdGain;
if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >=
@@ -3380,7 +3461,7 @@
struct chan_centers centers;
int tx_chainmask;
u16 twiceMinEdgePower;
- struct ar9287_eeprom_t *pEepData = &ah->eeprom.map9287;
+ struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
tx_chainmask = ah->txchainmask;
ath9k_hw_get_channel_centers(ah, chan, ¢ers);
@@ -3613,7 +3694,7 @@
{
#define INCREASE_MAXPOW_BY_TWO_CHAIN 6
#define INCREASE_MAXPOW_BY_THREE_CHAIN 10
- struct ar9287_eeprom_t *pEepData = &ah->eeprom.map9287;
+ struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader;
int16_t ratesArray[Ar5416RateSize];
int16_t txPowerIndexOffset = 0;
@@ -3776,7 +3857,7 @@
static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah,
struct ath9k_channel *chan)
{
- struct ar9287_eeprom_t *eep = &ah->eeprom.map9287;
+ struct ar9287_eeprom *eep = &ah->eeprom.map9287;
struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
u16 antWrites[AR9287_ANT_16S];
@@ -3928,7 +4009,7 @@
static u16 ath9k_hw_AR9287_get_eeprom_antenna_cfg(struct ath_hw *ah,
struct ath9k_channel *chan)
{
- struct ar9287_eeprom_t *eep = &ah->eeprom.map9287;
+ struct ar9287_eeprom *eep = &ah->eeprom.map9287;
struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
return pModal->antCtrlCommon & 0xFFFF;
}
@@ -3978,13 +4059,13 @@
};
-int ath9k_hw_eeprom_attach(struct ath_hw *ah)
+int ath9k_hw_eeprom_init(struct ath_hw *ah)
{
int status;
if (AR_SREV_9287(ah)) {
ah->eep_map = EEP_MAP_AR9287;
ah->eep_ops = &eep_AR9287_ops;
- } else if (AR_SREV_9285(ah)) {
+ } else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
ah->eep_map = EEP_MAP_4KBITS;
ah->eep_ops = &eep_4k_ops;
} else {
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index 7ddd016..db77e90 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -600,7 +600,7 @@
u8 padding;
} __packed;
-struct ar9287_eeprom_t {
+struct ar9287_eeprom {
struct base_eep_ar9287_header baseEepHeader;
u8 custData[AR9287_DATA_SZ];
struct modal_eep_ar9287_header modalHeader;
@@ -665,6 +665,6 @@
(((_txchainmask >> 2) & 1) + \
((_txchainmask >> 1) & 1) + (_txchainmask & 1))
-int ath9k_hw_eeprom_attach(struct ath_hw *ah);
+int ath9k_hw_eeprom_init(struct ath_hw *ah);
#endif /* EEPROM_H */
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 431854c..71a3bcc 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -388,7 +388,7 @@
return NULL;
}
-static void ath9k_hw_set_defaults(struct ath_hw *ah)
+static void ath9k_hw_init_config(struct ath_hw *ah)
{
int i;
@@ -437,27 +437,14 @@
ah->config.serialize_regmode = SER_REG_MODE_AUTO;
}
-static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc,
- int *status)
+static void ath9k_hw_init_defaults(struct ath_hw *ah)
{
- struct ath_hw *ah;
-
- ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
- if (ah == NULL) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Cannot allocate memory for state block\n");
- *status = -ENOMEM;
- return NULL;
- }
-
- ah->ah_sc = sc;
ah->hw_version.magic = AR5416_MAGIC;
ah->regulatory.country_code = CTRY_DEFAULT;
- ah->hw_version.devid = devid;
ah->hw_version.subvendorid = 0;
ah->ah_flags = 0;
- if ((devid == AR5416_AR9100_DEVID))
+ if (ah->hw_version.devid == AR5416_AR9100_DEVID)
ah->hw_version.macVersion = AR_SREV_VERSION_9100;
if (!AR_SREV_9100(ah))
ah->ah_flags = AH_USE_EEPROM;
@@ -479,8 +466,6 @@
ah->gbeacon_rate = 0;
ah->power_mode = ATH9K_PM_UNDEFINED;
-
- return ah;
}
static int ath9k_hw_rfattach(struct ath_hw *ah)
@@ -593,7 +578,7 @@
}
}
-static int ath9k_hw_post_attach(struct ath_hw *ah)
+static int ath9k_hw_post_init(struct ath_hw *ah)
{
int ecode;
@@ -604,7 +589,7 @@
if (ecode != 0)
return ecode;
- ecode = ath9k_hw_eeprom_attach(ah);
+ ecode = ath9k_hw_eeprom_init(ah);
if (ecode != 0)
return ecode;
@@ -617,71 +602,52 @@
if (!AR_SREV_9100(ah)) {
ath9k_hw_ani_setup(ah);
- ath9k_hw_ani_attach(ah);
+ ath9k_hw_ani_init(ah);
}
return 0;
}
-static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
- int *status)
+static bool ath9k_hw_devid_supported(u16 devid)
{
- struct ath_hw *ah;
- int ecode;
- u32 i, j;
-
- ah = ath9k_hw_newstate(devid, sc, status);
- if (ah == NULL)
- return NULL;
-
- ath9k_hw_set_defaults(ah);
-
- if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
- DPRINTF(sc, ATH_DBG_FATAL, "Couldn't reset chip\n");
- ecode = -EIO;
- goto bad;
+ switch (devid) {
+ case AR5416_DEVID_PCI:
+ case AR5416_DEVID_PCIE:
+ case AR5416_AR9100_DEVID:
+ case AR9160_DEVID_PCI:
+ case AR9280_DEVID_PCI:
+ case AR9280_DEVID_PCIE:
+ case AR9285_DEVID_PCIE:
+ case AR5416_DEVID_AR9287_PCI:
+ case AR5416_DEVID_AR9287_PCIE:
+ return true;
+ default:
+ break;
}
+ return false;
+}
- if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
- DPRINTF(sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n");
- ecode = -EIO;
- goto bad;
+static bool ath9k_hw_macversion_supported(u32 macversion)
+{
+ switch (macversion) {
+ case AR_SREV_VERSION_5416_PCI:
+ case AR_SREV_VERSION_5416_PCIE:
+ case AR_SREV_VERSION_9160:
+ case AR_SREV_VERSION_9100:
+ case AR_SREV_VERSION_9280:
+ case AR_SREV_VERSION_9285:
+ case AR_SREV_VERSION_9287:
+ return true;
+ /* Not yet */
+ case AR_SREV_VERSION_9271:
+ default:
+ break;
}
+ return false;
+}
- if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) {
- if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI ||
- (AR_SREV_9280(ah) && !ah->is_pciexpress)) {
- ah->config.serialize_regmode =
- SER_REG_MODE_ON;
- } else {
- ah->config.serialize_regmode =
- SER_REG_MODE_OFF;
- }
- }
-
- DPRINTF(sc, ATH_DBG_RESET, "serialize_regmode is %d\n",
- ah->config.serialize_regmode);
-
- if ((ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCI) &&
- (ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) &&
- (ah->hw_version.macVersion != AR_SREV_VERSION_9160) &&
- (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) &&
- (!AR_SREV_9285(ah)) && (!AR_SREV_9287(ah))) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Mac Chip Rev 0x%02x.%x is not supported by "
- "this driver\n", ah->hw_version.macVersion,
- ah->hw_version.macRev);
- ecode = -EOPNOTSUPP;
- goto bad;
- }
-
- if (AR_SREV_9100(ah)) {
- ah->iq_caldata.calData = &iq_cal_multi_sample;
- ah->supp_cals = IQ_MISMATCH_CAL;
- ah->is_pciexpress = false;
- }
- ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID);
-
+static void ath9k_hw_init_cal_settings(struct ath_hw *ah)
+{
if (AR_SREV_9160_10_OR_LATER(ah)) {
if (AR_SREV_9280_10_OR_LATER(ah)) {
ah->iq_caldata.calData = &iq_cal_single_sample;
@@ -702,10 +668,18 @@
}
ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
}
+}
- ah->ani_function = ATH9K_ANI_ALL;
- if (AR_SREV_9280_10_OR_LATER(ah))
- ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
+static void ath9k_hw_init_mode_regs(struct ath_hw *ah)
+{
+ if (AR_SREV_9271(ah)) {
+ INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271_1_0,
+ ARRAY_SIZE(ar9271Modes_9271_1_0), 6);
+ INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271_1_0,
+ ARRAY_SIZE(ar9271Common_9271_1_0), 2);
+ return;
+ }
+
if (AR_SREV_9287_11_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1,
ARRAY_SIZE(ar9287Modes_9287_1_1), 6);
@@ -867,16 +841,10 @@
INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac,
ARRAY_SIZE(ar5416Addac), 2);
}
+}
- if (ah->is_pciexpress)
- ath9k_hw_configpcipowersave(ah, 0);
- else
- ath9k_hw_disablepcie(ah);
-
- ecode = ath9k_hw_post_attach(ah);
- if (ecode != 0)
- goto bad;
-
+static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah)
+{
if (AR_SREV_9287_11(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9287Modes_rx_gain_9287_1_1,
@@ -913,8 +881,11 @@
}
}
+}
- ath9k_hw_fill_cap_info(ah);
+static void ath9k_hw_init_11a_eeprom_fix(struct ath_hw *ah)
+{
+ u32 i, j;
if ((ah->hw_version.devid == AR9280_DEVID_PCI) &&
test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) {
@@ -933,29 +904,97 @@
}
}
}
+}
- ecode = ath9k_hw_init_macaddr(ah);
- if (ecode != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Failed to initialize MAC address\n");
- goto bad;
+int ath9k_hw_init(struct ath_hw *ah)
+{
+ int r = 0;
+
+ if (!ath9k_hw_devid_supported(ah->hw_version.devid))
+ return -EOPNOTSUPP;
+
+ ath9k_hw_init_defaults(ah);
+ ath9k_hw_init_config(ah);
+
+ if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't reset chip\n");
+ return -EIO;
}
- if (AR_SREV_9285(ah))
+ if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n");
+ return -EIO;
+ }
+
+ if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) {
+ if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI ||
+ (AR_SREV_9280(ah) && !ah->is_pciexpress)) {
+ ah->config.serialize_regmode =
+ SER_REG_MODE_ON;
+ } else {
+ ah->config.serialize_regmode =
+ SER_REG_MODE_OFF;
+ }
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET, "serialize_regmode is %d\n",
+ ah->config.serialize_regmode);
+
+ if (!ath9k_hw_macversion_supported(ah->hw_version.macVersion)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "Mac Chip Rev 0x%02x.%x is not supported by "
+ "this driver\n", ah->hw_version.macVersion,
+ ah->hw_version.macRev);
+ return -EOPNOTSUPP;
+ }
+
+ if (AR_SREV_9100(ah)) {
+ ah->iq_caldata.calData = &iq_cal_multi_sample;
+ ah->supp_cals = IQ_MISMATCH_CAL;
+ ah->is_pciexpress = false;
+ }
+
+ if (AR_SREV_9271(ah))
+ ah->is_pciexpress = false;
+
+ ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID);
+
+ ath9k_hw_init_cal_settings(ah);
+
+ ah->ani_function = ATH9K_ANI_ALL;
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
+
+ ath9k_hw_init_mode_regs(ah);
+
+ if (ah->is_pciexpress)
+ ath9k_hw_configpcipowersave(ah, 0);
+ else
+ ath9k_hw_disablepcie(ah);
+
+ r = ath9k_hw_post_init(ah);
+ if (r)
+ return r;
+
+ ath9k_hw_init_mode_gain_regs(ah);
+ ath9k_hw_fill_cap_info(ah);
+ ath9k_hw_init_11a_eeprom_fix(ah);
+
+ r = ath9k_hw_init_macaddr(ah);
+ if (r) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "Failed to initialize MAC address\n");
+ return r;
+ }
+
+ if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S);
else
ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);
ath9k_init_nfcal_hist_buffer(ah);
- return ah;
-bad:
- if (ah)
- ath9k_hw_detach(ah);
- if (status)
- *status = ecode;
-
- return NULL;
+ return 0;
}
static void ath9k_hw_init_bb(struct ath_hw *ah,
@@ -1194,35 +1233,12 @@
void ath9k_hw_detach(struct ath_hw *ah)
{
if (!AR_SREV_9100(ah))
- ath9k_hw_ani_detach(ah);
+ ath9k_hw_ani_disable(ah);
- ath9k_hw_rfdetach(ah);
+ ath9k_hw_rf_free(ah);
ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
kfree(ah);
-}
-
-struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error)
-{
- struct ath_hw *ah = NULL;
-
- switch (devid) {
- case AR5416_DEVID_PCI:
- case AR5416_DEVID_PCIE:
- case AR5416_AR9100_DEVID:
- case AR9160_DEVID_PCI:
- case AR9280_DEVID_PCI:
- case AR9280_DEVID_PCIE:
- case AR9285_DEVID_PCIE:
- case AR5416_DEVID_AR9287_PCI:
- case AR5416_DEVID_AR9287_PCIE:
- ah = ath9k_hw_do_attach(devid, sc, error);
- break;
- default:
- *error = -ENXIO;
- break;
- }
-
- return ah;
+ ah = NULL;
}
/*******/
@@ -1232,6 +1248,27 @@
static void ath9k_hw_override_ini(struct ath_hw *ah,
struct ath9k_channel *chan)
{
+ u32 val;
+
+ if (AR_SREV_9271(ah)) {
+ /*
+ * Enable spectral scan to solution for issues with stuck
+ * beacons on AR9271 1.0. The beacon stuck issue is not seeon on
+ * AR9271 1.1
+ */
+ if (AR_SREV_9271_10(ah)) {
+ val = REG_READ(ah, AR_PHY_SPECTRAL_SCAN) | AR_PHY_SPECTRAL_SCAN_ENABLE;
+ REG_WRITE(ah, AR_PHY_SPECTRAL_SCAN, val);
+ }
+ else if (AR_SREV_9271_11(ah))
+ /*
+ * change AR_PHY_RF_CTL3 setting to fix MAC issue
+ * present on AR9271 1.1
+ */
+ REG_WRITE(ah, AR_PHY_RF_CTL3, 0x3a020001);
+ return;
+ }
+
/*
* Set the RX_ABORT and RX_DIS and clear if off only after
* RXE is set for MAC. This prevents frames with corrupted
@@ -1243,7 +1280,10 @@
if (!AR_SREV_5416_20_OR_LATER(ah) ||
AR_SREV_9280_10_OR_LATER(ah))
return;
-
+ /*
+ * Disable BB clock gating
+ * Necessary to avoid issues on AR5416 2.0
+ */
REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
}
@@ -1475,23 +1515,48 @@
{
u32 regval;
+ /*
+ * set AHB_MODE not to do cacheline prefetches
+ */
regval = REG_READ(ah, AR_AHB_MODE);
REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN);
+ /*
+ * let mac dma reads be in 128 byte chunks
+ */
regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
+ /*
+ * Restore TX Trigger Level to its pre-reset value.
+ * The initial value depends on whether aggregation is enabled, and is
+ * adjusted whenever underruns are detected.
+ */
REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->tx_trig_level);
+ /*
+ * let mac dma writes be in 128 byte chunks
+ */
regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK;
REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B);
+ /*
+ * Setup receive FIFO threshold to hold off TX activities
+ */
REG_WRITE(ah, AR_RXFIFO_CFG, 0x200);
+ /*
+ * reduce the number of usable entries in PCU TXBUF to avoid
+ * wrap around issues.
+ */
if (AR_SREV_9285(ah)) {
+ /* For AR9285 the number of Fifos are reduced to half.
+ * So set the usable tx buf size also to half to
+ * avoid data/delimiter underruns
+ */
REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE);
- } else {
+ } else if (!AR_SREV_9271(ah)) {
REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
AR_PCU_TXBUF_CTRL_USABLE_SIZE);
}
@@ -2297,11 +2362,26 @@
ath9k_hw_mark_phy_inactive(ah);
+ if (AR_SREV_9271(ah) && ah->htc_reset_init) {
+ REG_WRITE(ah,
+ AR9271_RESET_POWER_DOWN_CONTROL,
+ AR9271_RADIO_RF_RST);
+ udelay(50);
+ }
+
if (!ath9k_hw_chip_reset(ah, chan)) {
DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Chip reset failed\n");
return -EINVAL;
}
+ if (AR_SREV_9271(ah) && ah->htc_reset_init) {
+ ah->htc_reset_init = false;
+ REG_WRITE(ah,
+ AR9271_RESET_POWER_DOWN_CONTROL,
+ AR9271_GATE_MAC_CTL);
+ udelay(50);
+ }
+
if (AR_SREV_9280_10_OR_LATER(ah))
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
@@ -2437,6 +2517,9 @@
REG_WRITE(ah, AR_CFG_LED, saveLedState | AR_CFG_SCLK_32KHZ);
+ /*
+ * For big endian systems turn on swapping for descriptors
+ */
if (AR_SREV_9100(ah)) {
u32 mask;
mask = REG_READ(ah, AR_CFG);
@@ -2451,8 +2534,12 @@
"Setting CFG 0x%x\n", REG_READ(ah, AR_CFG));
}
} else {
+ /* Configure AR9271 target WLAN */
+ if (AR_SREV_9271(ah))
+ REG_WRITE(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB);
#ifdef __BIG_ENDIAN
- REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
+ else
+ REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
#endif
}
@@ -2494,9 +2581,6 @@
}
- if (ah->curchan == NULL)
- return true;
-
return true;
}
@@ -2921,7 +3005,7 @@
/*
* AR9280 2.0 or later chips use SerDes values from the
* initvals.h initialized depending on chipset during
- * ath9k_hw_do_attach()
+ * ath9k_hw_init()
*/
for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) {
REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0),
@@ -2982,7 +3066,7 @@
if (ah->config.pcie_waen) {
REG_WRITE(ah, AR_WA, ah->config.pcie_waen);
} else {
- if (AR_SREV_9285(ah))
+ if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT);
/*
* On AR9280 chips bit 22 of 0x4004 needs to be set to
@@ -3152,11 +3236,6 @@
return true;
}
-enum ath9k_int ath9k_hw_intrget(struct ath_hw *ah)
-{
- return ah->mask_reg;
-}
-
enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
{
u32 omask = ah->mask_reg;
@@ -3451,10 +3530,17 @@
}
pCap->tx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_TX_MASK);
+ /*
+ * For AR9271 we will temporarilly uses the rx chainmax as read from
+ * the EEPROM.
+ */
if ((ah->hw_version.devid == AR5416_DEVID_PCI) &&
- !(eeval & AR5416_OPFLAGS_11A))
+ !(eeval & AR5416_OPFLAGS_11A) &&
+ !(AR_SREV_9271(ah)))
+ /* CB71: GPIO 0 is pulled down to indicate 3 rx chains */
pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7;
else
+ /* Use rx_chainmask from EEPROM. */
pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK);
if (!(AR_SREV_9280(ah) && (ah->hw_version.macRev == 0)))
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 2e196df..d4aaf4f 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -403,7 +403,7 @@
union {
struct ar5416_eeprom_def def;
struct ar5416_eeprom_4k map4k;
- struct ar9287_eeprom_t map9287;
+ struct ar9287_eeprom map9287;
} eeprom;
const struct eeprom_ops *eep_ops;
enum ath9k_eep_map eep_map;
@@ -419,6 +419,8 @@
u32 wlanactive_gpio;
u32 ah_flags;
+ bool htc_reset_init;
+
enum nl80211_iftype opmode;
enum ath9k_power_mode power_mode;
@@ -541,11 +543,11 @@
struct ar5416IniArray iniModesTxGain;
};
-/* Attach, Detach, Reset */
+/* Initialization, Detach, Reset */
const char *ath9k_hw_probe(u16 vendorid, u16 devid);
void ath9k_hw_detach(struct ath_hw *ah);
-struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error);
-void ath9k_hw_rfdetach(struct ath_hw *ah);
+int ath9k_hw_init(struct ath_hw *ah);
+void ath9k_hw_rf_free(struct ath_hw *ah);
int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
bool bChannelChange);
void ath9k_hw_fill_cap_info(struct ath_hw *ah);
@@ -612,7 +614,6 @@
/* Interrupt Handling */
bool ath9k_hw_intrpend(struct ath_hw *ah);
bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked);
-enum ath9k_int ath9k_hw_intrget(struct ath_hw *ah);
enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints);
void ath9k_hw_btcoex_enable(struct ath_hw *ah);
diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h
index af4a1ba..27a86bb 100644
--- a/drivers/net/wireless/ath/ath9k/initvals.h
+++ b/drivers/net/wireless/ath/ath9k/initvals.h
@@ -6365,3 +6365,669 @@
};
+/* AR9271 initialization values automaticaly created: 03/23/09 */
+static const u_int32_t ar9271Modes_9271_1_0[][6] = {
+ { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
+ { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
+ { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
+ { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 },
+ { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
+ { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f },
+ { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 },
+ { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
+ { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
+ { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+ { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
+ { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+ { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
+ { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e },
+ { 0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0 },
+ { 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
+ { 0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
+ { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
+ { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
+ { 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e },
+ { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18 },
+ { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+ { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
+ { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
+ { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
+ { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
+ { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d },
+ { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010 },
+ { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c },
+ { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
+ { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
+ { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
+ { 0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329 },
+ { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
+ { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
+ { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000 },
+ { 0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 },
+ { 0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 },
+ { 0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 },
+ { 0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 },
+ { 0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 },
+ { 0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 },
+ { 0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 },
+ { 0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 },
+ { 0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 },
+ { 0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 },
+ { 0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 },
+ { 0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 },
+ { 0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 },
+ { 0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 },
+ { 0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 },
+ { 0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 },
+ { 0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 },
+ { 0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 },
+ { 0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 },
+ { 0x00009a50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 },
+ { 0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 },
+ { 0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 },
+ { 0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 },
+ { 0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 },
+ { 0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 },
+ { 0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 },
+ { 0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000 },
+ { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 },
+ { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 },
+ { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 },
+ { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
+ { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
+ { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
+ { 0x00009a88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
+ { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
+ { 0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
+ { 0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 },
+ { 0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 },
+ { 0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 },
+ { 0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 },
+ { 0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 },
+ { 0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 },
+ { 0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 },
+ { 0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 },
+ { 0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 },
+ { 0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 },
+ { 0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 },
+ { 0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 },
+ { 0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 },
+ { 0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 },
+ { 0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 },
+ { 0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 },
+ { 0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 },
+ { 0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 },
+ { 0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 },
+ { 0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 },
+ { 0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 },
+ { 0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 },
+ { 0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 },
+ { 0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 },
+ { 0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 },
+ { 0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 },
+ { 0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 },
+ { 0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 },
+ { 0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 },
+ { 0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 },
+ { 0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 },
+ { 0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 },
+ { 0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 },
+ { 0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 },
+ { 0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 },
+ { 0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 },
+ { 0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 },
+ { 0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 },
+ { 0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 },
+ { 0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 },
+ { 0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 },
+ { 0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 },
+ { 0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 },
+ { 0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 },
+ { 0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 },
+ { 0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 },
+ { 0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 },
+ { 0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 },
+ { 0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 },
+ { 0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 },
+ { 0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 },
+ { 0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 },
+ { 0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000 },
+ { 0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000 },
+ { 0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000 },
+ { 0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000 },
+ { 0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000 },
+ { 0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000 },
+ { 0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000 },
+ { 0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000 },
+ { 0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000 },
+ { 0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000 },
+ { 0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000 },
+ { 0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000 },
+ { 0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000 },
+ { 0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000 },
+ { 0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000 },
+ { 0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000 },
+ { 0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000 },
+ { 0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 },
+ { 0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 },
+ { 0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 },
+ { 0x0000aa50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 },
+ { 0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 },
+ { 0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 },
+ { 0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 },
+ { 0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000 },
+ { 0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000 },
+ { 0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000 },
+ { 0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000 },
+ { 0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 },
+ { 0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 },
+ { 0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 },
+ { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
+ { 0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
+ { 0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
+ { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
+ { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
+ { 0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
+ { 0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 },
+ { 0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 },
+ { 0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000 },
+ { 0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000 },
+ { 0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000 },
+ { 0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000 },
+ { 0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000 },
+ { 0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000 },
+ { 0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000 },
+ { 0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000 },
+ { 0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000 },
+ { 0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000 },
+ { 0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000 },
+ { 0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000 },
+ { 0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000 },
+ { 0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000 },
+ { 0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000 },
+ { 0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000 },
+ { 0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000 },
+ { 0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000 },
+ { 0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000 },
+ { 0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000 },
+ { 0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000 },
+ { 0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000 },
+ { 0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000 },
+ { 0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000 },
+ { 0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000 },
+ { 0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000 },
+ { 0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000 },
+ { 0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000 },
+ { 0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000 },
+ { 0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000 },
+ { 0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000 },
+ { 0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000 },
+ { 0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000 },
+ { 0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000 },
+ { 0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000 },
+ { 0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000 },
+ { 0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000 },
+ { 0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000 },
+ { 0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000 },
+ { 0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000 },
+ { 0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000 },
+ { 0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000 },
+ { 0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000 },
+ { 0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000 },
+ { 0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000 },
+ { 0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000 },
+ { 0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000 },
+ { 0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000 },
+ { 0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000 },
+ { 0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000 },
+ { 0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
+ { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 },
+ { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
+ { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
+ { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
+ { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+ { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 },
+ { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a218652, 0x0a218652, 0x0a22a652 },
+ { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 },
+ { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 },
+ { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 },
+ { 0x0000a310, 0x00000000, 0x00000000, 0x0001e610, 0x0001e610, 0x00000000 },
+ { 0x0000a314, 0x00000000, 0x00000000, 0x0002d6d0, 0x0002d6d0, 0x00000000 },
+ { 0x0000a318, 0x00000000, 0x00000000, 0x00039758, 0x00039758, 0x00000000 },
+ { 0x0000a31c, 0x00000000, 0x00000000, 0x0003b759, 0x0003b759, 0x00000000 },
+ { 0x0000a320, 0x00000000, 0x00000000, 0x0003d75a, 0x0003d75a, 0x00000000 },
+ { 0x0000a324, 0x00000000, 0x00000000, 0x0004175c, 0x0004175c, 0x00000000 },
+ { 0x0000a328, 0x00000000, 0x00000000, 0x0004575e, 0x0004575e, 0x00000000 },
+ { 0x0000a32c, 0x00000000, 0x00000000, 0x0004979f, 0x0004979f, 0x00000000 },
+ { 0x0000a330, 0x00000000, 0x00000000, 0x0004d7df, 0x0004d7df, 0x00000000 },
+ { 0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000 },
+ { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
+ { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
+ { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+ { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+ { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
+};
+
+static const u_int32_t ar9271Common_9271_1_0[][2] = {
+ { 0x0000000c, 0x00000000 },
+ { 0x00000030, 0x00020045 },
+ { 0x00000034, 0x00000005 },
+ { 0x00000040, 0x00000000 },
+ { 0x00000044, 0x00000008 },
+ { 0x00000048, 0x00000008 },
+ { 0x0000004c, 0x00000010 },
+ { 0x00000050, 0x00000000 },
+ { 0x00000054, 0x0000001f },
+ { 0x00000800, 0x00000000 },
+ { 0x00000804, 0x00000000 },
+ { 0x00000808, 0x00000000 },
+ { 0x0000080c, 0x00000000 },
+ { 0x00000810, 0x00000000 },
+ { 0x00000814, 0x00000000 },
+ { 0x00000818, 0x00000000 },
+ { 0x0000081c, 0x00000000 },
+ { 0x00000820, 0x00000000 },
+ { 0x00000824, 0x00000000 },
+ { 0x00001040, 0x002ffc0f },
+ { 0x00001044, 0x002ffc0f },
+ { 0x00001048, 0x002ffc0f },
+ { 0x0000104c, 0x002ffc0f },
+ { 0x00001050, 0x002ffc0f },
+ { 0x00001054, 0x002ffc0f },
+ { 0x00001058, 0x002ffc0f },
+ { 0x0000105c, 0x002ffc0f },
+ { 0x00001060, 0x002ffc0f },
+ { 0x00001064, 0x002ffc0f },
+ { 0x00001230, 0x00000000 },
+ { 0x00001270, 0x00000000 },
+ { 0x00001038, 0x00000000 },
+ { 0x00001078, 0x00000000 },
+ { 0x000010b8, 0x00000000 },
+ { 0x000010f8, 0x00000000 },
+ { 0x00001138, 0x00000000 },
+ { 0x00001178, 0x00000000 },
+ { 0x000011b8, 0x00000000 },
+ { 0x000011f8, 0x00000000 },
+ { 0x00001238, 0x00000000 },
+ { 0x00001278, 0x00000000 },
+ { 0x000012b8, 0x00000000 },
+ { 0x000012f8, 0x00000000 },
+ { 0x00001338, 0x00000000 },
+ { 0x00001378, 0x00000000 },
+ { 0x000013b8, 0x00000000 },
+ { 0x000013f8, 0x00000000 },
+ { 0x00001438, 0x00000000 },
+ { 0x00001478, 0x00000000 },
+ { 0x000014b8, 0x00000000 },
+ { 0x000014f8, 0x00000000 },
+ { 0x00001538, 0x00000000 },
+ { 0x00001578, 0x00000000 },
+ { 0x000015b8, 0x00000000 },
+ { 0x000015f8, 0x00000000 },
+ { 0x00001638, 0x00000000 },
+ { 0x00001678, 0x00000000 },
+ { 0x000016b8, 0x00000000 },
+ { 0x000016f8, 0x00000000 },
+ { 0x00001738, 0x00000000 },
+ { 0x00001778, 0x00000000 },
+ { 0x000017b8, 0x00000000 },
+ { 0x000017f8, 0x00000000 },
+ { 0x0000103c, 0x00000000 },
+ { 0x0000107c, 0x00000000 },
+ { 0x000010bc, 0x00000000 },
+ { 0x000010fc, 0x00000000 },
+ { 0x0000113c, 0x00000000 },
+ { 0x0000117c, 0x00000000 },
+ { 0x000011bc, 0x00000000 },
+ { 0x000011fc, 0x00000000 },
+ { 0x0000123c, 0x00000000 },
+ { 0x0000127c, 0x00000000 },
+ { 0x000012bc, 0x00000000 },
+ { 0x000012fc, 0x00000000 },
+ { 0x0000133c, 0x00000000 },
+ { 0x0000137c, 0x00000000 },
+ { 0x000013bc, 0x00000000 },
+ { 0x000013fc, 0x00000000 },
+ { 0x0000143c, 0x00000000 },
+ { 0x0000147c, 0x00000000 },
+ { 0x00004030, 0x00000002 },
+ { 0x0000403c, 0x00000002 },
+ { 0x00004024, 0x0000001f },
+ { 0x00004060, 0x00000000 },
+ { 0x00004064, 0x00000000 },
+ { 0x00008004, 0x00000000 },
+ { 0x00008008, 0x00000000 },
+ { 0x0000800c, 0x00000000 },
+ { 0x00008018, 0x00000700 },
+ { 0x00008020, 0x00000000 },
+ { 0x00008038, 0x00000000 },
+ { 0x0000803c, 0x00000000 },
+ { 0x00008048, 0x00000000 },
+ { 0x00008054, 0x00000000 },
+ { 0x00008058, 0x02000000 },
+ { 0x0000805c, 0x000fc78f },
+ { 0x00008060, 0x0000000f },
+ { 0x00008064, 0x00000000 },
+ { 0x00008070, 0x00000000 },
+ { 0x000080b0, 0x00000000 },
+ { 0x000080b4, 0x00000000 },
+ { 0x000080b8, 0x00000000 },
+ { 0x000080bc, 0x00000000 },
+ { 0x000080c0, 0x2a80001a },
+ { 0x000080c4, 0x05dc01e0 },
+ { 0x000080c8, 0x1f402710 },
+ { 0x000080cc, 0x01f40000 },
+ { 0x000080d0, 0x00001e00 },
+ { 0x000080d4, 0x00000000 },
+ { 0x000080d8, 0x00400000 },
+ { 0x000080e0, 0xffffffff },
+ { 0x000080e4, 0x0000ffff },
+ { 0x000080e8, 0x003f3f3f },
+ { 0x000080ec, 0x00000000 },
+ { 0x000080f0, 0x00000000 },
+ { 0x000080f4, 0x00000000 },
+ { 0x000080f8, 0x00000000 },
+ { 0x000080fc, 0x00020000 },
+ { 0x00008100, 0x00020000 },
+ { 0x00008104, 0x00000001 },
+ { 0x00008108, 0x00000052 },
+ { 0x0000810c, 0x00000000 },
+ { 0x00008110, 0x00000168 },
+ { 0x00008118, 0x000100aa },
+ { 0x0000811c, 0x00003210 },
+ { 0x00008120, 0x08f04814 },
+ { 0x00008124, 0x00000000 },
+ { 0x00008128, 0x00000000 },
+ { 0x0000812c, 0x00000000 },
+ { 0x00008130, 0x00000000 },
+ { 0x00008134, 0x00000000 },
+ { 0x00008138, 0x00000000 },
+ { 0x0000813c, 0x00000000 },
+ { 0x00008144, 0xffffffff },
+ { 0x00008168, 0x00000000 },
+ { 0x0000816c, 0x00000000 },
+ { 0x00008170, 0x32143320 },
+ { 0x00008174, 0xfaa4fa50 },
+ { 0x00008178, 0x00000100 },
+ { 0x0000817c, 0x00000000 },
+ { 0x000081c0, 0x00000000 },
+ { 0x000081d0, 0x0000320a },
+ { 0x000081ec, 0x00000000 },
+ { 0x000081f0, 0x00000000 },
+ { 0x000081f4, 0x00000000 },
+ { 0x000081f8, 0x00000000 },
+ { 0x000081fc, 0x00000000 },
+ { 0x00008200, 0x00000000 },
+ { 0x00008204, 0x00000000 },
+ { 0x00008208, 0x00000000 },
+ { 0x0000820c, 0x00000000 },
+ { 0x00008210, 0x00000000 },
+ { 0x00008214, 0x00000000 },
+ { 0x00008218, 0x00000000 },
+ { 0x0000821c, 0x00000000 },
+ { 0x00008220, 0x00000000 },
+ { 0x00008224, 0x00000000 },
+ { 0x00008228, 0x00000000 },
+ { 0x0000822c, 0x00000000 },
+ { 0x00008230, 0x00000000 },
+ { 0x00008234, 0x00000000 },
+ { 0x00008238, 0x00000000 },
+ { 0x0000823c, 0x00000000 },
+ { 0x00008240, 0x00100000 },
+ { 0x00008244, 0x0010f400 },
+ { 0x00008248, 0x00000100 },
+ { 0x0000824c, 0x0001e800 },
+ { 0x00008250, 0x00000000 },
+ { 0x00008254, 0x00000000 },
+ { 0x00008258, 0x00000000 },
+ { 0x0000825c, 0x400000ff },
+ { 0x00008260, 0x00080922 },
+ { 0x00008264, 0xa8a00010 },
+ { 0x00008270, 0x00000000 },
+ { 0x00008274, 0x40000000 },
+ { 0x00008278, 0x003e4180 },
+ { 0x0000827c, 0x00000000 },
+ { 0x00008284, 0x0000002c },
+ { 0x00008288, 0x0000002c },
+ { 0x0000828c, 0x00000000 },
+ { 0x00008294, 0x00000000 },
+ { 0x00008298, 0x00000000 },
+ { 0x0000829c, 0x00000000 },
+ { 0x00008300, 0x00000040 },
+ { 0x00008314, 0x00000000 },
+ { 0x00008328, 0x00000000 },
+ { 0x0000832c, 0x00000001 },
+ { 0x00008330, 0x00000302 },
+ { 0x00008334, 0x00000e00 },
+ { 0x00008338, 0x00ff0000 },
+ { 0x0000833c, 0x00000000 },
+ { 0x00008340, 0x00010380 },
+ { 0x00008344, 0x00581043 },
+ { 0x00007010, 0x00000030 },
+ { 0x00007034, 0x00000002 },
+ { 0x00007038, 0x000004c2 },
+ { 0x00007800, 0x00140000 },
+ { 0x00007804, 0x0e4548d8 },
+ { 0x00007808, 0x54214514 },
+ { 0x0000780c, 0x02025820 },
+ { 0x00007810, 0x71c0d388 },
+ { 0x00007814, 0x924934a8 },
+ { 0x0000781c, 0x00000000 },
+ { 0x00007820, 0x00000c04 },
+ { 0x00007824, 0x00d86bff },
+ { 0x00007828, 0x66964300 },
+ { 0x0000782c, 0x8db6d961 },
+ { 0x00007830, 0x8db6d96c },
+ { 0x00007834, 0x6140008b },
+ { 0x00007838, 0x00000029 },
+ { 0x0000783c, 0x72ee0a72 },
+ { 0x00007840, 0xbbfffffc },
+ { 0x00007844, 0x000c0db6 },
+ { 0x00007848, 0x6db61b6f },
+ { 0x0000784c, 0x6d9b66db },
+ { 0x00007850, 0x6d8c6dba },
+ { 0x00007854, 0x00040000 },
+ { 0x00007858, 0xdb003012 },
+ { 0x0000785c, 0x04924914 },
+ { 0x00007860, 0x21084210 },
+ { 0x00007864, 0xf7d7ffde },
+ { 0x00007868, 0xc2034080 },
+ { 0x0000786c, 0x48609eb4 },
+ { 0x00007870, 0x10142c00 },
+ { 0x00009808, 0x00000000 },
+ { 0x0000980c, 0xafe68e30 },
+ { 0x00009810, 0xfd14e000 },
+ { 0x00009814, 0x9c0a9f6b },
+ { 0x0000981c, 0x00000000 },
+ { 0x0000982c, 0x0000a000 },
+ { 0x00009830, 0x00000000 },
+ { 0x0000983c, 0x00200400 },
+ { 0x0000984c, 0x0040233c },
+ { 0x00009854, 0x00000044 },
+ { 0x00009900, 0x00000000 },
+ { 0x00009904, 0x00000000 },
+ { 0x00009908, 0x00000000 },
+ { 0x0000990c, 0x00000000 },
+ { 0x00009910, 0x30002310 },
+ { 0x0000991c, 0x10000fff },
+ { 0x00009920, 0x04900000 },
+ { 0x00009928, 0x00000001 },
+ { 0x0000992c, 0x00000004 },
+ { 0x00009934, 0x1e1f2022 },
+ { 0x00009938, 0x0a0b0c0d },
+ { 0x0000993c, 0x00000000 },
+ { 0x00009940, 0x14750604 },
+ { 0x00009948, 0x9280c00a },
+ { 0x0000994c, 0x00020028 },
+ { 0x00009954, 0x5f3ca3de },
+ { 0x00009958, 0x0108ecff },
+ { 0x00009968, 0x000003ce },
+ { 0x00009970, 0x192bb515 },
+ { 0x00009974, 0x00000000 },
+ { 0x00009978, 0x00000001 },
+ { 0x0000997c, 0x00000000 },
+ { 0x00009980, 0x00000000 },
+ { 0x00009984, 0x00000000 },
+ { 0x00009988, 0x00000000 },
+ { 0x0000998c, 0x00000000 },
+ { 0x00009990, 0x00000000 },
+ { 0x00009994, 0x00000000 },
+ { 0x00009998, 0x00000000 },
+ { 0x0000999c, 0x00000000 },
+ { 0x000099a0, 0x00000000 },
+ { 0x000099a4, 0x00000001 },
+ { 0x000099a8, 0x201fff00 },
+ { 0x000099ac, 0x2def0400 },
+ { 0x000099b0, 0x03051000 },
+ { 0x000099b4, 0x00000820 },
+ { 0x000099dc, 0x00000000 },
+ { 0x000099e0, 0x00000000 },
+ { 0x000099e4, 0xaaaaaaaa },
+ { 0x000099e8, 0x3c466478 },
+ { 0x000099ec, 0x0cc80caa },
+ { 0x000099f0, 0x00000000 },
+ { 0x0000a1f4, 0x00000000 },
+ { 0x0000a1f8, 0x71733d01 },
+ { 0x0000a1fc, 0xd0ad5c12 },
+ { 0x0000a208, 0x803e68c8 },
+ { 0x0000a210, 0x4080a333 },
+ { 0x0000a214, 0x00206c10 },
+ { 0x0000a218, 0x009c4060 },
+ { 0x0000a220, 0x01834061 },
+ { 0x0000a224, 0x00000400 },
+ { 0x0000a228, 0x000003b5 },
+ { 0x0000a22c, 0x00000000 },
+ { 0x0000a234, 0x20202020 },
+ { 0x0000a238, 0x20202020 },
+ { 0x0000a244, 0x00000000 },
+ { 0x0000a248, 0xfffffffc },
+ { 0x0000a24c, 0x00000000 },
+ { 0x0000a254, 0x00000000 },
+ { 0x0000a258, 0x0ccb5380 },
+ { 0x0000a25c, 0x15151501 },
+ { 0x0000a260, 0xdfa90f01 },
+ { 0x0000a268, 0x00000000 },
+ { 0x0000a26c, 0x0ebae9e6 },
+ { 0x0000a278, 0x3bdef7bd },
+ { 0x0000a27c, 0x050e83bd },
+ { 0x0000a388, 0x0c000000 },
+ { 0x0000a38c, 0x20202020 },
+ { 0x0000a390, 0x20202020 },
+ { 0x0000a394, 0x3bdef7bd },
+ { 0x0000a398, 0x000003bd },
+ { 0x0000a39c, 0x00000001 },
+ { 0x0000a3a0, 0x00000000 },
+ { 0x0000a3a4, 0x00000000 },
+ { 0x0000a3a8, 0x00000000 },
+ { 0x0000a3ac, 0x00000000 },
+ { 0x0000a3b0, 0x00000000 },
+ { 0x0000a3b4, 0x00000000 },
+ { 0x0000a3b8, 0x00000000 },
+ { 0x0000a3bc, 0x00000000 },
+ { 0x0000a3c0, 0x00000000 },
+ { 0x0000a3c4, 0x00000000 },
+ { 0x0000a3cc, 0x20202020 },
+ { 0x0000a3d0, 0x20202020 },
+ { 0x0000a3d4, 0x20202020 },
+ { 0x0000a3dc, 0x3bdef7bd },
+ { 0x0000a3e0, 0x000003bd },
+ { 0x0000a3e4, 0x00000000 },
+ { 0x0000a3e8, 0x18c43433 },
+ { 0x0000a3ec, 0x00f70081 },
+ { 0x0000a3f0, 0x01036a2f },
+ { 0x0000a3f4, 0x00000000 },
+ { 0x0000d270, 0x0d820820 },
+ { 0x0000d35c, 0x07ffffef },
+ { 0x0000d360, 0x0fffffe7 },
+ { 0x0000d364, 0x17ffffe5 },
+ { 0x0000d368, 0x1fffffe4 },
+ { 0x0000d36c, 0x37ffffe3 },
+ { 0x0000d370, 0x3fffffe3 },
+ { 0x0000d374, 0x57ffffe3 },
+ { 0x0000d378, 0x5fffffe2 },
+ { 0x0000d37c, 0x7fffffe2 },
+ { 0x0000d380, 0x7f3c7bba },
+ { 0x0000d384, 0xf3307ff0 },
+};
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 75ddb2a..a9e43f7 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -973,10 +973,11 @@
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN,
(sc->sc_flags & SC_OP_LED_ON) ? 1 : 0);
- queue_delayed_work(sc->hw->workqueue, &sc->ath_led_blink_work,
- (sc->sc_flags & SC_OP_LED_ON) ?
- msecs_to_jiffies(sc->led_off_duration) :
- msecs_to_jiffies(sc->led_on_duration));
+ ieee80211_queue_delayed_work(sc->hw,
+ &sc->ath_led_blink_work,
+ (sc->sc_flags & SC_OP_LED_ON) ?
+ msecs_to_jiffies(sc->led_off_duration) :
+ msecs_to_jiffies(sc->led_on_duration));
sc->led_on_duration = sc->led_on_cnt ?
max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) :
@@ -1013,8 +1014,8 @@
case LED_FULL:
if (led->led_type == ATH_LED_ASSOC) {
sc->sc_flags |= SC_OP_LED_ASSOCIATED;
- queue_delayed_work(sc->hw->workqueue,
- &sc->ath_led_blink_work, 0);
+ ieee80211_queue_delayed_work(sc->hw,
+ &sc->ath_led_blink_work, 0);
} else if (led->led_type == ATH_LED_RADIO) {
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0);
sc->sc_flags |= SC_OP_LED_ON;
@@ -1056,7 +1057,6 @@
static void ath_deinit_leds(struct ath_softc *sc)
{
- cancel_delayed_work_sync(&sc->ath_led_blink_work);
ath_unregister_led(&sc->assoc_led);
sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
ath_unregister_led(&sc->tx_led);
@@ -1113,6 +1113,7 @@
return;
fail:
+ cancel_delayed_work_sync(&sc->ath_led_blink_work);
ath_deinit_leds(sc);
}
@@ -1252,9 +1253,6 @@
DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n");
ath_deinit_leds(sc);
- cancel_work_sync(&sc->chan_work);
- cancel_delayed_work_sync(&sc->wiphy_work);
- cancel_delayed_work_sync(&sc->tx_complete_work);
for (i = 0; i < sc->num_sec_wiphy; i++) {
struct ath_wiphy *aphy = sc->sec_wiphy[i];
@@ -1280,6 +1278,7 @@
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
ath9k_hw_detach(sc->sc_ah);
+ sc->sc_ah = NULL;
ath9k_exit_debug(sc);
}
@@ -1294,11 +1293,16 @@
return ath_reg_notifier_apply(wiphy, request, reg);
}
-static int ath_init(u16 devid, struct ath_softc *sc)
+/*
+ * Initialize and fill ath_softc, ath_sofct is the
+ * "Software Carrier" struct. Historically it has existed
+ * to allow the separation between hardware specific
+ * variables (now in ath_hw) and driver specific variables.
+ */
+static int ath_init_softc(u16 devid, struct ath_softc *sc)
{
struct ath_hw *ah = NULL;
- int status;
- int error = 0, i;
+ int r = 0, i;
int csz = 0;
/* XXX: hardware will not be ready until ath_open() being called */
@@ -1325,14 +1329,23 @@
/* XXX assert csz is non-zero */
sc->cachelsz = csz << 2; /* convert to bytes */
- ah = ath9k_hw_attach(devid, sc, &status);
- if (ah == NULL) {
+ ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
+ if (!ah) {
+ r = -ENOMEM;
+ goto bad_no_ah;
+ }
+
+ ah->ah_sc = sc;
+ ah->hw_version.devid = devid;
+ sc->sc_ah = ah;
+
+ r = ath9k_hw_init(ah);
+ if (r) {
DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to attach hardware; HAL status %d\n", status);
- error = -ENXIO;
+ "Unable to initialize hardware; "
+ "initialization status: %d\n", r);
goto bad;
}
- sc->sc_ah = ah;
/* Get the hardware key cache size. */
sc->keymax = ah->caps.keycache_size;
@@ -1350,9 +1363,6 @@
for (i = 0; i < sc->keymax; i++)
ath9k_hw_keyreset(ah, (u16) i);
- if (error)
- goto bad;
-
/* default to MONITOR mode */
sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR;
@@ -1372,14 +1382,14 @@
if (sc->beacon.beaconq == -1) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to setup a beacon xmit queue\n");
- error = -EIO;
+ r = -EIO;
goto bad2;
}
sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
if (sc->beacon.cabq == NULL) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to setup CAB xmit queue\n");
- error = -EIO;
+ r = -EIO;
goto bad2;
}
@@ -1394,26 +1404,26 @@
if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to setup xmit queue for BK traffic\n");
- error = -EIO;
+ r = -EIO;
goto bad2;
}
if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to setup xmit queue for BE traffic\n");
- error = -EIO;
+ r = -EIO;
goto bad2;
}
if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to setup xmit queue for VI traffic\n");
- error = -EIO;
+ r = -EIO;
goto bad2;
}
if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to setup xmit queue for VO traffic\n");
- error = -EIO;
+ r = -EIO;
goto bad2;
}
@@ -1507,11 +1517,12 @@
if (ATH_TXQ_SETUP(sc, i))
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
bad:
- if (ah)
- ath9k_hw_detach(ah);
+ ath9k_hw_detach(ah);
+ sc->sc_ah = NULL;
+bad_no_ah:
ath9k_exit_debug(sc);
- return error;
+ return r;
}
void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
@@ -1551,7 +1562,8 @@
&sc->sbands[IEEE80211_BAND_5GHZ];
}
-int ath_attach(u16 devid, struct ath_softc *sc)
+/* Device driver core initialization */
+int ath_init_device(u16 devid, struct ath_softc *sc)
{
struct ieee80211_hw *hw = sc->hw;
int error = 0, i;
@@ -1559,7 +1571,7 @@
DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n");
- error = ath_init(devid, sc);
+ error = ath_init_softc(devid, sc);
if (error != 0)
return error;
@@ -1617,6 +1629,7 @@
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
ath9k_hw_detach(sc->sc_ah);
+ sc->sc_ah = NULL;
ath9k_exit_debug(sc);
return error;
@@ -1975,7 +1988,7 @@
ieee80211_wake_queues(hw);
- queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work, 0);
+ ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
mutex_unlock:
mutex_unlock(&sc->mutex);
@@ -2089,6 +2102,14 @@
aphy->state = ATH_WIPHY_INACTIVE;
+ cancel_delayed_work_sync(&sc->ath_led_blink_work);
+ cancel_delayed_work_sync(&sc->tx_complete_work);
+
+ if (!sc->num_sec_wiphy) {
+ cancel_delayed_work_sync(&sc->wiphy_work);
+ cancel_work_sync(&sc->chan_work);
+ }
+
if (sc->sc_flags & SC_OP_INVALID) {
DPRINTF(sc, ATH_DBG_ANY, "Device not present\n");
return;
@@ -2096,6 +2117,8 @@
mutex_lock(&sc->mutex);
+ cancel_delayed_work_sync(&sc->tx_complete_work);
+
if (ath9k_wiphy_started(sc)) {
mutex_unlock(&sc->mutex);
return; /* another wiphy still in use */
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index cd4841b..3546504 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -178,7 +178,7 @@
sc->mem = mem;
sc->bus_ops = &ath_pci_bus_ops;
- if (ath_attach(id->device, sc) != 0) {
+ if (ath_init_device(id->device, sc) != 0) {
ret = -ENODEV;
goto bad3;
}
diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c
index aaa9415..59bb3ce 100644
--- a/drivers/net/wireless/ath/ath9k/phy.c
+++ b/drivers/net/wireless/ath/ath9k/phy.c
@@ -264,44 +264,23 @@
}
void
-ath9k_hw_rfdetach(struct ath_hw *ah)
+ath9k_hw_rf_free(struct ath_hw *ah)
{
- if (ah->analogBank0Data != NULL) {
- kfree(ah->analogBank0Data);
- ah->analogBank0Data = NULL;
- }
- if (ah->analogBank1Data != NULL) {
- kfree(ah->analogBank1Data);
- ah->analogBank1Data = NULL;
- }
- if (ah->analogBank2Data != NULL) {
- kfree(ah->analogBank2Data);
- ah->analogBank2Data = NULL;
- }
- if (ah->analogBank3Data != NULL) {
- kfree(ah->analogBank3Data);
- ah->analogBank3Data = NULL;
- }
- if (ah->analogBank6Data != NULL) {
- kfree(ah->analogBank6Data);
- ah->analogBank6Data = NULL;
- }
- if (ah->analogBank6TPCData != NULL) {
- kfree(ah->analogBank6TPCData);
- ah->analogBank6TPCData = NULL;
- }
- if (ah->analogBank7Data != NULL) {
- kfree(ah->analogBank7Data);
- ah->analogBank7Data = NULL;
- }
- if (ah->addac5416_21 != NULL) {
- kfree(ah->addac5416_21);
- ah->addac5416_21 = NULL;
- }
- if (ah->bank6Temp != NULL) {
- kfree(ah->bank6Temp);
- ah->bank6Temp = NULL;
- }
+#define ATH_FREE_BANK(bank) do { \
+ kfree(bank); \
+ bank = NULL; \
+ } while (0);
+
+ ATH_FREE_BANK(ah->analogBank0Data);
+ ATH_FREE_BANK(ah->analogBank1Data);
+ ATH_FREE_BANK(ah->analogBank2Data);
+ ATH_FREE_BANK(ah->analogBank3Data);
+ ATH_FREE_BANK(ah->analogBank6Data);
+ ATH_FREE_BANK(ah->analogBank6TPCData);
+ ATH_FREE_BANK(ah->analogBank7Data);
+ ATH_FREE_BANK(ah->addac5416_21);
+ ATH_FREE_BANK(ah->bank6Temp);
+#undef ATH_FREE_BANK
}
bool ath9k_hw_init_rf(struct ath_hw *ah, int *status)
diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h
index de4fada..27bd93c 100644
--- a/drivers/net/wireless/ath/ath9k/phy.h
+++ b/drivers/net/wireless/ath/ath9k/phy.h
@@ -185,6 +185,9 @@
#define AR_PHY_PLL_CTL_44_2133 0xeb
#define AR_PHY_PLL_CTL_40_2133 0xea
+#define AR_PHY_SPECTRAL_SCAN 0x9912
+#define AR_PHY_SPECTRAL_SCAN_ENABLE 0x1
+
#define AR_PHY_RX_DELAY 0x9914
#define AR_PHY_SEARCH_START_DELAY 0x9918
#define AR_PHY_RX_DELAY_DELAY 0x00003FFF
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index a07efa2..16a2717 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -44,7 +44,7 @@
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
4, 7, 7, 7, 7, 0 },
- { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
+ { VALID_2040, VALID_2040, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
6400, 0x80, 0x00, 0,
0, 8, 24, 8, 24, 3216 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
@@ -463,8 +463,6 @@
if (!ignore_cw && WLAN_RC_PHY_HT(phy))
if (WLAN_RC_PHY_40(phy) && !(capflag & WLAN_RC_40_FLAG))
return 0;
- if (!WLAN_RC_PHY_40(phy) && (capflag & WLAN_RC_40_FLAG))
- return 0;
return 1;
}
@@ -1043,9 +1041,6 @@
/* Monotonicity is kept only for rates below the current rate. */
if (ath_rc_priv->per[tx_rate] < last_per) {
for (rate = tx_rate - 1; rate >= 0; rate--) {
- if (rate_table->info[rate].phy !=
- rate_table->info[tx_rate].phy)
- break;
if (ath_rc_priv->per[rate] >
ath_rc_priv->per[rate+1]) {
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 8302aeb..13fd658 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -744,6 +744,9 @@
#define AR_SREV_VERSION_9287 0x180
#define AR_SREV_REVISION_9287_10 0
#define AR_SREV_REVISION_9287_11 1
+#define AR_SREV_VERSION_9271 0x140
+#define AR_SREV_REVISION_9271_10 0
+#define AR_SREV_REVISION_9271_11 1
#define AR_SREV_5416(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
@@ -815,6 +818,15 @@
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_11)))
+#define AR_SREV_9271(_ah) \
+ (((_ah))->hw_version.macVersion == AR_SREV_VERSION_9271)
+#define AR_SREV_9271_10(_ah) \
+ (AR_SREV_9271(_ah) && \
+ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9271_10))
+#define AR_SREV_9271_11(_ah) \
+ (AR_SREV_9271(_ah) && \
+ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9271_11))
+
#define AR_RADIO_SREV_MAJOR 0xf0
#define AR_RAD5133_SREV_MAJOR 0xc0
#define AR_RAD2133_SREV_MAJOR 0xd0
@@ -1142,12 +1154,32 @@
#define AR9285_AN_RF2G4_DB2_4 0x00003800
#define AR9285_AN_RF2G4_DB2_4_S 11
+/* AR9271 : 0x7828, 0x782c different setting from AR9285 */
+#define AR9271_AN_RF2G3_OB_cck 0x001C0000
+#define AR9271_AN_RF2G3_OB_cck_S 18
+#define AR9271_AN_RF2G3_OB_psk 0x00038000
+#define AR9271_AN_RF2G3_OB_psk_S 15
+#define AR9271_AN_RF2G3_OB_qam 0x00007000
+#define AR9271_AN_RF2G3_OB_qam_S 12
+
+#define AR9271_AN_RF2G3_DB_1 0x00E00000
+#define AR9271_AN_RF2G3_DB_1_S 21
+
+#define AR9271_AN_RF2G3_CCOMP 0xFFF
+#define AR9271_AN_RF2G3_CCOMP_S 0
+
+#define AR9271_AN_RF2G4_DB_2 0xE0000000
+#define AR9271_AN_RF2G4_DB_2_S 29
+
#define AR9285_AN_RF2G6 0x7834
#define AR9285_AN_RF2G6_CCOMP 0x00007800
#define AR9285_AN_RF2G6_CCOMP_S 11
#define AR9285_AN_RF2G6_OFFS 0x03f00000
#define AR9285_AN_RF2G6_OFFS_S 20
+#define AR9271_AN_RF2G6_OFFS 0x07f00000
+#define AR9271_AN_RF2G6_OFFS_S 20
+
#define AR9285_AN_RF2G7 0x7838
#define AR9285_AN_RF2G7_PWDDB 0x00000002
#define AR9285_AN_RF2G7_PWDDB_S 1
@@ -1208,6 +1240,11 @@
#define AR9287_AN_TOP2_XPABIAS_LVL 0xC0000000
#define AR9287_AN_TOP2_XPABIAS_LVL_S 30
+/* AR9271 specific stuff */
+#define AR9271_RESET_POWER_DOWN_CONTROL 0x50044
+#define AR9271_RADIO_RF_RST 0x20
+#define AR9271_GATE_MAC_CTL 0x4000
+
#define AR_STA_ID0 0x8000
#define AR_STA_ID1 0x8004
#define AR_STA_ID1_SADH_MASK 0x0000FFFF
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index e1d419e..19b88f8 100644
--- a/drivers/net/wireless/ath/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
@@ -351,7 +351,7 @@
* Drop from tasklet to work to allow mutex for channel
* change.
*/
- queue_work(aphy->sc->hw->workqueue,
+ ieee80211_queue_work(aphy->sc->hw,
&aphy->sc->chan_work);
}
}
@@ -367,7 +367,7 @@
struct ath_softc *sc = aphy->sc;
aphy->state = ATH_WIPHY_PAUSED;
if (!__ath9k_wiphy_pausing(sc))
- queue_work(sc->hw->workqueue, &sc->chan_work);
+ ieee80211_queue_work(sc->hw, &sc->chan_work);
}
static void ath9k_pause_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
@@ -521,7 +521,7 @@
spin_unlock_bh(&sc->wiphy_lock);
ath_radio_disable(sc);
ath_radio_enable(sc);
- queue_work(aphy->sc->hw->workqueue,
+ ieee80211_queue_work(aphy->sc->hw,
&aphy->sc->chan_work);
return -EBUSY; /* previous select still in progress */
}
@@ -541,7 +541,7 @@
if (now) {
/* Ready to request channel change immediately */
- queue_work(aphy->sc->hw->workqueue, &aphy->sc->chan_work);
+ ieee80211_queue_work(aphy->sc->hw, &aphy->sc->chan_work);
}
/*
@@ -648,8 +648,9 @@
"change\n");
}
- queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work,
- sc->wiphy_scheduler_int);
+ ieee80211_queue_delayed_work(sc->hw,
+ &sc->wiphy_work,
+ sc->wiphy_scheduler_int);
}
void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int)
@@ -657,8 +658,8 @@
cancel_delayed_work_sync(&sc->wiphy_work);
sc->wiphy_scheduler_int = msecs_to_jiffies(msec_int);
if (sc->wiphy_scheduler_int)
- queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work,
- sc->wiphy_scheduler_int);
+ ieee80211_queue_delayed_work(sc->hw, &sc->wiphy_work,
+ sc->wiphy_scheduler_int);
}
/* caller must hold wiphy_lock */
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index b7806e2..87762da 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -2063,7 +2063,7 @@
ath_reset(sc, false);
}
- queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work,
+ ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
}
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 4044806..b6811cf 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -142,6 +142,17 @@
#define B43_BFL_BTCMOD 0x4000 /* BFL_BTCOEXIST is given in alternate GPIOs */
#define B43_BFL_ALTIQ 0x8000 /* alternate I/Q settings */
+/* SPROM boardflags_hi values */
+#define B43_BFH_NOPA 0x0001 /* has no PA */
+#define B43_BFH_RSSIINV 0x0002 /* RSSI uses positive slope (not TSSI) */
+#define B43_BFH_PAREF 0x0004 /* uses the PARef LDO */
+#define B43_BFH_3TSWITCH 0x0008 /* uses a triple throw switch shared
+ * with bluetooth */
+#define B43_BFH_PHASESHIFT 0x0010 /* can support phase shifter */
+#define B43_BFH_BUCKBOOST 0x0020 /* has buck/booster */
+#define B43_BFH_FEM_BT 0x0040 /* has FEM and switch to share antenna
+ * with bluetooth */
+
/* GPIO register offset, in both ChipCommon and PCI core. */
#define B43_GPIO_CONTROL 0x6c
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 7964cc3..41a0e9c 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -1334,13 +1334,22 @@
spin_lock_irqsave(&ring->lock, flags);
B43_WARN_ON(!ring->tx);
- /* Check if the queue was stopped in mac80211,
- * but we got called nevertheless.
- * That would be a mac80211 bug. */
- B43_WARN_ON(ring->stopped);
- if (unlikely(free_slots(ring) < TX_SLOTS_PER_FRAME)) {
- b43warn(dev->wl, "DMA queue overflow\n");
+ if (unlikely(ring->stopped)) {
+ /* We get here only because of a bug in mac80211.
+ * Because of a race, one packet may be queued after
+ * the queue is stopped, thus we got called when we shouldn't.
+ * For now, just refuse the transmit. */
+ if (b43_debug(dev, B43_DBG_DMAVERBOSE))
+ b43err(dev->wl, "Packet after queue stopped\n");
+ err = -ENOSPC;
+ goto out_unlock;
+ }
+
+ if (unlikely(WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME))) {
+ /* If we get here, we have a real error with the queue
+ * full, but queues not stopped. */
+ b43err(dev->wl, "DMA queue overflow\n");
err = -ENOSPC;
goto out_unlock;
}
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 3f4360a..925f346 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -395,9 +395,8 @@
/* Unaligned access */
b43_shm_control_word(dev, routing, offset >> 2);
ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
- ret <<= 16;
b43_shm_control_word(dev, routing, (offset >> 2) + 1);
- ret |= b43_read16(dev, B43_MMIO_SHM_DATA);
+ ret |= ((u32)b43_read16(dev, B43_MMIO_SHM_DATA)) << 16;
goto out;
}
@@ -464,9 +463,10 @@
/* Unaligned access */
b43_shm_control_word(dev, routing, offset >> 2);
b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED,
- (value >> 16) & 0xffff);
+ value & 0xFFFF);
b43_shm_control_word(dev, routing, (offset >> 2) + 1);
- b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff);
+ b43_write16(dev, B43_MMIO_SHM_DATA,
+ (value >> 16) & 0xFFFF);
return;
}
offset >>= 2;
@@ -1524,10 +1524,13 @@
/* Looks like PLCP headers plus packet timings are stored for
* all possible basic rates
*/
+ /* FIXME this is the wrong offset : it goes in tkip rx phase1 shm */
+#if 0
b43_write_probe_resp_plcp(dev, 0x31A, size, &b43_b_ratetable[0]);
b43_write_probe_resp_plcp(dev, 0x32C, size, &b43_b_ratetable[1]);
b43_write_probe_resp_plcp(dev, 0x33E, size, &b43_b_ratetable[2]);
b43_write_probe_resp_plcp(dev, 0x350, size, &b43_b_ratetable[3]);
+#endif
size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6));
b43_write_template_common(dev, probe_resp_data,
@@ -1654,7 +1657,7 @@
wl->current_beacon = beacon;
wl->beacon0_uploaded = 0;
wl->beacon1_uploaded = 0;
- queue_work(wl->hw->workqueue, &wl->beacon_update_trigger);
+ ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger);
}
static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
@@ -2914,7 +2917,7 @@
delay = msecs_to_jiffies(50);
else
delay = round_jiffies_relative(HZ * 15);
- queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay);
+ ieee80211_queue_delayed_work(wl->hw, &dev->periodic_work, delay);
out:
mutex_unlock(&wl->mutex);
}
@@ -2925,15 +2928,16 @@
dev->periodic_state = 0;
INIT_DELAYED_WORK(work, b43_periodic_work_handler);
- queue_delayed_work(dev->wl->hw->workqueue, work, 0);
+ ieee80211_queue_delayed_work(dev->wl->hw, work, 0);
}
/* Check if communication with the device works correctly. */
static int b43_validate_chipaccess(struct b43_wldev *dev)
{
- u32 v, backup;
+ u32 v, backup0, backup4;
- backup = b43_shm_read32(dev, B43_SHM_SHARED, 0);
+ backup0 = b43_shm_read32(dev, B43_SHM_SHARED, 0);
+ backup4 = b43_shm_read32(dev, B43_SHM_SHARED, 4);
/* Check for read/write and endianness problems. */
b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55);
@@ -2943,7 +2947,23 @@
if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA)
goto error;
- b43_shm_write32(dev, B43_SHM_SHARED, 0, backup);
+ /* Check if unaligned 32bit SHM_SHARED access works properly.
+ * However, don't bail out on failure, because it's noncritical. */
+ b43_shm_write16(dev, B43_SHM_SHARED, 0, 0x1122);
+ b43_shm_write16(dev, B43_SHM_SHARED, 2, 0x3344);
+ b43_shm_write16(dev, B43_SHM_SHARED, 4, 0x5566);
+ b43_shm_write16(dev, B43_SHM_SHARED, 6, 0x7788);
+ if (b43_shm_read32(dev, B43_SHM_SHARED, 2) != 0x55663344)
+ b43warn(dev->wl, "Unaligned 32bit SHM read access is broken\n");
+ b43_shm_write32(dev, B43_SHM_SHARED, 2, 0xAABBCCDD);
+ if (b43_shm_read16(dev, B43_SHM_SHARED, 0) != 0x1122 ||
+ b43_shm_read16(dev, B43_SHM_SHARED, 2) != 0xCCDD ||
+ b43_shm_read16(dev, B43_SHM_SHARED, 4) != 0xAABB ||
+ b43_shm_read16(dev, B43_SHM_SHARED, 6) != 0x7788)
+ b43warn(dev->wl, "Unaligned 32bit SHM write access is broken\n");
+
+ b43_shm_write32(dev, B43_SHM_SHARED, 0, backup0);
+ b43_shm_write32(dev, B43_SHM_SHARED, 4, backup4);
if ((dev->dev->id.revision >= 3) && (dev->dev->id.revision <= 10)) {
/* The 32bit register shadows the two 16bit registers
@@ -4871,7 +4891,7 @@
if (b43_status(dev) < B43_STAT_INITIALIZED)
return;
b43info(dev->wl, "Controller RESET (%s) ...\n", reason);
- queue_work(dev->wl->hw->workqueue, &dev->restart_work);
+ ieee80211_queue_work(dev->wl->hw, &dev->restart_work);
}
#ifdef CONFIG_PM
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index 6d24162..51686ec 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -240,6 +240,13 @@
dev->phy.ops->phy_write(dev, reg, value);
}
+void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg)
+{
+ assert_mac_suspended(dev);
+ dev->phy.ops->phy_write(dev, destreg,
+ dev->phy.ops->phy_read(dev, srcreg));
+}
+
void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask)
{
b43_phy_write(dev, offset,
@@ -352,7 +359,7 @@
/* We must adjust the transmission power in hardware.
* Schedule b43_phy_txpower_adjust_work(). */
- queue_work(dev->wl->hw->workqueue, &dev->wl->txpower_adjust_work);
+ ieee80211_queue_work(dev->wl->hw, &dev->wl->txpower_adjust_work);
}
int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset)
diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h
index 44cc918..9f9f23c 100644
--- a/drivers/net/wireless/b43/phy_common.h
+++ b/drivers/net/wireless/b43/phy_common.h
@@ -291,6 +291,11 @@
void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value);
/**
+ * b43_phy_copy - copy contents of 16bit PHY register to another
+ */
+void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg);
+
+/**
* b43_phy_mask - Mask a PHY register with a mask
*/
void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask);
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c
index ea0d3a3..aa1486a 100644
--- a/drivers/net/wireless/b43/phy_lp.c
+++ b/drivers/net/wireless/b43/phy_lp.c
@@ -66,7 +66,99 @@
static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
{
- B43_WARN_ON(1);//TODO rev < 2 not supported, yet.
+ struct ssb_bus *bus = dev->dev->bus;
+ u16 tmp, tmp2;
+
+ if (dev->phy.rev == 1 &&
+ (bus->sprom.boardflags_hi & B43_BFH_FEM_BT)) {
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0x3F00, 0x0900);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x000A);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0B00);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x000A);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0400);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x000A);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0B00);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_5, 0xFFC0, 0x000A);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_5, 0xC0FF, 0x0900);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_6, 0xFFC0, 0x000A);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_6, 0xC0FF, 0x0B00);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_7, 0xFFC0, 0x000A);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_7, 0xC0FF, 0x0900);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xFFC0, 0x000A);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xC0FF, 0x0B00);
+ } else if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ ||
+ (bus->boardinfo.type == 0x048A) || ((dev->phy.rev == 0) &&
+ (bus->sprom.boardflags_lo & B43_BFL_FEM))) {
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0001);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0400);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0001);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0500);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0002);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0800);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0002);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0A00);
+ } else if (dev->phy.rev == 1 ||
+ (bus->sprom.boardflags_lo & B43_BFL_FEM)) {
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0004);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0800);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0004);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0C00);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0002);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0100);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0002);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0300);
+ } else {
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0900);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x000A);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xC0FF, 0x0B00);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xFFC0, 0x0006);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_3, 0xC0FF, 0x0500);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0006);
+ b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0700);
+ }
+ if (dev->phy.rev == 1) {
+ b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_5, B43_LPPHY_TR_LOOKUP_1);
+ b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_6, B43_LPPHY_TR_LOOKUP_2);
+ b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_7, B43_LPPHY_TR_LOOKUP_3);
+ b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_8, B43_LPPHY_TR_LOOKUP_4);
+ }
+ if ((bus->sprom.boardflags_hi & B43_BFH_FEM_BT) &&
+ (bus->chip_id == 0x5354) &&
+ (bus->chip_package == SSB_CHIPPACK_BCM4712S)) {
+ b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0006);
+ b43_phy_write(dev, B43_LPPHY_GPIO_SELECT, 0x0005);
+ b43_phy_write(dev, B43_LPPHY_GPIO_OUTEN, 0xFFFF);
+ b43_hf_write(dev, b43_hf_read(dev) | 0x0800ULL << 32);
+ }
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ b43_phy_set(dev, B43_LPPHY_LP_PHY_CTL, 0x8000);
+ b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0040);
+ b43_phy_maskset(dev, B43_LPPHY_MINPWR_LEVEL, 0x00FF, 0xA400);
+ b43_phy_maskset(dev, B43_LPPHY_CRSGAIN_CTL, 0xF0FF, 0x0B00);
+ b43_phy_maskset(dev, B43_LPPHY_SYNCPEAKCNT, 0xFFF8, 0x0007);
+ b43_phy_maskset(dev, B43_LPPHY_DSSS_CONFIRM_CNT, 0xFFF8, 0x0003);
+ b43_phy_maskset(dev, B43_LPPHY_DSSS_CONFIRM_CNT, 0xFFC7, 0x0020);
+ b43_phy_mask(dev, B43_LPPHY_IDLEAFTERPKTRXTO, 0x00FF);
+ } else { /* 5GHz */
+ b43_phy_mask(dev, B43_LPPHY_LP_PHY_CTL, 0x7FFF);
+ b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, 0xFFBF);
+ }
+ if (dev->phy.rev == 1) {
+ tmp = b43_phy_read(dev, B43_LPPHY_CLIPCTRTHRESH);
+ tmp2 = (tmp & 0x03E0) >> 5;
+ tmp2 |= tmp << 5;
+ b43_phy_write(dev, B43_LPPHY_4C3, tmp2);
+ tmp = b43_phy_read(dev, B43_LPPHY_OFDMSYNCTHRESH0);
+ tmp2 = (tmp & 0x1F00) >> 8;
+ tmp2 |= tmp << 5;
+ b43_phy_write(dev, B43_LPPHY_4C4, tmp2);
+ tmp = b43_phy_read(dev, B43_LPPHY_VERYLOWGAINDB);
+ tmp2 = tmp & 0x00FF;
+ tmp2 |= tmp << 8;
+ b43_phy_write(dev, B43_LPPHY_4C5, tmp2);
+ }
}
static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h
index 18370b4..829b2bb 100644
--- a/drivers/net/wireless/b43/phy_lp.h
+++ b/drivers/net/wireless/b43/phy_lp.h
@@ -273,12 +273,19 @@
#define B43_LPPHY_AFE_DDFS_POINTER_INIT B43_PHY_OFDM(0xB8) /* AFE DDFS pointer init */
#define B43_LPPHY_AFE_DDFS_INCR_INIT B43_PHY_OFDM(0xB9) /* AFE DDFS incr init */
#define B43_LPPHY_MRCNOISEREDUCTION B43_PHY_OFDM(0xBA) /* mrcNoiseReduction */
-#define B43_LPPHY_TRLOOKUP3 B43_PHY_OFDM(0xBB) /* TRLookup3 */
-#define B43_LPPHY_TRLOOKUP4 B43_PHY_OFDM(0xBC) /* TRLookup4 */
+#define B43_LPPHY_TR_LOOKUP_3 B43_PHY_OFDM(0xBB) /* TR Lookup 3 */
+#define B43_LPPHY_TR_LOOKUP_4 B43_PHY_OFDM(0xBC) /* TR Lookup 4 */
#define B43_LPPHY_RADAR_FIFO_STAT B43_PHY_OFDM(0xBD) /* Radar FIFO Status */
#define B43_LPPHY_GPIO_OUTEN B43_PHY_OFDM(0xBE) /* GPIO Out enable */
#define B43_LPPHY_GPIO_SELECT B43_PHY_OFDM(0xBF) /* GPIO Select */
#define B43_LPPHY_GPIO_OUT B43_PHY_OFDM(0xC0) /* GPIO Out */
+#define B43_LPPHY_4C3 B43_PHY_OFDM(0xC3) /* unknown, used during BB init */
+#define B43_LPPHY_4C4 B43_PHY_OFDM(0xC4) /* unknown, used during BB init */
+#define B43_LPPHY_4C5 B43_PHY_OFDM(0xC5) /* unknown, used during BB init */
+#define B43_LPPHY_TR_LOOKUP_5 B43_PHY_OFDM(0xC7) /* TR Lookup 5 */
+#define B43_LPPHY_TR_LOOKUP_6 B43_PHY_OFDM(0xC8) /* TR Lookup 6 */
+#define B43_LPPHY_TR_LOOKUP_7 B43_PHY_OFDM(0xC9) /* TR Lookup 7 */
+#define B43_LPPHY_TR_LOOKUP_8 B43_PHY_OFDM(0xCA) /* TR Lookup 8 */
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
index be7b560..992318a 100644
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -137,7 +137,8 @@
b43_radio_mask(dev, B2055_MASTER1, 0xFFF3);
msleep(1);
- if ((sprom->revision != 4) || !(sprom->boardflags_hi & 0x0002)) {
+ if ((sprom->revision != 4) ||
+ !(sprom->boardflags_hi & B43_BFH_RSSIINV)) {
if ((binfo->vendor != PCI_VENDOR_ID_BROADCOM) ||
(binfo->type != 0x46D) ||
(binfo->rev < 0x41)) {
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c
index 69138e8..73c047d 100644
--- a/drivers/net/wireless/b43/pio.c
+++ b/drivers/net/wireless/b43/pio.c
@@ -783,7 +783,7 @@
{
/* Due to latency issues we must run the RX path in
* a workqueue to be able to schedule between packets. */
- queue_work(q->dev->wl->hw->workqueue, &q->rx_work);
+ ieee80211_queue_work(q->dev->wl->hw, &q->rx_work);
}
static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q)
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index 2f90fb9..8664034 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -1366,15 +1366,25 @@
ring = priority_to_txring(dev, skb_get_queue_mapping(skb));
spin_lock_irqsave(&ring->lock, flags);
B43legacy_WARN_ON(!ring->tx);
- if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
- b43legacywarn(dev->wl, "DMA queue overflow\n");
+
+ if (unlikely(ring->stopped)) {
+ /* We get here only because of a bug in mac80211.
+ * Because of a race, one packet may be queued after
+ * the queue is stopped, thus we got called when we shouldn't.
+ * For now, just refuse the transmit. */
+ if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
+ b43legacyerr(dev->wl, "Packet after queue stopped\n");
err = -ENOSPC;
goto out_unlock;
}
- /* Check if the queue was stopped in mac80211,
- * but we got called nevertheless.
- * That would be a mac80211 bug. */
- B43legacy_BUG_ON(ring->stopped);
+
+ if (unlikely(WARN_ON(free_slots(ring) < SLOTS_PER_PACKET))) {
+ /* If we get here, we have a real error with the queue
+ * full, but queues not stopped. */
+ b43legacyerr(dev->wl, "DMA queue overflow\n");
+ err = -ENOSPC;
+ goto out_unlock;
+ }
err = dma_tx_fragment(ring, skb);
if (unlikely(err == -ENOKEY)) {
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index c4973c1..b143559 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -1252,7 +1252,7 @@
wl->current_beacon = beacon;
wl->beacon0_uploaded = 0;
wl->beacon1_uploaded = 0;
- queue_work(wl->hw->workqueue, &wl->beacon_update_trigger);
+ ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger);
}
static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev,
@@ -2300,7 +2300,7 @@
delay = msecs_to_jiffies(50);
else
delay = round_jiffies_relative(HZ * 15);
- queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay);
+ ieee80211_queue_delayed_work(wl->hw, &dev->periodic_work, delay);
out:
mutex_unlock(&wl->mutex);
}
@@ -2311,7 +2311,7 @@
dev->periodic_state = 0;
INIT_DELAYED_WORK(work, b43legacy_periodic_work_handler);
- queue_delayed_work(dev->wl->hw->workqueue, work, 0);
+ ieee80211_queue_delayed_work(dev->wl->hw, work, 0);
}
/* Validate access to the chip (SHM) */
@@ -3885,7 +3885,7 @@
if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)
return;
b43legacyinfo(dev->wl, "Controller RESET (%s) ...\n", reason);
- queue_work(dev->wl->hw->workqueue, &dev->restart_work);
+ ieee80211_queue_work(dev->wl->hw, &dev->restart_work);
}
#ifdef CONFIG_PM
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 5f7c520..cf3fbc6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -73,6 +73,18 @@
priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
}
+/* NIC configuration for 1000 series */
+static void iwl1000_nic_config(struct iwl_priv *priv)
+{
+ iwl5000_nic_config(priv);
+
+ /* Setting digital SVR for 1000 card to 1.32V */
+ /* locking is acquired in iwl_set_bits_mask_prph() function */
+ iwl_set_bits_mask_prph(priv, APMG_DIGITAL_SVR_REG,
+ APMG_SVR_DIGITAL_VOLTAGE_1_32,
+ ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
+}
+
static struct iwl_lib_ops iwl1000_lib = {
.set_hw_params = iwl5000_hw_set_hw_params,
.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
@@ -95,7 +107,7 @@
.init = iwl5000_apm_init,
.reset = iwl5000_apm_reset,
.stop = iwl5000_apm_stop,
- .config = iwl5000_nic_config,
+ .config = iwl1000_nic_config,
.set_pwr_src = iwl_set_pwr_src,
},
.eeprom_ops = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index ddd64fe..87957c0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -198,6 +198,7 @@
}
+/* NIC configuration for 5000 series and up */
void iwl5000_nic_config(struct iwl_priv *priv)
{
unsigned long flags;
@@ -239,18 +240,11 @@
APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
- if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_1000) {
- /* Setting digital SVR for 1000 card to 1.32V */
- iwl_set_bits_mask_prph(priv, APMG_DIGITAL_SVR_REG,
- APMG_SVR_DIGITAL_VOLTAGE_1_32,
- ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
- }
spin_unlock_irqrestore(&priv->lock, flags);
}
-
/*
* EEPROM
*/
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 59ff735..4450943 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -68,6 +68,24 @@
priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD;
}
+/* NIC configuration for 6000 series */
+static void iwl6000_nic_config(struct iwl_priv *priv)
+{
+ iwl5000_nic_config(priv);
+
+ /* no locking required for register write */
+ if (priv->cfg->pa_type == IWL_PA_HYBRID) {
+ /* 2x2 hybrid phy type */
+ iwl_write32(priv, CSR_GP_DRIVER_REG,
+ CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_HYB);
+ } else if (priv->cfg->pa_type == IWL_PA_INTERNAL) {
+ /* 2x2 IPA phy type */
+ iwl_write32(priv, CSR_GP_DRIVER_REG,
+ CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
+ }
+ /* else do nothing, uCode configured */
+}
+
static struct iwl_lib_ops iwl6000_lib = {
.set_hw_params = iwl5000_hw_set_hw_params,
.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
@@ -90,7 +108,7 @@
.init = iwl5000_apm_init,
.reset = iwl5000_apm_reset,
.stop = iwl5000_apm_stop,
- .config = iwl5000_nic_config,
+ .config = iwl6000_nic_config,
.set_pwr_src = iwl_set_pwr_src,
},
.eeprom_ops = {
@@ -132,23 +150,11 @@
.utils = &iwl6000_hcmd_utils,
};
-struct iwl_cfg iwl6000_2ag_cfg = {
- .name = "6000 Series 2x2 AG",
- .fw_name_pre = IWL6000_FW_PRE,
- .ucode_api_max = IWL6000_UCODE_API_MAX,
- .ucode_api_min = IWL6000_UCODE_API_MIN,
- .sku = IWL_SKU_A|IWL_SKU_G,
- .ops = &iwl6000_ops,
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
- .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
- .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
- .mod_params = &iwl50_mod_params,
- .valid_tx_ant = ANT_BC,
- .valid_rx_ant = ANT_BC,
- .need_pll_cfg = false,
-};
-struct iwl_cfg iwl6000_2agn_cfg = {
+/*
+ * "h": Hybrid configuration, use both internal and external Power Amplifier
+ */
+struct iwl_cfg iwl6000h_2agn_cfg = {
.name = "6000 Series 2x2 AGN",
.fw_name_pre = IWL6000_FW_PRE,
.ucode_api_max = IWL6000_UCODE_API_MAX,
@@ -162,6 +168,27 @@
.valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB,
.need_pll_cfg = false,
+ .pa_type = IWL_PA_HYBRID,
+};
+
+/*
+ * "i": Internal configuration, use internal Power Amplifier
+ */
+struct iwl_cfg iwl6000i_2agn_cfg = {
+ .name = "6000 Series 2x2 AGN",
+ .fw_name_pre = IWL6000_FW_PRE,
+ .ucode_api_max = IWL6000_UCODE_API_MAX,
+ .ucode_api_min = IWL6000_UCODE_API_MIN,
+ .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+ .ops = &iwl6000_ops,
+ .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .mod_params = &iwl50_mod_params,
+ .valid_tx_ant = ANT_BC,
+ .valid_rx_ant = ANT_BC,
+ .need_pll_cfg = false,
+ .pa_type = IWL_PA_INTERNAL,
};
struct iwl_cfg iwl6050_2agn_cfg = {
@@ -178,6 +205,7 @@
.valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB,
.need_pll_cfg = false,
+ .pa_type = IWL_PA_SYSTEM,
};
struct iwl_cfg iwl6000_3agn_cfg = {
@@ -194,6 +222,7 @@
.valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC,
.need_pll_cfg = false,
+ .pa_type = IWL_PA_SYSTEM,
};
struct iwl_cfg iwl6050_3agn_cfg = {
@@ -210,6 +239,7 @@
.valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC,
.need_pll_cfg = false,
+ .pa_type = IWL_PA_SYSTEM,
};
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 4cb1a1b..db580cb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -1291,6 +1291,7 @@
size_t len;
u32 api_ver, build;
u32 inst_size, data_size, init_size, init_data_size, boot_size;
+ u16 eeprom_ver;
/* Ask kernel firmware_class module to get the boot firmware off disk.
* request_firmware() is synchronous, file is in memory on return. */
@@ -1368,6 +1369,11 @@
if (build)
IWL_DEBUG_INFO(priv, "Build %u\n", build);
+ eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
+ IWL_DEBUG_INFO(priv, "NVM Type: %s, version: 0x%x\n",
+ (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+ ? "OTP" : "EEPROM", eeprom_ver);
+
IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
priv->ucode_ver);
IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n",
@@ -2483,39 +2489,6 @@
#endif /* CONFIG_IWLWIFI_DEBUG */
-static ssize_t show_version(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- struct iwl_alive_resp *palive = &priv->card_alive;
- ssize_t pos = 0;
- u16 eeprom_ver;
-
- if (palive->is_valid)
- pos += sprintf(buf + pos,
- "fw version: 0x%01X.0x%01X.0x%01X.0x%01X\n"
- "fw type: 0x%01X 0x%01X\n",
- palive->ucode_major, palive->ucode_minor,
- palive->sw_rev[0], palive->sw_rev[1],
- palive->ver_type, palive->ver_subtype);
- else
- pos += sprintf(buf + pos, "fw not loaded\n");
-
- if (priv->eeprom) {
- eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
- pos += sprintf(buf + pos, "NVM Type: %s, version: 0x%x\n",
- (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
- ? "OTP" : "EEPROM", eeprom_ver);
-
- } else {
- pos += sprintf(buf + pos, "EEPROM not initialzed\n");
- }
-
- return pos;
-}
-
-static DEVICE_ATTR(version, S_IWUSR | S_IRUGO, show_version, NULL);
-
static ssize_t show_temperature(struct device *d,
struct device_attribute *attr, char *buf)
{
@@ -2779,7 +2752,6 @@
#ifdef CONFIG_IWLWIFI_DEBUG
&dev_attr_debug_level.attr,
#endif
- &dev_attr_version.attr,
NULL
};
@@ -3139,15 +3111,12 @@
{IWL_PCI_DEVICE(0x423C, PCI_ANY_ID, iwl5150_agn_cfg)},
{IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)},
/* 6000/6050 Series */
- {IWL_PCI_DEVICE(0x0082, 0x1102, iwl6000_2ag_cfg)},
- {IWL_PCI_DEVICE(0x0085, 0x1112, iwl6000_2ag_cfg)},
- {IWL_PCI_DEVICE(0x0082, 0x1122, iwl6000_2ag_cfg)},
+ {IWL_PCI_DEVICE(0x008D, PCI_ANY_ID, iwl6000h_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x008E, PCI_ANY_ID, iwl6000h_2agn_cfg)},
{IWL_PCI_DEVICE(0x422B, PCI_ANY_ID, iwl6000_3agn_cfg)},
- {IWL_PCI_DEVICE(0x422C, PCI_ANY_ID, iwl6000_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x422C, PCI_ANY_ID, iwl6000i_2agn_cfg)},
{IWL_PCI_DEVICE(0x4238, PCI_ANY_ID, iwl6000_3agn_cfg)},
- {IWL_PCI_DEVICE(0x4239, PCI_ANY_ID, iwl6000_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0082, PCI_ANY_ID, iwl6000_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0085, PCI_ANY_ID, iwl6000_3agn_cfg)},
+ {IWL_PCI_DEVICE(0x4239, PCI_ANY_ID, iwl6000i_2agn_cfg)},
{IWL_PCI_DEVICE(0x0086, PCI_ANY_ID, iwl6050_3agn_cfg)},
{IWL_PCI_DEVICE(0x0087, PCI_ANY_ID, iwl6050_2agn_cfg)},
{IWL_PCI_DEVICE(0x0088, PCI_ANY_ID, iwl6050_3agn_cfg)},
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 8570d56..6797076 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -548,9 +548,6 @@
geo_ch->flags |= IEEE80211_CHAN_DISABLED;
}
- /* Save flags for reg domain usage */
- geo_ch->orig_flags = geo_ch->flags;
-
IWL_DEBUG_INFO(priv, "Channel %d Freq=%d[%sGHz] %s flag=0x%X\n",
ch->channel, geo_ch->center_freq,
is_channel_a_band(ch) ? "5.2" : "2.4",
@@ -1140,7 +1137,6 @@
priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK;
}
}
-EXPORT_SYMBOL(iwl_set_flags_for_band);
/*
* initialize rxon structure with default values from eeprom
@@ -2291,7 +2287,6 @@
return iwl_send_cmd(priv, &cmd);
}
-EXPORT_SYMBOL(iwl_send_card_state);
void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
@@ -2335,7 +2330,6 @@
{
memset(&priv->isr_stats, 0, sizeof(priv->isr_stats));
}
-EXPORT_SYMBOL(iwl_clear_isr_stats);
int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params)
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index febcf76..10ddcdd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -206,6 +206,7 @@
* filename is constructed as fw_name_pre<api>.ucode.
* @ucode_api_max: Highest version of uCode API supported by driver.
* @ucode_api_min: Lowest version of uCode API supported by driver.
+ * @pa_type: used by 6000 series only to identify the type of Power Amplifier
*
* We enable the driver to be backward compatible wrt API version. The
* driver specifies which APIs it supports (with @ucode_api_max being the
@@ -226,6 +227,7 @@
* iwl_hcmd_utils_ops etc. we accommodate different command structures
* and flows between hardware versions (4965/5000) as well as their API
* versions.
+ *
*/
struct iwl_cfg {
const char *name;
@@ -242,6 +244,7 @@
u8 valid_rx_ant;
bool need_pll_cfg;
bool use_isr_legacy;
+ enum iwl_pa_type pa_type;
};
/***************************
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index f03dae1..06437d1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -91,7 +91,8 @@
#define CSR_EEPROM_GP (CSR_BASE+0x030)
#define CSR_OTP_GP_REG (CSR_BASE+0x034)
#define CSR_GIO_REG (CSR_BASE+0x03C)
-#define CSR_GP_UCODE (CSR_BASE+0x044)
+#define CSR_GP_UCODE_REG (CSR_BASE+0x048)
+#define CSR_GP_DRIVER_REG (CSR_BASE+0x050)
#define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054)
#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058)
#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c)
@@ -245,6 +246,13 @@
#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004)
#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008)
+/* GP Driver */
+#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_MSK (0x00000003)
+#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_3x3_HYB (0x00000000)
+#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_HYB (0x00000001)
+#define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA (0x00000002)
+
+
/* GI Chicken Bits */
#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000)
#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000)
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 0ee3ad2..cab6255 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -56,8 +56,8 @@
extern struct iwl_cfg iwl5100_bg_cfg;
extern struct iwl_cfg iwl5100_abg_cfg;
extern struct iwl_cfg iwl5150_agn_cfg;
-extern struct iwl_cfg iwl6000_2ag_cfg;
-extern struct iwl_cfg iwl6000_2agn_cfg;
+extern struct iwl_cfg iwl6000h_2agn_cfg;
+extern struct iwl_cfg iwl6000i_2agn_cfg;
extern struct iwl_cfg iwl6000_3agn_cfg;
extern struct iwl_cfg iwl6050_2agn_cfg;
extern struct iwl_cfg iwl6050_3agn_cfg;
@@ -888,6 +888,19 @@
NVM_DEVICE_TYPE_OTP,
};
+
+/**
+ * enum iwl_pa_type - Power Amplifier type
+ * @IWL_PA_SYSTEM: based on uCode configuration
+ * @IWL_PA_HYBRID: use both Internal and external PA
+ * @IWL_PA_INTERNAL: use Internal only
+ */
+enum iwl_pa_type {
+ IWL_PA_SYSTEM = 0,
+ IWL_PA_HYBRID = 1,
+ IWL_PA_INTERNAL = 2,
+};
+
/* interrupt statistics */
struct isr_statistics {
u32 hw;
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index 7cce8f8..3d61cb4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -335,7 +335,6 @@
priv->last_blink_time = jiffies;
priv->last_blink_rate = blink_idx;
}
-EXPORT_SYMBOL(iwl_leds_background);
/* Register all led handler */
int iwl_leds_register(struct iwl_priv *priv)
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 5d5f215..e002c8b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -406,7 +406,6 @@
rxq->free_count = 0;
spin_unlock_irqrestore(&rxq->lock, flags);
}
-EXPORT_SYMBOL(iwl_rx_queue_reset);
int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
{
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 79ea5cc..efcae0d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -464,7 +464,6 @@
spin_unlock_irqrestore(&priv->sta_lock, flags);
return ret;
}
-EXPORT_SYMBOL(iwl_remove_station);
/**
* iwl_clear_stations_table - Clear the driver's station table
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 6bb9602..288b871 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -970,6 +970,7 @@
out_cmd = txq->cmd[idx];
out_meta = &txq->meta[idx];
+ memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */
out_meta->flags = cmd->flags;
if (cmd->flags & CMD_WANT_SKB)
out_meta->source = cmd;
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index 3f5a08f..a6e852f 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -484,6 +484,8 @@
static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version)
{
+ IWM_DBG_WEXT(iwm, DBG, "wpa_version: %d\n", wpa_version);
+
if (!wpa_version) {
iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
return 0;
@@ -508,6 +510,9 @@
return 0;
}
+ IWM_DBG_WEXT(iwm, DBG, "%ccast cipher is 0x%x\n", ucast ? 'u' : 'm',
+ cipher);
+
switch (cipher) {
case IW_AUTH_CIPHER_NONE:
*profile_cipher = UMAC_CIPHER_TYPE_NONE;
@@ -584,11 +589,11 @@
iwm->umac_profile->bss_num = 0;
}
- ret = iwm_set_auth_type(iwm, sme->auth_type);
+ ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions);
if (ret < 0)
return ret;
- ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions);
+ ret = iwm_set_auth_type(iwm, sme->auth_type);
if (ret < 0)
return ret;
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c
index 0d66370..f0c8acd 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.c
+++ b/drivers/net/wireless/iwmc3200wifi/commands.c
@@ -526,19 +526,6 @@
return 0;
}
-int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx)
-{
- struct iwm_umac_tx_key_id tx_key_id;
-
- tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID;
- tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) -
- sizeof(struct iwm_umac_wifi_if));
-
- tx_key_id.key_idx = key_idx;
-
- return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1);
-}
-
static int iwm_check_profile(struct iwm_priv *iwm)
{
if (!iwm->umac_profile_active)
@@ -572,6 +559,32 @@
return 0;
}
+int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx)
+{
+ struct iwm_umac_tx_key_id tx_key_id;
+ int ret;
+
+ ret = iwm_check_profile(iwm);
+ if (ret < 0)
+ return ret;
+
+ /* UMAC only allows to set default key for WEP and auth type is
+ * NOT 802.1X or RSNA. */
+ if ((iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_40 &&
+ iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_104) ||
+ iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_8021X ||
+ iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_RSNA_PSK)
+ return 0;
+
+ tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID;
+ tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) -
+ sizeof(struct iwm_umac_wifi_if));
+
+ tx_key_id.key_idx = key_idx;
+
+ return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1);
+}
+
int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
{
int ret = 0;
@@ -596,6 +609,8 @@
key_idx = key->hdr.key_idx;
if (!remove) {
+ u8 auth_type = iwm->umac_profile->sec.auth_type;
+
IWM_DBG_WEXT(iwm, DBG, "key_idx:%d\n", key_idx);
IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len);
IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n",
@@ -618,7 +633,9 @@
memcpy(&wep40->key_hdr, key_hdr,
sizeof(struct iwm_umac_key_hdr));
memcpy(wep40->key, key_data, key_len);
- wep40->static_key = 1;
+ wep40->static_key =
+ !!((auth_type != UMAC_AUTH_TYPE_8021X) &&
+ (auth_type != UMAC_AUTH_TYPE_RSNA_PSK));
cmd_size = sizeof(struct iwm_umac_key_wep40);
break;
@@ -632,7 +649,9 @@
memcpy(&wep104->key_hdr, key_hdr,
sizeof(struct iwm_umac_key_hdr));
memcpy(wep104->key, key_data, key_len);
- wep104->static_key = 1;
+ wep104->static_key =
+ !!((auth_type != UMAC_AUTH_TYPE_8021X) &&
+ (auth_type != UMAC_AUTH_TYPE_RSNA_PSK));
cmd_size = sizeof(struct iwm_umac_key_wep104);
break;
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index 963c201..446e327 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -376,7 +376,7 @@
err = spu_read_u16(card, IF_SPI_SPU_BUS_MODE_REG, &rval);
if (err)
return err;
- if (rval != mode) {
+ if ((rval & 0xF) != mode) {
lbs_pr_err("Can't read bus mode register.\n");
return -EIO;
}
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index e96451c..be837a0d25 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -1728,6 +1728,8 @@
}
switch (dwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_PRIVACY_INVOKED:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
case IW_AUTH_TKIP_COUNTERMEASURES:
case IW_AUTH_CIPHER_PAIRWISE:
case IW_AUTH_CIPHER_GROUP:
diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
index 1a87d3a..27f2d33 100644
--- a/drivers/net/wireless/orinoco/cfg.c
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -156,7 +156,48 @@
return err;
}
+static int orinoco_set_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ int err = 0;
+ unsigned long flags;
+ int channel;
+
+ if (!chan)
+ return -EINVAL;
+
+ if (channel_type != NL80211_CHAN_NO_HT)
+ return -EINVAL;
+
+ if (chan->band != IEEE80211_BAND_2GHZ)
+ return -EINVAL;
+
+ channel = ieee80211_freq_to_dsss_chan(chan->center_freq);
+
+ if ((channel < 1) || (channel > NUM_CHANNELS) ||
+ !(priv->channel_mask & (1 << (channel-1))))
+ return -EINVAL;
+
+ if (orinoco_lock(priv, &flags) != 0)
+ return -EBUSY;
+
+ priv->channel = channel;
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
+ /* Fast channel change - no commit if successful */
+ hermes_t *hw = &priv->hw;
+ err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+ HERMES_TEST_SET_CHANNEL,
+ channel, NULL);
+ }
+ orinoco_unlock(priv, &flags);
+
+ return err;
+}
+
const struct cfg80211_ops orinoco_cfg_ops = {
.change_virtual_intf = orinoco_change_vif,
+ .set_channel = orinoco_set_channel,
.scan = orinoco_scan,
};
diff --git a/drivers/net/wireless/p54/led.c b/drivers/net/wireless/p54/led.c
index c00115b..9575ac0 100644
--- a/drivers/net/wireless/p54/led.c
+++ b/drivers/net/wireless/p54/led.c
@@ -61,7 +61,7 @@
wiphy_name(priv->hw->wiphy), err);
if (rerun)
- queue_delayed_work(priv->hw->workqueue, &priv->led_work,
+ ieee80211_queue_delayed_work(priv->hw, &priv->led_work,
msecs_to_jiffies(blink_delay));
}
@@ -78,8 +78,7 @@
if ((brightness) && (led->registered)) {
led->toggled++;
- queue_delayed_work(priv->hw->workqueue, &priv->led_work,
- HZ/10);
+ ieee80211_queue_delayed_work(priv->hw, &priv->led_work, HZ/10);
}
}
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index 955f6d7..a0d0e72 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -180,7 +180,7 @@
goto out;
}
- queue_delayed_work(dev->workqueue, &priv->work, 0);
+ ieee80211_queue_delayed_work(dev, &priv->work, 0);
priv->softled_state = 0;
err = p54_set_leds(priv);
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c
index eef5329..05458d9 100644
--- a/drivers/net/wireless/p54/p54spi.c
+++ b/drivers/net/wireless/p54/p54spi.c
@@ -391,7 +391,7 @@
struct spi_device *spi = config;
struct p54s_priv *priv = dev_get_drvdata(&spi->dev);
- queue_work(priv->hw->workqueue, &priv->work);
+ ieee80211_queue_work(priv->hw, &priv->work);
return IRQ_HANDLED;
}
@@ -479,7 +479,7 @@
list_add_tail(&di->tx_list, &priv->tx_pending);
spin_unlock_irqrestore(&priv->tx_lock, flags);
- queue_work(priv->hw->workqueue, &priv->work);
+ ieee80211_queue_work(priv->hw, &priv->work);
}
static void p54spi_work(struct work_struct *work)
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
index c32a0d2..704685f 100644
--- a/drivers/net/wireless/p54/txrx.c
+++ b/drivers/net/wireless/p54/txrx.c
@@ -380,7 +380,7 @@
ieee80211_rx_irqsafe(priv->hw, skb);
- queue_delayed_work(priv->hw->workqueue, &priv->work,
+ ieee80211_queue_delayed_work(priv->hw, &priv->work,
msecs_to_jiffies(P54_STATISTICS_UPDATE));
return -1;
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 09c0702..828dc18 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -100,7 +100,6 @@
#define OID_GEN_RCV_ERROR cpu_to_le32(0x00020104)
#define OID_GEN_RCV_NO_BUFFER cpu_to_le32(0x00020105)
-#define OID_802_3_PERMANENT_ADDRESS cpu_to_le32(0x01010101)
#define OID_802_3_CURRENT_ADDRESS cpu_to_le32(0x01010102)
#define OID_802_3_MULTICAST_LIST cpu_to_le32(0x01010103)
#define OID_802_3_MAXIMUM_LIST_SIZE cpu_to_le32(0x01010104)
@@ -202,6 +201,24 @@
NDIS_80211_PRIV_8021X_WEP
};
+enum ndis_80211_status_type {
+ NDIS_80211_STATUSTYPE_AUTHENTICATION,
+ NDIS_80211_STATUSTYPE_MEDIASTREAMMODE,
+ NDIS_80211_STATUSTYPE_PMKID_CANDIDATELIST,
+ NDIS_80211_STATUSTYPE_RADIOSTATE,
+};
+
+enum ndis_80211_media_stream_mode {
+ NDIS_80211_MEDIA_STREAM_OFF,
+ NDIS_80211_MEDIA_STREAM_ON
+};
+
+enum ndis_80211_radio_status {
+ NDIS_80211_RADIO_STATUS_ON,
+ NDIS_80211_RADIO_STATUS_HARDWARE_OFF,
+ NDIS_80211_RADIO_STATUS_SOFTWARE_OFF,
+};
+
enum ndis_80211_addkey_bits {
NDIS_80211_ADDKEY_8021X_AUTH = cpu_to_le32(1 << 28),
NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ = cpu_to_le32(1 << 29),
@@ -214,6 +231,35 @@
NDIS_80211_ADDWEP_TRANSMIT_KEY = cpu_to_le32(1 << 31)
};
+struct ndis_80211_auth_request {
+ __le32 length;
+ u8 bssid[6];
+ u8 padding[2];
+ __le32 flags;
+} __attribute__((packed));
+
+struct ndis_80211_pmkid_candidate {
+ u8 bssid[6];
+ u8 padding[2];
+ __le32 flags;
+} __attribute__((packed));
+
+struct ndis_80211_pmkid_cand_list {
+ __le32 version;
+ __le32 num_candidates;
+ struct ndis_80211_pmkid_candidate candidate_list[0];
+} __attribute__((packed));
+
+struct ndis_80211_status_indication {
+ __le32 status_type;
+ union {
+ enum ndis_80211_media_stream_mode media_stream_mode;
+ enum ndis_80211_radio_status radio_status;
+ struct ndis_80211_auth_request auth_request[0];
+ struct ndis_80211_pmkid_cand_list cand_list;
+ } u;
+} __attribute__((packed));
+
struct ndis_80211_ssid {
__le32 length;
u8 essid[NDIS_802_11_LENGTH_SSID];
@@ -281,6 +327,7 @@
__le32 size;
__le32 index;
u8 bssid[6];
+ u8 padding[2];
} __attribute__((packed));
struct ndis_config_param {
@@ -366,6 +413,15 @@
{ .bitrate = 540 }
};
+struct rndis_wlan_encr_key {
+ int len;
+ int cipher;
+ u8 material[32];
+ u8 bssid[ETH_ALEN];
+ bool pairwise;
+ bool tx_key;
+};
+
/* RNDIS device private data */
struct rndis_wlan_private {
struct usbnet *usbdev;
@@ -409,9 +465,7 @@
/* encryption stuff */
int encr_tx_key_index;
- char encr_keys[4][32];
- int encr_key_len[4];
- char encr_key_wpa[4];
+ struct rndis_wlan_encr_key encr_keys[4];
int wpa_version;
int wpa_keymgmt;
int wpa_authalg;
@@ -478,6 +532,77 @@
}
+static bool is_wpa_key(struct rndis_wlan_private *priv, int idx)
+{
+ int cipher = priv->encr_keys[idx].cipher;
+
+ return (cipher == WLAN_CIPHER_SUITE_CCMP ||
+ cipher == WLAN_CIPHER_SUITE_TKIP);
+}
+
+
+#ifdef DEBUG
+static const char *oid_to_string(__le32 oid)
+{
+ switch (oid) {
+#define OID_STR(oid) case oid: return(#oid)
+ /* from rndis_host.h */
+ OID_STR(OID_802_3_PERMANENT_ADDRESS);
+ OID_STR(OID_GEN_MAXIMUM_FRAME_SIZE);
+ OID_STR(OID_GEN_CURRENT_PACKET_FILTER);
+ OID_STR(OID_GEN_PHYSICAL_MEDIUM);
+
+ /* from rndis_wlan.c */
+ OID_STR(OID_GEN_LINK_SPEED);
+ OID_STR(OID_GEN_RNDIS_CONFIG_PARAMETER);
+
+ OID_STR(OID_GEN_XMIT_OK);
+ OID_STR(OID_GEN_RCV_OK);
+ OID_STR(OID_GEN_XMIT_ERROR);
+ OID_STR(OID_GEN_RCV_ERROR);
+ OID_STR(OID_GEN_RCV_NO_BUFFER);
+
+ OID_STR(OID_802_3_CURRENT_ADDRESS);
+ OID_STR(OID_802_3_MULTICAST_LIST);
+ OID_STR(OID_802_3_MAXIMUM_LIST_SIZE);
+
+ OID_STR(OID_802_11_BSSID);
+ OID_STR(OID_802_11_SSID);
+ OID_STR(OID_802_11_INFRASTRUCTURE_MODE);
+ OID_STR(OID_802_11_ADD_WEP);
+ OID_STR(OID_802_11_REMOVE_WEP);
+ OID_STR(OID_802_11_DISASSOCIATE);
+ OID_STR(OID_802_11_AUTHENTICATION_MODE);
+ OID_STR(OID_802_11_PRIVACY_FILTER);
+ OID_STR(OID_802_11_BSSID_LIST_SCAN);
+ OID_STR(OID_802_11_ENCRYPTION_STATUS);
+ OID_STR(OID_802_11_ADD_KEY);
+ OID_STR(OID_802_11_REMOVE_KEY);
+ OID_STR(OID_802_11_ASSOCIATION_INFORMATION);
+ OID_STR(OID_802_11_PMKID);
+ OID_STR(OID_802_11_NETWORK_TYPES_SUPPORTED);
+ OID_STR(OID_802_11_NETWORK_TYPE_IN_USE);
+ OID_STR(OID_802_11_TX_POWER_LEVEL);
+ OID_STR(OID_802_11_RSSI);
+ OID_STR(OID_802_11_RSSI_TRIGGER);
+ OID_STR(OID_802_11_FRAGMENTATION_THRESHOLD);
+ OID_STR(OID_802_11_RTS_THRESHOLD);
+ OID_STR(OID_802_11_SUPPORTED_RATES);
+ OID_STR(OID_802_11_CONFIGURATION);
+ OID_STR(OID_802_11_BSSID_LIST);
+#undef OID_STR
+ }
+
+ return "?";
+}
+#else
+static const char *oid_to_string(__le32 oid)
+{
+ return "?";
+}
+#endif
+
+
/* translate error code */
static int rndis_error_status(__le32 rndis_status)
{
@@ -533,11 +658,21 @@
u.get->oid = oid;
ret = rndis_command(dev, u.header, buflen);
+ if (ret < 0)
+ devdbg(dev, "rndis_query_oid(%s): rndis_command() failed, %d "
+ "(%08x)", oid_to_string(oid), ret,
+ le32_to_cpu(u.get_c->status));
+
if (ret == 0) {
ret = le32_to_cpu(u.get_c->len);
*len = (*len > ret) ? ret : *len;
memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len);
ret = rndis_error_status(u.get_c->status);
+
+ if (ret < 0)
+ devdbg(dev, "rndis_query_oid(%s): device returned "
+ "error, 0x%08x (%d)", oid_to_string(oid),
+ le32_to_cpu(u.get_c->status), ret);
}
mutex_unlock(&priv->command_lock);
@@ -583,9 +718,20 @@
memcpy(u.buf + sizeof(*u.set), data, len);
ret = rndis_command(dev, u.header, buflen);
- if (ret == 0)
+ if (ret < 0)
+ devdbg(dev, "rndis_set_oid(%s): rndis_command() failed, %d "
+ "(%08x)", oid_to_string(oid), ret,
+ le32_to_cpu(u.set_c->status));
+
+ if (ret == 0) {
ret = rndis_error_status(u.set_c->status);
+ if (ret < 0)
+ devdbg(dev, "rndis_set_oid(%s): device returned error, "
+ "0x%08x (%d)", oid_to_string(oid),
+ le32_to_cpu(u.set_c->status), ret);
+ }
+
mutex_unlock(&priv->command_lock);
if (u.buf != priv->command_buffer)
@@ -594,6 +740,28 @@
}
+static int rndis_reset(struct usbnet *usbdev)
+{
+ struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ struct rndis_reset *reset;
+ int ret;
+
+ mutex_lock(&priv->command_lock);
+
+ reset = (void *)priv->command_buffer;
+ memset(reset, 0, sizeof(*reset));
+ reset->msg_type = RNDIS_MSG_RESET;
+ reset->msg_len = cpu_to_le32(sizeof(*reset));
+ ret = rndis_command(usbdev, (void *)reset, CONTROL_BUFFER_SIZE);
+
+ mutex_unlock(&priv->command_lock);
+
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+
/*
* Specs say that we can only set config parameters only soon after device
* initialization.
@@ -743,8 +911,7 @@
/*
* common functions
*/
-static int
-add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index);
+static void restore_keys(struct usbnet *usbdev);
static int get_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid)
{
@@ -963,7 +1130,7 @@
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
__le32 tmp;
- int ret, i;
+ int ret;
devdbg(usbdev, "set_infra_mode: infra_mode=0x%x", priv->infra_mode);
@@ -978,14 +1145,7 @@
/* NDIS drivers clear keys when infrastructure mode is
* changed. But Linux tools assume otherwise. So set the
* keys */
- if (priv->wpa_keymgmt == 0 ||
- priv->wpa_keymgmt == IW_AUTH_KEY_MGMT_802_1X) {
- for (i = 0; i < 4; i++) {
- if (priv->encr_key_len[i] > 0 && !priv->encr_key_wpa[i])
- add_wep_key(usbdev, priv->encr_keys[i],
- priv->encr_key_len[i], i);
- }
- }
+ restore_keys(usbdev);
priv->infra_mode = mode;
return 0;
@@ -1052,11 +1212,16 @@
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
struct ndis_80211_wep_key ndis_key;
- int ret;
+ int cipher, ret;
- if (key_len <= 0 || key_len > 32 || index < 0 || index >= 4)
+ if ((key_len != 5 || key_len != 13) || index < 0 || index > 3)
return -EINVAL;
+ if (key_len == 5)
+ cipher = WLAN_CIPHER_SUITE_WEP40;
+ else
+ cipher = WLAN_CIPHER_SUITE_WEP104;
+
memset(&ndis_key, 0, sizeof(ndis_key));
ndis_key.size = cpu_to_le32(sizeof(ndis_key));
@@ -1081,30 +1246,44 @@
return ret;
}
- priv->encr_key_len[index] = key_len;
- priv->encr_key_wpa[index] = 0;
- memcpy(&priv->encr_keys[index], key, key_len);
+ priv->encr_keys[index].len = key_len;
+ priv->encr_keys[index].cipher = cipher;
+ memcpy(&priv->encr_keys[index].material, key, key_len);
+ memset(&priv->encr_keys[index].bssid, 0xff, ETH_ALEN);
return 0;
}
static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
- int index, const struct sockaddr *addr,
- const u8 *rx_seq, int alg, int flags)
+ int index, const u8 *addr, const u8 *rx_seq, int cipher,
+ int flags)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
struct ndis_80211_key ndis_key;
+ bool is_addr_ok;
int ret;
- if (index < 0 || index >= 4)
+ if (index < 0 || index >= 4) {
+ devdbg(usbdev, "add_wpa_key: index out of range (%i)", index);
return -EINVAL;
- if (key_len > sizeof(ndis_key.material) || key_len < 0)
+ }
+ if (key_len > sizeof(ndis_key.material) || key_len < 0) {
+ devdbg(usbdev, "add_wpa_key: key length out of range (%i)",
+ key_len);
return -EINVAL;
- if ((flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) && !rx_seq)
+ }
+ if ((flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) && !rx_seq) {
+ devdbg(usbdev, "add_wpa_key: recv seq flag without buffer");
return -EINVAL;
- if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !addr)
+ }
+ is_addr_ok = addr && memcmp(addr, zero_bssid, ETH_ALEN) != 0 &&
+ memcmp(addr, ffff_bssid, ETH_ALEN) != 0;
+ if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !is_addr_ok) {
+ devdbg(usbdev, "add_wpa_key: pairwise but bssid invalid (%pM)",
+ addr);
return -EINVAL;
+ }
devdbg(usbdev, "add_wpa_key(%i): flags:%i%i%i", index,
!!(flags & NDIS_80211_ADDKEY_TRANSMIT_KEY),
@@ -1118,7 +1297,7 @@
ndis_key.length = cpu_to_le32(key_len);
ndis_key.index = cpu_to_le32(index) | flags;
- if (alg == IW_ENCODE_ALG_TKIP && key_len == 32) {
+ if (cipher == WLAN_CIPHER_SUITE_TKIP && key_len == 32) {
/* wpa_supplicant gives us the Michael MIC RX/TX keys in
* different order than NDIS spec, so swap the order here. */
memcpy(ndis_key.material, key, 16);
@@ -1132,7 +1311,7 @@
if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) {
/* pairwise key */
- memcpy(ndis_key.bssid, addr->sa_data, ETH_ALEN);
+ memcpy(ndis_key.bssid, addr, ETH_ALEN);
} else {
/* group key */
if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
@@ -1147,8 +1326,14 @@
if (ret != 0)
return ret;
- priv->encr_key_len[index] = key_len;
- priv->encr_key_wpa[index] = 1;
+ memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index]));
+ priv->encr_keys[index].len = key_len;
+ priv->encr_keys[index].cipher = cipher;
+ memcpy(&priv->encr_keys[index].material, key, key_len);
+ if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY)
+ memcpy(&priv->encr_keys[index].bssid, ndis_key.bssid, ETH_ALEN);
+ else
+ memset(&priv->encr_keys[index].bssid, 0xff, ETH_ALEN);
if (flags & NDIS_80211_ADDKEY_TRANSMIT_KEY)
priv->encr_tx_key_index = index;
@@ -1157,25 +1342,74 @@
}
+static int restore_key(struct usbnet *usbdev, int key_idx)
+{
+ struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ struct rndis_wlan_encr_key key;
+ int flags;
+
+ key = priv->encr_keys[key_idx];
+
+ devdbg(usbdev, "restore_key: %i:%s:%i", key_idx,
+ is_wpa_key(priv, key_idx) ? "wpa" : "wep",
+ key.len);
+
+ if (key.len == 0)
+ return 0;
+
+ if (is_wpa_key(priv, key_idx)) {
+ flags = 0;
+
+ /*if (priv->encr_tx_key_index == key_idx)
+ flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY;*/
+
+ if (memcmp(key.bssid, zero_bssid, ETH_ALEN) != 0 &&
+ memcmp(key.bssid, ffff_bssid, ETH_ALEN) != 0)
+ flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY;
+
+ return add_wpa_key(usbdev, key.material, key.len, key_idx,
+ key.bssid, NULL, key.cipher, flags);
+ }
+
+ return add_wep_key(usbdev, key.material, key.len, key_idx);
+}
+
+
+static void restore_keys(struct usbnet *usbdev)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ restore_key(usbdev, i);
+}
+
+
+static void clear_key(struct rndis_wlan_private *priv, int idx)
+{
+ memset(&priv->encr_keys[idx], 0, sizeof(priv->encr_keys[idx]));
+}
+
+
/* remove_key is for both wep and wpa */
static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN])
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
struct ndis_80211_remove_key remove_key;
__le32 keyindex;
+ bool is_wpa;
int ret;
- if (priv->encr_key_len[index] == 0)
+ if (priv->encr_keys[index].len == 0)
return 0;
- priv->encr_key_len[index] = 0;
- priv->encr_key_wpa[index] = 0;
- memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index]));
+ is_wpa = is_wpa_key(priv, index);
- if (priv->wpa_cipher_pair == IW_AUTH_CIPHER_TKIP ||
- priv->wpa_cipher_pair == IW_AUTH_CIPHER_CCMP ||
- priv->wpa_cipher_group == IW_AUTH_CIPHER_TKIP ||
- priv->wpa_cipher_group == IW_AUTH_CIPHER_CCMP) {
+ devdbg(usbdev, "remove_key: %i:%s:%i", index, is_wpa ? "wpa" : "wep",
+ priv->encr_keys[index].len);
+
+ clear_key(priv, index);
+
+ if (is_wpa) {
remove_key.size = cpu_to_le32(sizeof(remove_key));
remove_key.index = cpu_to_le32(index);
if (bssid) {
@@ -1484,6 +1718,9 @@
devdbg(usbdev, "get_scan_results");
+ if (!priv->scan_request)
+ return;
+
ret = rndis_check_bssid_list(usbdev);
cfg80211_scan_done(priv->scan_request, ret < 0);
@@ -1716,8 +1953,9 @@
{
struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ struct rndis_wlan_encr_key key;
int ret, index, key_len;
- u8 *key;
+ u8 *keybuf;
index = (wrqu->encoding.flags & IW_ENCODE_INDEX);
@@ -1752,17 +1990,18 @@
if (wrqu->data.length > 0) {
key_len = wrqu->data.length;
- key = extra;
+ keybuf = extra;
} else {
/* must be set as tx key */
- if (priv->encr_key_len[index] == 0)
+ if (priv->encr_keys[index].len == 0)
return -EINVAL;
- key_len = priv->encr_key_len[index];
key = priv->encr_keys[index];
+ key_len = key.len;
+ keybuf = key.material;
priv->encr_tx_key_index = index;
}
- if (add_wep_key(usbdev, key, key_len, index) != 0)
+ if (add_wep_key(usbdev, keybuf, key_len, index) != 0)
return -EINVAL;
if (index == priv->encr_tx_key_index)
@@ -1779,7 +2018,7 @@
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- int keyidx, flags;
+ int keyidx, flags, cipher;
keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX;
@@ -1789,8 +2028,10 @@
else
keyidx = priv->encr_tx_key_index;
- if (keyidx < 0 || keyidx >= 4)
+ if (keyidx < 0 || keyidx >= 4) {
+ devwarn(usbdev, "encryption index out of range (%u)", keyidx);
return -EINVAL;
+ }
if (ext->alg == WPA_ALG_WEP) {
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
@@ -1798,10 +2039,19 @@
return add_wep_key(usbdev, ext->key, ext->key_len, keyidx);
}
+ cipher = -1;
+ if (ext->alg == IW_ENCODE_ALG_TKIP)
+ cipher = WLAN_CIPHER_SUITE_TKIP;
+ else if (ext->alg == IW_ENCODE_ALG_CCMP)
+ cipher = WLAN_CIPHER_SUITE_CCMP;
+
if ((wrqu->encoding.flags & IW_ENCODE_DISABLED) ||
ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0)
return remove_key(usbdev, keyidx, NULL);
+ if (cipher == -1)
+ return -EOPNOTSUPP;
+
flags = 0;
if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
flags |= NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ;
@@ -1810,8 +2060,9 @@
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY;
- return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx, &ext->addr,
- ext->rx_seq, ext->alg, flags);
+ return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx,
+ (u8 *)&ext->addr.sa_data, ext->rx_seq, cipher,
+ flags);
}
@@ -2104,13 +2355,216 @@
queue_work(priv->workqueue, &priv->work);
}
-static void rndis_wlan_link_change(struct usbnet *usbdev, int state)
+
+static void rndis_wlan_auth_indication(struct usbnet *usbdev,
+ struct ndis_80211_status_indication *indication,
+ int len)
+{
+ u8 *buf;
+ const char *type;
+ int flags, buflen;
+ bool pairwise_error, group_error;
+ struct ndis_80211_auth_request *auth_req;
+
+ /* must have at least one array entry */
+ if (len < offsetof(struct ndis_80211_status_indication, u) +
+ sizeof(struct ndis_80211_auth_request)) {
+ devinfo(usbdev, "authentication indication: "
+ "too short message (%i)", len);
+ return;
+ }
+
+ buf = (void *)&indication->u.auth_request[0];
+ buflen = len - offsetof(struct ndis_80211_status_indication, u);
+
+ while (buflen >= sizeof(*auth_req)) {
+ auth_req = (void *)buf;
+ type = "unknown";
+ flags = le32_to_cpu(auth_req->flags);
+ pairwise_error = false;
+ group_error = false;
+
+ if (flags & 0x1)
+ type = "reauth request";
+ if (flags & 0x2)
+ type = "key update request";
+ if (flags & 0x6) {
+ pairwise_error = true;
+ type = "pairwise_error";
+ }
+ if (flags & 0xe) {
+ group_error = true;
+ type = "group_error";
+ }
+
+ devinfo(usbdev, "authentication indication: %s (0x%08x)", type,
+ le32_to_cpu(auth_req->flags));
+
+ if (pairwise_error || group_error) {
+ union iwreq_data wrqu;
+ struct iw_michaelmicfailure micfailure;
+
+ memset(&micfailure, 0, sizeof(micfailure));
+ if (pairwise_error)
+ micfailure.flags |= IW_MICFAILURE_PAIRWISE;
+ if (group_error)
+ micfailure.flags |= IW_MICFAILURE_GROUP;
+
+ memcpy(micfailure.src_addr.sa_data, auth_req->bssid,
+ ETH_ALEN);
+
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = sizeof(micfailure);
+ wireless_send_event(usbdev->net, IWEVMICHAELMICFAILURE,
+ &wrqu, (u8 *)&micfailure);
+ }
+
+ buflen -= le32_to_cpu(auth_req->length);
+ buf += le32_to_cpu(auth_req->length);
+ }
+}
+
+static void rndis_wlan_pmkid_cand_list_indication(struct usbnet *usbdev,
+ struct ndis_80211_status_indication *indication,
+ int len)
+{
+ struct ndis_80211_pmkid_cand_list *cand_list;
+ int list_len, expected_len, i;
+
+ if (len < offsetof(struct ndis_80211_status_indication, u) +
+ sizeof(struct ndis_80211_pmkid_cand_list)) {
+ devinfo(usbdev, "pmkid candidate list indication: "
+ "too short message (%i)", len);
+ return;
+ }
+
+ list_len = le32_to_cpu(indication->u.cand_list.num_candidates) *
+ sizeof(struct ndis_80211_pmkid_candidate);
+ expected_len = sizeof(struct ndis_80211_pmkid_cand_list) + list_len +
+ offsetof(struct ndis_80211_status_indication, u);
+
+ if (len < expected_len) {
+ devinfo(usbdev, "pmkid candidate list indication: "
+ "list larger than buffer (%i < %i)",
+ len, expected_len);
+ return;
+ }
+
+ cand_list = &indication->u.cand_list;
+
+ devinfo(usbdev, "pmkid candidate list indication: "
+ "version %i, candidates %i",
+ le32_to_cpu(cand_list->version),
+ le32_to_cpu(cand_list->num_candidates));
+
+ if (le32_to_cpu(cand_list->version) != 1)
+ return;
+
+ for (i = 0; i < le32_to_cpu(cand_list->num_candidates); i++) {
+ struct iw_pmkid_cand pcand;
+ union iwreq_data wrqu;
+ struct ndis_80211_pmkid_candidate *cand =
+ &cand_list->candidate_list[i];
+
+ devdbg(usbdev, "cand[%i]: flags: 0x%08x, bssid: %pM",
+ i, le32_to_cpu(cand->flags), cand->bssid);
+
+ memset(&pcand, 0, sizeof(pcand));
+ if (le32_to_cpu(cand->flags) & 0x01)
+ pcand.flags |= IW_PMKID_CAND_PREAUTH;
+ pcand.index = i;
+ memcpy(pcand.bssid.sa_data, cand->bssid, ETH_ALEN);
+
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = sizeof(pcand);
+ wireless_send_event(usbdev->net, IWEVPMKIDCAND, &wrqu,
+ (u8 *)&pcand);
+ }
+}
+
+static void rndis_wlan_media_specific_indication(struct usbnet *usbdev,
+ struct rndis_indicate *msg, int buflen)
+{
+ struct ndis_80211_status_indication *indication;
+ int len, offset;
+
+ offset = offsetof(struct rndis_indicate, status) +
+ le32_to_cpu(msg->offset);
+ len = le32_to_cpu(msg->length);
+
+ if (len < 8) {
+ devinfo(usbdev, "media specific indication, "
+ "ignore too short message (%i < 8)", len);
+ return;
+ }
+
+ if (offset + len > buflen) {
+ devinfo(usbdev, "media specific indication, "
+ "too large to fit to buffer (%i > %i)",
+ offset + len, buflen);
+ return;
+ }
+
+ indication = (void *)((u8 *)msg + offset);
+
+ switch (le32_to_cpu(indication->status_type)) {
+ case NDIS_80211_STATUSTYPE_RADIOSTATE:
+ devinfo(usbdev, "radio state indication: %i",
+ le32_to_cpu(indication->u.radio_status));
+ return;
+
+ case NDIS_80211_STATUSTYPE_MEDIASTREAMMODE:
+ devinfo(usbdev, "media stream mode indication: %i",
+ le32_to_cpu(indication->u.media_stream_mode));
+ return;
+
+ case NDIS_80211_STATUSTYPE_AUTHENTICATION:
+ rndis_wlan_auth_indication(usbdev, indication, len);
+ return;
+
+ case NDIS_80211_STATUSTYPE_PMKID_CANDIDATELIST:
+ rndis_wlan_pmkid_cand_list_indication(usbdev, indication, len);
+ return;
+
+ default:
+ devinfo(usbdev, "media specific indication: "
+ "unknown status type 0x%08x",
+ le32_to_cpu(indication->status_type));
+ }
+}
+
+
+static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ struct rndis_indicate *msg = ind;
- /* queue work to avoid recursive calls into rndis_command */
- set_bit(state ? WORK_LINK_UP : WORK_LINK_DOWN, &priv->work_pending);
- queue_work(priv->workqueue, &priv->work);
+ switch (msg->status) {
+ case RNDIS_STATUS_MEDIA_CONNECT:
+ devinfo(usbdev, "media connect");
+
+ /* queue work to avoid recursive calls into rndis_command */
+ set_bit(WORK_LINK_UP, &priv->work_pending);
+ queue_work(priv->workqueue, &priv->work);
+ break;
+
+ case RNDIS_STATUS_MEDIA_DISCONNECT:
+ devinfo(usbdev, "media disconnect");
+
+ /* queue work to avoid recursive calls into rndis_command */
+ set_bit(WORK_LINK_DOWN, &priv->work_pending);
+ queue_work(priv->workqueue, &priv->work);
+ break;
+
+ case RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION:
+ rndis_wlan_media_specific_indication(usbdev, msg, buflen);
+ break;
+
+ default:
+ devinfo(usbdev, "indication: 0x%08x",
+ le32_to_cpu(msg->status));
+ break;
+ }
}
@@ -2457,9 +2911,6 @@
disassociate(usbdev, 1);
netif_carrier_off(usbdev->net);
- queue_delayed_work(priv->workqueue, &priv->stats_work,
- round_jiffies_relative(STATS_UPDATE_JIFFIES));
-
return 0;
fail:
@@ -2499,21 +2950,61 @@
static int rndis_wlan_reset(struct usbnet *usbdev)
{
+ struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ int retval;
+
devdbg(usbdev, "rndis_wlan_reset");
+
+ retval = rndis_reset(usbdev);
+ if (retval)
+ devwarn(usbdev, "rndis_reset() failed: %d", retval);
+
+ /* rndis_reset cleared multicast list, so restore here.
+ (set_multicast_list() also turns on current packet filter) */
+ set_multicast_list(usbdev);
+
+ queue_delayed_work(priv->workqueue, &priv->stats_work,
+ round_jiffies_relative(STATS_UPDATE_JIFFIES));
+
return deauthenticate(usbdev);
}
static int rndis_wlan_stop(struct usbnet *usbdev)
{
+ struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+ int retval;
+ __le32 filter;
+
devdbg(usbdev, "rndis_wlan_stop");
- return disassociate(usbdev, 0);
+
+ retval = disassociate(usbdev, 0);
+
+ priv->work_pending = 0;
+ cancel_delayed_work_sync(&priv->stats_work);
+ cancel_delayed_work_sync(&priv->scan_work);
+ cancel_work_sync(&priv->work);
+ flush_workqueue(priv->workqueue);
+
+ if (priv->scan_request) {
+ cfg80211_scan_done(priv->scan_request, true);
+ priv->scan_request = NULL;
+ }
+
+ /* Set current packet filter zero to block receiving data packets from
+ device. */
+ filter = 0;
+ rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &filter,
+ sizeof(filter));
+
+ return retval;
}
static const struct driver_info bcm4320b_info = {
.description = "Wireless RNDIS device, BCM4320b based",
- .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
+ .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT |
+ FLAG_AVOID_UNLINK_URBS,
.bind = rndis_wlan_bind,
.unbind = rndis_wlan_unbind,
.status = rndis_status,
@@ -2522,12 +3013,13 @@
.reset = rndis_wlan_reset,
.stop = rndis_wlan_stop,
.early_init = bcm4320b_early_init,
- .link_change = rndis_wlan_link_change,
+ .indication = rndis_wlan_indication,
};
static const struct driver_info bcm4320a_info = {
.description = "Wireless RNDIS device, BCM4320a based",
- .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
+ .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT |
+ FLAG_AVOID_UNLINK_URBS,
.bind = rndis_wlan_bind,
.unbind = rndis_wlan_unbind,
.status = rndis_status,
@@ -2536,12 +3028,13 @@
.reset = rndis_wlan_reset,
.stop = rndis_wlan_stop,
.early_init = bcm4320a_early_init,
- .link_change = rndis_wlan_link_change,
+ .indication = rndis_wlan_indication,
};
static const struct driver_info rndis_wlan_info = {
.description = "Wireless RNDIS device",
- .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
+ .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT |
+ FLAG_AVOID_UNLINK_URBS,
.bind = rndis_wlan_bind,
.unbind = rndis_wlan_unbind,
.status = rndis_status,
@@ -2550,7 +3043,7 @@
.reset = rndis_wlan_reset,
.stop = rndis_wlan_stop,
.early_init = bcm4320a_early_init,
- .link_change = rndis_wlan_link_change,
+ .indication = rndis_wlan_indication,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index f970aa2..ed1f997 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -1,8 +1,8 @@
menuconfig RT2X00
tristate "Ralink driver support"
- depends on MAC80211 && WLAN_80211 && EXPERIMENTAL
+ depends on MAC80211 && WLAN_80211
---help---
- This will enable the experimental support for the Ralink drivers,
+ This will enable the support for the Ralink drivers,
developed in the rt2x00 project <http://rt2x00.serialmonkey.com>.
These drivers make use of the mac80211 stack.
@@ -79,14 +79,14 @@
config RT2800USB
tristate "Ralink rt2800 (USB) support"
- depends on USB
+ depends on USB && EXPERIMENTAL
select RT2X00_LIB_USB
select RT2X00_LIB_HT
select RT2X00_LIB_FIRMWARE
select RT2X00_LIB_CRYPTO
select CRC_CCITT
---help---
- This adds support for rt2800 wireless chipset family.
+ This adds experimental support for rt2800 wireless chipset family.
Supported chips: RT2770, RT2870 & RT3070.
When compiled as a module, this driver will be called "rt2800usb.ko".
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 658a63b..db54fcc 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -215,7 +215,7 @@
rt2x00lib_beacondone_iter,
rt2x00dev);
- queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work);
+ ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work);
}
EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
@@ -893,6 +893,12 @@
rt2x00lib_disable_radio(rt2x00dev);
/*
+ * Stop all work.
+ */
+ cancel_work_sync(&rt2x00dev->filter_work);
+ cancel_work_sync(&rt2x00dev->intf_work);
+
+ /*
* Uninitialize device.
*/
rt2x00lib_uninitialize(rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c
index 7991568..9178316 100644
--- a/drivers/net/wireless/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/rt2x00/rt2x00link.c
@@ -351,8 +351,8 @@
rt2x00link_reset_tuner(rt2x00dev, false);
- queue_delayed_work(rt2x00dev->hw->workqueue,
- &link->work, LINK_TUNE_INTERVAL);
+ ieee80211_queue_delayed_work(rt2x00dev->hw,
+ &link->work, LINK_TUNE_INTERVAL);
}
void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev)
@@ -461,8 +461,8 @@
* Increase tuner counter, and reschedule the next link tuner run.
*/
link->count++;
- queue_delayed_work(rt2x00dev->hw->workqueue,
- &link->work, LINK_TUNE_INTERVAL);
+ ieee80211_queue_delayed_work(rt2x00dev->hw,
+ &link->work, LINK_TUNE_INTERVAL);
}
void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 7de1a2c..81febdf 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -431,10 +431,20 @@
if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags);
else
- queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work);
+ ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->filter_work);
}
EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter);
+int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+ bool set)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ rt2x00lib_beacondone(rt2x00dev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_set_tim);
+
#ifdef CONFIG_RT2X00_LIB_CRYPTO
static void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len)
{
@@ -454,16 +464,6 @@
sizeof(crypto->rx_mic));
}
-int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
- bool set)
-{
- struct rt2x00_dev *rt2x00dev = hw->priv;
-
- rt2x00lib_beacondone(rt2x00dev);
- return 0;
-}
-EXPORT_SYMBOL_GPL(rt2x00mac_set_tim);
-
int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index fb95b8c..e20dd74 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -2601,6 +2601,11 @@
int retval;
/*
+ * Disable power saving.
+ */
+ rt2x00pci_register_write(rt2x00dev, SOFT_RESET_CSR, 0x00000007);
+
+ /*
* Allocate eeprom data.
*/
retval = rt61pci_validate_eeprom(rt2x00dev);
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
index c9b9dbe..53f57dc 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -220,7 +220,7 @@
* reading a register in the device. We are in interrupt mode
* here, thus queue the skb and finish on a work queue. */
skb_queue_tail(&priv->b_tx_status.queue, skb);
- queue_delayed_work(hw->workqueue, &priv->work, 0);
+ ieee80211_queue_delayed_work(hw, &priv->work, 0);
}
}
diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.c b/drivers/net/wireless/rtl818x/rtl8187_leds.c
index cf9f899..a6cfb7e 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_leds.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_leds.c
@@ -108,11 +108,11 @@
struct rtl8187_priv *priv = hw->priv;
if (brightness == LED_OFF) {
- queue_delayed_work(hw->workqueue, &priv->led_off, 0);
+ ieee80211_queue_delayed_work(hw, &priv->led_off, 0);
/* The LED is off for 1/20 sec so that it just blinks. */
- queue_delayed_work(hw->workqueue, &priv->led_on, HZ / 20);
+ ieee80211_queue_delayed_work(hw, &priv->led_on, HZ / 20);
} else
- queue_delayed_work(hw->workqueue, &priv->led_on, 0);
+ ieee80211_queue_delayed_work(hw, &priv->led_on, 0);
}
static int rtl8187_register_led(struct ieee80211_hw *dev,
@@ -193,7 +193,7 @@
err = rtl8187_register_led(dev, &priv->led_rx, name,
ieee80211_get_rx_led_name(dev), ledpin);
if (!err) {
- queue_delayed_work(dev->workqueue, &priv->led_on, 0);
+ ieee80211_queue_delayed_work(dev, &priv->led_on, 0);
return;
}
/* registration of RX LED failed - unregister TX */
@@ -209,7 +209,7 @@
struct rtl8187_priv *priv = dev->priv;
/* turn the LED off before exiting */
- queue_delayed_work(dev->workqueue, &priv->led_off, 0);
+ ieee80211_queue_delayed_work(dev, &priv->led_off, 0);
cancel_delayed_work_sync(&priv->led_off);
cancel_delayed_work_sync(&priv->led_on);
rtl8187_unregister_led(&priv->led_rx);
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index 73300c2..ef2cb20 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -1550,9 +1550,12 @@
if (time_after(jiffies, strip_info->pps_timer + HZ)) {
unsigned long t = jiffies - strip_info->pps_timer;
- unsigned long rx_pps_count = (strip_info->rx_pps_count * HZ * 8 + t / 2) / t;
- unsigned long tx_pps_count = (strip_info->tx_pps_count * HZ * 8 + t / 2) / t;
- unsigned long sx_pps_count = (strip_info->sx_pps_count * HZ * 8 + t / 2) / t;
+ unsigned long rx_pps_count =
+ DIV_ROUND_CLOSEST(strip_info->rx_pps_count*HZ*8, t);
+ unsigned long tx_pps_count =
+ DIV_ROUND_CLOSEST(strip_info->tx_pps_count*HZ*8, t);
+ unsigned long sx_pps_count =
+ DIV_ROUND_CLOSEST(strip_info->sx_pps_count*HZ*8, t);
strip_info->pps_timer = jiffies;
strip_info->rx_pps_count = 0;
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 9600b72..54abdd0c 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -698,7 +698,7 @@
&& !mac->pass_ctrl)
return 0;
- fc = *(__le16 *)buffer;
+ fc = get_unaligned((__le16*)buffer);
need_padding = ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc);
skb = dev_alloc_skb(length + (need_padding ? 2 : 0));
diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
index 1020290..21ca51b 100644
--- a/include/linux/rfkill.h
+++ b/include/linux/rfkill.h
@@ -47,6 +47,7 @@
RFKILL_TYPE_UWB,
RFKILL_TYPE_WIMAX,
RFKILL_TYPE_WWAN,
+ RFKILL_TYPE_GPS,
NUM_RFKILL_TYPES,
};
diff --git a/include/linux/usb/rndis_host.h b/include/linux/usb/rndis_host.h
index 37836b9..1ef1ebc 100644
--- a/include/linux/usb/rndis_host.h
+++ b/include/linux/usb/rndis_host.h
@@ -70,12 +70,13 @@
#define RNDIS_MSG_KEEPALIVE_C (RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION)
/* codes for "status" field of completion messages */
-#define RNDIS_STATUS_SUCCESS cpu_to_le32(0x00000000)
-#define RNDIS_STATUS_FAILURE cpu_to_le32(0xc0000001)
-#define RNDIS_STATUS_INVALID_DATA cpu_to_le32(0xc0010015)
-#define RNDIS_STATUS_NOT_SUPPORTED cpu_to_le32(0xc00000bb)
-#define RNDIS_STATUS_MEDIA_CONNECT cpu_to_le32(0x4001000b)
-#define RNDIS_STATUS_MEDIA_DISCONNECT cpu_to_le32(0x4001000c)
+#define RNDIS_STATUS_SUCCESS cpu_to_le32(0x00000000)
+#define RNDIS_STATUS_FAILURE cpu_to_le32(0xc0000001)
+#define RNDIS_STATUS_INVALID_DATA cpu_to_le32(0xc0010015)
+#define RNDIS_STATUS_NOT_SUPPORTED cpu_to_le32(0xc00000bb)
+#define RNDIS_STATUS_MEDIA_CONNECT cpu_to_le32(0x4001000b)
+#define RNDIS_STATUS_MEDIA_DISCONNECT cpu_to_le32(0x4001000c)
+#define RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION cpu_to_le32(0x40010012)
/* codes for OID_GEN_PHYSICAL_MEDIUM */
#define RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED cpu_to_le32(0x00000000)
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index 7c17b2e..de8b4b1 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -86,6 +86,7 @@
#define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */
#define FLAG_WLAN 0x0080 /* use "wlan%d" names */
+#define FLAG_AVOID_UNLINK_URBS 0x0100 /* don't unlink urbs at usbnet_stop() */
/* init device ... can sleep, or cause probe() failure */
@@ -121,9 +122,8 @@
* right after minidriver have initialized hardware. */
int (*early_init)(struct usbnet *dev);
- /* called by minidriver when link state changes, state: 0=disconnect,
- * 1=connect */
- void (*link_change)(struct usbnet *dev, int state);
+ /* called by minidriver when receiving indication */
+ void (*indication)(struct usbnet *dev, void *ind, int indlen);
/* for new devices, use the descriptor-reading code instead */
int in; /* rx endpoint */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index e1b9235..fa72997 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1514,20 +1514,6 @@
extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
/**
- * regulatory_hint_11d - hints a country IE as a regulatory domain
- * @wiphy: the wireless device giving the hint (used only for reporting
- * conflicts)
- * @country_ie: pointer to the country IE
- * @country_ie_len: length of the country IE
- *
- * We will intersect the rd with the what CRDA tells us should apply
- * for the alpha2 this country IE belongs to, this prevents APs from
- * sending us incorrect or outdated information against a country.
- */
-extern void regulatory_hint_11d(struct wiphy *wiphy,
- u8 *country_ie,
- u8 country_ie_len);
-/**
* wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
* @wiphy: the wireless device we want to process the regulatory domain on
* @regd: the custom regulatory domain to use for this wiphy
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index d4e09a0..e2fb576 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -73,6 +73,21 @@
*/
/**
+ * DOC: mac80211 workqueue
+ *
+ * mac80211 provides its own workqueue for drivers and internal mac80211 use.
+ * The workqueue is a single threaded workqueue and can only be accessed by
+ * helpers for sanity checking. Drivers must ensure all work added onto the
+ * mac80211 workqueue should be cancelled on the driver stop() callback.
+ *
+ * mac80211 will flushed the workqueue upon interface removal and during
+ * suspend.
+ *
+ * All work performed on the mac80211 workqueue must not acquire the RTNL lock.
+ *
+ */
+
+/**
* enum ieee80211_max_queues - maximum number of queues
*
* @IEEE80211_MAX_QUEUES: Maximum number of regular device queues.
@@ -913,12 +928,6 @@
*
* @conf: &struct ieee80211_conf, device configuration, don't use.
*
- * @workqueue: single threaded workqueue available for driver use,
- * allocated by mac80211 on registration and flushed when an
- * interface is removed.
- * NOTICE: All work performed on this workqueue must not
- * acquire the RTNL lock.
- *
* @priv: pointer to private area that was allocated for driver use
* along with this structure.
*
@@ -954,7 +963,6 @@
struct ieee80211_hw {
struct ieee80211_conf conf;
struct wiphy *wiphy;
- struct workqueue_struct *workqueue;
const char *rate_control_algorithm;
void *priv;
u32 flags;
@@ -1236,10 +1244,13 @@
* mac80211 needs to do and the amount of CPU wakeups, so you should
* honour this flag if possible.
*
- * @FIF_CONTROL: pass control frames, if PROMISC_IN_BSS is not set then
- * only those addressed to this station
+ * @FIF_CONTROL: pass control frames (except for PS Poll), if PROMISC_IN_BSS
+ * is not set then only those addressed to this station.
*
* @FIF_OTHER_BSS: pass frames destined to other BSSes
+ *
+ * @FIF_PSPOLL: pass PS Poll frames, if PROMISC_IN_BSS is not set then only
+ * those addressed to this station.
*/
enum ieee80211_filter_flags {
FIF_PROMISC_IN_BSS = 1<<0,
@@ -1249,6 +1260,7 @@
FIF_BCN_PRBRESP_PROMISC = 1<<4,
FIF_CONTROL = 1<<5,
FIF_OTHER_BSS = 1<<6,
+ FIF_PSPOLL = 1<<7,
};
/**
@@ -1301,7 +1313,8 @@
* is disabled. This should turn off the hardware (at least
* it must turn off frame reception.)
* May be called right after add_interface if that rejects
- * an interface.
+ * an interface. If you added any work onto the mac80211 workqueue
+ * you should ensure to cancel it on this callback.
* Must be implemented.
*
* @add_interface: Called when a netdevice attached to the hardware is
@@ -1928,6 +1941,31 @@
void *data);
/**
+ * ieee80211_queue_work - add work onto the mac80211 workqueue
+ *
+ * Drivers and mac80211 use this to add work onto the mac80211 workqueue.
+ * This helper ensures drivers are not queueing work when they should not be.
+ *
+ * @hw: the hardware struct for the interface we are adding work for
+ * @work: the work we want to add onto the mac80211 workqueue
+ */
+void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work);
+
+/**
+ * ieee80211_queue_delayed_work - add work onto the mac80211 workqueue
+ *
+ * Drivers and mac80211 use this to queue delayed work onto the mac80211
+ * workqueue.
+ *
+ * @hw: the hardware struct for the interface we are adding work for
+ * @dwork: delayable work to queue onto the mac80211 workqueue
+ * @delay: number of jiffies to wait before queueing
+ */
+void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
+ struct delayed_work *dwork,
+ unsigned long delay);
+
+/**
* ieee80211_start_tx_ba_session - Start a tx Block Ack session.
* @hw: pointer as obtained from ieee80211_alloc_hw().
* @ra: receiver address of the BA session recipient
diff --git a/net/mac80211/driver-trace.c b/net/mac80211/driver-trace.c
index 6da6f79..8ed8711 100644
--- a/net/mac80211/driver-trace.c
+++ b/net/mac80211/driver-trace.c
@@ -1,6 +1,9 @@
/* bug in tracepoint.h, it should include this */
#include <linux/module.h>
+/* sparse isn't too happy with all macros... */
+#ifndef __CHECKER__
#include "driver-ops.h"
#define CREATE_TRACE_POINTS
#include "driver-trace.h"
+#endif
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 6e3cca6..920ec87 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -781,7 +781,7 @@
}
set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request);
- queue_work(local->hw.workqueue, &ifibss->work);
+ ieee80211_queue_work(&local->hw, &ifibss->work);
}
#ifdef CONFIG_PM
@@ -853,7 +853,7 @@
case IEEE80211_STYPE_PROBE_REQ:
case IEEE80211_STYPE_AUTH:
skb_queue_tail(&sdata->u.ibss.skb_queue, skb);
- queue_work(local->hw.workqueue, &sdata->u.ibss.work);
+ ieee80211_queue_work(&local->hw, &sdata->u.ibss.work);
return RX_QUEUED;
}
@@ -912,7 +912,7 @@
ieee80211_recalc_idle(sdata->local);
set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request);
- queue_work(sdata->local->hw.workqueue, &sdata->u.ibss.work);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->u.ibss.work);
return 0;
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index aec6853..630a438 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -280,6 +280,7 @@
struct work_struct beacon_loss_work;
unsigned long probe_timeout;
+ int probe_send_count;
struct mutex mtx;
struct ieee80211_bss *associated;
@@ -614,6 +615,12 @@
const struct ieee80211_ops *ops;
+ /*
+ * private workqueue to mac80211. mac80211 makes this accessible
+ * via ieee80211_queue_work()
+ */
+ struct workqueue_struct *workqueue;
+
unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES];
/* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */
spinlock_t queue_stop_reason_lock;
@@ -621,7 +628,7 @@
int open_count;
int monitors, cooked_mntrs;
/* number of interfaces with corresponding FIF_ flags */
- int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss;
+ int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll;
unsigned int filter_flags; /* FIF_* */
struct iw_statistics wstats;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 6c655b6..e8fb03b 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -220,8 +220,10 @@
local->fif_fcsfail++;
if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
local->fif_plcpfail++;
- if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL)
+ if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) {
local->fif_control++;
+ local->fif_pspoll++;
+ }
if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
local->fif_other_bss++;
@@ -244,7 +246,14 @@
spin_unlock_bh(&local->filter_lock);
ieee80211_start_mesh(sdata);
+ } else if (sdata->vif.type == NL80211_IFTYPE_AP) {
+ local->fif_pspoll++;
+
+ spin_lock_bh(&local->filter_lock);
+ ieee80211_configure_filter(local);
+ spin_unlock_bh(&local->filter_lock);
}
+
changed |= ieee80211_reset_erp_info(sdata);
ieee80211_bss_info_change_notify(sdata, changed);
ieee80211_enable_keys(sdata);
@@ -312,7 +321,7 @@
* to fix this.
*/
if (sdata->vif.type == NL80211_IFTYPE_STATION)
- queue_work(local->hw.workqueue, &sdata->u.mgd.work);
+ ieee80211_queue_work(&local->hw, &sdata->u.mgd.work);
netif_tx_start_all_queues(dev);
@@ -388,6 +397,9 @@
if (sdata->flags & IEEE80211_SDATA_PROMISC)
atomic_dec(&local->iff_promiscs);
+ if (sdata->vif.type == NL80211_IFTYPE_AP)
+ local->fif_pspoll--;
+
netif_addr_lock_bh(dev);
spin_lock_bh(&local->filter_lock);
__dev_addr_unsync(&local->mc_list, &local->mc_count,
@@ -401,7 +413,7 @@
/* APs need special treatment */
if (sdata->vif.type == NL80211_IFTYPE_AP) {
- struct ieee80211_sub_if_data *vlan, *tmp;
+ struct ieee80211_sub_if_data *vlan, *tmpsdata;
struct beacon_data *old_beacon = sdata->u.ap.beacon;
/* remove beacon */
@@ -410,7 +422,7 @@
kfree(old_beacon);
/* down all dependent devices, that is VLANs */
- list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans,
+ list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
u.vlan.list)
dev_close(vlan->dev);
WARN_ON(!list_empty(&sdata->u.ap.vlans));
@@ -439,8 +451,10 @@
local->fif_fcsfail--;
if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
local->fif_plcpfail--;
- if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL)
+ if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) {
+ local->fif_pspoll--;
local->fif_control--;
+ }
if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
local->fif_other_bss--;
@@ -522,6 +536,16 @@
ieee80211_scan_completed(&local->hw, true);
}
+ /*
+ * Disable beaconing for AP and mesh, IBSS can't
+ * still be joined to a network at this point.
+ */
+ if (sdata->vif.type == NL80211_IFTYPE_AP ||
+ sdata->vif.type == NL80211_IFTYPE_MESH_POINT) {
+ ieee80211_bss_info_change_notify(sdata,
+ BSS_CHANGED_BEACON_ENABLED);
+ }
+
conf.vif = &sdata->vif;
conf.type = sdata->vif.type;
conf.mac_addr = dev->dev_addr;
@@ -541,7 +565,7 @@
ieee80211_led_radio(local, false);
- flush_workqueue(local->hw.workqueue);
+ flush_workqueue(local->workqueue);
tasklet_disable(&local->tx_pending_tasklet);
tasklet_disable(&local->tasklet);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index c1a7991..0c4f8e1 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -77,6 +77,9 @@
if (local->fif_other_bss)
new_flags |= FIF_OTHER_BSS;
+ if (local->fif_pspoll)
+ new_flags |= FIF_PSPOLL;
+
changed_flags = local->filter_flags ^ new_flags;
/* be a bit nasty */
@@ -198,7 +201,8 @@
}
if (changed & BSS_CHANGED_BEACON_ENABLED) {
- if (test_bit(SCAN_SW_SCANNING, &local->scanning)) {
+ if (local->quiescing || !netif_running(sdata->dev) ||
+ test_bit(SCAN_SW_SCANNING, &local->scanning)) {
sdata->vif.bss_conf.enable_beacon = false;
} else {
/*
@@ -310,6 +314,31 @@
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ /*
+ * XXX: This is temporary!
+ *
+ * The problem here is that when we get here, the driver will
+ * quite likely have pretty much overwritten info->control by
+ * using info->driver_data or info->rate_driver_data. Thus,
+ * when passing out the frame to the driver again, we would be
+ * passing completely bogus data since the driver would then
+ * expect a properly filled info->control. In mac80211 itself
+ * the same problem occurs, since we need info->control.vif
+ * internally.
+ *
+ * To fix this, we should send the frame through TX processing
+ * again. However, it's not that simple, since the frame will
+ * have been software-encrypted (if applicable) already, and
+ * encrypting it again doesn't do much good. So to properly do
+ * that, we not only have to skip the actual 'raw' encryption
+ * (key selection etc. still has to be done!) but also the
+ * sequence number assignment since that impacts the crypto
+ * encapsulation, of course.
+ *
+ * Hence, for now, fix the bug by just dropping the frame.
+ */
+ goto drop;
+
sta->tx_filtered_count++;
/*
@@ -363,6 +392,7 @@
return;
}
+ drop:
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "%s: dropped TX filtered frame, "
@@ -794,9 +824,9 @@
if (hw->queues > IEEE80211_MAX_QUEUES)
hw->queues = IEEE80211_MAX_QUEUES;
- local->hw.workqueue =
+ local->workqueue =
create_singlethread_workqueue(wiphy_name(local->hw.wiphy));
- if (!local->hw.workqueue) {
+ if (!local->workqueue) {
result = -ENOMEM;
goto fail_workqueue;
}
@@ -886,7 +916,7 @@
sta_info_stop(local);
fail_sta_info:
debugfs_hw_del(local);
- destroy_workqueue(local->hw.workqueue);
+ destroy_workqueue(local->workqueue);
fail_workqueue:
wiphy_unregister(local->hw.wiphy);
fail_wiphy_register:
@@ -928,7 +958,7 @@
skb_queue_purge(&local->skb_queue);
skb_queue_purge(&local->skb_queue_unreliable);
- destroy_workqueue(local->hw.workqueue);
+ destroy_workqueue(local->workqueue);
wiphy_unregister(local->hw.wiphy);
ieee80211_wep_free(local);
ieee80211_led_exit(local);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 9a38269..2f4f518 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -54,7 +54,7 @@
return;
}
- queue_work(local->hw.workqueue, &ifmsh->work);
+ ieee80211_queue_work(local->hw.workqueue, &ifmsh->work);
}
/**
@@ -357,7 +357,7 @@
return;
}
- queue_work(local->hw.workqueue, &ifmsh->work);
+ ieee80211_queue_work(local->hw.workqueue, &ifmsh->work);
}
struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
@@ -471,7 +471,7 @@
struct ieee80211_local *local = sdata->local;
ifmsh->housekeeping = true;
- queue_work(local->hw.workqueue, &ifmsh->work);
+ ieee80211_queue_work(local->hw.workqueue, &ifmsh->work);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
BSS_CHANGED_BEACON_ENABLED);
}
@@ -619,7 +619,7 @@
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list)
if (ieee80211_vif_is_mesh(&sdata->vif))
- queue_work(local->hw.workqueue, &sdata->u.mesh.work);
+ ieee80211_queue_work(local->hw.workqueue, &sdata->u.mesh.work);
rcu_read_unlock();
}
@@ -692,7 +692,7 @@
case IEEE80211_STYPE_PROBE_RESP:
case IEEE80211_STYPE_BEACON:
skb_queue_tail(&ifmsh->skb_queue, skb);
- queue_work(local->hw.workqueue, &ifmsh->work);
+ ieee80211_queue_work(local->hw.workqueue, &ifmsh->work);
return RX_QUEUED;
}
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index e93c37e..11ab71a 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -660,14 +660,14 @@
spin_unlock(&ifmsh->mesh_preq_queue_lock);
if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata)))
- queue_work(sdata->local->hw.workqueue, &ifmsh->work);
+ ieee80211_queue_work(sdata->local->hw.workqueue, &ifmsh->work);
else if (time_before(jiffies, ifmsh->last_preq)) {
/* avoid long wait if did not send preqs for a long time
* and jiffies wrapped around
*/
ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1;
- queue_work(sdata->local->hw.workqueue, &ifmsh->work);
+ ieee80211_queue_work(sdata->local->hw.workqueue, &ifmsh->work);
} else
mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq +
min_preq_int_jiff(sdata));
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index ee83125..6d5a1ee 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -31,6 +31,7 @@
#define IEEE80211_AUTH_MAX_TRIES 3
#define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
#define IEEE80211_ASSOC_MAX_TRIES 3
+#define IEEE80211_MAX_PROBE_TRIES 5
/*
* beacon loss detection timeout
@@ -41,13 +42,13 @@
* Time the connection can be idle before we probe
* it to see if we can still talk to the AP.
*/
-#define IEEE80211_CONNECTION_IDLE_TIME (2 * HZ)
+#define IEEE80211_CONNECTION_IDLE_TIME (30 * HZ)
/*
* Time we wait for a probe response after sending
* a probe request because of beacon loss or for
* checking the connection still works.
*/
-#define IEEE80211_PROBE_WAIT (HZ / 5)
+#define IEEE80211_PROBE_WAIT (HZ / 2)
#define TMR_RUNNING_TIMER 0
#define TMR_RUNNING_CHANSW 1
@@ -565,7 +566,7 @@
return;
}
- queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work);
+ ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
}
void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
@@ -597,7 +598,7 @@
sdata->local->csa_channel = new_ch;
if (sw_elem->count <= 1) {
- queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work);
+ ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
} else {
ieee80211_stop_queues_by_reason(&sdata->local->hw,
IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -763,7 +764,7 @@
if (local->quiescing || local->suspended)
return;
- queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work);
+ ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work);
}
/* MLME */
@@ -916,12 +917,9 @@
ieee80211_bss_info_change_notify(sdata, bss_info_changed);
- /* will be same as sdata */
- if (local->ps_sdata) {
- mutex_lock(&local->iflist_mtx);
- ieee80211_recalc_ps(local, -1);
- mutex_unlock(&local->iflist_mtx);
- }
+ mutex_lock(&local->iflist_mtx);
+ ieee80211_recalc_ps(local, -1);
+ mutex_unlock(&local->iflist_mtx);
netif_tx_start_all_queues(sdata->dev);
netif_carrier_on(sdata->dev);
@@ -950,7 +948,7 @@
* due to work needing to be done. Hence, queue the STAs work
* again for that.
*/
- queue_work(local->hw.workqueue, &ifmgd->work);
+ ieee80211_queue_work(&local->hw, &ifmgd->work);
return RX_MGMT_CFG80211_AUTH_TO;
}
@@ -995,7 +993,7 @@
* due to work needing to be done. Hence, queue the STAs work
* again for that.
*/
- queue_work(local->hw.workqueue, &ifmgd->work);
+ ieee80211_queue_work(&local->hw, &ifmgd->work);
return RX_MGMT_CFG80211_AUTH_TO;
}
@@ -1124,7 +1122,7 @@
* due to work needing to be done. Hence, queue the STAs work
* again for that.
*/
- queue_work(local->hw.workqueue, &ifmgd->work);
+ ieee80211_queue_work(&local->hw, &ifmgd->work);
return RX_MGMT_CFG80211_ASSOC_TO;
}
@@ -1156,11 +1154,24 @@
round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME));
}
+static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ const u8 *ssid;
+
+ ssid = ieee80211_bss_get_ie(&ifmgd->associated->cbss, WLAN_EID_SSID);
+ ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid,
+ ssid + 2, ssid[1], NULL, 0);
+
+ ifmgd->probe_send_count++;
+ ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT;
+ run_again(ifmgd, ifmgd->probe_timeout);
+}
+
static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
bool beacon)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- const u8 *ssid;
bool already = false;
if (!netif_running(sdata->dev))
@@ -1203,18 +1214,12 @@
if (already)
goto out;
- ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT;
-
mutex_lock(&sdata->local->iflist_mtx);
ieee80211_recalc_ps(sdata->local, -1);
mutex_unlock(&sdata->local->iflist_mtx);
- ssid = ieee80211_bss_get_ie(&ifmgd->associated->cbss, WLAN_EID_SSID);
- ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid,
- ssid + 2, ssid[1], NULL, 0);
-
- run_again(ifmgd, ifmgd->probe_timeout);
-
+ ifmgd->probe_send_count = 0;
+ ieee80211_mgd_probe_ap_send(sdata);
out:
mutex_unlock(&ifmgd->mtx);
}
@@ -1232,8 +1237,7 @@
{
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
- queue_work(sdata->local->hw.workqueue,
- &sdata->u.mgd.beacon_loss_work);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.beacon_loss_work);
}
EXPORT_SYMBOL(ieee80211_beacon_loss);
@@ -1570,6 +1574,9 @@
wk->bss->cbss.bssid,
ap_ht_cap_flags);
+ /* delete work item -- must be before set_associated for PS */
+ list_del(&wk->list);
+
/* set AID and assoc capability,
* ieee80211_set_associated() will tell the driver */
bss_conf->aid = aid;
@@ -1583,7 +1590,6 @@
ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt);
mod_beacon_timer(sdata);
- list_del(&wk->list);
kfree(wk);
return RX_MGMT_CFG80211_ASSOC;
}
@@ -1847,12 +1853,8 @@
bssid, ap_ht_cap_flags);
}
+ /* Note: country IE parsing is done for us by cfg80211 */
if (elems.country_elem) {
- /* Note we are only reviewing this on beacons
- * for the BSSID we are associated to */
- regulatory_hint_11d(local->hw.wiphy,
- elems.country_elem, elems.country_elem_len);
-
/* TODO: IBSS also needs this */
if (elems.pwr_constr_elem)
ieee80211_handle_pwr_constr(sdata,
@@ -1888,7 +1890,7 @@
case IEEE80211_STYPE_DISASSOC:
case IEEE80211_STYPE_ACTION:
skb_queue_tail(&sdata->u.mgd.skb_queue, skb);
- queue_work(local->hw.workqueue, &sdata->u.mgd.work);
+ ieee80211_queue_work(&local->hw, &sdata->u.mgd.work);
return RX_QUEUED;
}
@@ -2026,7 +2028,7 @@
return;
}
- queue_work(local->hw.workqueue, &ifmgd->work);
+ ieee80211_queue_work(&local->hw, &ifmgd->work);
}
static void ieee80211_sta_work(struct work_struct *work)
@@ -2051,13 +2053,11 @@
return;
/*
- * Nothing should have been stuffed into the workqueue during
- * the suspend->resume cycle. If this WARN is seen then there
- * is a bug with either the driver suspend or something in
- * mac80211 stuffing into the workqueue which we haven't yet
- * cleared during mac80211's suspend cycle.
+ * ieee80211_queue_work() should have picked up most cases,
+ * here we'll pick the the rest.
*/
- if (WARN_ON(local->suspended))
+ if (WARN(local->suspended, "STA MLME work scheduled while "
+ "going to suspend\n"))
return;
ifmgd = &sdata->u.mgd;
@@ -2072,17 +2072,27 @@
if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
IEEE80211_STA_CONNECTION_POLL) &&
ifmgd->associated) {
+ u8 bssid[ETH_ALEN];
+
+ memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN);
if (time_is_after_jiffies(ifmgd->probe_timeout))
run_again(ifmgd, ifmgd->probe_timeout);
- else {
- u8 bssid[ETH_ALEN];
+
+ else if (ifmgd->probe_send_count < IEEE80211_MAX_PROBE_TRIES) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "No probe response from AP %pM"
+ " after %dms, try %d\n", bssid,
+ (1000 * IEEE80211_PROBE_WAIT)/HZ,
+ ifmgd->probe_send_count);
+#endif
+ ieee80211_mgd_probe_ap_send(sdata);
+ } else {
/*
* We actually lost the connection ... or did we?
* Let's make sure!
*/
ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
IEEE80211_STA_BEACON_POLL);
- memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN);
printk(KERN_DEBUG "No probe response from AP %pM"
" after %dms, disconnecting.\n",
bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ);
@@ -2113,9 +2123,9 @@
mutex_unlock(&ifmgd->mtx);
if (test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request))
- queue_delayed_work(local->hw.workqueue,
- &local->scan_work,
- round_jiffies_relative(0));
+ ieee80211_queue_delayed_work(&local->hw,
+ &local->scan_work,
+ round_jiffies_relative(0));
return;
}
@@ -2196,8 +2206,7 @@
if (local->quiescing)
return;
- queue_work(sdata->local->hw.workqueue,
- &sdata->u.mgd.beacon_loss_work);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.beacon_loss_work);
}
static void ieee80211_sta_conn_mon_timer(unsigned long data)
@@ -2210,7 +2219,7 @@
if (local->quiescing)
return;
- queue_work(local->hw.workqueue, &ifmgd->monitor_work);
+ ieee80211_queue_work(&local->hw, &ifmgd->monitor_work);
}
static void ieee80211_sta_monitor_work(struct work_struct *work)
@@ -2229,10 +2238,10 @@
IEEE80211_STA_CONNECTION_POLL);
/* let's probe the connection once */
- queue_work(sdata->local->hw.workqueue,
+ ieee80211_queue_work(&sdata->local->hw,
&sdata->u.mgd.monitor_work);
/* and do all the other regular work too */
- queue_work(sdata->local->hw.workqueue,
+ ieee80211_queue_work(&sdata->local->hw,
&sdata->u.mgd.work);
}
}
@@ -2393,7 +2402,7 @@
list_add(&wk->list, &sdata->u.mgd.work_list);
mutex_unlock(&ifmgd->mtx);
- queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work);
return 0;
}
@@ -2467,7 +2476,7 @@
else
ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT;
- queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work);
err = 0;
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index 5e3d476..a5d2f1f 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -26,7 +26,7 @@
/* make quiescing visible to timers everywhere */
mb();
- flush_workqueue(local->hw.workqueue);
+ flush_workqueue(local->workqueue);
/* Don't try to run timers while suspended. */
del_timer_sync(&local->sta_cleanup);
@@ -96,6 +96,10 @@
if (!netif_running(sdata->dev))
continue;
+ /* disable beaconing */
+ ieee80211_bss_info_change_notify(sdata,
+ BSS_CHANGED_BEACON_ENABLED);
+
conf.vif = &sdata->vif;
conf.type = sdata->vif.type;
conf.mac_addr = sdata->dev->dev_addr;
@@ -113,7 +117,7 @@
* shouldn't be doing (or cancel everything in the
* stop callback) that but better safe than sorry.
*/
- flush_workqueue(local->hw.workqueue);
+ flush_workqueue(local->workqueue);
local->suspended = true;
/* need suspended to be visible before quiescing is false */
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 4573100..244f53f 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -385,8 +385,9 @@
spin_unlock_bh(&local->filter_lock);
/* TODO: start scan as soon as all nullfunc frames are ACKed */
- queue_delayed_work(local->hw.workqueue, &local->scan_work,
- IEEE80211_CHANNEL_TIME);
+ ieee80211_queue_delayed_work(&local->hw,
+ &local->scan_work,
+ IEEE80211_CHANNEL_TIME);
return 0;
}
@@ -715,8 +716,7 @@
}
} while (next_delay == 0);
- queue_delayed_work(local->hw.workqueue, &local->scan_work,
- next_delay);
+ ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay);
}
int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 4e1b2ba..7cffaa0 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1400,7 +1400,7 @@
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
ieee80211_stop_queues_by_reason(&local->hw,
IEEE80211_QUEUE_STOP_REASON_PS);
- queue_work(local->hw.workqueue,
+ ieee80211_queue_work(&local->hw,
&local->dynamic_ps_disable_work);
}
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 8502936..e55d57f 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -511,6 +511,46 @@
}
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
+/*
+ * Nothing should have been stuffed into the workqueue during
+ * the suspend->resume cycle. If this WARN is seen then there
+ * is a bug with either the driver suspend or something in
+ * mac80211 stuffing into the workqueue which we haven't yet
+ * cleared during mac80211's suspend cycle.
+ */
+static bool ieee80211_can_queue_work(struct ieee80211_local *local)
+{
+ if (WARN(local->suspended, "queueing ieee80211 work while "
+ "going to suspend\n"))
+ return false;
+
+ return true;
+}
+
+void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ if (!ieee80211_can_queue_work(local))
+ return;
+
+ queue_work(local->workqueue, work);
+}
+EXPORT_SYMBOL(ieee80211_queue_work);
+
+void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
+ struct delayed_work *dwork,
+ unsigned long delay)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ if (!ieee80211_can_queue_work(local))
+ return;
+
+ queue_delayed_work(local->workqueue, dwork, delay);
+}
+EXPORT_SYMBOL(ieee80211_queue_delayed_work);
+
void ieee802_11_parse_elems(u8 *start, size_t len,
struct ieee802_11_elems *elems)
{
@@ -1114,3 +1154,4 @@
#endif
return 0;
}
+
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index 044de1c..dbeaf29 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -589,11 +589,13 @@
return "wimax";
case RFKILL_TYPE_WWAN:
return "wwan";
+ case RFKILL_TYPE_GPS:
+ return "gps";
default:
BUG();
}
- BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_WWAN + 1);
+ BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_GPS + 1);
}
static ssize_t rfkill_type_show(struct device *dev,
diff --git a/net/wireless/core.c b/net/wireless/core.c
index f9fee65..1e18930 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -34,9 +34,7 @@
LIST_HEAD(cfg80211_rdev_list);
/*
- * This is used to protect the cfg80211_rdev_list, cfg80211_regdomain,
- * country_ie_regdomain, the reg_beacon_list and the the last regulatory
- * request receipt (last_request).
+ * This is used to protect the cfg80211_rdev_list
*/
DEFINE_MUTEX(cfg80211_mutex);
@@ -314,7 +312,8 @@
ev->cr.req_ie, ev->cr.req_ie_len,
ev->cr.resp_ie, ev->cr.resp_ie_len,
ev->cr.status,
- ev->cr.status == WLAN_STATUS_SUCCESS);
+ ev->cr.status == WLAN_STATUS_SUCCESS,
+ NULL);
break;
case EVENT_ROAMED:
__cfg80211_roamed(wdev, ev->rm.bssid,
@@ -672,7 +671,7 @@
wdev->wext.default_mgmt_key = -1;
wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
wdev->wext.ps = CONFIG_CFG80211_DEFAULT_PS_VALUE;
- wdev->wext.ps_timeout = 500;
+ wdev->wext.ps_timeout = 100;
if (rdev->ops->set_power_mgmt)
if (rdev->ops->set_power_mgmt(wdev->wiphy, dev,
wdev->wext.ps,
@@ -724,15 +723,22 @@
break;
case NETDEV_UNREGISTER:
mutex_lock(&rdev->devlist_mtx);
+ /*
+ * It is possible to get NETDEV_UNREGISTER
+ * multiple times. To detect that, check
+ * that the interface is still on the list
+ * of registered interfaces, and only then
+ * remove and clean it up.
+ */
if (!list_empty(&wdev->list)) {
sysfs_remove_link(&dev->dev.kobj, "phy80211");
list_del_init(&wdev->list);
+ mutex_destroy(&wdev->mtx);
+#ifdef CONFIG_WIRELESS_EXT
+ kfree(wdev->wext.keys);
+#endif
}
mutex_unlock(&rdev->devlist_mtx);
- mutex_destroy(&wdev->mtx);
-#ifdef CONFIG_WIRELESS_EXT
- kfree(wdev->wext.keys);
-#endif
break;
case NETDEV_PRE_UP:
if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 6d903c1..325c17e 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -127,6 +127,11 @@
return container_of(pub, struct cfg80211_internal_bss, pub);
}
+static inline void cfg80211_ref_bss(struct cfg80211_internal_bss *bss)
+{
+ kref_get(&bss->ref);
+}
+
static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss)
{
atomic_inc(&bss->hold);
@@ -323,7 +328,8 @@
void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
const u8 *req_ie, size_t req_ie_len,
const u8 *resp_ie, size_t resp_ie_len,
- u16 status, bool wextev);
+ u16 status, bool wextev,
+ struct cfg80211_bss *bss);
/* SME */
int __cfg80211_connect(struct cfg80211_registered_device *rdev,
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 097a87d..525e8e2 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -61,7 +61,7 @@
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
u8 *ie = mgmt->u.assoc_resp.variable;
int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
- bool done;
+ struct cfg80211_internal_bss *bss = NULL;
wdev_lock(wdev);
@@ -69,22 +69,32 @@
nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL);
- __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
- status_code,
- status_code == WLAN_STATUS_SUCCESS);
-
if (status_code == WLAN_STATUS_SUCCESS) {
- for (i = 0; wdev->current_bss && i < MAX_AUTH_BSSES; i++) {
- if (wdev->auth_bsses[i] == wdev->current_bss) {
- cfg80211_unhold_bss(wdev->auth_bsses[i]);
- cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
+ for (i = 0; i < MAX_AUTH_BSSES; i++) {
+ if (!wdev->auth_bsses[i])
+ continue;
+ if (memcmp(wdev->auth_bsses[i]->pub.bssid, mgmt->bssid,
+ ETH_ALEN) == 0) {
+ bss = wdev->auth_bsses[i];
wdev->auth_bsses[i] = NULL;
- done = true;
+ /* additional reference to drop hold */
+ cfg80211_ref_bss(bss);
break;
}
}
- WARN_ON(!done);
+ WARN_ON(!bss);
+ }
+
+ /* this consumes one bss reference (unless bss is NULL) */
+ __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
+ status_code,
+ status_code == WLAN_STATUS_SUCCESS,
+ bss ? &bss->pub : NULL);
+ /* drop hold now, and also reference acquired above */
+ if (bss) {
+ cfg80211_unhold_bss(bss);
+ cfg80211_put_bss(&bss->pub);
}
wdev_unlock(wdev);
@@ -144,7 +154,7 @@
} else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
__cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
- false);
+ false, NULL);
}
}
@@ -241,7 +251,7 @@
if (wdev->sme_state == CFG80211_SME_CONNECTING)
__cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
- false);
+ false, NULL);
for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
if (wdev->authtry_bsses[i] &&
@@ -275,7 +285,7 @@
if (wdev->sme_state == CFG80211_SME_CONNECTING)
__cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
- false);
+ false, NULL);
for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
if (wdev->auth_bsses[i] &&
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index fb40428..b3ac0aa 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -62,6 +62,16 @@
*/
static const struct ieee80211_regdomain *country_ie_regdomain;
+/*
+ * Protects static reg.c components:
+ * - cfg80211_world_regdom
+ * - cfg80211_regdom
+ * - country_ie_regdomain
+ * - last_request
+ */
+DEFINE_MUTEX(reg_mutex);
+#define assert_reg_lock() WARN_ON(!mutex_is_locked(®_mutex))
+
/* Used to queue up regulatory hints */
static LIST_HEAD(reg_requests_list);
static spinlock_t reg_requests_lock;
@@ -1293,7 +1303,7 @@
struct ieee80211_supported_band *sband;
struct ieee80211_channel *chan;
- assert_cfg80211_lock();
+ assert_reg_lock();
sband = wiphy->bands[band];
BUG_ON(chan_idx >= sband->n_channels);
@@ -1342,14 +1352,14 @@
enum ieee80211_band band;
unsigned int bands_set = 0;
- mutex_lock(&cfg80211_mutex);
+ mutex_lock(®_mutex);
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
if (!wiphy->bands[band])
continue;
handle_band_custom(wiphy, band, regd);
bands_set++;
}
- mutex_unlock(&cfg80211_mutex);
+ mutex_unlock(®_mutex);
/*
* no point in calling this if it won't have any effect
@@ -1495,7 +1505,7 @@
* Returns zero if all went fine, %-EALREADY if a regulatory domain had
* already been set or other standard error codes.
*
- * Caller must hold &cfg80211_mutex
+ * Caller must hold &cfg80211_mutex and ®_mutex
*/
static int __regulatory_hint(struct wiphy *wiphy,
struct regulatory_request *pending_request)
@@ -1570,6 +1580,7 @@
BUG_ON(!reg_request->alpha2);
mutex_lock(&cfg80211_mutex);
+ mutex_lock(®_mutex);
if (wiphy_idx_valid(reg_request->wiphy_idx))
wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);
@@ -1585,6 +1596,7 @@
if (r == -EALREADY && wiphy && wiphy->strict_regulatory)
wiphy_update_regulatory(wiphy, reg_request->initiator);
out:
+ mutex_unlock(®_mutex);
mutex_unlock(&cfg80211_mutex);
}
@@ -1613,6 +1625,10 @@
struct cfg80211_registered_device *rdev;
struct reg_beacon *pending_beacon, *tmp;
+ /*
+ * No need to hold the reg_mutex here as we just touch wiphys
+ * and do not read or access regulatory variables.
+ */
mutex_lock(&cfg80211_mutex);
/* This goes through the _pending_ beacon list */
@@ -1734,12 +1750,13 @@
}
EXPORT_SYMBOL(regulatory_hint);
+/* Caller must hold reg_mutex */
static bool reg_same_country_ie_hint(struct wiphy *wiphy,
u32 country_ie_checksum)
{
struct wiphy *request_wiphy;
- assert_cfg80211_lock();
+ assert_reg_lock();
if (unlikely(last_request->initiator !=
NL80211_REGDOM_SET_BY_COUNTRY_IE))
@@ -1762,6 +1779,10 @@
return false;
}
+/*
+ * We hold wdev_lock() here so we cannot hold cfg80211_mutex() and
+ * therefore cannot iterate over the rdev list here.
+ */
void regulatory_hint_11d(struct wiphy *wiphy,
u8 *country_ie,
u8 country_ie_len)
@@ -1772,12 +1793,10 @@
enum environment_cap env = ENVIRON_ANY;
struct regulatory_request *request;
- mutex_lock(&cfg80211_mutex);
+ mutex_lock(®_mutex);
- if (unlikely(!last_request)) {
- mutex_unlock(&cfg80211_mutex);
- return;
- }
+ if (unlikely(!last_request))
+ goto out;
/* IE len must be evenly divisible by 2 */
if (country_ie_len & 0x01)
@@ -1803,54 +1822,14 @@
env = ENVIRON_OUTDOOR;
/*
- * We will run this for *every* beacon processed for the BSSID, so
- * we optimize an early check to exit out early if we don't have to
- * do anything
+ * We will run this only upon a successful connection on cfg80211.
+ * We leave conflict resolution to the workqueue, where can hold
+ * cfg80211_mutex.
*/
if (likely(last_request->initiator ==
NL80211_REGDOM_SET_BY_COUNTRY_IE &&
- wiphy_idx_valid(last_request->wiphy_idx))) {
- struct cfg80211_registered_device *rdev_last_ie;
-
- rdev_last_ie =
- cfg80211_rdev_by_wiphy_idx(last_request->wiphy_idx);
-
- /*
- * Lets keep this simple -- we trust the first AP
- * after we intersect with CRDA
- */
- if (likely(&rdev_last_ie->wiphy == wiphy)) {
- /*
- * Ignore IEs coming in on this wiphy with
- * the same alpha2 and environment cap
- */
- if (likely(alpha2_equal(rdev_last_ie->country_ie_alpha2,
- alpha2) &&
- env == rdev_last_ie->env)) {
- goto out;
- }
- /*
- * the wiphy moved on to another BSSID or the AP
- * was reconfigured. XXX: We need to deal with the
- * case where the user suspends and goes to goes
- * to another country, and then gets IEs from an
- * AP with different settings
- */
- goto out;
- } else {
- /*
- * Ignore IEs coming in on two separate wiphys with
- * the same alpha2 and environment cap
- */
- if (likely(alpha2_equal(rdev_last_ie->country_ie_alpha2,
- alpha2) &&
- env == rdev_last_ie->env)) {
- goto out;
- }
- /* We could potentially intersect though */
- goto out;
- }
- }
+ wiphy_idx_valid(last_request->wiphy_idx)))
+ goto out;
rd = country_ie_2_rd(country_ie, country_ie_len, &checksum);
if (!rd)
@@ -1885,7 +1864,7 @@
request->country_ie_checksum = checksum;
request->country_ie_env = env;
- mutex_unlock(&cfg80211_mutex);
+ mutex_unlock(®_mutex);
queue_regulatory_request(request);
@@ -1894,9 +1873,8 @@
free_rd_out:
kfree(rd);
out:
- mutex_unlock(&cfg80211_mutex);
+ mutex_unlock(®_mutex);
}
-EXPORT_SYMBOL(regulatory_hint_11d);
static bool freq_is_chan_12_13_14(u16 freq)
{
@@ -2227,10 +2205,13 @@
assert_cfg80211_lock();
+ mutex_lock(®_mutex);
+
/* Note that this doesn't update the wiphys, this is done below */
r = __set_regdom(rd);
if (r) {
kfree(rd);
+ mutex_unlock(®_mutex);
return r;
}
@@ -2245,6 +2226,8 @@
nl80211_send_reg_change_event(last_request);
+ mutex_unlock(®_mutex);
+
return r;
}
@@ -2255,16 +2238,20 @@
assert_cfg80211_lock();
+ mutex_lock(®_mutex);
+
kfree(wiphy->regd);
if (last_request)
request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
if (!request_wiphy || request_wiphy != wiphy)
- return;
+ goto out;
last_request->wiphy_idx = WIPHY_IDX_STALE;
last_request->country_ie_env = ENVIRON_ANY;
+out:
+ mutex_unlock(®_mutex);
}
int regulatory_init(void)
@@ -2325,6 +2312,7 @@
cancel_work_sync(®_work);
mutex_lock(&cfg80211_mutex);
+ mutex_lock(®_mutex);
reset_regdomains();
@@ -2363,5 +2351,6 @@
}
spin_unlock(®_requests_lock);
+ mutex_unlock(®_mutex);
mutex_unlock(&cfg80211_mutex);
}
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index e37829a..662a9da 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -36,4 +36,19 @@
struct ieee80211_channel *beacon_chan,
gfp_t gfp);
+/**
+ * regulatory_hint_11d - hints a country IE as a regulatory domain
+ * @wiphy: the wireless device giving the hint (used only for reporting
+ * conflicts)
+ * @country_ie: pointer to the country IE
+ * @country_ie_len: length of the country IE
+ *
+ * We will intersect the rd with the what CRDA tells us should apply
+ * for the alpha2 this country IE belongs to, this prevents APs from
+ * sending us incorrect or outdated information against a country.
+ */
+void regulatory_hint_11d(struct wiphy *wiphy,
+ u8 *country_ie,
+ u8 country_ie_len);
+
#endif /* __NET_WIRELESS_REG_H */
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index d2b5d4c..8a7dcbf 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -13,6 +13,7 @@
#include <net/cfg80211.h>
#include <net/rtnetlink.h>
#include "nl80211.h"
+#include "reg.h"
struct cfg80211_conn {
struct cfg80211_connect_params params;
@@ -182,7 +183,7 @@
wdev->conn->params.bssid,
NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
- false);
+ false, NULL);
wdev_unlock(wdev);
}
@@ -247,7 +248,7 @@
wdev->conn->params.bssid,
NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
- false);
+ false, NULL);
}
}
@@ -305,7 +306,7 @@
schedule_work(&rdev->conn_work);
} else if (status_code != WLAN_STATUS_SUCCESS) {
__cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
- status_code, false);
+ status_code, false, NULL);
} else if (wdev->sme_state == CFG80211_SME_CONNECTING &&
wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
@@ -316,10 +317,11 @@
void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
const u8 *req_ie, size_t req_ie_len,
const u8 *resp_ie, size_t resp_ie_len,
- u16 status, bool wextev)
+ u16 status, bool wextev,
+ struct cfg80211_bss *bss)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct cfg80211_bss *bss;
+ u8 *country_ie;
#ifdef CONFIG_WIRELESS_EXT
union iwreq_data wrqu;
#endif
@@ -361,6 +363,12 @@
}
#endif
+ if (wdev->current_bss) {
+ cfg80211_unhold_bss(wdev->current_bss);
+ cfg80211_put_bss(&wdev->current_bss->pub);
+ wdev->current_bss = NULL;
+ }
+
if (status == WLAN_STATUS_SUCCESS &&
wdev->sme_state == CFG80211_SME_IDLE)
goto success;
@@ -368,12 +376,6 @@
if (wdev->sme_state != CFG80211_SME_CONNECTING)
return;
- if (wdev->current_bss) {
- cfg80211_unhold_bss(wdev->current_bss);
- cfg80211_put_bss(&wdev->current_bss->pub);
- wdev->current_bss = NULL;
- }
-
if (wdev->conn)
wdev->conn->state = CFG80211_CONN_IDLE;
@@ -383,13 +385,16 @@
wdev->conn = NULL;
kfree(wdev->connect_keys);
wdev->connect_keys = NULL;
+ wdev->ssid_len = 0;
return;
}
- bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
- wdev->ssid, wdev->ssid_len,
- WLAN_CAPABILITY_ESS,
- WLAN_CAPABILITY_ESS);
+ success:
+ if (!bss)
+ bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
+ wdev->ssid, wdev->ssid_len,
+ WLAN_CAPABILITY_ESS,
+ WLAN_CAPABILITY_ESS);
if (WARN_ON(!bss))
return;
@@ -397,9 +402,22 @@
cfg80211_hold_bss(bss_from_pub(bss));
wdev->current_bss = bss_from_pub(bss);
- success:
wdev->sme_state = CFG80211_SME_CONNECTED;
cfg80211_upload_connect_keys(wdev);
+
+ country_ie = (u8 *) ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);
+
+ if (!country_ie)
+ return;
+
+ /*
+ * ieee80211_bss_get_ie() ensures we can access:
+ * - country_ie + 2, the start of the country ie data, and
+ * - and country_ie[1] which is the IE length
+ */
+ regulatory_hint_11d(wdev->wiphy,
+ country_ie + 2,
+ country_ie[1]);
}
void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
@@ -549,6 +567,7 @@
wdev->current_bss = NULL;
wdev->sme_state = CFG80211_SME_IDLE;
+ wdev->ssid_len = 0;
if (wdev->conn) {
kfree(wdev->conn->ie);
@@ -704,6 +723,7 @@
wdev->conn = NULL;
wdev->sme_state = CFG80211_SME_IDLE;
wdev->connect_keys = NULL;
+ wdev->ssid_len = 0;
}
return err;
@@ -768,6 +788,7 @@
wdev->sme_state = CFG80211_SME_IDLE;
kfree(wdev->conn);
wdev->conn = NULL;
+ wdev->ssid_len = 0;
return 0;
}
@@ -788,7 +809,7 @@
else if (wdev->sme_state == CFG80211_SME_CONNECTING)
__cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
- wextev);
+ wextev, NULL);
return 0;
}
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index 3fe3c2c..5b4a0ce 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -1291,7 +1291,6 @@
static int __init wireless_nlevent_init(void)
{
return register_pernet_subsys(&wext_pernet_ops);
- return 0;
}
subsys_initcall(wireless_nlevent_init);