Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6

This commit is contained in:
David S. Miller 2009-08-06 12:57:18 -07:00
commit bfe34ebbaa
96 changed files with 2763 additions and 802 deletions

View File

@ -64,6 +64,32 @@ void rndis_status(struct usbnet *dev, struct urb *urb)
}
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
@ -143,27 +169,9 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen)
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;

View File

@ -601,21 +601,25 @@ int usbnet_stop (struct net_device *net)
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);

View File

@ -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 @@ config PCMCIA_NETWAVE
called netwave_cs. If unsure, say N.
config WLAN_80211
menuconfig WLAN_80211
bool "Wireless LAN (IEEE 802.11)"
depends on NETDEVICES
---help---

View File

@ -1773,6 +1773,9 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw)
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 @@ static void at76_dwork_hw_scan(struct work_struct *work)
/* 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 @@ static int at76_hw_scan(struct ieee80211_hw *hw,
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 @@ static void at76_configure_filter(struct ieee80211_hw *hw,
} 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 @@ static void at76_delete_device(struct at76_priv *priv)
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);

View File

@ -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

View File

@ -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.

View File

@ -90,9 +90,12 @@ static void ar9170_update_leds(struct work_struct *work)
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 @@ static void ar9170_led_brightness_set(struct led_classdev *led,
}
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,

View File

@ -595,10 +595,12 @@ static void ar9170_tx_janitor(struct work_struct *work)
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 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
* 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 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
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 @@ static void ar9170_tx(struct ar9170 *ar)
}
}
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 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
}
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 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw,
}
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,

View File

@ -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

View File

@ -1117,6 +1117,8 @@ ath5k_mode_setup(struct ath5k_softc *sc)
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 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
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 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
}
ath5k_hw_set_lladdr(sc->ah, conf->mac_addr);
ath5k_mode_setup(sc);
ret = 0;
end:

View File

@ -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

View File

@ -119,7 +119,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
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;

View File

@ -777,7 +777,7 @@ void ath9k_hw_ani_setup(struct ath_hw *ah)
}
}
void ath9k_hw_ani_attach(struct ath_hw *ah)
void ath9k_hw_ani_init(struct ath_hw *ah)
{
int i;
@ -822,9 +822,9 @@ void ath9k_hw_ani_attach(struct ath_hw *ah)
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);

View File

@ -132,7 +132,7 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt,
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 */

View File

@ -642,7 +642,7 @@ extern struct ieee80211_ops ath9k_ops;
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);

View File

@ -753,6 +753,98 @@ static void ath9k_olc_temp_compensation(struct ath_hw *ah)
}
}
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 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
}
}
/* 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);
}

View File

@ -1237,6 +1237,10 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
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 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
}
}
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 int ath9k_hw_AR9287_get_eeprom_rev(struct ath_hw *ah)
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 @@ static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah)
"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 bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah)
}
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 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
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 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
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 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
}
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 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah,
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 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
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, &centers);
@ -3613,7 +3694,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
{
#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_addac(struct ath_hw *ah,
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 u8 ath9k_hw_AR9287_get_num_ant_config(struct ath_hw *ah,
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 @@ static struct eeprom_ops eep_AR9287_ops = {
};
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 {

View File

@ -600,7 +600,7 @@ struct ar5416_eeprom_4k {
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 @@ struct eeprom_ops {
(((_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 */

View File

@ -388,7 +388,7 @@ static const char *ath9k_hw_devname(u16 devid)
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 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah)
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 @@ static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc,
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 void ath9k_hw_init_txgain_ini(struct ath_hw *ah)
}
}
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 @@ static int ath9k_hw_post_attach(struct ath_hw *ah)
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 @@ static int ath9k_hw_post_attach(struct ath_hw *ah)
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 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
}
ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
}
}
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;
}
ah->ani_function = ATH9K_ANI_ALL;
if (AR_SREV_9280_10_OR_LATER(ah))
ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
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 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
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 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
}
}
}
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 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
}
}
}
}
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 @@ const char *ath9k_hw_probe(u16 vendorid, u16 devid)
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 @@ struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error)
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 @@ static void ath9k_hw_override_ini(struct ath_hw *ah,
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 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
{
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 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
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 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
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 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
"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 @@ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry)
}
if (ah->curchan == NULL)
return true;
return true;
}
@ -2921,7 +3005,7 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore)
/*
* 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 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore)
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 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
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 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
}
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)))

View File

@ -403,7 +403,7 @@ struct ath_hw {
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 @@ struct ath_hw {
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 ath_hw {
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 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore);
/* 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);

View File

@ -6365,3 +6365,669 @@ static const u_int32_t ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = {
};
/* 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 },
};

View File

@ -973,10 +973,11 @@ static void ath_led_blink_work(struct work_struct *work)
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 @@ static void ath_led_brightness(struct led_classdev *led_cdev,
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_unregister_led(struct ath_led *led)
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 @@ static void ath_init_leds(struct ath_softc *sc)
return;
fail:
cancel_delayed_work_sync(&sc->ath_led_blink_work);
ath_deinit_leds(sc);
}
@ -1252,9 +1253,6 @@ void ath_detach(struct ath_softc *sc)
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 @@ void ath_detach(struct ath_softc *sc)
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 @@ static int ath9k_reg_notifier(struct wiphy *wiphy,
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 @@ static int ath_init(u16 devid, struct ath_softc *sc)
/* 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 @@ static int ath_init(u16 devid, struct ath_softc *sc)
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 @@ static int ath_init(u16 devid, struct ath_softc *sc)
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 @@ static int ath_init(u16 devid, struct ath_softc *sc)
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 @@ static int ath_init(u16 devid, struct ath_softc *sc)
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 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
&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 @@ int ath_attach(u16 devid, struct ath_softc *sc)
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 @@ int ath_attach(u16 devid, struct ath_softc *sc)
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 @@ static int ath9k_start(struct ieee80211_hw *hw)
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 @@ static void ath9k_stop(struct ieee80211_hw *hw)
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 @@ static void ath9k_stop(struct ieee80211_hw *hw)
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 */

View File

@ -178,7 +178,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
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;
}

View File

@ -264,44 +264,23 @@ ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan,
}
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)

View File

@ -185,6 +185,9 @@ bool ath9k_hw_init_rf(struct ath_hw *ah,
#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

View File

@ -44,7 +44,7 @@ static const struct ath_rate_table ar5416_11na_ratetable = {
{ 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 @@ static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw)
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 @@ static void ath_rc_update_ht(struct ath_softc *sc,
/* 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]) {

View File

@ -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 @@ enum {
#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 @@ enum {
#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

View File

@ -351,7 +351,7 @@ void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
* 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 @@ static void ath9k_mark_paused(struct ath_wiphy *aphy)
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 @@ int ath9k_wiphy_select(struct ath_wiphy *aphy)
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 @@ int ath9k_wiphy_select(struct ath_wiphy *aphy)
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 @@ void ath9k_wiphy_work(struct work_struct *work)
"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 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int)
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 */

View File

@ -2063,7 +2063,7 @@ static void ath_tx_complete_poll_work(struct work_struct *work)
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));
}

View File

@ -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

View File

@ -1334,13 +1334,22 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
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;
}

View File

@ -395,9 +395,8 @@ u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
/* 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 @@ void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value
/* 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 @@ static void b43_write_probe_resp_template(struct b43_wldev *dev,
/* 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 @@ static void b43_update_templates(struct b43_wl *wl)
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 @@ static void b43_periodic_work_handler(struct work_struct *work)
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 @@ static void b43_periodic_tasks_setup(struct b43_wldev *dev)
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 @@ static int b43_validate_chipaccess(struct b43_wldev *dev)
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 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason)
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

View File

@ -240,6 +240,13 @@ void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
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 @@ void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags)
/* 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)

View File

@ -290,6 +290,11 @@ u16 b43_phy_read(struct b43_wldev *dev, u16 reg);
*/
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
*/

View File

@ -66,7 +66,99 @@ static void lpphy_table_init(struct b43_wldev *dev)
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)

View File

@ -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 */

View File

@ -137,7 +137,8 @@ static void b43_radio_init2055_post(struct b43_wldev *dev)
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)) {

View File

@ -783,7 +783,7 @@ void b43_pio_rx(struct b43_pio_rxqueue *q)
{
/* 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)

View File

@ -1366,15 +1366,25 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev,
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;
}
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;
}
/* Check if the queue was stopped in mac80211,
* but we got called nevertheless.
* That would be a mac80211 bug. */
B43legacy_BUG_ON(ring->stopped);
err = dma_tx_fragment(ring, skb);
if (unlikely(err == -ENOKEY)) {

View File

@ -1252,7 +1252,7 @@ static void b43legacy_update_templates(struct b43legacy_wl *wl)
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 @@ static void b43legacy_periodic_work_handler(struct work_struct *work)
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 @@ static void b43legacy_periodic_tasks_setup(struct b43legacy_wldev *dev)
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 @@ void b43legacy_controller_restart(struct b43legacy_wldev *dev,
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

View File

@ -73,6 +73,18 @@ static void iwl1000_set_ct_threshold(struct iwl_priv *priv)
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 @@ static struct iwl_lib_ops iwl1000_lib = {
.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 = {

View File

@ -198,6 +198,7 @@ int iwl5000_apm_reset(struct iwl_priv *priv)
}
/* NIC configuration for 5000 series and up */
void iwl5000_nic_config(struct iwl_priv *priv)
{
unsigned long flags;
@ -239,18 +240,11 @@ void iwl5000_nic_config(struct iwl_priv *priv)
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
*/

View File

@ -68,6 +68,24 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
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 @@ static struct iwl_lib_ops iwl6000_lib = {
.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 @@ static struct iwl_ops iwl6000_ops = {
.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 @@ struct iwl_cfg iwl6000_2agn_cfg = {
.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 @@ struct iwl_cfg iwl6050_2agn_cfg = {
.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 @@ struct iwl_cfg iwl6000_3agn_cfg = {
.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 @@ struct iwl_cfg iwl6050_3agn_cfg = {
.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));

View File

@ -1291,6 +1291,7 @@ static int iwl_read_ucode(struct iwl_priv *priv)
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 @@ static int iwl_read_ucode(struct iwl_priv *priv)
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 @@ static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO,
#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 @@ static struct attribute *iwl_sysfs_entries[] = {
#ifdef CONFIG_IWLWIFI_DEBUG
&dev_attr_debug_level.attr,
#endif
&dev_attr_version.attr,
NULL
};
@ -3139,15 +3111,12 @@ static struct pci_device_id iwl_hw_card_ids[] = {
{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)},

View File

@ -548,9 +548,6 @@ int iwlcore_init_geos(struct iwl_priv *priv)
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 @@ void iwl_set_flags_for_band(struct iwl_priv *priv,
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 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
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 @@ void iwl_clear_isr_stats(struct iwl_priv *priv)
{
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)

View File

@ -206,6 +206,7 @@ struct iwl_mod_params {
* 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 @@ struct iwl_mod_params {
* 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 @@ struct iwl_cfg {
u8 valid_rx_ant;
bool need_pll_cfg;
bool use_isr_legacy;
enum iwl_pa_type pa_type;
};
/***************************

View File

@ -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)

View File

@ -56,8 +56,8 @@ extern struct iwl_cfg iwl5350_agn_cfg;
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 @@ enum iwl_nvm_type {
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;

View File

@ -335,7 +335,6 @@ void iwl_leds_background(struct iwl_priv *priv)
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)

View File

@ -406,7 +406,6 @@ void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
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)
{

View File

@ -464,7 +464,6 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap)
spin_unlock_irqrestore(&priv->sta_lock, flags);
return ret;
}
EXPORT_SYMBOL(iwl_remove_station);
/**
* iwl_clear_stations_table - Clear the driver's station table

View File

@ -970,6 +970,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
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;

View File

@ -484,6 +484,8 @@ static int iwm_set_auth_type(struct iwm_priv *iwm,
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 @@ static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast)
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 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
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;

View File

@ -526,19 +526,6 @@ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
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 @@ static int iwm_check_profile(struct iwm_priv *iwm)
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 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
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 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
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 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
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;

View File

@ -376,7 +376,7 @@ static int spu_set_bus_mode(struct if_spi_card *card, u16 mode)
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;
}

View File

@ -1728,6 +1728,8 @@ static int lbs_set_auth(struct net_device *dev,
}
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:

View File

@ -156,7 +156,48 @@ static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev,
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,
};

View File

@ -61,7 +61,7 @@ static void p54_update_leds(struct work_struct *work)
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 @@ static void p54_led_brightness_set(struct led_classdev *led_dev,
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);
}
}

View File

@ -180,7 +180,7 @@ static int p54_start(struct ieee80211_hw *dev)
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);

View File

@ -391,7 +391,7 @@ static irqreturn_t p54spi_interrupt(int irq, void *config)
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 @@ static void p54spi_op_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
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)

View File

@ -380,7 +380,7 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
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;

View File

@ -100,7 +100,6 @@ MODULE_PARM_DESC(workaround_interval,
#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 @@ enum ndis_80211_priv_filter {
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 @@ enum ndis_80211_addwep_bits {
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 @@ struct ndis_80211_remove_key {
__le32 size;
__le32 index;
u8 bssid[6];
u8 padding[2];
} __attribute__((packed));
struct ndis_config_param {
@ -366,6 +413,15 @@ static const struct ieee80211_rate rndis_rates[] = {
{ .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 @@ struct rndis_wlan_private {
/* 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 u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv)
}
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 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len)
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 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len)
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_set_oid(struct usbnet *dev, __le32 oid, void *data, int len)
}
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 @@ static int freq_to_dsconfig(struct iw_freq *freq, unsigned int *dsconfig)
/*
* 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 @@ static int set_infra_mode(struct usbnet *usbdev, int mode)
{
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 @@ static int set_infra_mode(struct usbnet *usbdev, int mode)
/* 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 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index)
{
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 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index)
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 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
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 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
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 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
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 add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
}
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 @@ static void rndis_get_scan_results(struct work_struct *work)
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 @@ static int rndis_iw_set_encode(struct net_device *dev,
{
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 @@ static int rndis_iw_set_encode(struct net_device *dev,
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 @@ static int rndis_iw_set_encode_ext(struct net_device *dev,
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 @@ static int rndis_iw_set_encode_ext(struct net_device *dev,
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 @@ static int rndis_iw_set_encode_ext(struct net_device *dev,
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 @@ static int rndis_iw_set_encode_ext(struct net_device *dev,
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 @@ static void rndis_wlan_set_multicast_list(struct net_device *dev)
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 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
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 void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf)
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 @@ static const struct driver_info bcm4320b_info = {
.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 @@ static const struct driver_info bcm4320a_info = {
.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 @@ static const struct driver_info rndis_wlan_info = {
.reset = rndis_wlan_reset,
.stop = rndis_wlan_stop,
.early_init = bcm4320a_early_init,
.link_change = rndis_wlan_link_change,
.indication = rndis_wlan_indication,
};
/*-------------------------------------------------------------------------*/

View File

@ -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 RT73USB
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".

View File

@ -215,7 +215,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
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);
@ -892,6 +892,12 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
*/
rt2x00lib_disable_radio(rt2x00dev);
/*
* Stop all work.
*/
cancel_work_sync(&rt2x00dev->filter_work);
cancel_work_sync(&rt2x00dev->intf_work);
/*
* Uninitialize device.
*/

View File

@ -351,8 +351,8 @@ void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
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 @@ static void rt2x00link_tuner(struct work_struct *work)
* 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)

View File

@ -431,10 +431,20 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
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 @@ static void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len)
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)

View File

@ -2600,6 +2600,11 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
{
int retval;
/*
* Disable power saving.
*/
rt2x00pci_register_write(rt2x00dev, SOFT_RESET_CSR, 0x00000007);
/*
* Allocate eeprom data.
*/

View File

@ -220,7 +220,7 @@ static void rtl8187_tx_cb(struct urb *urb)
* 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);
}
}

View File

@ -108,11 +108,11 @@ static void rtl8187_led_brightness_set(struct led_classdev *led_dev,
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 @@ void rtl8187_leds_init(struct ieee80211_hw *dev, u16 custid)
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 @@ void rtl8187_leds_exit(struct ieee80211_hw *dev)
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);

View File

@ -1550,9 +1550,12 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
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;

View File

@ -698,7 +698,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
&& !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));

View File

@ -47,6 +47,7 @@ enum rfkill_type {
RFKILL_TYPE_UWB,
RFKILL_TYPE_WIMAX,
RFKILL_TYPE_WWAN,
RFKILL_TYPE_GPS,
NUM_RFKILL_TYPES,
};

View File

@ -70,12 +70,13 @@ struct rndis_msg_hdr {
#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)

View File

@ -86,6 +86,7 @@ struct driver_info {
#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 @@ struct driver_info {
* 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 */

View File

@ -1513,20 +1513,6 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb);
*/
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

View File

@ -72,6 +72,21 @@
* not do so then mac80211 may add this under certain circumstances.
*/
/**
* 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
*
@ -913,12 +928,6 @@ enum ieee80211_hw_flags {
*
* @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 @@ enum ieee80211_hw_flags {
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 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
* 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 @@ enum ieee80211_filter_flags {
FIF_BCN_PRBRESP_PROMISC = 1<<4,
FIF_CONTROL = 1<<5,
FIF_OTHER_BSS = 1<<6,
FIF_PSPOLL = 1<<7,
};
/**
@ -1301,7 +1313,8 @@ enum ieee80211_ampdu_mlme_action {
* 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
@ -1927,6 +1940,31 @@ void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw,
struct ieee80211_vif *vif),
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().

View File

@ -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

View File

@ -781,7 +781,7 @@ static void ieee80211_ibss_timer(unsigned long data)
}
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 @@ ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
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 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
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;
}

View File

@ -280,6 +280,7 @@ struct ieee80211_if_managed {
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 @@ struct ieee80211_local {
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 @@ struct ieee80211_local {
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;

View File

@ -220,8 +220,10 @@ static int ieee80211_open(struct net_device *dev)
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 @@ static int ieee80211_open(struct net_device *dev)
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 @@ static int ieee80211_open(struct net_device *dev)
* 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 @@ static int ieee80211_stop(struct net_device *dev)
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 @@ static int ieee80211_stop(struct net_device *dev)
/* 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 @@ static int ieee80211_stop(struct net_device *dev)
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 @@ static int ieee80211_stop(struct net_device *dev)
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 @@ static int ieee80211_stop(struct net_device *dev)
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 @@ static int ieee80211_stop(struct net_device *dev)
ieee80211_led_radio(local, false);
flush_workqueue(local->hw.workqueue);
flush_workqueue(local->workqueue);
tasklet_disable(&local->tx_pending_tasklet);
tasklet_disable(&local->tasklet);

View File

@ -77,6 +77,9 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
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 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
}
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 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
{
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 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
return;
}
drop:
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "%s: dropped TX filtered frame, "
@ -794,9 +824,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
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 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
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 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
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);

View File

@ -54,7 +54,7 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data)
return;
}
queue_work(local->hw.workqueue, &ifmsh->work);
ieee80211_queue_work(local->hw.workqueue, &ifmsh->work);
}
/**
@ -357,7 +357,7 @@ static void ieee80211_mesh_path_timer(unsigned long data)
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 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
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 @@ void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
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 @@ ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
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;
}

View File

@ -660,14 +660,14 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
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));

View File

@ -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 @@ static void ieee80211_chswitch_timer(unsigned long data)
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 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
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 @@ void ieee80211_dynamic_ps_timer(unsigned long data)
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 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
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 @@ ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata,
* 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 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
* 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 @@ ieee80211_associate(struct ieee80211_sub_if_data *sdata,
* 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 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
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 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
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 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif)
{
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 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
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_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
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 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
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 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
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 @@ static void ieee80211_sta_timer(unsigned long data)
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 @@ static void ieee80211_sta_work(struct work_struct *work)
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 @@ static void ieee80211_sta_work(struct work_struct *work)
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 @@ static void ieee80211_sta_work(struct work_struct *work)
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 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data)
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 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data)
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 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
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 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
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 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
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;

View File

@ -26,7 +26,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
/* 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 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
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 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
* 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 */

View File

@ -385,8 +385,9 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
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 @@ void ieee80211_scan_work(struct work_struct *work)
}
} 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,

View File

@ -1400,7 +1400,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
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);
}

View File

@ -511,6 +511,46 @@ void ieee80211_iterate_active_interfaces_atomic(
}
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 @@ int ieee80211_reconfig(struct ieee80211_local *local)
#endif
return 0;
}

View File

@ -589,11 +589,13 @@ static const char *rfkill_get_type_str(enum rfkill_type type)
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,

View File

@ -34,9 +34,7 @@ MODULE_DESCRIPTION("wireless configuration support");
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 @@ static void cfg80211_process_events(struct wireless_dev *wdev)
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 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
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 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
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)))

View File

@ -127,6 +127,11 @@ static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pu
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_mlme_down(struct cfg80211_registered_device *rdev,
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,

View File

@ -61,7 +61,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
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 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
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 @@ static void __cfg80211_send_deauth(struct net_device *dev,
} 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 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
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 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
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] &&

View File

@ -62,6 +62,16 @@ const struct ieee80211_regdomain *cfg80211_regdomain;
*/
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(&reg_mutex))
/* Used to queue up regulatory hints */
static LIST_HEAD(reg_requests_list);
static spinlock_t reg_requests_lock;
@ -1293,7 +1303,7 @@ static void handle_channel_custom(struct wiphy *wiphy,
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 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
enum ieee80211_band band;
unsigned int bands_set = 0;
mutex_lock(&cfg80211_mutex);
mutex_lock(&reg_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(&reg_mutex);
/*
* no point in calling this if it won't have any effect
@ -1495,7 +1505,7 @@ static int ignore_request(struct wiphy *wiphy,
* 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 &reg_mutex
*/
static int __regulatory_hint(struct wiphy *wiphy,
struct regulatory_request *pending_request)
@ -1570,6 +1580,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
BUG_ON(!reg_request->alpha2);
mutex_lock(&cfg80211_mutex);
mutex_lock(&reg_mutex);
if (wiphy_idx_valid(reg_request->wiphy_idx))
wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);
@ -1585,6 +1596,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
if (r == -EALREADY && wiphy && wiphy->strict_regulatory)
wiphy_update_regulatory(wiphy, reg_request->initiator);
out:
mutex_unlock(&reg_mutex);
mutex_unlock(&cfg80211_mutex);
}
@ -1613,6 +1625,10 @@ static void reg_process_pending_beacon_hints(void)
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 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
}
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 @@ static bool reg_same_country_ie_hint(struct wiphy *wiphy,
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 @@ void regulatory_hint_11d(struct wiphy *wiphy,
enum environment_cap env = ENVIRON_ANY;
struct regulatory_request *request;
mutex_lock(&cfg80211_mutex);
mutex_lock(&reg_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 @@ void regulatory_hint_11d(struct wiphy *wiphy,
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 @@ void regulatory_hint_11d(struct wiphy *wiphy,
request->country_ie_checksum = checksum;
request->country_ie_env = env;
mutex_unlock(&cfg80211_mutex);
mutex_unlock(&reg_mutex);
queue_regulatory_request(request);
@ -1894,9 +1873,8 @@ void regulatory_hint_11d(struct wiphy *wiphy,
free_rd_out:
kfree(rd);
out:
mutex_unlock(&cfg80211_mutex);
mutex_unlock(&reg_mutex);
}
EXPORT_SYMBOL(regulatory_hint_11d);
static bool freq_is_chan_12_13_14(u16 freq)
{
@ -2227,10 +2205,13 @@ int set_regdom(const struct ieee80211_regdomain *rd)
assert_cfg80211_lock();
mutex_lock(&reg_mutex);
/* Note that this doesn't update the wiphys, this is done below */
r = __set_regdom(rd);
if (r) {
kfree(rd);
mutex_unlock(&reg_mutex);
return r;
}
@ -2245,6 +2226,8 @@ int set_regdom(const struct ieee80211_regdomain *rd)
nl80211_send_reg_change_event(last_request);
mutex_unlock(&reg_mutex);
return r;
}
@ -2255,16 +2238,20 @@ void reg_device_remove(struct wiphy *wiphy)
assert_cfg80211_lock();
mutex_lock(&reg_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(&reg_mutex);
}
int regulatory_init(void)
@ -2325,6 +2312,7 @@ void regulatory_exit(void)
cancel_work_sync(&reg_work);
mutex_lock(&cfg80211_mutex);
mutex_lock(&reg_mutex);
reset_regdomains();
@ -2363,5 +2351,6 @@ void regulatory_exit(void)
}
spin_unlock(&reg_requests_lock);
mutex_unlock(&reg_mutex);
mutex_unlock(&cfg80211_mutex);
}

View File

@ -36,4 +36,19 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
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 */

View File

@ -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 @@ void cfg80211_conn_work(struct work_struct *work)
wdev->conn->params.bssid,
NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
false);
false, NULL);
wdev_unlock(wdev);
}
@ -247,7 +248,7 @@ static void __cfg80211_sme_scan_done(struct net_device *dev)
wdev->conn->params.bssid,
NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
false);
false, NULL);
}
}
@ -305,7 +306,7 @@ void cfg80211_sme_rx_auth(struct net_device *dev,
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_sme_rx_auth(struct net_device *dev,
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 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
}
#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 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
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 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
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 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
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 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
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 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
wdev->conn = NULL;
wdev->sme_state = CFG80211_SME_IDLE;
wdev->connect_keys = NULL;
wdev->ssid_len = 0;
}
return err;
@ -768,6 +788,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
wdev->sme_state = CFG80211_SME_IDLE;
kfree(wdev->conn);
wdev->conn = NULL;
wdev->ssid_len = 0;
return 0;
}
@ -788,7 +809,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
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;
}

View File

@ -1291,7 +1291,6 @@ static struct pernet_operations wext_pernet_ops = {
static int __init wireless_nlevent_init(void)
{
return register_pernet_subsys(&wext_pernet_ops);
return 0;
}
subsys_initcall(wireless_nlevent_init);